| author | |
| committer | |
| log | 529ef75101e21bd45402c516138343b4770238eb |
| tree | 56c925bd7df84e5f223c31a7c8fa90606c8e2dc9 |
| parent | 1e7dcaa3ae57294ab5998b44a8c13ccc5019e7ea |
| parent | 2ad073ec6d4e2be967f18c9907844404a7eed42e |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
Use InternPool for all types and constant values76 files changed, 29849 insertions(+), 28510 deletions(-)
build.zig+2| ... | @@ -30,6 +30,7 @@ pub fn build(b: *std.Build) !void { | ... | @@ -30,6 +30,7 @@ pub fn build(b: *std.Build) !void { |
| 30 | const test_step = b.step("test", "Run all the tests"); | 30 | const test_step = b.step("test", "Run all the tests"); |
| 31 | const skip_install_lib_files = b.option(bool, "no-lib", "skip copying of lib/ files and langref to installation prefix. Useful for development") orelse false; | 31 | const skip_install_lib_files = b.option(bool, "no-lib", "skip copying of lib/ files and langref to installation prefix. Useful for development") orelse false; |
| 32 | const skip_install_langref = b.option(bool, "no-langref", "skip copying of langref to the installation prefix") orelse skip_install_lib_files; | 32 | const skip_install_langref = b.option(bool, "no-langref", "skip copying of langref to the installation prefix") orelse skip_install_lib_files; |
| 33 | const no_bin = b.option(bool, "no-bin", "skip emitting compiler binary") orelse false; | ||
| 33 | 34 | ||
| 34 | const docgen_exe = b.addExecutable(.{ | 35 | const docgen_exe = b.addExecutable(.{ |
| 35 | .name = "docgen", | 36 | .name = "docgen", |
| ... | @@ -166,6 +167,7 @@ pub fn build(b: *std.Build) !void { | ... | @@ -166,6 +167,7 @@ pub fn build(b: *std.Build) !void { |
| 166 | exe.pie = pie; | 167 | exe.pie = pie; |
| 167 | exe.sanitize_thread = sanitize_thread; | 168 | exe.sanitize_thread = sanitize_thread; |
| 168 | exe.entitlements = entitlements; | 169 | exe.entitlements = entitlements; |
| 170 | if (no_bin) exe.emit_bin = .no_emit; | ||
| 169 | 171 | ||
| 170 | exe.build_id = b.option( | 172 | exe.build_id = b.option( |
| 171 | std.Build.Step.Compile.BuildId, | 173 | std.Build.Step.Compile.BuildId, |
doc/langref.html.in+1-1| ... | @@ -10176,7 +10176,7 @@ pub fn main() void { | ... | @@ -10176,7 +10176,7 @@ pub fn main() void { |
| 10176 | 10176 | ||
| 10177 | {#header_open|Invalid Error Set Cast#} | 10177 | {#header_open|Invalid Error Set Cast#} |
| 10178 | <p>At compile-time:</p> | 10178 | <p>At compile-time:</p> |
| 10179 | {#code_begin|test_err|test_comptime_invalid_error_set_cast|'error.B' not a member of error set 'error{A,C}'#} | 10179 | {#code_begin|test_err|test_comptime_invalid_error_set_cast|'error.B' not a member of error set 'error{C,A}'#} |
| 10180 | const Set1 = error{ | 10180 | const Set1 = error{ |
| 10181 | A, | 10181 | A, |
| 10182 | B, | 10182 | B, |
lib/std/array_list.zig+44| ... | @@ -459,6 +459,28 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -459,6 +459,28 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 459 | return self.items[prev_len..][0..n]; | 459 | return self.items[prev_len..][0..n]; |
| 460 | } | 460 | } |
| 461 | 461 | ||
| 462 | /// Resize the array, adding `n` new elements, which have `undefined` values. | ||
| 463 | /// The return value is a slice pointing to the newly allocated elements. | ||
| 464 | /// The returned pointer becomes invalid when the list is resized. | ||
| 465 | /// Resizes list if `self.capacity` is not large enough. | ||
| 466 | pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T { | ||
| 467 | const prev_len = self.items.len; | ||
| 468 | try self.resize(self.items.len + n); | ||
| 469 | return self.items[prev_len..][0..n]; | ||
| 470 | } | ||
| 471 | |||
| 472 | /// Resize the array, adding `n` new elements, which have `undefined` values. | ||
| 473 | /// The return value is a slice pointing to the newly allocated elements. | ||
| 474 | /// Asserts that there is already space for the new item without allocating more. | ||
| 475 | /// **Does not** invalidate element pointers. | ||
| 476 | /// The returned pointer becomes invalid when the list is resized. | ||
| 477 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { | ||
| 478 | assert(self.items.len + n <= self.capacity); | ||
| 479 | const prev_len = self.items.len; | ||
| 480 | self.items.len += n; | ||
| 481 | return self.items[prev_len..][0..n]; | ||
| 482 | } | ||
| 483 | |||
| 462 | /// Remove and return the last element from the list. | 484 | /// Remove and return the last element from the list. |
| 463 | /// Asserts the list has at least one item. | 485 | /// Asserts the list has at least one item. |
| 464 | /// Invalidates pointers to the removed element. | 486 | /// Invalidates pointers to the removed element. |
| ... | @@ -949,6 +971,28 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -949,6 +971,28 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 949 | return self.items[prev_len..][0..n]; | 971 | return self.items[prev_len..][0..n]; |
| 950 | } | 972 | } |
| 951 | 973 | ||
| 974 | /// Resize the array, adding `n` new elements, which have `undefined` values. | ||
| 975 | /// The return value is a slice pointing to the newly allocated elements. | ||
| 976 | /// The returned pointer becomes invalid when the list is resized. | ||
| 977 | /// Resizes list if `self.capacity` is not large enough. | ||
| 978 | pub fn addManyAsSlice(self: *Self, allocator: Allocator, n: usize) Allocator.Error![]T { | ||
| 979 | const prev_len = self.items.len; | ||
| 980 | try self.resize(allocator, self.items.len + n); | ||
| 981 | return self.items[prev_len..][0..n]; | ||
| 982 | } | ||
| 983 | |||
| 984 | /// Resize the array, adding `n` new elements, which have `undefined` values. | ||
| 985 | /// The return value is a slice pointing to the newly allocated elements. | ||
| 986 | /// Asserts that there is already space for the new item without allocating more. | ||
| 987 | /// **Does not** invalidate element pointers. | ||
| 988 | /// The returned pointer becomes invalid when the list is resized. | ||
| 989 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { | ||
| 990 | assert(self.items.len + n <= self.capacity); | ||
| 991 | const prev_len = self.items.len; | ||
| 992 | self.items.len += n; | ||
| 993 | return self.items[prev_len..][0..n]; | ||
| 994 | } | ||
| 995 | |||
| 952 | /// Remove and return the last element from the list. | 996 | /// Remove and return the last element from the list. |
| 953 | /// Asserts the list has at least one item. | 997 | /// Asserts the list has at least one item. |
| 954 | /// Invalidates pointers to last element. | 998 | /// Invalidates pointers to last element. |
lib/std/builtin.zig+3-3| ... | @@ -143,7 +143,7 @@ pub const Mode = OptimizeMode; | ... | @@ -143,7 +143,7 @@ pub const Mode = OptimizeMode; |
| 143 | 143 | ||
| 144 | /// This data structure is used by the Zig language code generation and | 144 | /// This data structure is used by the Zig language code generation and |
| 145 | /// therefore must be kept in sync with the compiler implementation. | 145 | /// therefore must be kept in sync with the compiler implementation. |
| 146 | pub const CallingConvention = enum { | 146 | pub const CallingConvention = enum(u8) { |
| 147 | /// This is the default Zig calling convention used when not using `export` on `fn` | 147 | /// This is the default Zig calling convention used when not using `export` on `fn` |
| 148 | /// and no other calling convention is specified. | 148 | /// and no other calling convention is specified. |
| 149 | Unspecified, | 149 | Unspecified, |
| ... | @@ -190,7 +190,7 @@ pub const CallingConvention = enum { | ... | @@ -190,7 +190,7 @@ pub const CallingConvention = enum { |
| 190 | 190 | ||
| 191 | /// This data structure is used by the Zig language code generation and | 191 | /// This data structure is used by the Zig language code generation and |
| 192 | /// therefore must be kept in sync with the compiler implementation. | 192 | /// therefore must be kept in sync with the compiler implementation. |
| 193 | pub const AddressSpace = enum { | 193 | pub const AddressSpace = enum(u5) { |
| 194 | generic, | 194 | generic, |
| 195 | gs, | 195 | gs, |
| 196 | fs, | 196 | fs, |
| ... | @@ -283,7 +283,7 @@ pub const Type = union(enum) { | ... | @@ -283,7 +283,7 @@ pub const Type = union(enum) { |
| 283 | 283 | ||
| 284 | /// This data structure is used by the Zig language code generation and | 284 | /// This data structure is used by the Zig language code generation and |
| 285 | /// therefore must be kept in sync with the compiler implementation. | 285 | /// therefore must be kept in sync with the compiler implementation. |
| 286 | pub const Size = enum { | 286 | pub const Size = enum(u2) { |
| 287 | One, | 287 | One, |
| 288 | Many, | 288 | Many, |
| 289 | Slice, | 289 | Slice, |
lib/std/child_process.zig+2-2| ... | @@ -530,7 +530,7 @@ pub const ChildProcess = struct { | ... | @@ -530,7 +530,7 @@ pub const ChildProcess = struct { |
| 530 | // can fail between fork() and execve(). | 530 | // can fail between fork() and execve(). |
| 531 | // Therefore, we do all the allocation for the execve() before the fork(). | 531 | // Therefore, we do all the allocation for the execve() before the fork(). |
| 532 | // This means we must do the null-termination of argv and env vars here. | 532 | // This means we must do the null-termination of argv and env vars here. |
| 533 | const argv_buf = try arena.allocSentinel(?[*:0]u8, self.argv.len, null); | 533 | const argv_buf = try arena.allocSentinel(?[*:0]const u8, self.argv.len, null); |
| 534 | for (self.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr; | 534 | for (self.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr; |
| 535 | 535 | ||
| 536 | const envp = m: { | 536 | const envp = m: { |
| ... | @@ -542,7 +542,7 @@ pub const ChildProcess = struct { | ... | @@ -542,7 +542,7 @@ pub const ChildProcess = struct { |
| 542 | } else if (builtin.output_mode == .Exe) { | 542 | } else if (builtin.output_mode == .Exe) { |
| 543 | // Then we have Zig start code and this works. | 543 | // Then we have Zig start code and this works. |
| 544 | // TODO type-safety for null-termination of `os.environ`. | 544 | // TODO type-safety for null-termination of `os.environ`. |
| 545 | break :m @ptrCast([*:null]?[*:0]u8, os.environ.ptr); | 545 | break :m @ptrCast([*:null]const ?[*:0]const u8, os.environ.ptr); |
| 546 | } else { | 546 | } else { |
| 547 | // TODO come up with a solution for this. | 547 | // TODO come up with a solution for this. |
| 548 | @compileError("missing std lib enhancement: ChildProcess implementation has no way to collect the environment variables to forward to the child process"); | 548 | @compileError("missing std lib enhancement: ChildProcess implementation has no way to collect the environment variables to forward to the child process"); |
lib/std/crypto/tls/Client.zig+2-4| ... | @@ -1256,10 +1256,8 @@ fn limitedOverlapCopy(frag: []u8, in: usize) void { | ... | @@ -1256,10 +1256,8 @@ fn limitedOverlapCopy(frag: []u8, in: usize) void { |
| 1256 | // A single, non-overlapping memcpy suffices. | 1256 | // A single, non-overlapping memcpy suffices. |
| 1257 | @memcpy(frag[0..first.len], first); | 1257 | @memcpy(frag[0..first.len], first); |
| 1258 | } else { | 1258 | } else { |
| 1259 | // Need two memcpy calls because one alone would overlap. | 1259 | // One memcpy call would overlap, so just do this instead. |
| 1260 | @memcpy(frag[0..in], first[0..in]); | 1260 | std.mem.copyForwards(u8, frag, first); |
| 1261 | const leftover = first.len - in; | ||
| 1262 | @memcpy(frag[in..][0..leftover], first[in..][0..leftover]); | ||
| 1263 | } | 1261 | } |
| 1264 | } | 1262 | } |
| 1265 | 1263 |
lib/std/dwarf.zig+1| ... | @@ -936,6 +936,7 @@ pub const DwarfInfo = struct { | ... | @@ -936,6 +936,7 @@ pub const DwarfInfo = struct { |
| 936 | const ranges_val = compile_unit.die.getAttr(AT.ranges) orelse continue; | 936 | const ranges_val = compile_unit.die.getAttr(AT.ranges) orelse continue; |
| 937 | const ranges_offset = switch (ranges_val.*) { | 937 | const ranges_offset = switch (ranges_val.*) { |
| 938 | .SecOffset => |off| off, | 938 | .SecOffset => |off| off, |
| 939 | .Const => |c| try c.asUnsignedLe(), | ||
| 939 | .RangeListOffset => |idx| off: { | 940 | .RangeListOffset => |idx| off: { |
| 940 | if (compile_unit.is_64) { | 941 | if (compile_unit.is_64) { |
| 941 | const offset_loc = @intCast(usize, compile_unit.rnglists_base + 8 * idx); | 942 | const offset_loc = @intCast(usize, compile_unit.rnglists_base + 8 * idx); |
lib/std/hash.zig+14| ... | @@ -36,6 +36,20 @@ const xxhash = @import("hash/xxhash.zig"); | ... | @@ -36,6 +36,20 @@ const xxhash = @import("hash/xxhash.zig"); |
| 36 | pub const XxHash64 = xxhash.XxHash64; | 36 | pub const XxHash64 = xxhash.XxHash64; |
| 37 | pub const XxHash32 = xxhash.XxHash32; | 37 | pub const XxHash32 = xxhash.XxHash32; |
| 38 | 38 | ||
| 39 | /// This is handy if you have a u32 and want a u32 and don't want to take a | ||
| 40 | /// detour through many layers of abstraction elsewhere in the std.hash | ||
| 41 | /// namespace. | ||
| 42 | /// Copied from https://nullprogram.com/blog/2018/07/31/ | ||
| 43 | pub fn uint32(input: u32) u32 { | ||
| 44 | var x: u32 = input; | ||
| 45 | x ^= x >> 16; | ||
| 46 | x *%= 0x7feb352d; | ||
| 47 | x ^= x >> 15; | ||
| 48 | x *%= 0x846ca68b; | ||
| 49 | x ^= x >> 16; | ||
| 50 | return x; | ||
| 51 | } | ||
| 52 | |||
| 39 | test { | 53 | test { |
| 40 | _ = adler; | 54 | _ = adler; |
| 41 | _ = auto_hash; | 55 | _ = auto_hash; |
lib/std/hash/auto_hash.zig+15-9| ... | @@ -91,15 +91,21 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { | ... | @@ -91,15 +91,21 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 91 | 91 | ||
| 92 | // Help the optimizer see that hashing an int is easy by inlining! | 92 | // Help the optimizer see that hashing an int is easy by inlining! |
| 93 | // TODO Check if the situation is better after #561 is resolved. | 93 | // TODO Check if the situation is better after #561 is resolved. |
| 94 | .Int => { | 94 | .Int => |int| switch (int.signedness) { |
| 95 | if (comptime meta.trait.hasUniqueRepresentation(Key)) { | 95 | .signed => hash(hasher, @bitCast(@Type(.{ .Int = .{ |
| 96 | @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key) }); | 96 | .bits = int.bits, |
| 97 | } else { | 97 | .signedness = .unsigned, |
| 98 | // Take only the part containing the key value, the remaining | 98 | } }), key), strat), |
| 99 | // bytes are undefined and must not be hashed! | 99 | .unsigned => { |
| 100 | const byte_size = comptime std.math.divCeil(comptime_int, @bitSizeOf(Key), 8) catch unreachable; | 100 | if (comptime meta.trait.hasUniqueRepresentation(Key)) { |
| 101 | @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key)[0..byte_size] }); | 101 | @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key) }); |
| 102 | } | 102 | } else { |
| 103 | // Take only the part containing the key value, the remaining | ||
| 104 | // bytes are undefined and must not be hashed! | ||
| 105 | const byte_size = comptime std.math.divCeil(comptime_int, @bitSizeOf(Key), 8) catch unreachable; | ||
| 106 | @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key)[0..byte_size] }); | ||
| 107 | } | ||
| 108 | }, | ||
| 103 | }, | 109 | }, |
| 104 | 110 | ||
| 105 | .Bool => hash(hasher, @boolToInt(key), strat), | 111 | .Bool => hash(hasher, @boolToInt(key), strat), |
lib/std/math/big/int.zig+5-2| ... | @@ -2158,6 +2158,9 @@ pub const Const = struct { | ... | @@ -2158,6 +2158,9 @@ pub const Const = struct { |
| 2158 | pub fn to(self: Const, comptime T: type) ConvertError!T { | 2158 | pub fn to(self: Const, comptime T: type) ConvertError!T { |
| 2159 | switch (@typeInfo(T)) { | 2159 | switch (@typeInfo(T)) { |
| 2160 | .Int => |info| { | 2160 | .Int => |info| { |
| 2161 | // Make sure -0 is handled correctly. | ||
| 2162 | if (self.eqZero()) return 0; | ||
| 2163 | |||
| 2161 | const UT = std.meta.Int(.unsigned, info.bits); | 2164 | const UT = std.meta.Int(.unsigned, info.bits); |
| 2162 | 2165 | ||
| 2163 | if (!self.fitsInTwosComp(info.signedness, info.bits)) { | 2166 | if (!self.fitsInTwosComp(info.signedness, info.bits)) { |
| ... | @@ -2509,7 +2512,7 @@ pub const Const = struct { | ... | @@ -2509,7 +2512,7 @@ pub const Const = struct { |
| 2509 | return total_limb_lz + bits - total_limb_bits; | 2512 | return total_limb_lz + bits - total_limb_bits; |
| 2510 | } | 2513 | } |
| 2511 | 2514 | ||
| 2512 | pub fn ctz(a: Const) Limb { | 2515 | pub fn ctz(a: Const, bits: Limb) Limb { |
| 2513 | // Limbs are stored in little-endian order. | 2516 | // Limbs are stored in little-endian order. |
| 2514 | var result: Limb = 0; | 2517 | var result: Limb = 0; |
| 2515 | for (a.limbs) |limb| { | 2518 | for (a.limbs) |limb| { |
| ... | @@ -2517,7 +2520,7 @@ pub const Const = struct { | ... | @@ -2517,7 +2520,7 @@ pub const Const = struct { |
| 2517 | result += limb_tz; | 2520 | result += limb_tz; |
| 2518 | if (limb_tz != @sizeOf(Limb) * 8) break; | 2521 | if (limb_tz != @sizeOf(Limb) * 8) break; |
| 2519 | } | 2522 | } |
| 2520 | return result; | 2523 | return @min(result, bits); |
| 2521 | } | 2524 | } |
| 2522 | }; | 2525 | }; |
| 2523 | 2526 |
lib/std/mem.zig+2-1| ... | @@ -4226,7 +4226,8 @@ pub fn alignForwardLog2(addr: usize, log2_alignment: u8) usize { | ... | @@ -4226,7 +4226,8 @@ pub fn alignForwardLog2(addr: usize, log2_alignment: u8) usize { |
| 4226 | /// The alignment must be a power of 2 and greater than 0. | 4226 | /// The alignment must be a power of 2 and greater than 0. |
| 4227 | /// Asserts that rounding up the address does not cause integer overflow. | 4227 | /// Asserts that rounding up the address does not cause integer overflow. |
| 4228 | pub fn alignForwardGeneric(comptime T: type, addr: T, alignment: T) T { | 4228 | pub fn alignForwardGeneric(comptime T: type, addr: T, alignment: T) T { |
| 4229 | assert(isValidAlignGeneric(T, alignment)); | 4229 | assert(alignment > 0); |
| 4230 | assert(std.math.isPowerOfTwo(alignment)); | ||
| 4230 | return alignBackwardGeneric(T, addr + (alignment - 1), alignment); | 4231 | return alignBackwardGeneric(T, addr + (alignment - 1), alignment); |
| 4231 | } | 4232 | } |
| 4232 | 4233 |
lib/std/process.zig+2-2| ... | @@ -1131,7 +1131,7 @@ pub fn execve( | ... | @@ -1131,7 +1131,7 @@ pub fn execve( |
| 1131 | defer arena_allocator.deinit(); | 1131 | defer arena_allocator.deinit(); |
| 1132 | const arena = arena_allocator.allocator(); | 1132 | const arena = arena_allocator.allocator(); |
| 1133 | 1133 | ||
| 1134 | const argv_buf = try arena.allocSentinel(?[*:0]u8, argv.len, null); | 1134 | const argv_buf = try arena.allocSentinel(?[*:0]const u8, argv.len, null); |
| 1135 | for (argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr; | 1135 | for (argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr; |
| 1136 | 1136 | ||
| 1137 | const envp = m: { | 1137 | const envp = m: { |
| ... | @@ -1143,7 +1143,7 @@ pub fn execve( | ... | @@ -1143,7 +1143,7 @@ pub fn execve( |
| 1143 | } else if (builtin.output_mode == .Exe) { | 1143 | } else if (builtin.output_mode == .Exe) { |
| 1144 | // Then we have Zig start code and this works. | 1144 | // Then we have Zig start code and this works. |
| 1145 | // TODO type-safety for null-termination of `os.environ`. | 1145 | // TODO type-safety for null-termination of `os.environ`. |
| 1146 | break :m @ptrCast([*:null]?[*:0]u8, os.environ.ptr); | 1146 | break :m @ptrCast([*:null]const ?[*:0]const u8, os.environ.ptr); |
| 1147 | } else { | 1147 | } else { |
| 1148 | // TODO come up with a solution for this. | 1148 | // TODO come up with a solution for this. |
| 1149 | @compileError("missing std lib enhancement: std.process.execv implementation has no way to collect the environment variables to forward to the child process"); | 1149 | @compileError("missing std lib enhancement: std.process.execv implementation has no way to collect the environment variables to forward to the child process"); |
src/Air.zig+200-71| ... | @@ -5,16 +5,18 @@ | ... | @@ -5,16 +5,18 @@ |
| 5 | 5 | ||
| 6 | const std = @import("std"); | 6 | const std = @import("std"); |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const Value = @import("value.zig").Value; | ||
| 9 | const Type = @import("type.zig").Type; | ||
| 10 | const assert = std.debug.assert; | 8 | const assert = std.debug.assert; |
| 9 | |||
| 11 | const Air = @This(); | 10 | const Air = @This(); |
| 11 | const Value = @import("value.zig").Value; | ||
| 12 | const Type = @import("type.zig").Type; | ||
| 13 | const InternPool = @import("InternPool.zig"); | ||
| 14 | const Module = @import("Module.zig"); | ||
| 12 | 15 | ||
| 13 | instructions: std.MultiArrayList(Inst).Slice, | 16 | instructions: std.MultiArrayList(Inst).Slice, |
| 14 | /// The meaning of this data is determined by `Inst.Tag` value. | 17 | /// The meaning of this data is determined by `Inst.Tag` value. |
| 15 | /// The first few indexes are reserved. See `ExtraIndex` for the values. | 18 | /// The first few indexes are reserved. See `ExtraIndex` for the values. |
| 16 | extra: []const u32, | 19 | extra: []const u32, |
| 17 | values: []const Value, | ||
| 18 | 20 | ||
| 19 | pub const ExtraIndex = enum(u32) { | 21 | pub const ExtraIndex = enum(u32) { |
| 20 | /// Payload index of the main `Block` in the `extra` array. | 22 | /// Payload index of the main `Block` in the `extra` array. |
| ... | @@ -183,6 +185,18 @@ pub const Inst = struct { | ... | @@ -183,6 +185,18 @@ pub const Inst = struct { |
| 183 | /// Allocates stack local memory. | 185 | /// Allocates stack local memory. |
| 184 | /// Uses the `ty` field. | 186 | /// Uses the `ty` field. |
| 185 | alloc, | 187 | alloc, |
| 188 | /// This special instruction only exists temporarily during semantic | ||
| 189 | /// analysis and is guaranteed to be unreachable in machine code | ||
| 190 | /// backends. It tracks a set of types that have been stored to an | ||
| 191 | /// inferred allocation. | ||
| 192 | /// Uses the `inferred_alloc` field. | ||
| 193 | inferred_alloc, | ||
| 194 | /// This special instruction only exists temporarily during semantic | ||
| 195 | /// analysis and is guaranteed to be unreachable in machine code | ||
| 196 | /// backends. Used to coordinate alloc_inferred, store_to_inferred_ptr, | ||
| 197 | /// and resolve_inferred_alloc instructions for comptime code. | ||
| 198 | /// Uses the `inferred_alloc_comptime` field. | ||
| 199 | inferred_alloc_comptime, | ||
| 186 | /// If the function will pass the result by-ref, this instruction returns the | 200 | /// If the function will pass the result by-ref, this instruction returns the |
| 187 | /// result pointer. Otherwise it is equivalent to `alloc`. | 201 | /// result pointer. Otherwise it is equivalent to `alloc`. |
| 188 | /// Uses the `ty` field. | 202 | /// Uses the `ty` field. |
| ... | @@ -394,11 +408,9 @@ pub const Inst = struct { | ... | @@ -394,11 +408,9 @@ pub const Inst = struct { |
| 394 | /// was executed on the operand. | 408 | /// was executed on the operand. |
| 395 | /// Uses the `ty_pl` field. Payload is `TryPtr`. | 409 | /// Uses the `ty_pl` field. Payload is `TryPtr`. |
| 396 | try_ptr, | 410 | try_ptr, |
| 397 | /// A comptime-known value. Uses the `ty_pl` field, payload is index of | 411 | /// A comptime-known value via an index into the InternPool. |
| 398 | /// `values` array. | 412 | /// Uses the `interned` field. |
| 399 | constant, | 413 | interned, |
| 400 | /// A comptime-known type. Uses the `ty` field. | ||
| 401 | const_ty, | ||
| 402 | /// Notes the beginning of a source code statement and marks the line and column. | 414 | /// Notes the beginning of a source code statement and marks the line and column. |
| 403 | /// Result type is always void. | 415 | /// Result type is always void. |
| 404 | /// Uses the `dbg_stmt` field. | 416 | /// Uses the `dbg_stmt` field. |
| ... | @@ -408,10 +420,10 @@ pub const Inst = struct { | ... | @@ -408,10 +420,10 @@ pub const Inst = struct { |
| 408 | /// Marks the end of a semantic scope for debug info variables. | 420 | /// Marks the end of a semantic scope for debug info variables. |
| 409 | dbg_block_end, | 421 | dbg_block_end, |
| 410 | /// Marks the start of an inline call. | 422 | /// Marks the start of an inline call. |
| 411 | /// Uses `ty_pl` with the payload being the index of a Value.Function in air.values. | 423 | /// Uses the `ty_fn` field. |
| 412 | dbg_inline_begin, | 424 | dbg_inline_begin, |
| 413 | /// Marks the end of an inline call. | 425 | /// Marks the end of an inline call. |
| 414 | /// Uses `ty_pl` with the payload being the index of a Value.Function in air.values. | 426 | /// Uses the `ty_fn` field. |
| 415 | dbg_inline_end, | 427 | dbg_inline_end, |
| 416 | /// Marks the beginning of a local variable. The operand is a pointer pointing | 428 | /// Marks the beginning of a local variable. The operand is a pointer pointing |
| 417 | /// to the storage for the variable. The local may be a const or a var. | 429 | /// to the storage for the variable. The local may be a const or a var. |
| ... | @@ -837,7 +849,96 @@ pub const Inst = struct { | ... | @@ -837,7 +849,96 @@ pub const Inst = struct { |
| 837 | /// The position of an AIR instruction within the `Air` instructions array. | 849 | /// The position of an AIR instruction within the `Air` instructions array. |
| 838 | pub const Index = u32; | 850 | pub const Index = u32; |
| 839 | 851 | ||
| 840 | pub const Ref = @import("Zir.zig").Inst.Ref; | 852 | pub const Ref = enum(u32) { |
| 853 | u1_type = @enumToInt(InternPool.Index.u1_type), | ||
| 854 | u8_type = @enumToInt(InternPool.Index.u8_type), | ||
| 855 | i8_type = @enumToInt(InternPool.Index.i8_type), | ||
| 856 | u16_type = @enumToInt(InternPool.Index.u16_type), | ||
| 857 | i16_type = @enumToInt(InternPool.Index.i16_type), | ||
| 858 | u29_type = @enumToInt(InternPool.Index.u29_type), | ||
| 859 | u32_type = @enumToInt(InternPool.Index.u32_type), | ||
| 860 | i32_type = @enumToInt(InternPool.Index.i32_type), | ||
| 861 | u64_type = @enumToInt(InternPool.Index.u64_type), | ||
| 862 | i64_type = @enumToInt(InternPool.Index.i64_type), | ||
| 863 | u80_type = @enumToInt(InternPool.Index.u80_type), | ||
| 864 | u128_type = @enumToInt(InternPool.Index.u128_type), | ||
| 865 | i128_type = @enumToInt(InternPool.Index.i128_type), | ||
| 866 | usize_type = @enumToInt(InternPool.Index.usize_type), | ||
| 867 | isize_type = @enumToInt(InternPool.Index.isize_type), | ||
| 868 | c_char_type = @enumToInt(InternPool.Index.c_char_type), | ||
| 869 | c_short_type = @enumToInt(InternPool.Index.c_short_type), | ||
| 870 | c_ushort_type = @enumToInt(InternPool.Index.c_ushort_type), | ||
| 871 | c_int_type = @enumToInt(InternPool.Index.c_int_type), | ||
| 872 | c_uint_type = @enumToInt(InternPool.Index.c_uint_type), | ||
| 873 | c_long_type = @enumToInt(InternPool.Index.c_long_type), | ||
| 874 | c_ulong_type = @enumToInt(InternPool.Index.c_ulong_type), | ||
| 875 | c_longlong_type = @enumToInt(InternPool.Index.c_longlong_type), | ||
| 876 | c_ulonglong_type = @enumToInt(InternPool.Index.c_ulonglong_type), | ||
| 877 | c_longdouble_type = @enumToInt(InternPool.Index.c_longdouble_type), | ||
| 878 | f16_type = @enumToInt(InternPool.Index.f16_type), | ||
| 879 | f32_type = @enumToInt(InternPool.Index.f32_type), | ||
| 880 | f64_type = @enumToInt(InternPool.Index.f64_type), | ||
| 881 | f80_type = @enumToInt(InternPool.Index.f80_type), | ||
| 882 | f128_type = @enumToInt(InternPool.Index.f128_type), | ||
| 883 | anyopaque_type = @enumToInt(InternPool.Index.anyopaque_type), | ||
| 884 | bool_type = @enumToInt(InternPool.Index.bool_type), | ||
| 885 | void_type = @enumToInt(InternPool.Index.void_type), | ||
| 886 | type_type = @enumToInt(InternPool.Index.type_type), | ||
| 887 | anyerror_type = @enumToInt(InternPool.Index.anyerror_type), | ||
| 888 | comptime_int_type = @enumToInt(InternPool.Index.comptime_int_type), | ||
| 889 | comptime_float_type = @enumToInt(InternPool.Index.comptime_float_type), | ||
| 890 | noreturn_type = @enumToInt(InternPool.Index.noreturn_type), | ||
| 891 | anyframe_type = @enumToInt(InternPool.Index.anyframe_type), | ||
| 892 | null_type = @enumToInt(InternPool.Index.null_type), | ||
| 893 | undefined_type = @enumToInt(InternPool.Index.undefined_type), | ||
| 894 | enum_literal_type = @enumToInt(InternPool.Index.enum_literal_type), | ||
| 895 | atomic_order_type = @enumToInt(InternPool.Index.atomic_order_type), | ||
| 896 | atomic_rmw_op_type = @enumToInt(InternPool.Index.atomic_rmw_op_type), | ||
| 897 | calling_convention_type = @enumToInt(InternPool.Index.calling_convention_type), | ||
| 898 | address_space_type = @enumToInt(InternPool.Index.address_space_type), | ||
| 899 | float_mode_type = @enumToInt(InternPool.Index.float_mode_type), | ||
| 900 | reduce_op_type = @enumToInt(InternPool.Index.reduce_op_type), | ||
| 901 | call_modifier_type = @enumToInt(InternPool.Index.call_modifier_type), | ||
| 902 | prefetch_options_type = @enumToInt(InternPool.Index.prefetch_options_type), | ||
| 903 | export_options_type = @enumToInt(InternPool.Index.export_options_type), | ||
| 904 | extern_options_type = @enumToInt(InternPool.Index.extern_options_type), | ||
| 905 | type_info_type = @enumToInt(InternPool.Index.type_info_type), | ||
| 906 | manyptr_u8_type = @enumToInt(InternPool.Index.manyptr_u8_type), | ||
| 907 | manyptr_const_u8_type = @enumToInt(InternPool.Index.manyptr_const_u8_type), | ||
| 908 | manyptr_const_u8_sentinel_0_type = @enumToInt(InternPool.Index.manyptr_const_u8_sentinel_0_type), | ||
| 909 | single_const_pointer_to_comptime_int_type = @enumToInt(InternPool.Index.single_const_pointer_to_comptime_int_type), | ||
| 910 | slice_const_u8_type = @enumToInt(InternPool.Index.slice_const_u8_type), | ||
| 911 | slice_const_u8_sentinel_0_type = @enumToInt(InternPool.Index.slice_const_u8_sentinel_0_type), | ||
| 912 | anyerror_void_error_union_type = @enumToInt(InternPool.Index.anyerror_void_error_union_type), | ||
| 913 | generic_poison_type = @enumToInt(InternPool.Index.generic_poison_type), | ||
| 914 | empty_struct_type = @enumToInt(InternPool.Index.empty_struct_type), | ||
| 915 | undef = @enumToInt(InternPool.Index.undef), | ||
| 916 | zero = @enumToInt(InternPool.Index.zero), | ||
| 917 | zero_usize = @enumToInt(InternPool.Index.zero_usize), | ||
| 918 | zero_u8 = @enumToInt(InternPool.Index.zero_u8), | ||
| 919 | one = @enumToInt(InternPool.Index.one), | ||
| 920 | one_usize = @enumToInt(InternPool.Index.one_usize), | ||
| 921 | one_u8 = @enumToInt(InternPool.Index.one_u8), | ||
| 922 | four_u8 = @enumToInt(InternPool.Index.four_u8), | ||
| 923 | negative_one = @enumToInt(InternPool.Index.negative_one), | ||
| 924 | calling_convention_c = @enumToInt(InternPool.Index.calling_convention_c), | ||
| 925 | calling_convention_inline = @enumToInt(InternPool.Index.calling_convention_inline), | ||
| 926 | void_value = @enumToInt(InternPool.Index.void_value), | ||
| 927 | unreachable_value = @enumToInt(InternPool.Index.unreachable_value), | ||
| 928 | null_value = @enumToInt(InternPool.Index.null_value), | ||
| 929 | bool_true = @enumToInt(InternPool.Index.bool_true), | ||
| 930 | bool_false = @enumToInt(InternPool.Index.bool_false), | ||
| 931 | empty_struct = @enumToInt(InternPool.Index.empty_struct), | ||
| 932 | generic_poison = @enumToInt(InternPool.Index.generic_poison), | ||
| 933 | |||
| 934 | /// This Ref does not correspond to any AIR instruction or constant | ||
| 935 | /// value. It is used to handle argument types of var args functions. | ||
| 936 | var_args_param_type = @enumToInt(InternPool.Index.var_args_param_type), | ||
| 937 | /// This Ref does not correspond to any AIR instruction or constant | ||
| 938 | /// value and may instead be used as a sentinel to indicate null. | ||
| 939 | none = @enumToInt(InternPool.Index.none), | ||
| 940 | _, | ||
| 941 | }; | ||
| 841 | 942 | ||
| 842 | /// All instructions have an 8-byte payload, which is contained within | 943 | /// All instructions have an 8-byte payload, which is contained within |
| 843 | /// this union. `Tag` determines which union field is active, as well as | 944 | /// this union. `Tag` determines which union field is active, as well as |
| ... | @@ -845,6 +946,7 @@ pub const Inst = struct { | ... | @@ -845,6 +946,7 @@ pub const Inst = struct { |
| 845 | pub const Data = union { | 946 | pub const Data = union { |
| 846 | no_op: void, | 947 | no_op: void, |
| 847 | un_op: Ref, | 948 | un_op: Ref, |
| 949 | interned: InternPool.Index, | ||
| 848 | 950 | ||
| 849 | bin_op: struct { | 951 | bin_op: struct { |
| 850 | lhs: Ref, | 952 | lhs: Ref, |
| ... | @@ -864,6 +966,10 @@ pub const Inst = struct { | ... | @@ -864,6 +966,10 @@ pub const Inst = struct { |
| 864 | // Index into a different array. | 966 | // Index into a different array. |
| 865 | payload: u32, | 967 | payload: u32, |
| 866 | }, | 968 | }, |
| 969 | ty_fn: struct { | ||
| 970 | ty: Ref, | ||
| 971 | func: Module.Fn.Index, | ||
| 972 | }, | ||
| 867 | br: struct { | 973 | br: struct { |
| 868 | block_inst: Index, | 974 | block_inst: Index, |
| 869 | operand: Ref, | 975 | operand: Ref, |
| ... | @@ -896,6 +1002,19 @@ pub const Inst = struct { | ... | @@ -896,6 +1002,19 @@ pub const Inst = struct { |
| 896 | // Index into a different array. | 1002 | // Index into a different array. |
| 897 | payload: u32, | 1003 | payload: u32, |
| 898 | }, | 1004 | }, |
| 1005 | inferred_alloc_comptime: InferredAllocComptime, | ||
| 1006 | inferred_alloc: InferredAlloc, | ||
| 1007 | |||
| 1008 | pub const InferredAllocComptime = struct { | ||
| 1009 | decl_index: Module.Decl.Index, | ||
| 1010 | alignment: InternPool.Alignment, | ||
| 1011 | is_const: bool, | ||
| 1012 | }; | ||
| 1013 | |||
| 1014 | pub const InferredAlloc = struct { | ||
| 1015 | alignment: InternPool.Alignment, | ||
| 1016 | is_const: bool, | ||
| 1017 | }; | ||
| 899 | 1018 | ||
| 900 | // Make sure we don't accidentally add a field to make this union | 1019 | // Make sure we don't accidentally add a field to make this union |
| 901 | // bigger than expected. Note that in Debug builds, Zig is allowed | 1020 | // bigger than expected. Note that in Debug builds, Zig is allowed |
| ... | @@ -974,8 +1093,7 @@ pub const FieldParentPtr = struct { | ... | @@ -974,8 +1093,7 @@ pub const FieldParentPtr = struct { |
| 974 | pub const Shuffle = struct { | 1093 | pub const Shuffle = struct { |
| 975 | a: Inst.Ref, | 1094 | a: Inst.Ref, |
| 976 | b: Inst.Ref, | 1095 | b: Inst.Ref, |
| 977 | // index to air_values | 1096 | mask: InternPool.Index, |
| 978 | mask: u32, | ||
| 979 | mask_len: u32, | 1097 | mask_len: u32, |
| 980 | }; | 1098 | }; |
| 981 | 1099 | ||
| ... | @@ -1064,15 +1182,15 @@ pub fn getMainBody(air: Air) []const Air.Inst.Index { | ... | @@ -1064,15 +1182,15 @@ pub fn getMainBody(air: Air) []const Air.Inst.Index { |
| 1064 | return air.extra[extra.end..][0..extra.data.body_len]; | 1182 | return air.extra[extra.end..][0..extra.data.body_len]; |
| 1065 | } | 1183 | } |
| 1066 | 1184 | ||
| 1067 | pub fn typeOf(air: Air, inst: Air.Inst.Ref) Type { | 1185 | pub fn typeOf(air: Air, inst: Air.Inst.Ref, ip: *const InternPool) Type { |
| 1068 | const ref_int = @enumToInt(inst); | 1186 | const ref_int = @enumToInt(inst); |
| 1069 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | 1187 | if (ref_int < InternPool.static_keys.len) { |
| 1070 | return Air.Inst.Ref.typed_value_map[ref_int].ty; | 1188 | return InternPool.static_keys[ref_int].typeOf().toType(); |
| 1071 | } | 1189 | } |
| 1072 | return air.typeOfIndex(@intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len)); | 1190 | return air.typeOfIndex(ref_int - ref_start_index, ip); |
| 1073 | } | 1191 | } |
| 1074 | 1192 | ||
| 1075 | pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | 1193 | pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: *const InternPool) Type { |
| 1076 | const datas = air.instructions.items(.data); | 1194 | const datas = air.instructions.items(.data); |
| 1077 | switch (air.instructions.items(.tag)[inst]) { | 1195 | switch (air.instructions.items(.tag)[inst]) { |
| 1078 | .add, | 1196 | .add, |
| ... | @@ -1114,7 +1232,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1114,7 +1232,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1114 | .div_exact_optimized, | 1232 | .div_exact_optimized, |
| 1115 | .rem_optimized, | 1233 | .rem_optimized, |
| 1116 | .mod_optimized, | 1234 | .mod_optimized, |
| 1117 | => return air.typeOf(datas[inst].bin_op.lhs), | 1235 | => return air.typeOf(datas[inst].bin_op.lhs, ip), |
| 1118 | 1236 | ||
| 1119 | .sqrt, | 1237 | .sqrt, |
| 1120 | .sin, | 1238 | .sin, |
| ... | @@ -1132,7 +1250,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1132,7 +1250,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1132 | .trunc_float, | 1250 | .trunc_float, |
| 1133 | .neg, | 1251 | .neg, |
| 1134 | .neg_optimized, | 1252 | .neg_optimized, |
| 1135 | => return air.typeOf(datas[inst].un_op), | 1253 | => return air.typeOf(datas[inst].un_op, ip), |
| 1136 | 1254 | ||
| 1137 | .cmp_lt, | 1255 | .cmp_lt, |
| 1138 | .cmp_lte, | 1256 | .cmp_lte, |
| ... | @@ -1159,8 +1277,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1159,8 +1277,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1159 | .error_set_has_value, | 1277 | .error_set_has_value, |
| 1160 | => return Type.bool, | 1278 | => return Type.bool, |
| 1161 | 1279 | ||
| 1162 | .const_ty => return Type.type, | ||
| 1163 | |||
| 1164 | .alloc, | 1280 | .alloc, |
| 1165 | .ret_ptr, | 1281 | .ret_ptr, |
| 1166 | .err_return_trace, | 1282 | .err_return_trace, |
| ... | @@ -1171,7 +1287,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1171,7 +1287,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1171 | 1287 | ||
| 1172 | .assembly, | 1288 | .assembly, |
| 1173 | .block, | 1289 | .block, |
| 1174 | .constant, | ||
| 1175 | .struct_field_ptr, | 1290 | .struct_field_ptr, |
| 1176 | .struct_field_val, | 1291 | .struct_field_val, |
| 1177 | .slice_elem_ptr, | 1292 | .slice_elem_ptr, |
| ... | @@ -1194,6 +1309,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1194,6 +1309,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1194 | .try_ptr, | 1309 | .try_ptr, |
| 1195 | => return air.getRefType(datas[inst].ty_pl.ty), | 1310 | => return air.getRefType(datas[inst].ty_pl.ty), |
| 1196 | 1311 | ||
| 1312 | .interned => return ip.typeOf(datas[inst].interned).toType(), | ||
| 1313 | |||
| 1197 | .not, | 1314 | .not, |
| 1198 | .bitcast, | 1315 | .bitcast, |
| 1199 | .load, | 1316 | .load, |
| ... | @@ -1243,7 +1360,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1243,7 +1360,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1243 | .ret_load, | 1360 | .ret_load, |
| 1244 | .unreach, | 1361 | .unreach, |
| 1245 | .trap, | 1362 | .trap, |
| 1246 | => return Type.initTag(.noreturn), | 1363 | => return Type.noreturn, |
| 1247 | 1364 | ||
| 1248 | .breakpoint, | 1365 | .breakpoint, |
| 1249 | .dbg_stmt, | 1366 | .dbg_stmt, |
| ... | @@ -1280,63 +1397,67 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -1280,63 +1397,67 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 1280 | .wasm_memory_grow => return Type.i32, | 1397 | .wasm_memory_grow => return Type.i32, |
| 1281 | .wasm_memory_size => return Type.u32, | 1398 | .wasm_memory_size => return Type.u32, |
| 1282 | 1399 | ||
| 1283 | .bool_to_int => return Type.initTag(.u1), | 1400 | .bool_to_int => return Type.u1, |
| 1284 | 1401 | ||
| 1285 | .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0), | 1402 | .tag_name, .error_name => return Type.slice_const_u8_sentinel_0, |
| 1286 | 1403 | ||
| 1287 | .call, .call_always_tail, .call_never_tail, .call_never_inline => { | 1404 | .call, .call_always_tail, .call_never_tail, .call_never_inline => { |
| 1288 | const callee_ty = air.typeOf(datas[inst].pl_op.operand); | 1405 | const callee_ty = air.typeOf(datas[inst].pl_op.operand, ip); |
| 1289 | switch (callee_ty.zigTypeTag()) { | 1406 | return callee_ty.fnReturnTypeIp(ip); |
| 1290 | .Fn => return callee_ty.fnReturnType(), | ||
| 1291 | .Pointer => return callee_ty.childType().fnReturnType(), | ||
| 1292 | else => unreachable, | ||
| 1293 | } | ||
| 1294 | }, | 1407 | }, |
| 1295 | 1408 | ||
| 1296 | .slice_elem_val, .ptr_elem_val, .array_elem_val => { | 1409 | .slice_elem_val, .ptr_elem_val, .array_elem_val => { |
| 1297 | const ptr_ty = air.typeOf(datas[inst].bin_op.lhs); | 1410 | const ptr_ty = air.typeOf(datas[inst].bin_op.lhs, ip); |
| 1298 | return ptr_ty.elemType(); | 1411 | return ptr_ty.childTypeIp(ip); |
| 1299 | }, | 1412 | }, |
| 1300 | .atomic_load => { | 1413 | .atomic_load => { |
| 1301 | const ptr_ty = air.typeOf(datas[inst].atomic_load.ptr); | 1414 | const ptr_ty = air.typeOf(datas[inst].atomic_load.ptr, ip); |
| 1302 | return ptr_ty.elemType(); | 1415 | return ptr_ty.childTypeIp(ip); |
| 1303 | }, | 1416 | }, |
| 1304 | .atomic_rmw => { | 1417 | .atomic_rmw => { |
| 1305 | const ptr_ty = air.typeOf(datas[inst].pl_op.operand); | 1418 | const ptr_ty = air.typeOf(datas[inst].pl_op.operand, ip); |
| 1306 | return ptr_ty.elemType(); | 1419 | return ptr_ty.childTypeIp(ip); |
| 1307 | }, | 1420 | }, |
| 1308 | 1421 | ||
| 1309 | .reduce, .reduce_optimized => return air.typeOf(datas[inst].reduce.operand).childType(), | 1422 | .reduce, .reduce_optimized => { |
| 1423 | const operand_ty = air.typeOf(datas[inst].reduce.operand, ip); | ||
| 1424 | return ip.indexToKey(operand_ty.ip_index).vector_type.child.toType(); | ||
| 1425 | }, | ||
| 1310 | 1426 | ||
| 1311 | .mul_add => return air.typeOf(datas[inst].pl_op.operand), | 1427 | .mul_add => return air.typeOf(datas[inst].pl_op.operand, ip), |
| 1312 | .select => { | 1428 | .select => { |
| 1313 | const extra = air.extraData(Air.Bin, datas[inst].pl_op.payload).data; | 1429 | const extra = air.extraData(Air.Bin, datas[inst].pl_op.payload).data; |
| 1314 | return air.typeOf(extra.lhs); | 1430 | return air.typeOf(extra.lhs, ip); |
| 1315 | }, | 1431 | }, |
| 1316 | 1432 | ||
| 1317 | .@"try" => { | 1433 | .@"try" => { |
| 1318 | const err_union_ty = air.typeOf(datas[inst].pl_op.operand); | 1434 | const err_union_ty = air.typeOf(datas[inst].pl_op.operand, ip); |
| 1319 | return err_union_ty.errorUnionPayload(); | 1435 | return ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type.toType(); |
| 1320 | }, | 1436 | }, |
| 1321 | 1437 | ||
| 1322 | .work_item_id, | 1438 | .work_item_id, |
| 1323 | .work_group_size, | 1439 | .work_group_size, |
| 1324 | .work_group_id, | 1440 | .work_group_id, |
| 1325 | => return Type.u32, | 1441 | => return Type.u32, |
| 1442 | |||
| 1443 | .inferred_alloc => unreachable, | ||
| 1444 | .inferred_alloc_comptime => unreachable, | ||
| 1326 | } | 1445 | } |
| 1327 | } | 1446 | } |
| 1328 | 1447 | ||
| 1329 | pub fn getRefType(air: Air, ref: Air.Inst.Ref) Type { | 1448 | pub fn getRefType(air: Air, ref: Air.Inst.Ref) Type { |
| 1330 | const ref_int = @enumToInt(ref); | 1449 | const ref_int = @enumToInt(ref); |
| 1331 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | 1450 | if (ref_int < ref_start_index) { |
| 1332 | var buffer: Value.ToTypeBuffer = undefined; | 1451 | const ip_index = @intToEnum(InternPool.Index, ref_int); |
| 1333 | return Air.Inst.Ref.typed_value_map[ref_int].val.toType(&buffer); | 1452 | return ip_index.toType(); |
| 1334 | } | 1453 | } |
| 1335 | const inst_index = ref_int - Air.Inst.Ref.typed_value_map.len; | 1454 | const inst_index = ref_int - ref_start_index; |
| 1336 | const air_tags = air.instructions.items(.tag); | 1455 | const air_tags = air.instructions.items(.tag); |
| 1337 | const air_datas = air.instructions.items(.data); | 1456 | const air_datas = air.instructions.items(.data); |
| 1338 | assert(air_tags[inst_index] == .const_ty); | 1457 | return switch (air_tags[inst_index]) { |
| 1339 | return air_datas[inst_index].ty; | 1458 | .interned => air_datas[inst_index].interned.toType(), |
| 1459 | else => unreachable, | ||
| 1460 | }; | ||
| 1340 | } | 1461 | } |
| 1341 | 1462 | ||
| 1342 | /// Returns the requested data, as well as the new index which is at the start of the | 1463 | /// Returns the requested data, as well as the new index which is at the start of the |
| ... | @@ -1350,7 +1471,8 @@ pub fn extraData(air: Air, comptime T: type, index: usize) struct { data: T, end | ... | @@ -1350,7 +1471,8 @@ pub fn extraData(air: Air, comptime T: type, index: usize) struct { data: T, end |
| 1350 | u32 => air.extra[i], | 1471 | u32 => air.extra[i], |
| 1351 | Inst.Ref => @intToEnum(Inst.Ref, air.extra[i]), | 1472 | Inst.Ref => @intToEnum(Inst.Ref, air.extra[i]), |
| 1352 | i32 => @bitCast(i32, air.extra[i]), | 1473 | i32 => @bitCast(i32, air.extra[i]), |
| 1353 | else => @compileError("bad field type"), | 1474 | InternPool.Index => @intToEnum(InternPool.Index, air.extra[i]), |
| 1475 | else => @compileError("bad field type: " ++ @typeName(field.type)), | ||
| 1354 | }; | 1476 | }; |
| 1355 | i += 1; | 1477 | i += 1; |
| 1356 | } | 1478 | } |
| ... | @@ -1363,17 +1485,17 @@ pub fn extraData(air: Air, comptime T: type, index: usize) struct { data: T, end | ... | @@ -1363,17 +1485,17 @@ pub fn extraData(air: Air, comptime T: type, index: usize) struct { data: T, end |
| 1363 | pub fn deinit(air: *Air, gpa: std.mem.Allocator) void { | 1485 | pub fn deinit(air: *Air, gpa: std.mem.Allocator) void { |
| 1364 | air.instructions.deinit(gpa); | 1486 | air.instructions.deinit(gpa); |
| 1365 | gpa.free(air.extra); | 1487 | gpa.free(air.extra); |
| 1366 | gpa.free(air.values); | ||
| 1367 | air.* = undefined; | 1488 | air.* = undefined; |
| 1368 | } | 1489 | } |
| 1369 | 1490 | ||
| 1370 | const ref_start_index: u32 = Air.Inst.Ref.typed_value_map.len; | 1491 | pub const ref_start_index: u32 = InternPool.static_len; |
| 1371 | 1492 | ||
| 1372 | pub fn indexToRef(inst: Air.Inst.Index) Air.Inst.Ref { | 1493 | pub fn indexToRef(inst: Inst.Index) Inst.Ref { |
| 1373 | return @intToEnum(Air.Inst.Ref, ref_start_index + inst); | 1494 | return @intToEnum(Inst.Ref, ref_start_index + inst); |
| 1374 | } | 1495 | } |
| 1375 | 1496 | ||
| 1376 | pub fn refToIndex(inst: Air.Inst.Ref) ?Air.Inst.Index { | 1497 | pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { |
| 1498 | assert(inst != .none); | ||
| 1377 | const ref_int = @enumToInt(inst); | 1499 | const ref_int = @enumToInt(inst); |
| 1378 | if (ref_int >= ref_start_index) { | 1500 | if (ref_int >= ref_start_index) { |
| 1379 | return ref_int - ref_start_index; | 1501 | return ref_int - ref_start_index; |
| ... | @@ -1382,18 +1504,23 @@ pub fn refToIndex(inst: Air.Inst.Ref) ?Air.Inst.Index { | ... | @@ -1382,18 +1504,23 @@ pub fn refToIndex(inst: Air.Inst.Ref) ?Air.Inst.Index { |
| 1382 | } | 1504 | } |
| 1383 | } | 1505 | } |
| 1384 | 1506 | ||
| 1507 | pub fn refToIndexAllowNone(inst: Inst.Ref) ?Inst.Index { | ||
| 1508 | if (inst == .none) return null; | ||
| 1509 | return refToIndex(inst); | ||
| 1510 | } | ||
| 1511 | |||
| 1385 | /// Returns `null` if runtime-known. | 1512 | /// Returns `null` if runtime-known. |
| 1386 | pub fn value(air: Air, inst: Air.Inst.Ref) ?Value { | 1513 | pub fn value(air: Air, inst: Inst.Ref, mod: *Module) !?Value { |
| 1387 | const ref_int = @enumToInt(inst); | 1514 | const ref_int = @enumToInt(inst); |
| 1388 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | 1515 | if (ref_int < ref_start_index) { |
| 1389 | return Air.Inst.Ref.typed_value_map[ref_int].val; | 1516 | const ip_index = @intToEnum(InternPool.Index, ref_int); |
| 1517 | return ip_index.toValue(); | ||
| 1390 | } | 1518 | } |
| 1391 | const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); | 1519 | const inst_index = @intCast(Air.Inst.Index, ref_int - ref_start_index); |
| 1392 | const air_datas = air.instructions.items(.data); | 1520 | const air_datas = air.instructions.items(.data); |
| 1393 | switch (air.instructions.items(.tag)[inst_index]) { | 1521 | switch (air.instructions.items(.tag)[inst_index]) { |
| 1394 | .constant => return air.values[air_datas[inst_index].ty_pl.payload], | 1522 | .interned => return air_datas[inst_index].interned.toValue(), |
| 1395 | .const_ty => unreachable, | 1523 | else => return air.typeOfIndex(inst_index, &mod.intern_pool).onePossibleValue(mod), |
| 1396 | else => return air.typeOfIndex(inst_index).onePossibleValue(), | ||
| 1397 | } | 1524 | } |
| 1398 | } | 1525 | } |
| 1399 | 1526 | ||
| ... | @@ -1406,10 +1533,11 @@ pub fn nullTerminatedString(air: Air, index: usize) [:0]const u8 { | ... | @@ -1406,10 +1533,11 @@ pub fn nullTerminatedString(air: Air, index: usize) [:0]const u8 { |
| 1406 | return bytes[0..end :0]; | 1533 | return bytes[0..end :0]; |
| 1407 | } | 1534 | } |
| 1408 | 1535 | ||
| 1409 | /// Returns whether the given instruction must always be lowered, for instance because it can cause | 1536 | /// Returns whether the given instruction must always be lowered, for instance |
| 1410 | /// side effects. If an instruction does not need to be lowered, and Liveness determines its result | 1537 | /// because it can cause side effects. If an instruction does not need to be |
| 1411 | /// is unused, backends should avoid lowering it. | 1538 | /// lowered, and Liveness determines its result is unused, backends should |
| 1412 | pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { | 1539 | /// avoid lowering it. |
| 1540 | pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { | ||
| 1413 | const data = air.instructions.items(.data)[inst]; | 1541 | const data = air.instructions.items(.data)[inst]; |
| 1414 | return switch (air.instructions.items(.tag)[inst]) { | 1542 | return switch (air.instructions.items(.tag)[inst]) { |
| 1415 | .arg, | 1543 | .arg, |
| ... | @@ -1498,6 +1626,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { | ... | @@ -1498,6 +1626,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { |
| 1498 | .mul_with_overflow, | 1626 | .mul_with_overflow, |
| 1499 | .shl_with_overflow, | 1627 | .shl_with_overflow, |
| 1500 | .alloc, | 1628 | .alloc, |
| 1629 | .inferred_alloc, | ||
| 1630 | .inferred_alloc_comptime, | ||
| 1501 | .ret_ptr, | 1631 | .ret_ptr, |
| 1502 | .bit_and, | 1632 | .bit_and, |
| 1503 | .bit_or, | 1633 | .bit_or, |
| ... | @@ -1546,8 +1676,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { | ... | @@ -1546,8 +1676,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { |
| 1546 | .cmp_neq_optimized, | 1676 | .cmp_neq_optimized, |
| 1547 | .cmp_vector, | 1677 | .cmp_vector, |
| 1548 | .cmp_vector_optimized, | 1678 | .cmp_vector_optimized, |
| 1549 | .constant, | 1679 | .interned, |
| 1550 | .const_ty, | ||
| 1551 | .is_null, | 1680 | .is_null, |
| 1552 | .is_non_null, | 1681 | .is_non_null, |
| 1553 | .is_null_ptr, | 1682 | .is_null_ptr, |
| ... | @@ -1616,8 +1745,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { | ... | @@ -1616,8 +1745,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index) bool { |
| 1616 | => false, | 1745 | => false, |
| 1617 | 1746 | ||
| 1618 | .assembly => @truncate(u1, air.extraData(Air.Asm, data.ty_pl.payload).data.flags >> 31) != 0, | 1747 | .assembly => @truncate(u1, air.extraData(Air.Asm, data.ty_pl.payload).data.flags >> 31) != 0, |
| 1619 | .load => air.typeOf(data.ty_op.operand).isVolatilePtr(), | 1748 | .load => air.typeOf(data.ty_op.operand, ip).isVolatilePtrIp(ip), |
| 1620 | .slice_elem_val, .ptr_elem_val => air.typeOf(data.bin_op.lhs).isVolatilePtr(), | 1749 | .slice_elem_val, .ptr_elem_val => air.typeOf(data.bin_op.lhs, ip).isVolatilePtrIp(ip), |
| 1621 | .atomic_load => air.typeOf(data.atomic_load.ptr).isVolatilePtr(), | 1750 | .atomic_load => air.typeOf(data.atomic_load.ptr, ip).isVolatilePtrIp(ip), |
| 1622 | }; | 1751 | }; |
| 1623 | } | 1752 | } |
src/AstGen.zig+41-24| ... | @@ -3934,7 +3934,7 @@ fn fnDecl( | ... | @@ -3934,7 +3934,7 @@ fn fnDecl( |
| 3934 | var section_gz = decl_gz.makeSubBlock(params_scope); | 3934 | var section_gz = decl_gz.makeSubBlock(params_scope); |
| 3935 | defer section_gz.unstack(); | 3935 | defer section_gz.unstack(); |
| 3936 | const section_ref: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: { | 3936 | const section_ref: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: { |
| 3937 | const inst = try expr(&decl_gz, params_scope, .{ .rl = .{ .coerced_ty = .const_slice_u8_type } }, fn_proto.ast.section_expr); | 3937 | const inst = try expr(&decl_gz, params_scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, fn_proto.ast.section_expr); |
| 3938 | if (section_gz.instructionsSlice().len == 0) { | 3938 | if (section_gz.instructionsSlice().len == 0) { |
| 3939 | // In this case we will send a len=0 body which can be encoded more efficiently. | 3939 | // In this case we will send a len=0 body which can be encoded more efficiently. |
| 3940 | break :inst inst; | 3940 | break :inst inst; |
| ... | @@ -4137,7 +4137,7 @@ fn globalVarDecl( | ... | @@ -4137,7 +4137,7 @@ fn globalVarDecl( |
| 4137 | break :inst try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .address_space_type } }, var_decl.ast.addrspace_node); | 4137 | break :inst try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .address_space_type } }, var_decl.ast.addrspace_node); |
| 4138 | }; | 4138 | }; |
| 4139 | const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: { | 4139 | const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: { |
| 4140 | break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .const_slice_u8_type } }, var_decl.ast.section_node); | 4140 | break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .slice_const_u8_type } }, var_decl.ast.section_node); |
| 4141 | }; | 4141 | }; |
| 4142 | const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none; | 4142 | const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none; |
| 4143 | wip_members.nextDecl(is_pub, is_export, align_inst != .none, has_section_or_addrspace); | 4143 | wip_members.nextDecl(is_pub, is_export, align_inst != .none, has_section_or_addrspace); |
| ... | @@ -4497,7 +4497,7 @@ fn testDecl( | ... | @@ -4497,7 +4497,7 @@ fn testDecl( |
| 4497 | .cc_gz = null, | 4497 | .cc_gz = null, |
| 4498 | .align_ref = .none, | 4498 | .align_ref = .none, |
| 4499 | .align_gz = null, | 4499 | .align_gz = null, |
| 4500 | .ret_ref = .void_type, | 4500 | .ret_ref = .anyerror_void_error_union_type, |
| 4501 | .ret_gz = null, | 4501 | .ret_gz = null, |
| 4502 | .section_ref = .none, | 4502 | .section_ref = .none, |
| 4503 | .section_gz = null, | 4503 | .section_gz = null, |
| ... | @@ -4510,7 +4510,7 @@ fn testDecl( | ... | @@ -4510,7 +4510,7 @@ fn testDecl( |
| 4510 | .body_gz = &fn_block, | 4510 | .body_gz = &fn_block, |
| 4511 | .lib_name = 0, | 4511 | .lib_name = 0, |
| 4512 | .is_var_args = false, | 4512 | .is_var_args = false, |
| 4513 | .is_inferred_error = true, | 4513 | .is_inferred_error = false, |
| 4514 | .is_test = true, | 4514 | .is_test = true, |
| 4515 | .is_extern = false, | 4515 | .is_extern = false, |
| 4516 | .is_noinline = false, | 4516 | .is_noinline = false, |
| ... | @@ -7878,7 +7878,7 @@ fn unionInit( | ... | @@ -7878,7 +7878,7 @@ fn unionInit( |
| 7878 | params: []const Ast.Node.Index, | 7878 | params: []const Ast.Node.Index, |
| 7879 | ) InnerError!Zir.Inst.Ref { | 7879 | ) InnerError!Zir.Inst.Ref { |
| 7880 | const union_type = try typeExpr(gz, scope, params[0]); | 7880 | const union_type = try typeExpr(gz, scope, params[0]); |
| 7881 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]); | 7881 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]); |
| 7882 | const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ | 7882 | const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ |
| 7883 | .container_type = union_type, | 7883 | .container_type = union_type, |
| 7884 | .field_name = field_name, | 7884 | .field_name = field_name, |
| ... | @@ -8100,12 +8100,12 @@ fn builtinCall( | ... | @@ -8100,12 +8100,12 @@ fn builtinCall( |
| 8100 | if (ri.rl == .ref) { | 8100 | if (ri.rl == .ref) { |
| 8101 | return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ | 8101 | return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ |
| 8102 | .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]), | 8102 | .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]), |
| 8103 | .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]), | 8103 | .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]), |
| 8104 | }); | 8104 | }); |
| 8105 | } | 8105 | } |
| 8106 | const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ | 8106 | const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ |
| 8107 | .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]), | 8107 | .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]), |
| 8108 | .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]), | 8108 | .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]), |
| 8109 | }); | 8109 | }); |
| 8110 | return rvalue(gz, ri, result, node); | 8110 | return rvalue(gz, ri, result, node); |
| 8111 | }, | 8111 | }, |
| ... | @@ -8271,11 +8271,11 @@ fn builtinCall( | ... | @@ -8271,11 +8271,11 @@ fn builtinCall( |
| 8271 | .align_of => return simpleUnOpType(gz, scope, ri, node, params[0], .align_of), | 8271 | .align_of => return simpleUnOpType(gz, scope, ri, node, params[0], .align_of), |
| 8272 | 8272 | ||
| 8273 | .ptr_to_int => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ptr_to_int), | 8273 | .ptr_to_int => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ptr_to_int), |
| 8274 | .compile_error => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], .compile_error), | 8274 | .compile_error => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[0], .compile_error), |
| 8275 | .set_eval_branch_quota => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .set_eval_branch_quota), | 8275 | .set_eval_branch_quota => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .set_eval_branch_quota), |
| 8276 | .enum_to_int => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .enum_to_int), | 8276 | .enum_to_int => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .enum_to_int), |
| 8277 | .bool_to_int => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .bool_to_int), | 8277 | .bool_to_int => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .bool_to_int), |
| 8278 | .embed_file => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], .embed_file), | 8278 | .embed_file => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[0], .embed_file), |
| 8279 | .error_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .anyerror_type } }, params[0], .error_name), | 8279 | .error_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .anyerror_type } }, params[0], .error_name), |
| 8280 | .set_runtime_safety => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .set_runtime_safety), | 8280 | .set_runtime_safety => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .set_runtime_safety), |
| 8281 | .sqrt => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sqrt), | 8281 | .sqrt => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sqrt), |
| ... | @@ -8334,7 +8334,7 @@ fn builtinCall( | ... | @@ -8334,7 +8334,7 @@ fn builtinCall( |
| 8334 | }, | 8334 | }, |
| 8335 | .panic => { | 8335 | .panic => { |
| 8336 | try emitDbgNode(gz, node); | 8336 | try emitDbgNode(gz, node); |
| 8337 | return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], .panic); | 8337 | return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[0], .panic); |
| 8338 | }, | 8338 | }, |
| 8339 | .trap => { | 8339 | .trap => { |
| 8340 | try emitDbgNode(gz, node); | 8340 | try emitDbgNode(gz, node); |
| ... | @@ -8450,7 +8450,7 @@ fn builtinCall( | ... | @@ -8450,7 +8450,7 @@ fn builtinCall( |
| 8450 | }, | 8450 | }, |
| 8451 | .c_define => { | 8451 | .c_define => { |
| 8452 | if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{}); | 8452 | if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{}); |
| 8453 | const name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0]); | 8453 | const name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[0]); |
| 8454 | const value = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]); | 8454 | const value = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]); |
| 8455 | const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ | 8455 | const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ |
| 8456 | .node = gz.nodeIndexToRelative(node), | 8456 | .node = gz.nodeIndexToRelative(node), |
| ... | @@ -8530,7 +8530,7 @@ fn builtinCall( | ... | @@ -8530,7 +8530,7 @@ fn builtinCall( |
| 8530 | return rvalue(gz, ri, result, node); | 8530 | return rvalue(gz, ri, result, node); |
| 8531 | }, | 8531 | }, |
| 8532 | .call => { | 8532 | .call => { |
| 8533 | const modifier = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .modifier_type } }, params[0]); | 8533 | const modifier = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .call_modifier_type } }, params[0]); |
| 8534 | const callee = try expr(gz, scope, .{ .rl = .none }, params[1]); | 8534 | const callee = try expr(gz, scope, .{ .rl = .none }, params[1]); |
| 8535 | const args = try expr(gz, scope, .{ .rl = .none }, params[2]); | 8535 | const args = try expr(gz, scope, .{ .rl = .none }, params[2]); |
| 8536 | const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ | 8536 | const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{ |
| ... | @@ -8546,7 +8546,7 @@ fn builtinCall( | ... | @@ -8546,7 +8546,7 @@ fn builtinCall( |
| 8546 | }, | 8546 | }, |
| 8547 | .field_parent_ptr => { | 8547 | .field_parent_ptr => { |
| 8548 | const parent_type = try typeExpr(gz, scope, params[0]); | 8548 | const parent_type = try typeExpr(gz, scope, params[0]); |
| 8549 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]); | 8549 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]); |
| 8550 | const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{ | 8550 | const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{ |
| 8551 | .parent_type = parent_type, | 8551 | .parent_type = parent_type, |
| 8552 | .field_name = field_name, | 8552 | .field_name = field_name, |
| ... | @@ -8701,7 +8701,7 @@ fn hasDeclOrField( | ... | @@ -8701,7 +8701,7 @@ fn hasDeclOrField( |
| 8701 | tag: Zir.Inst.Tag, | 8701 | tag: Zir.Inst.Tag, |
| 8702 | ) InnerError!Zir.Inst.Ref { | 8702 | ) InnerError!Zir.Inst.Ref { |
| 8703 | const container_type = try typeExpr(gz, scope, lhs_node); | 8703 | const container_type = try typeExpr(gz, scope, lhs_node); |
| 8704 | const name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, rhs_node); | 8704 | const name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, rhs_node); |
| 8705 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ | 8705 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ |
| 8706 | .lhs = container_type, | 8706 | .lhs = container_type, |
| 8707 | .rhs = name, | 8707 | .rhs = name, |
| ... | @@ -8851,7 +8851,7 @@ fn simpleCBuiltin( | ... | @@ -8851,7 +8851,7 @@ fn simpleCBuiltin( |
| 8851 | ) InnerError!Zir.Inst.Ref { | 8851 | ) InnerError!Zir.Inst.Ref { |
| 8852 | const name: []const u8 = if (tag == .c_undef) "C undef" else "C include"; | 8852 | const name: []const u8 = if (tag == .c_undef) "C undef" else "C include"; |
| 8853 | if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name}); | 8853 | if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name}); |
| 8854 | const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, operand_node); | 8854 | const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, operand_node); |
| 8855 | _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ | 8855 | _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ |
| 8856 | .node = gz.nodeIndexToRelative(node), | 8856 | .node = gz.nodeIndexToRelative(node), |
| 8857 | .operand = operand, | 8857 | .operand = operand, |
| ... | @@ -8869,7 +8869,7 @@ fn offsetOf( | ... | @@ -8869,7 +8869,7 @@ fn offsetOf( |
| 8869 | tag: Zir.Inst.Tag, | 8869 | tag: Zir.Inst.Tag, |
| 8870 | ) InnerError!Zir.Inst.Ref { | 8870 | ) InnerError!Zir.Inst.Ref { |
| 8871 | const type_inst = try typeExpr(gz, scope, lhs_node); | 8871 | const type_inst = try typeExpr(gz, scope, lhs_node); |
| 8872 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, rhs_node); | 8872 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, rhs_node); |
| 8873 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ | 8873 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ |
| 8874 | .lhs = type_inst, | 8874 | .lhs = type_inst, |
| 8875 | .rhs = field_name, | 8875 | .rhs = field_name, |
| ... | @@ -10271,6 +10271,8 @@ fn rvalue( | ... | @@ -10271,6 +10271,8 @@ fn rvalue( |
| 10271 | as_ty | @enumToInt(Zir.Inst.Ref.i32_type), | 10271 | as_ty | @enumToInt(Zir.Inst.Ref.i32_type), |
| 10272 | as_ty | @enumToInt(Zir.Inst.Ref.u64_type), | 10272 | as_ty | @enumToInt(Zir.Inst.Ref.u64_type), |
| 10273 | as_ty | @enumToInt(Zir.Inst.Ref.i64_type), | 10273 | as_ty | @enumToInt(Zir.Inst.Ref.i64_type), |
| 10274 | as_ty | @enumToInt(Zir.Inst.Ref.u128_type), | ||
| 10275 | as_ty | @enumToInt(Zir.Inst.Ref.i128_type), | ||
| 10274 | as_ty | @enumToInt(Zir.Inst.Ref.usize_type), | 10276 | as_ty | @enumToInt(Zir.Inst.Ref.usize_type), |
| 10275 | as_ty | @enumToInt(Zir.Inst.Ref.isize_type), | 10277 | as_ty | @enumToInt(Zir.Inst.Ref.isize_type), |
| 10276 | as_ty | @enumToInt(Zir.Inst.Ref.c_char_type), | 10278 | as_ty | @enumToInt(Zir.Inst.Ref.c_char_type), |
| ... | @@ -10296,15 +10298,30 @@ fn rvalue( | ... | @@ -10296,15 +10298,30 @@ fn rvalue( |
| 10296 | as_ty | @enumToInt(Zir.Inst.Ref.comptime_int_type), | 10298 | as_ty | @enumToInt(Zir.Inst.Ref.comptime_int_type), |
| 10297 | as_ty | @enumToInt(Zir.Inst.Ref.comptime_float_type), | 10299 | as_ty | @enumToInt(Zir.Inst.Ref.comptime_float_type), |
| 10298 | as_ty | @enumToInt(Zir.Inst.Ref.noreturn_type), | 10300 | as_ty | @enumToInt(Zir.Inst.Ref.noreturn_type), |
| 10301 | as_ty | @enumToInt(Zir.Inst.Ref.anyframe_type), | ||
| 10299 | as_ty | @enumToInt(Zir.Inst.Ref.null_type), | 10302 | as_ty | @enumToInt(Zir.Inst.Ref.null_type), |
| 10300 | as_ty | @enumToInt(Zir.Inst.Ref.undefined_type), | 10303 | as_ty | @enumToInt(Zir.Inst.Ref.undefined_type), |
| 10301 | as_ty | @enumToInt(Zir.Inst.Ref.fn_noreturn_no_args_type), | ||
| 10302 | as_ty | @enumToInt(Zir.Inst.Ref.fn_void_no_args_type), | ||
| 10303 | as_ty | @enumToInt(Zir.Inst.Ref.fn_naked_noreturn_no_args_type), | ||
| 10304 | as_ty | @enumToInt(Zir.Inst.Ref.fn_ccc_void_no_args_type), | ||
| 10305 | as_ty | @enumToInt(Zir.Inst.Ref.single_const_pointer_to_comptime_int_type), | ||
| 10306 | as_ty | @enumToInt(Zir.Inst.Ref.const_slice_u8_type), | ||
| 10307 | as_ty | @enumToInt(Zir.Inst.Ref.enum_literal_type), | 10304 | as_ty | @enumToInt(Zir.Inst.Ref.enum_literal_type), |
| 10305 | as_ty | @enumToInt(Zir.Inst.Ref.atomic_order_type), | ||
| 10306 | as_ty | @enumToInt(Zir.Inst.Ref.atomic_rmw_op_type), | ||
| 10307 | as_ty | @enumToInt(Zir.Inst.Ref.calling_convention_type), | ||
| 10308 | as_ty | @enumToInt(Zir.Inst.Ref.address_space_type), | ||
| 10309 | as_ty | @enumToInt(Zir.Inst.Ref.float_mode_type), | ||
| 10310 | as_ty | @enumToInt(Zir.Inst.Ref.reduce_op_type), | ||
| 10311 | as_ty | @enumToInt(Zir.Inst.Ref.call_modifier_type), | ||
| 10312 | as_ty | @enumToInt(Zir.Inst.Ref.prefetch_options_type), | ||
| 10313 | as_ty | @enumToInt(Zir.Inst.Ref.export_options_type), | ||
| 10314 | as_ty | @enumToInt(Zir.Inst.Ref.extern_options_type), | ||
| 10315 | as_ty | @enumToInt(Zir.Inst.Ref.type_info_type), | ||
| 10316 | as_ty | @enumToInt(Zir.Inst.Ref.manyptr_u8_type), | ||
| 10317 | as_ty | @enumToInt(Zir.Inst.Ref.manyptr_const_u8_type), | ||
| 10318 | as_ty | @enumToInt(Zir.Inst.Ref.manyptr_const_u8_sentinel_0_type), | ||
| 10319 | as_ty | @enumToInt(Zir.Inst.Ref.single_const_pointer_to_comptime_int_type), | ||
| 10320 | as_ty | @enumToInt(Zir.Inst.Ref.slice_const_u8_type), | ||
| 10321 | as_ty | @enumToInt(Zir.Inst.Ref.slice_const_u8_sentinel_0_type), | ||
| 10322 | as_ty | @enumToInt(Zir.Inst.Ref.anyerror_void_error_union_type), | ||
| 10323 | as_ty | @enumToInt(Zir.Inst.Ref.generic_poison_type), | ||
| 10324 | as_ty | @enumToInt(Zir.Inst.Ref.empty_struct_type), | ||
| 10308 | as_comptime_int | @enumToInt(Zir.Inst.Ref.zero), | 10325 | as_comptime_int | @enumToInt(Zir.Inst.Ref.zero), |
| 10309 | as_comptime_int | @enumToInt(Zir.Inst.Ref.one), | 10326 | as_comptime_int | @enumToInt(Zir.Inst.Ref.one), |
| 10310 | as_bool | @enumToInt(Zir.Inst.Ref.bool_true), | 10327 | as_bool | @enumToInt(Zir.Inst.Ref.bool_true), |
| ... | @@ -10677,8 +10694,8 @@ fn identAsString(astgen: *AstGen, ident_token: Ast.TokenIndex) !u32 { | ... | @@ -10677,8 +10694,8 @@ fn identAsString(astgen: *AstGen, ident_token: Ast.TokenIndex) !u32 { |
| 10677 | const string_bytes = &astgen.string_bytes; | 10694 | const string_bytes = &astgen.string_bytes; |
| 10678 | const str_index = @intCast(u32, string_bytes.items.len); | 10695 | const str_index = @intCast(u32, string_bytes.items.len); |
| 10679 | try astgen.appendIdentStr(ident_token, string_bytes); | 10696 | try astgen.appendIdentStr(ident_token, string_bytes); |
| 10680 | const key = string_bytes.items[str_index..]; | 10697 | const key: []const u8 = string_bytes.items[str_index..]; |
| 10681 | const gop = try astgen.string_table.getOrPutContextAdapted(gpa, @as([]const u8, key), StringIndexAdapter{ | 10698 | const gop = try astgen.string_table.getOrPutContextAdapted(gpa, key, StringIndexAdapter{ |
| 10682 | .bytes = string_bytes, | 10699 | .bytes = string_bytes, |
| 10683 | }, StringIndexContext{ | 10700 | }, StringIndexContext{ |
| 10684 | .bytes = string_bytes, | 10701 | .bytes = string_bytes, |
src/Autodoc.zig+23-24| ... | @@ -8,6 +8,7 @@ const CompilationModule = @import("Module.zig"); | ... | @@ -8,6 +8,7 @@ const CompilationModule = @import("Module.zig"); |
| 8 | const File = CompilationModule.File; | 8 | const File = CompilationModule.File; |
| 9 | const Module = @import("Package.zig"); | 9 | const Module = @import("Package.zig"); |
| 10 | const Tokenizer = std.zig.Tokenizer; | 10 | const Tokenizer = std.zig.Tokenizer; |
| 11 | const InternPool = @import("InternPool.zig"); | ||
| 11 | const Zir = @import("Zir.zig"); | 12 | const Zir = @import("Zir.zig"); |
| 12 | const Ref = Zir.Inst.Ref; | 13 | const Ref = Zir.Inst.Ref; |
| 13 | const log = std.log.scoped(.autodoc); | 14 | const log = std.log.scoped(.autodoc); |
| ... | @@ -95,8 +96,6 @@ pub fn generateZirData(self: *Autodoc) !void { | ... | @@ -95,8 +96,6 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 95 | } | 96 | } |
| 96 | } | 97 | } |
| 97 | 98 | ||
| 98 | log.debug("Ref map size: {}", .{Ref.typed_value_map.len}); | ||
| 99 | |||
| 100 | const root_src_dir = self.comp_module.main_pkg.root_src_directory; | 99 | const root_src_dir = self.comp_module.main_pkg.root_src_directory; |
| 101 | const root_src_path = self.comp_module.main_pkg.root_src_path; | 100 | const root_src_path = self.comp_module.main_pkg.root_src_path; |
| 102 | const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path}); | 101 | const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path}); |
| ... | @@ -108,18 +107,20 @@ pub fn generateZirData(self: *Autodoc) !void { | ... | @@ -108,18 +107,20 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 108 | const file = self.comp_module.import_table.get(abs_root_src_path).?; // file is expected to be present in the import table | 107 | const file = self.comp_module.import_table.get(abs_root_src_path).?; // file is expected to be present in the import table |
| 109 | // Append all the types in Zir.Inst.Ref. | 108 | // Append all the types in Zir.Inst.Ref. |
| 110 | { | 109 | { |
| 111 | try self.types.append(self.arena, .{ | 110 | comptime std.debug.assert(@enumToInt(InternPool.Index.first_type) == 0); |
| 112 | .ComptimeExpr = .{ .name = "ComptimeExpr" }, | 111 | var i: u32 = 0; |
| 113 | }); | 112 | while (i <= @enumToInt(InternPool.Index.last_type)) : (i += 1) { |
| 114 | 113 | const ip_index = @intToEnum(InternPool.Index, i); | |
| 115 | // this skips Ref.none but it's ok becuse we replaced it with ComptimeExpr | ||
| 116 | var i: u32 = 1; | ||
| 117 | while (i <= @enumToInt(Ref.anyerror_void_error_union_type)) : (i += 1) { | ||
| 118 | var tmpbuf = std.ArrayList(u8).init(self.arena); | 114 | var tmpbuf = std.ArrayList(u8).init(self.arena); |
| 119 | try Ref.typed_value_map[i].val.fmtDebug().format("", .{}, tmpbuf.writer()); | 115 | if (ip_index == .generic_poison_type) { |
| 116 | // Not a real type, doesn't have a normal name | ||
| 117 | try tmpbuf.writer().writeAll("(generic poison)"); | ||
| 118 | } else { | ||
| 119 | try ip_index.toType().fmt(self.comp_module).format("", .{}, tmpbuf.writer()); | ||
| 120 | } | ||
| 120 | try self.types.append( | 121 | try self.types.append( |
| 121 | self.arena, | 122 | self.arena, |
| 122 | switch (@intToEnum(Ref, i)) { | 123 | switch (ip_index) { |
| 123 | else => blk: { | 124 | else => blk: { |
| 124 | // TODO: map the remaining refs to a correct type | 125 | // TODO: map the remaining refs to a correct type |
| 125 | // instead of just assinging "array" to them. | 126 | // instead of just assinging "array" to them. |
| ... | @@ -1040,7 +1041,7 @@ fn walkInstruction( | ... | @@ -1040,7 +1041,7 @@ fn walkInstruction( |
| 1040 | .ret_load => { | 1041 | .ret_load => { |
| 1041 | const un_node = data[inst_index].un_node; | 1042 | const un_node = data[inst_index].un_node; |
| 1042 | const res_ptr_ref = un_node.operand; | 1043 | const res_ptr_ref = un_node.operand; |
| 1043 | const res_ptr_inst = @enumToInt(res_ptr_ref) - Ref.typed_value_map.len; | 1044 | const res_ptr_inst = Zir.refToIndex(res_ptr_ref).?; |
| 1044 | // TODO: this instruction doesn't let us know trivially if there's | 1045 | // TODO: this instruction doesn't let us know trivially if there's |
| 1045 | // branching involved or not. For now here's the strat: | 1046 | // branching involved or not. For now here's the strat: |
| 1046 | // We search backwarts until `ret_ptr` for `store_node`, | 1047 | // We search backwarts until `ret_ptr` for `store_node`, |
| ... | @@ -2157,11 +2158,10 @@ fn walkInstruction( | ... | @@ -2157,11 +2158,10 @@ fn walkInstruction( |
| 2157 | const lhs_ref = blk: { | 2158 | const lhs_ref = blk: { |
| 2158 | var lhs_extra = extra; | 2159 | var lhs_extra = extra; |
| 2159 | while (true) { | 2160 | while (true) { |
| 2160 | if (@enumToInt(lhs_extra.data.lhs) < Ref.typed_value_map.len) { | 2161 | const lhs = Zir.refToIndex(lhs_extra.data.lhs) orelse { |
| 2161 | break :blk lhs_extra.data.lhs; | 2162 | break :blk lhs_extra.data.lhs; |
| 2162 | } | 2163 | }; |
| 2163 | 2164 | ||
| 2164 | const lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; | ||
| 2165 | if (tags[lhs] != .field_val and | 2165 | if (tags[lhs] != .field_val and |
| 2166 | tags[lhs] != .field_ptr and | 2166 | tags[lhs] != .field_ptr and |
| 2167 | tags[lhs] != .field_type) break :blk lhs_extra.data.lhs; | 2167 | tags[lhs] != .field_type) break :blk lhs_extra.data.lhs; |
| ... | @@ -2188,8 +2188,7 @@ fn walkInstruction( | ... | @@ -2188,8 +2188,7 @@ fn walkInstruction( |
| 2188 | // TODO: double check that we really don't need type info here | 2188 | // TODO: double check that we really don't need type info here |
| 2189 | 2189 | ||
| 2190 | const wr = blk: { | 2190 | const wr = blk: { |
| 2191 | if (@enumToInt(lhs_ref) >= Ref.typed_value_map.len) { | 2191 | if (Zir.refToIndex(lhs_ref)) |lhs_inst| { |
| 2192 | const lhs_inst = @enumToInt(lhs_ref) - Ref.typed_value_map.len; | ||
| 2193 | if (tags[lhs_inst] == .call or tags[lhs_inst] == .field_call) { | 2192 | if (tags[lhs_inst] == .call or tags[lhs_inst] == .field_call) { |
| 2194 | break :blk DocData.WalkResult{ | 2193 | break :blk DocData.WalkResult{ |
| 2195 | .expr = .{ | 2194 | .expr = .{ |
| ... | @@ -4672,16 +4671,19 @@ fn walkRef( | ... | @@ -4672,16 +4671,19 @@ fn walkRef( |
| 4672 | ref: Ref, | 4671 | ref: Ref, |
| 4673 | need_type: bool, // true when the caller needs also a typeRef for the return value | 4672 | need_type: bool, // true when the caller needs also a typeRef for the return value |
| 4674 | ) AutodocErrors!DocData.WalkResult { | 4673 | ) AutodocErrors!DocData.WalkResult { |
| 4675 | const enum_value = @enumToInt(ref); | 4674 | if (ref == .none) { |
| 4676 | if (enum_value <= @enumToInt(Ref.anyerror_void_error_union_type)) { | 4675 | return .{ .expr = .{ .comptimeExpr = 0 } }; |
| 4676 | } else if (@enumToInt(ref) <= @enumToInt(InternPool.Index.last_type)) { | ||
| 4677 | // We can just return a type that indexes into `types` with the | 4677 | // We can just return a type that indexes into `types` with the |
| 4678 | // enum value because in the beginning we pre-filled `types` with | 4678 | // enum value because in the beginning we pre-filled `types` with |
| 4679 | // the types that are listed in `Ref`. | 4679 | // the types that are listed in `Ref`. |
| 4680 | return DocData.WalkResult{ | 4680 | return DocData.WalkResult{ |
| 4681 | .typeRef = .{ .type = @enumToInt(std.builtin.TypeId.Type) }, | 4681 | .typeRef = .{ .type = @enumToInt(std.builtin.TypeId.Type) }, |
| 4682 | .expr = .{ .type = enum_value }, | 4682 | .expr = .{ .type = @enumToInt(ref) }, |
| 4683 | }; | 4683 | }; |
| 4684 | } else if (enum_value < Ref.typed_value_map.len) { | 4684 | } else if (Zir.refToIndex(ref)) |zir_index| { |
| 4685 | return self.walkInstruction(file, parent_scope, parent_src, zir_index, need_type); | ||
| 4686 | } else { | ||
| 4685 | switch (ref) { | 4687 | switch (ref) { |
| 4686 | else => { | 4688 | else => { |
| 4687 | panicWithContext( | 4689 | panicWithContext( |
| ... | @@ -4774,9 +4776,6 @@ fn walkRef( | ... | @@ -4774,9 +4776,6 @@ fn walkRef( |
| 4774 | // } }; | 4776 | // } }; |
| 4775 | // }, | 4777 | // }, |
| 4776 | } | 4778 | } |
| 4777 | } else { | ||
| 4778 | const zir_index = enum_value - Ref.typed_value_map.len; | ||
| 4779 | return self.walkInstruction(file, parent_scope, parent_src, zir_index, need_type); | ||
| 4780 | } | 4779 | } |
| 4781 | } | 4780 | } |
| 4782 | 4781 |
src/Compilation.zig+38-26| ... | @@ -87,6 +87,7 @@ clang_preprocessor_mode: ClangPreprocessorMode, | ... | @@ -87,6 +87,7 @@ clang_preprocessor_mode: ClangPreprocessorMode, |
| 87 | /// Whether to print clang argvs to stdout. | 87 | /// Whether to print clang argvs to stdout. |
| 88 | verbose_cc: bool, | 88 | verbose_cc: bool, |
| 89 | verbose_air: bool, | 89 | verbose_air: bool, |
| 90 | verbose_intern_pool: bool, | ||
| 90 | verbose_llvm_ir: ?[]const u8, | 91 | verbose_llvm_ir: ?[]const u8, |
| 91 | verbose_llvm_bc: ?[]const u8, | 92 | verbose_llvm_bc: ?[]const u8, |
| 92 | verbose_cimport: bool, | 93 | verbose_cimport: bool, |
| ... | @@ -226,7 +227,7 @@ const Job = union(enum) { | ... | @@ -226,7 +227,7 @@ const Job = union(enum) { |
| 226 | /// Write the constant value for a Decl to the output file. | 227 | /// Write the constant value for a Decl to the output file. |
| 227 | codegen_decl: Module.Decl.Index, | 228 | codegen_decl: Module.Decl.Index, |
| 228 | /// Write the machine code for a function to the output file. | 229 | /// Write the machine code for a function to the output file. |
| 229 | codegen_func: *Module.Fn, | 230 | codegen_func: Module.Fn.Index, |
| 230 | /// Render the .h file snippet for the Decl. | 231 | /// Render the .h file snippet for the Decl. |
| 231 | emit_h_decl: Module.Decl.Index, | 232 | emit_h_decl: Module.Decl.Index, |
| 232 | /// The Decl needs to be analyzed and possibly export itself. | 233 | /// The Decl needs to be analyzed and possibly export itself. |
| ... | @@ -593,6 +594,7 @@ pub const InitOptions = struct { | ... | @@ -593,6 +594,7 @@ pub const InitOptions = struct { |
| 593 | verbose_cc: bool = false, | 594 | verbose_cc: bool = false, |
| 594 | verbose_link: bool = false, | 595 | verbose_link: bool = false, |
| 595 | verbose_air: bool = false, | 596 | verbose_air: bool = false, |
| 597 | verbose_intern_pool: bool = false, | ||
| 596 | verbose_llvm_ir: ?[]const u8 = null, | 598 | verbose_llvm_ir: ?[]const u8 = null, |
| 597 | verbose_llvm_bc: ?[]const u8 = null, | 599 | verbose_llvm_bc: ?[]const u8 = null, |
| 598 | verbose_cimport: bool = false, | 600 | verbose_cimport: bool = false, |
| ... | @@ -1315,9 +1317,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1315,9 +1317,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1315 | .global_zir_cache = global_zir_cache, | 1317 | .global_zir_cache = global_zir_cache, |
| 1316 | .local_zir_cache = local_zir_cache, | 1318 | .local_zir_cache = local_zir_cache, |
| 1317 | .emit_h = emit_h, | 1319 | .emit_h = emit_h, |
| 1318 | .error_name_list = .{}, | 1320 | .tmp_hack_arena = std.heap.ArenaAllocator.init(gpa), |
| 1319 | }; | 1321 | }; |
| 1320 | try module.error_name_list.append(gpa, "(no error)"); | 1322 | try module.init(); |
| 1321 | 1323 | ||
| 1322 | break :blk module; | 1324 | break :blk module; |
| 1323 | } else blk: { | 1325 | } else blk: { |
| ... | @@ -1574,6 +1576,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { | ... | @@ -1574,6 +1576,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { |
| 1574 | .clang_preprocessor_mode = options.clang_preprocessor_mode, | 1576 | .clang_preprocessor_mode = options.clang_preprocessor_mode, |
| 1575 | .verbose_cc = options.verbose_cc, | 1577 | .verbose_cc = options.verbose_cc, |
| 1576 | .verbose_air = options.verbose_air, | 1578 | .verbose_air = options.verbose_air, |
| 1579 | .verbose_intern_pool = options.verbose_intern_pool, | ||
| 1577 | .verbose_llvm_ir = options.verbose_llvm_ir, | 1580 | .verbose_llvm_ir = options.verbose_llvm_ir, |
| 1578 | .verbose_llvm_bc = options.verbose_llvm_bc, | 1581 | .verbose_llvm_bc = options.verbose_llvm_bc, |
| 1579 | .verbose_cimport = options.verbose_cimport, | 1582 | .verbose_cimport = options.verbose_cimport, |
| ... | @@ -2026,6 +2029,13 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void | ... | @@ -2026,6 +2029,13 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void |
| 2026 | try comp.performAllTheWork(main_progress_node); | 2029 | try comp.performAllTheWork(main_progress_node); |
| 2027 | 2030 | ||
| 2028 | if (comp.bin_file.options.module) |module| { | 2031 | if (comp.bin_file.options.module) |module| { |
| 2032 | if (builtin.mode == .Debug and comp.verbose_intern_pool) { | ||
| 2033 | std.debug.print("intern pool stats for '{s}':\n", .{ | ||
| 2034 | comp.bin_file.options.root_name, | ||
| 2035 | }); | ||
| 2036 | module.intern_pool.dump(); | ||
| 2037 | } | ||
| 2038 | |||
| 2029 | if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) { | 2039 | if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) { |
| 2030 | // The `test_functions` decl has been intentionally postponed until now, | 2040 | // The `test_functions` decl has been intentionally postponed until now, |
| 2031 | // at which point we must populate it with the list of test functions that | 2041 | // at which point we must populate it with the list of test functions that |
| ... | @@ -2042,7 +2052,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void | ... | @@ -2042,7 +2052,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void |
| 2042 | assert(decl.deletion_flag); | 2052 | assert(decl.deletion_flag); |
| 2043 | assert(decl.dependants.count() == 0); | 2053 | assert(decl.dependants.count() == 0); |
| 2044 | const is_anon = if (decl.zir_decl_index == 0) blk: { | 2054 | const is_anon = if (decl.zir_decl_index == 0) blk: { |
| 2045 | break :blk decl.src_namespace.anon_decls.swapRemove(decl_index); | 2055 | break :blk module.namespacePtr(decl.src_namespace).anon_decls.swapRemove(decl_index); |
| 2046 | } else false; | 2056 | } else false; |
| 2047 | 2057 | ||
| 2048 | try module.clearDecl(decl_index, null); | 2058 | try module.clearDecl(decl_index, null); |
| ... | @@ -2523,8 +2533,7 @@ pub fn totalErrorCount(self: *Compilation) u32 { | ... | @@ -2523,8 +2533,7 @@ pub fn totalErrorCount(self: *Compilation) u32 { |
| 2523 | // the previous parse success, including compile errors, but we cannot | 2533 | // the previous parse success, including compile errors, but we cannot |
| 2524 | // emit them until the file succeeds parsing. | 2534 | // emit them until the file succeeds parsing. |
| 2525 | for (module.failed_decls.keys()) |key| { | 2535 | for (module.failed_decls.keys()) |key| { |
| 2526 | const decl = module.declPtr(key); | 2536 | if (module.declFileScope(key).okToReportErrors()) { |
| 2527 | if (decl.getFileScope().okToReportErrors()) { | ||
| 2528 | total += 1; | 2537 | total += 1; |
| 2529 | if (module.cimport_errors.get(key)) |errors| { | 2538 | if (module.cimport_errors.get(key)) |errors| { |
| 2530 | total += errors.len; | 2539 | total += errors.len; |
| ... | @@ -2533,8 +2542,7 @@ pub fn totalErrorCount(self: *Compilation) u32 { | ... | @@ -2533,8 +2542,7 @@ pub fn totalErrorCount(self: *Compilation) u32 { |
| 2533 | } | 2542 | } |
| 2534 | if (module.emit_h) |emit_h| { | 2543 | if (module.emit_h) |emit_h| { |
| 2535 | for (emit_h.failed_decls.keys()) |key| { | 2544 | for (emit_h.failed_decls.keys()) |key| { |
| 2536 | const decl = module.declPtr(key); | 2545 | if (module.declFileScope(key).okToReportErrors()) { |
| 2537 | if (decl.getFileScope().okToReportErrors()) { | ||
| 2538 | total += 1; | 2546 | total += 1; |
| 2539 | } | 2547 | } |
| 2540 | } | 2548 | } |
| ... | @@ -2618,7 +2626,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { | ... | @@ -2618,7 +2626,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { |
| 2618 | var it = module.failed_files.iterator(); | 2626 | var it = module.failed_files.iterator(); |
| 2619 | while (it.next()) |entry| { | 2627 | while (it.next()) |entry| { |
| 2620 | if (entry.value_ptr.*) |msg| { | 2628 | if (entry.value_ptr.*) |msg| { |
| 2621 | try addModuleErrorMsg(&bundle, msg.*); | 2629 | try addModuleErrorMsg(module, &bundle, msg.*); |
| 2622 | } else { | 2630 | } else { |
| 2623 | // Must be ZIR errors. Note that this may include AST errors. | 2631 | // Must be ZIR errors. Note that this may include AST errors. |
| 2624 | // addZirErrorMessages asserts that the tree is loaded. | 2632 | // addZirErrorMessages asserts that the tree is loaded. |
| ... | @@ -2631,17 +2639,17 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { | ... | @@ -2631,17 +2639,17 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { |
| 2631 | var it = module.failed_embed_files.iterator(); | 2639 | var it = module.failed_embed_files.iterator(); |
| 2632 | while (it.next()) |entry| { | 2640 | while (it.next()) |entry| { |
| 2633 | const msg = entry.value_ptr.*; | 2641 | const msg = entry.value_ptr.*; |
| 2634 | try addModuleErrorMsg(&bundle, msg.*); | 2642 | try addModuleErrorMsg(module, &bundle, msg.*); |
| 2635 | } | 2643 | } |
| 2636 | } | 2644 | } |
| 2637 | { | 2645 | { |
| 2638 | var it = module.failed_decls.iterator(); | 2646 | var it = module.failed_decls.iterator(); |
| 2639 | while (it.next()) |entry| { | 2647 | while (it.next()) |entry| { |
| 2640 | const decl = module.declPtr(entry.key_ptr.*); | 2648 | const decl_index = entry.key_ptr.*; |
| 2641 | // Skip errors for Decls within files that had a parse failure. | 2649 | // Skip errors for Decls within files that had a parse failure. |
| 2642 | // We'll try again once parsing succeeds. | 2650 | // We'll try again once parsing succeeds. |
| 2643 | if (decl.getFileScope().okToReportErrors()) { | 2651 | if (module.declFileScope(decl_index).okToReportErrors()) { |
| 2644 | try addModuleErrorMsg(&bundle, entry.value_ptr.*.*); | 2652 | try addModuleErrorMsg(module, &bundle, entry.value_ptr.*.*); |
| 2645 | if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| { | 2653 | if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| { |
| 2646 | try bundle.addRootErrorMessage(.{ | 2654 | try bundle.addRootErrorMessage(.{ |
| 2647 | .msg = try bundle.addString(std.mem.span(c_error.msg)), | 2655 | .msg = try bundle.addString(std.mem.span(c_error.msg)), |
| ... | @@ -2662,16 +2670,16 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { | ... | @@ -2662,16 +2670,16 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { |
| 2662 | if (module.emit_h) |emit_h| { | 2670 | if (module.emit_h) |emit_h| { |
| 2663 | var it = emit_h.failed_decls.iterator(); | 2671 | var it = emit_h.failed_decls.iterator(); |
| 2664 | while (it.next()) |entry| { | 2672 | while (it.next()) |entry| { |
| 2665 | const decl = module.declPtr(entry.key_ptr.*); | 2673 | const decl_index = entry.key_ptr.*; |
| 2666 | // Skip errors for Decls within files that had a parse failure. | 2674 | // Skip errors for Decls within files that had a parse failure. |
| 2667 | // We'll try again once parsing succeeds. | 2675 | // We'll try again once parsing succeeds. |
| 2668 | if (decl.getFileScope().okToReportErrors()) { | 2676 | if (module.declFileScope(decl_index).okToReportErrors()) { |
| 2669 | try addModuleErrorMsg(&bundle, entry.value_ptr.*.*); | 2677 | try addModuleErrorMsg(module, &bundle, entry.value_ptr.*.*); |
| 2670 | } | 2678 | } |
| 2671 | } | 2679 | } |
| 2672 | } | 2680 | } |
| 2673 | for (module.failed_exports.values()) |value| { | 2681 | for (module.failed_exports.values()) |value| { |
| 2674 | try addModuleErrorMsg(&bundle, value.*); | 2682 | try addModuleErrorMsg(module, &bundle, value.*); |
| 2675 | } | 2683 | } |
| 2676 | } | 2684 | } |
| 2677 | 2685 | ||
| ... | @@ -2703,7 +2711,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { | ... | @@ -2703,7 +2711,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { |
| 2703 | const values = module.compile_log_decls.values(); | 2711 | const values = module.compile_log_decls.values(); |
| 2704 | // First one will be the error; subsequent ones will be notes. | 2712 | // First one will be the error; subsequent ones will be notes. |
| 2705 | const err_decl = module.declPtr(keys[0]); | 2713 | const err_decl = module.declPtr(keys[0]); |
| 2706 | const src_loc = err_decl.nodeOffsetSrcLoc(values[0]); | 2714 | const src_loc = err_decl.nodeOffsetSrcLoc(values[0], module); |
| 2707 | const err_msg = Module.ErrorMsg{ | 2715 | const err_msg = Module.ErrorMsg{ |
| 2708 | .src_loc = src_loc, | 2716 | .src_loc = src_loc, |
| 2709 | .msg = "found compile log statement", | 2717 | .msg = "found compile log statement", |
| ... | @@ -2714,12 +2722,12 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { | ... | @@ -2714,12 +2722,12 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { |
| 2714 | for (keys[1..], 0..) |key, i| { | 2722 | for (keys[1..], 0..) |key, i| { |
| 2715 | const note_decl = module.declPtr(key); | 2723 | const note_decl = module.declPtr(key); |
| 2716 | err_msg.notes[i] = .{ | 2724 | err_msg.notes[i] = .{ |
| 2717 | .src_loc = note_decl.nodeOffsetSrcLoc(values[i + 1]), | 2725 | .src_loc = note_decl.nodeOffsetSrcLoc(values[i + 1], module), |
| 2718 | .msg = "also here", | 2726 | .msg = "also here", |
| 2719 | }; | 2727 | }; |
| 2720 | } | 2728 | } |
| 2721 | 2729 | ||
| 2722 | try addModuleErrorMsg(&bundle, err_msg); | 2730 | try addModuleErrorMsg(module, &bundle, err_msg); |
| 2723 | } | 2731 | } |
| 2724 | } | 2732 | } |
| 2725 | 2733 | ||
| ... | @@ -2775,8 +2783,9 @@ pub const ErrorNoteHashContext = struct { | ... | @@ -2775,8 +2783,9 @@ pub const ErrorNoteHashContext = struct { |
| 2775 | } | 2783 | } |
| 2776 | }; | 2784 | }; |
| 2777 | 2785 | ||
| 2778 | pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) !void { | 2786 | pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) !void { |
| 2779 | const gpa = eb.gpa; | 2787 | const gpa = eb.gpa; |
| 2788 | const ip = &mod.intern_pool; | ||
| 2780 | const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| { | 2789 | const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| { |
| 2781 | const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa); | 2790 | const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa); |
| 2782 | defer gpa.free(file_path); | 2791 | defer gpa.free(file_path); |
| ... | @@ -2802,7 +2811,7 @@ pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) | ... | @@ -2802,7 +2811,7 @@ pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) |
| 2802 | .src_loc = .none, | 2811 | .src_loc = .none, |
| 2803 | }); | 2812 | }); |
| 2804 | break; | 2813 | break; |
| 2805 | } else if (module_reference.decl == null) { | 2814 | } else if (module_reference.decl == .none) { |
| 2806 | try ref_traces.append(gpa, .{ | 2815 | try ref_traces.append(gpa, .{ |
| 2807 | .decl_name = 0, | 2816 | .decl_name = 0, |
| 2808 | .src_loc = .none, | 2817 | .src_loc = .none, |
| ... | @@ -2815,7 +2824,7 @@ pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) | ... | @@ -2815,7 +2824,7 @@ pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) |
| 2815 | const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa); | 2824 | const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa); |
| 2816 | defer gpa.free(rt_file_path); | 2825 | defer gpa.free(rt_file_path); |
| 2817 | try ref_traces.append(gpa, .{ | 2826 | try ref_traces.append(gpa, .{ |
| 2818 | .decl_name = try eb.addString(std.mem.sliceTo(module_reference.decl.?, 0)), | 2827 | .decl_name = try eb.addString(ip.stringToSliceUnwrap(module_reference.decl).?), |
| 2819 | .src_loc = try eb.addSourceLocation(.{ | 2828 | .src_loc = try eb.addSourceLocation(.{ |
| 2820 | .src_path = try eb.addString(rt_file_path), | 2829 | .src_path = try eb.addString(rt_file_path), |
| 2821 | .span_start = span.start, | 2830 | .span_start = span.start, |
| ... | @@ -3204,7 +3213,8 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v | ... | @@ -3204,7 +3213,8 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v |
| 3204 | // Tests are always emitted in test binaries. The decl_refs are created by | 3213 | // Tests are always emitted in test binaries. The decl_refs are created by |
| 3205 | // Module.populateTestFunctions, but this will not queue body analysis, so do | 3214 | // Module.populateTestFunctions, but this will not queue body analysis, so do |
| 3206 | // that now. | 3215 | // that now. |
| 3207 | try module.ensureFuncBodyAnalysisQueued(decl.val.castTag(.function).?.data); | 3216 | const func_index = module.intern_pool.indexToFunc(decl.val.ip_index).unwrap().?; |
| 3217 | try module.ensureFuncBodyAnalysisQueued(func_index); | ||
| 3208 | } | 3218 | } |
| 3209 | }, | 3219 | }, |
| 3210 | .update_embed_file => |embed_file| { | 3220 | .update_embed_file => |embed_file| { |
| ... | @@ -3228,7 +3238,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v | ... | @@ -3228,7 +3238,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v |
| 3228 | try module.failed_decls.ensureUnusedCapacity(gpa, 1); | 3238 | try module.failed_decls.ensureUnusedCapacity(gpa, 1); |
| 3229 | module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( | 3239 | module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( |
| 3230 | gpa, | 3240 | gpa, |
| 3231 | decl.srcLoc(), | 3241 | decl.srcLoc(module), |
| 3232 | "unable to update line number: {s}", | 3242 | "unable to update line number: {s}", |
| 3233 | .{@errorName(err)}, | 3243 | .{@errorName(err)}, |
| 3234 | )); | 3244 | )); |
| ... | @@ -3841,7 +3851,7 @@ fn reportRetryableEmbedFileError( | ... | @@ -3841,7 +3851,7 @@ fn reportRetryableEmbedFileError( |
| 3841 | const mod = comp.bin_file.options.module.?; | 3851 | const mod = comp.bin_file.options.module.?; |
| 3842 | const gpa = mod.gpa; | 3852 | const gpa = mod.gpa; |
| 3843 | 3853 | ||
| 3844 | const src_loc: Module.SrcLoc = mod.declPtr(embed_file.owner_decl).srcLoc(); | 3854 | const src_loc: Module.SrcLoc = mod.declPtr(embed_file.owner_decl).srcLoc(mod); |
| 3845 | 3855 | ||
| 3846 | const err_msg = if (embed_file.pkg.root_src_directory.path) |dir_path| | 3856 | const err_msg = if (embed_file.pkg.root_src_directory.path) |dir_path| |
| 3847 | try Module.ErrorMsg.create( | 3857 | try Module.ErrorMsg.create( |
| ... | @@ -5417,6 +5427,7 @@ fn buildOutputFromZig( | ... | @@ -5417,6 +5427,7 @@ fn buildOutputFromZig( |
| 5417 | .verbose_cc = comp.verbose_cc, | 5427 | .verbose_cc = comp.verbose_cc, |
| 5418 | .verbose_link = comp.bin_file.options.verbose_link, | 5428 | .verbose_link = comp.bin_file.options.verbose_link, |
| 5419 | .verbose_air = comp.verbose_air, | 5429 | .verbose_air = comp.verbose_air, |
| 5430 | .verbose_intern_pool = comp.verbose_intern_pool, | ||
| 5420 | .verbose_llvm_ir = comp.verbose_llvm_ir, | 5431 | .verbose_llvm_ir = comp.verbose_llvm_ir, |
| 5421 | .verbose_llvm_bc = comp.verbose_llvm_bc, | 5432 | .verbose_llvm_bc = comp.verbose_llvm_bc, |
| 5422 | .verbose_cimport = comp.verbose_cimport, | 5433 | .verbose_cimport = comp.verbose_cimport, |
| ... | @@ -5495,6 +5506,7 @@ pub fn build_crt_file( | ... | @@ -5495,6 +5506,7 @@ pub fn build_crt_file( |
| 5495 | .verbose_cc = comp.verbose_cc, | 5506 | .verbose_cc = comp.verbose_cc, |
| 5496 | .verbose_link = comp.bin_file.options.verbose_link, | 5507 | .verbose_link = comp.bin_file.options.verbose_link, |
| 5497 | .verbose_air = comp.verbose_air, | 5508 | .verbose_air = comp.verbose_air, |
| 5509 | .verbose_intern_pool = comp.verbose_intern_pool, | ||
| 5498 | .verbose_llvm_ir = comp.verbose_llvm_ir, | 5510 | .verbose_llvm_ir = comp.verbose_llvm_ir, |
| 5499 | .verbose_llvm_bc = comp.verbose_llvm_bc, | 5511 | .verbose_llvm_bc = comp.verbose_llvm_bc, |
| 5500 | .verbose_cimport = comp.verbose_cimport, | 5512 | .verbose_cimport = comp.verbose_cimport, |
src/InternPool.zig+5742-266| ... | @@ -1,316 +1,5792 @@ | ... | @@ -1,316 +1,5792 @@ |
| 1 | //! All interned objects have both a value and a type. | ||
| 2 | //! This data structure is self-contained, with the following exceptions: | ||
| 3 | //! * type_struct via Module.Struct.Index | ||
| 4 | //! * type_opaque via Module.Namespace.Index and Module.Decl.Index | ||
| 5 | |||
| 6 | /// Maps `Key` to `Index`. `Key` objects are not stored anywhere; they are | ||
| 7 | /// constructed lazily. | ||
| 1 | map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, | 8 | map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, |
| 2 | items: std.MultiArrayList(Item) = .{}, | 9 | items: std.MultiArrayList(Item) = .{}, |
| 3 | extra: std.ArrayListUnmanaged(u32) = .{}, | 10 | extra: std.ArrayListUnmanaged(u32) = .{}, |
| 11 | /// On 32-bit systems, this array is ignored and extra is used for everything. | ||
| 12 | /// On 64-bit systems, this array is used for big integers and associated metadata. | ||
| 13 | /// Use the helper methods instead of accessing this directly in order to not | ||
| 14 | /// violate the above mechanism. | ||
| 15 | limbs: std.ArrayListUnmanaged(u64) = .{}, | ||
| 16 | /// In order to store references to strings in fewer bytes, we copy all | ||
| 17 | /// string bytes into here. String bytes can be null. It is up to whomever | ||
| 18 | /// is referencing the data here whether they want to store both index and length, | ||
| 19 | /// thus allowing null bytes, or store only index, and use null-termination. The | ||
| 20 | /// `string_bytes` array is agnostic to either usage. | ||
| 21 | string_bytes: std.ArrayListUnmanaged(u8) = .{}, | ||
| 4 | 22 | ||
| 5 | const InternPool = @This(); | 23 | /// Struct objects are stored in this data structure because: |
| 24 | /// * They contain pointers such as the field maps. | ||
| 25 | /// * They need to be mutated after creation. | ||
| 26 | allocated_structs: std.SegmentedList(Module.Struct, 0) = .{}, | ||
| 27 | /// When a Struct object is freed from `allocated_structs`, it is pushed into this stack. | ||
| 28 | structs_free_list: std.ArrayListUnmanaged(Module.Struct.Index) = .{}, | ||
| 29 | |||
| 30 | /// Union objects are stored in this data structure because: | ||
| 31 | /// * They contain pointers such as the field maps. | ||
| 32 | /// * They need to be mutated after creation. | ||
| 33 | allocated_unions: std.SegmentedList(Module.Union, 0) = .{}, | ||
| 34 | /// When a Union object is freed from `allocated_unions`, it is pushed into this stack. | ||
| 35 | unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{}, | ||
| 36 | |||
| 37 | /// Fn objects are stored in this data structure because: | ||
| 38 | /// * They need to be mutated after creation. | ||
| 39 | allocated_funcs: std.SegmentedList(Module.Fn, 0) = .{}, | ||
| 40 | /// When a Fn object is freed from `allocated_funcs`, it is pushed into this stack. | ||
| 41 | funcs_free_list: std.ArrayListUnmanaged(Module.Fn.Index) = .{}, | ||
| 42 | |||
| 43 | /// InferredErrorSet objects are stored in this data structure because: | ||
| 44 | /// * They contain pointers such as the errors map and the set of other inferred error sets. | ||
| 45 | /// * They need to be mutated after creation. | ||
| 46 | allocated_inferred_error_sets: std.SegmentedList(Module.Fn.InferredErrorSet, 0) = .{}, | ||
| 47 | /// When a Struct object is freed from `allocated_inferred_error_sets`, it is | ||
| 48 | /// pushed into this stack. | ||
| 49 | inferred_error_sets_free_list: std.ArrayListUnmanaged(Module.Fn.InferredErrorSet.Index) = .{}, | ||
| 50 | |||
| 51 | /// Some types such as enums, structs, and unions need to store mappings from field names | ||
| 52 | /// to field index, or value to field index. In such cases, they will store the underlying | ||
| 53 | /// field names and values directly, relying on one of these maps, stored separately, | ||
| 54 | /// to provide lookup. | ||
| 55 | maps: std.ArrayListUnmanaged(std.AutoArrayHashMapUnmanaged(void, void)) = .{}, | ||
| 56 | |||
| 57 | /// Used for finding the index inside `string_bytes`. | ||
| 58 | string_table: std.HashMapUnmanaged( | ||
| 59 | u32, | ||
| 60 | void, | ||
| 61 | std.hash_map.StringIndexContext, | ||
| 62 | std.hash_map.default_max_load_percentage, | ||
| 63 | ) = .{}, | ||
| 64 | |||
| 65 | const builtin = @import("builtin"); | ||
| 6 | const std = @import("std"); | 66 | const std = @import("std"); |
| 7 | const Allocator = std.mem.Allocator; | 67 | const Allocator = std.mem.Allocator; |
| 8 | const assert = std.debug.assert; | 68 | const assert = std.debug.assert; |
| 69 | const BigIntConst = std.math.big.int.Const; | ||
| 70 | const BigIntMutable = std.math.big.int.Mutable; | ||
| 71 | const Limb = std.math.big.Limb; | ||
| 72 | const Hash = std.hash.Wyhash; | ||
| 73 | |||
| 74 | const InternPool = @This(); | ||
| 75 | const Module = @import("Module.zig"); | ||
| 76 | const Sema = @import("Sema.zig"); | ||
| 9 | 77 | ||
| 10 | const KeyAdapter = struct { | 78 | const KeyAdapter = struct { |
| 11 | intern_pool: *const InternPool, | 79 | intern_pool: *const InternPool, |
| 12 | 80 | ||
| 13 | pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool { | 81 | pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool { |
| 14 | _ = b_void; | 82 | _ = b_void; |
| 15 | return ctx.intern_pool.indexToKey(@intToEnum(Index, b_map_index)).eql(a); | 83 | return ctx.intern_pool.indexToKey(@intToEnum(Index, b_map_index)).eql(a, ctx.intern_pool); |
| 16 | } | 84 | } |
| 17 | 85 | ||
| 18 | pub fn hash(ctx: @This(), a: Key) u32 { | 86 | pub fn hash(ctx: @This(), a: Key) u32 { |
| 19 | _ = ctx; | 87 | return a.hash32(ctx.intern_pool); |
| 20 | return a.hash(); | ||
| 21 | } | 88 | } |
| 22 | }; | 89 | }; |
| 23 | 90 | ||
| 24 | pub const Key = union(enum) { | 91 | /// An index into `maps` which might be `none`. |
| 25 | int_type: struct { | 92 | pub const OptionalMapIndex = enum(u32) { |
| 26 | signedness: std.builtin.Signedness, | 93 | none = std.math.maxInt(u32), |
| 27 | bits: u16, | 94 | _, |
| 28 | }, | ||
| 29 | ptr_type: struct { | ||
| 30 | elem_type: Index, | ||
| 31 | sentinel: Index, | ||
| 32 | alignment: u16, | ||
| 33 | size: std.builtin.Type.Pointer.Size, | ||
| 34 | is_const: bool, | ||
| 35 | is_volatile: bool, | ||
| 36 | is_allowzero: bool, | ||
| 37 | address_space: std.builtin.AddressSpace, | ||
| 38 | }, | ||
| 39 | array_type: struct { | ||
| 40 | len: u64, | ||
| 41 | child: Index, | ||
| 42 | sentinel: Index, | ||
| 43 | }, | ||
| 44 | vector_type: struct { | ||
| 45 | len: u32, | ||
| 46 | child: Index, | ||
| 47 | }, | ||
| 48 | optional_type: struct { | ||
| 49 | payload_type: Index, | ||
| 50 | }, | ||
| 51 | error_union_type: struct { | ||
| 52 | error_set_type: Index, | ||
| 53 | payload_type: Index, | ||
| 54 | }, | ||
| 55 | simple: Simple, | ||
| 56 | 95 | ||
| 57 | pub fn hash(key: Key) u32 { | 96 | pub fn unwrap(oi: OptionalMapIndex) ?MapIndex { |
| 58 | var hasher = std.hash.Wyhash.init(0); | 97 | if (oi == .none) return null; |
| 59 | switch (key) { | 98 | return @intToEnum(MapIndex, @enumToInt(oi)); |
| 60 | .int_type => |int_type| { | ||
| 61 | std.hash.autoHash(&hasher, int_type); | ||
| 62 | }, | ||
| 63 | .array_type => |array_type| { | ||
| 64 | std.hash.autoHash(&hasher, array_type); | ||
| 65 | }, | ||
| 66 | else => @panic("TODO"), | ||
| 67 | } | ||
| 68 | return @truncate(u32, hasher.final()); | ||
| 69 | } | 99 | } |
| 100 | }; | ||
| 70 | 101 | ||
| 71 | pub fn eql(a: Key, b: Key) bool { | 102 | /// An index into `maps`. |
| 72 | const KeyTag = std.meta.Tag(Key); | 103 | pub const MapIndex = enum(u32) { |
| 73 | const a_tag: KeyTag = a; | 104 | _, |
| 74 | const b_tag: KeyTag = b; | 105 | |
| 75 | if (a_tag != b_tag) return false; | 106 | pub fn toOptional(i: MapIndex) OptionalMapIndex { |
| 76 | switch (a) { | 107 | return @intToEnum(OptionalMapIndex, @enumToInt(i)); |
| 77 | .int_type => |a_info| { | ||
| 78 | const b_info = b.int_type; | ||
| 79 | return std.meta.eql(a_info, b_info); | ||
| 80 | }, | ||
| 81 | .array_type => |a_info| { | ||
| 82 | const b_info = b.array_type; | ||
| 83 | return std.meta.eql(a_info, b_info); | ||
| 84 | }, | ||
| 85 | else => @panic("TODO"), | ||
| 86 | } | ||
| 87 | } | 108 | } |
| 88 | }; | 109 | }; |
| 89 | 110 | ||
| 90 | pub const Item = struct { | 111 | pub const RuntimeIndex = enum(u32) { |
| 91 | tag: Tag, | 112 | zero = 0, |
| 92 | /// The doc comments on the respective Tag explain how to interpret this. | 113 | comptime_field_ptr = std.math.maxInt(u32), |
| 93 | data: u32, | 114 | _, |
| 115 | |||
| 116 | pub fn increment(ri: *RuntimeIndex) void { | ||
| 117 | ri.* = @intToEnum(RuntimeIndex, @enumToInt(ri.*) + 1); | ||
| 118 | } | ||
| 94 | }; | 119 | }; |
| 95 | 120 | ||
| 96 | /// Represents an index into `map`. It represents the canonical index | 121 | /// An index into `string_bytes`. |
| 97 | /// of a `Value` within this `InternPool`. The values are typed. | 122 | pub const String = enum(u32) { |
| 98 | /// Two values which have the same type can be equality compared simply | ||
| 99 | /// by checking if their indexes are equal, provided they are both in | ||
| 100 | /// the same `InternPool`. | ||
| 101 | pub const Index = enum(u32) { | ||
| 102 | none = std.math.maxInt(u32), | ||
| 103 | _, | 123 | _, |
| 104 | }; | 124 | }; |
| 105 | 125 | ||
| 106 | pub const Tag = enum(u8) { | 126 | /// An index into `string_bytes`. |
| 107 | /// An integer type. | 127 | pub const NullTerminatedString = enum(u32) { |
| 108 | /// data is number of bits | 128 | /// This is distinct from `none` - it is a valid index that represents empty string. |
| 109 | type_int_signed, | 129 | empty = 0, |
| 110 | /// An integer type. | 130 | _, |
| 111 | /// data is number of bits | ||
| 112 | type_int_unsigned, | ||
| 113 | /// An array type. | ||
| 114 | /// data is payload to Array. | ||
| 115 | type_array, | ||
| 116 | /// A type or value that can be represented with only an enum tag. | ||
| 117 | /// data is Simple enum value | ||
| 118 | simple, | ||
| 119 | /// An unsigned integer value that can be represented by u32. | ||
| 120 | /// data is integer value | ||
| 121 | int_u32, | ||
| 122 | /// An unsigned integer value that can be represented by i32. | ||
| 123 | /// data is integer value bitcasted to u32. | ||
| 124 | int_i32, | ||
| 125 | /// A positive integer value that does not fit in 32 bits. | ||
| 126 | /// data is a extra index to BigInt. | ||
| 127 | int_big_positive, | ||
| 128 | /// A negative integer value that does not fit in 32 bits. | ||
| 129 | /// data is a extra index to BigInt. | ||
| 130 | int_big_negative, | ||
| 131 | /// A float value that can be represented by f32. | ||
| 132 | /// data is float value bitcasted to u32. | ||
| 133 | float_f32, | ||
| 134 | /// A float value that can be represented by f64. | ||
| 135 | /// data is payload index to Float64. | ||
| 136 | float_f64, | ||
| 137 | /// A float value that can be represented by f128. | ||
| 138 | /// data is payload index to Float128. | ||
| 139 | float_f128, | ||
| 140 | }; | ||
| 141 | 131 | ||
| 142 | pub const Simple = enum(u32) { | 132 | pub fn toString(self: NullTerminatedString) String { |
| 143 | f16, | 133 | return @intToEnum(String, @enumToInt(self)); |
| 144 | f32, | 134 | } |
| 145 | f64, | ||
| 146 | f80, | ||
| 147 | f128, | ||
| 148 | usize, | ||
| 149 | isize, | ||
| 150 | c_short, | ||
| 151 | c_ushort, | ||
| 152 | c_int, | ||
| 153 | c_uint, | ||
| 154 | c_long, | ||
| 155 | c_ulong, | ||
| 156 | c_longlong, | ||
| 157 | c_ulonglong, | ||
| 158 | c_longdouble, | ||
| 159 | anyopaque, | ||
| 160 | bool, | ||
| 161 | void, | ||
| 162 | type, | ||
| 163 | anyerror, | ||
| 164 | comptime_int, | ||
| 165 | comptime_float, | ||
| 166 | noreturn, | ||
| 167 | @"anyframe", | ||
| 168 | null_type, | ||
| 169 | undefined_type, | ||
| 170 | enum_literal_type, | ||
| 171 | undefined, | ||
| 172 | void_value, | ||
| 173 | null, | ||
| 174 | bool_true, | ||
| 175 | bool_false, | ||
| 176 | }; | ||
| 177 | 135 | ||
| 178 | pub const Array = struct { | 136 | pub fn toOptional(self: NullTerminatedString) OptionalNullTerminatedString { |
| 179 | len: u32, | 137 | return @intToEnum(OptionalNullTerminatedString, @enumToInt(self)); |
| 180 | child: Index, | 138 | } |
| 181 | }; | ||
| 182 | 139 | ||
| 183 | pub fn deinit(ip: *InternPool, gpa: Allocator) void { | 140 | const Adapter = struct { |
| 184 | ip.map.deinit(gpa); | 141 | strings: []const NullTerminatedString, |
| 185 | ip.items.deinit(gpa); | ||
| 186 | ip.extra.deinit(gpa); | ||
| 187 | } | ||
| 188 | 142 | ||
| 189 | pub fn indexToKey(ip: InternPool, index: Index) Key { | 143 | pub fn eql(ctx: @This(), a: NullTerminatedString, b_void: void, b_map_index: usize) bool { |
| 190 | const item = ip.items.get(@enumToInt(index)); | 144 | _ = b_void; |
| 191 | const data = item.data; | 145 | return a == ctx.strings[b_map_index]; |
| 192 | return switch (item.tag) { | 146 | } |
| 193 | .type_int_signed => .{ | ||
| 194 | .int_type = .{ | ||
| 195 | .signedness = .signed, | ||
| 196 | .bits = @intCast(u16, data), | ||
| 197 | }, | ||
| 198 | }, | ||
| 199 | .type_int_unsigned => .{ | ||
| 200 | .int_type = .{ | ||
| 201 | .signedness = .unsigned, | ||
| 202 | .bits = @intCast(u16, data), | ||
| 203 | }, | ||
| 204 | }, | ||
| 205 | .type_array => { | ||
| 206 | const array_info = ip.extraData(Array, data); | ||
| 207 | return .{ .array_type = .{ | ||
| 208 | .len = array_info.len, | ||
| 209 | .child = array_info.child, | ||
| 210 | .sentinel = .none, | ||
| 211 | } }; | ||
| 212 | }, | ||
| 213 | .simple => .{ .simple = @intToEnum(Simple, data) }, | ||
| 214 | 147 | ||
| 215 | else => @panic("TODO"), | 148 | pub fn hash(ctx: @This(), a: NullTerminatedString) u32 { |
| 149 | _ = ctx; | ||
| 150 | return std.hash.uint32(@enumToInt(a)); | ||
| 151 | } | ||
| 216 | }; | 152 | }; |
| 217 | } | ||
| 218 | 153 | ||
| 219 | pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | 154 | /// Compare based on integer value alone, ignoring the string contents. |
| 220 | const adapter: KeyAdapter = .{ .intern_pool = ip }; | 155 | pub fn indexLessThan(ctx: void, a: NullTerminatedString, b: NullTerminatedString) bool { |
| 221 | const gop = try ip.map.getOrPutAdapted(gpa, key, adapter); | 156 | _ = ctx; |
| 222 | if (gop.found_existing) { | 157 | return @enumToInt(a) < @enumToInt(b); |
| 223 | return @intToEnum(Index, gop.index); | ||
| 224 | } | 158 | } |
| 225 | switch (key) { | 159 | |
| 226 | .int_type => |int_type| { | 160 | pub fn toUnsigned(self: NullTerminatedString, ip: *const InternPool) ?u32 { |
| 227 | const tag: Tag = switch (int_type.signedness) { | 161 | const s = ip.stringToSlice(self); |
| 228 | .signed => .type_int_signed, | 162 | if (s.len > 1 and s[0] == '0') return null; |
| 229 | .unsigned => .type_int_unsigned, | 163 | if (std.mem.indexOfScalar(u8, s, '_')) |_| return null; |
| 230 | }; | 164 | return std.fmt.parseUnsigned(u32, s, 10) catch null; |
| 231 | try ip.items.append(gpa, .{ | ||
| 232 | .tag = tag, | ||
| 233 | .data = int_type.bits, | ||
| 234 | }); | ||
| 235 | }, | ||
| 236 | .array_type => |array_type| { | ||
| 237 | const len = @intCast(u32, array_type.len); // TODO have a big_array encoding | ||
| 238 | assert(array_type.sentinel == .none); // TODO have a sentinel_array encoding | ||
| 239 | try ip.items.append(gpa, .{ | ||
| 240 | .tag = .type_array, | ||
| 241 | .data = try ip.addExtra(gpa, Array{ | ||
| 242 | .len = len, | ||
| 243 | .child = array_type.child, | ||
| 244 | }), | ||
| 245 | }); | ||
| 246 | }, | ||
| 247 | else => @panic("TODO"), | ||
| 248 | } | 165 | } |
| 249 | return @intToEnum(Index, ip.items.len - 1); | ||
| 250 | } | ||
| 251 | 166 | ||
| 252 | fn addExtra(ip: *InternPool, gpa: Allocator, extra: anytype) Allocator.Error!u32 { | 167 | const FormatData = struct { |
| 253 | const fields = std.meta.fields(@TypeOf(extra)); | 168 | string: NullTerminatedString, |
| 254 | try ip.extra.ensureUnusedCapacity(gpa, fields.len); | 169 | ip: *const InternPool, |
| 255 | return ip.addExtraAssumeCapacity(extra); | 170 | }; |
| 256 | } | 171 | fn format( |
| 172 | data: FormatData, | ||
| 173 | comptime specifier: []const u8, | ||
| 174 | _: std.fmt.FormatOptions, | ||
| 175 | writer: anytype, | ||
| 176 | ) @TypeOf(writer).Error!void { | ||
| 177 | const s = data.ip.stringToSlice(data.string); | ||
| 178 | if (comptime std.mem.eql(u8, specifier, "")) { | ||
| 179 | try writer.writeAll(s); | ||
| 180 | } else if (comptime std.mem.eql(u8, specifier, "i")) { | ||
| 181 | try writer.print("{}", .{std.zig.fmtId(s)}); | ||
| 182 | } else @compileError("invalid format string '" ++ specifier ++ "' for '" ++ @typeName(NullTerminatedString) ++ "'"); | ||
| 183 | } | ||
| 257 | 184 | ||
| 258 | fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { | 185 | pub fn fmt(self: NullTerminatedString, ip: *const InternPool) std.fmt.Formatter(format) { |
| 259 | const fields = std.meta.fields(@TypeOf(extra)); | 186 | return .{ .data = .{ .string = self, .ip = ip } }; |
| 260 | const result = @intCast(u32, ip.extra.items.len); | ||
| 261 | inline for (fields) |field| { | ||
| 262 | ip.extra.appendAssumeCapacity(switch (field.type) { | ||
| 263 | u32 => @field(extra, field.name), | ||
| 264 | Index => @enumToInt(@field(extra, field.name)), | ||
| 265 | i32 => @bitCast(u32, @field(extra, field.name)), | ||
| 266 | else => @compileError("bad field type"), | ||
| 267 | }); | ||
| 268 | } | 187 | } |
| 269 | return result; | 188 | }; |
| 270 | } | ||
| 271 | 189 | ||
| 272 | fn extraData(ip: InternPool, comptime T: type, index: usize) T { | 190 | /// An index into `string_bytes` which might be `none`. |
| 273 | const fields = std.meta.fields(T); | 191 | pub const OptionalNullTerminatedString = enum(u32) { |
| 274 | var i: usize = index; | 192 | /// This is distinct from `none` - it is a valid index that represents empty string. |
| 275 | var result: T = undefined; | 193 | empty = 0, |
| 276 | inline for (fields) |field| { | 194 | none = std.math.maxInt(u32), |
| 277 | @field(result, field.name) = switch (field.type) { | 195 | _, |
| 278 | u32 => ip.extra.items[i], | 196 | |
| 279 | Index => @intToEnum(Index, ip.extra.items[i]), | 197 | pub fn unwrap(oi: OptionalNullTerminatedString) ?NullTerminatedString { |
| 280 | i32 => @bitCast(i32, ip.extra.items[i]), | 198 | if (oi == .none) return null; |
| 281 | else => @compileError("bad field type"), | 199 | return @intToEnum(NullTerminatedString, @enumToInt(oi)); |
| 282 | }; | ||
| 283 | i += 1; | ||
| 284 | } | 200 | } |
| 285 | return result; | 201 | }; |
| 286 | } | ||
| 287 | 202 | ||
| 288 | test "basic usage" { | 203 | pub const Key = union(enum) { |
| 289 | const gpa = std.testing.allocator; | 204 | int_type: IntType, |
| 205 | ptr_type: PtrType, | ||
| 206 | array_type: ArrayType, | ||
| 207 | vector_type: VectorType, | ||
| 208 | opt_type: Index, | ||
| 209 | /// `anyframe->T`. The payload is the child type, which may be `none` to indicate | ||
| 210 | /// `anyframe`. | ||
| 211 | anyframe_type: Index, | ||
| 212 | error_union_type: ErrorUnionType, | ||
| 213 | simple_type: SimpleType, | ||
| 214 | /// This represents a struct that has been explicitly declared in source code, | ||
| 215 | /// or was created with `@Type`. It is unique and based on a declaration. | ||
| 216 | /// It may be a tuple, if declared like this: `struct {A, B, C}`. | ||
| 217 | struct_type: StructType, | ||
| 218 | /// This is an anonymous struct or tuple type which has no corresponding | ||
| 219 | /// declaration. It is used for types that have no `struct` keyword in the | ||
| 220 | /// source code, and were not created via `@Type`. | ||
| 221 | anon_struct_type: AnonStructType, | ||
| 222 | union_type: UnionType, | ||
| 223 | opaque_type: OpaqueType, | ||
| 224 | enum_type: EnumType, | ||
| 225 | func_type: FuncType, | ||
| 226 | error_set_type: ErrorSetType, | ||
| 227 | inferred_error_set_type: Module.Fn.InferredErrorSet.Index, | ||
| 290 | 228 | ||
| 291 | var ip: InternPool = .{}; | 229 | /// Typed `undefined`. This will never be `none`; untyped `undefined` is represented |
| 292 | defer ip.deinit(gpa); | 230 | /// via `simple_value` and has a named `Index` tag for it. |
| 231 | undef: Index, | ||
| 232 | runtime_value: TypeValue, | ||
| 233 | simple_value: SimpleValue, | ||
| 234 | variable: Variable, | ||
| 235 | extern_func: ExternFunc, | ||
| 236 | func: Func, | ||
| 237 | int: Key.Int, | ||
| 238 | err: Error, | ||
| 239 | error_union: ErrorUnion, | ||
| 240 | enum_literal: NullTerminatedString, | ||
| 241 | /// A specific enum tag, indicated by the integer tag value. | ||
| 242 | enum_tag: EnumTag, | ||
| 243 | /// An empty enum or union. TODO: this value's existence is strange, because such a type in | ||
| 244 | /// reality has no values. See #15909. | ||
| 245 | /// Payload is the type for which we are an empty value. | ||
| 246 | empty_enum_value: Index, | ||
| 247 | float: Float, | ||
| 248 | ptr: Ptr, | ||
| 249 | opt: Opt, | ||
| 250 | /// An instance of a struct, array, or vector. | ||
| 251 | /// Each element/field stored as an `Index`. | ||
| 252 | /// In the case of sentinel-terminated arrays, the sentinel value *is* stored, | ||
| 253 | /// so the slice length will be one more than the type's array length. | ||
| 254 | aggregate: Aggregate, | ||
| 255 | /// An instance of a union. | ||
| 256 | un: Union, | ||
| 293 | 257 | ||
| 294 | const i32_type = try ip.get(gpa, .{ .int_type = .{ | 258 | /// A comptime function call with a memoized result. |
| 295 | .signedness = .signed, | 259 | memoized_call: Key.MemoizedCall, |
| 296 | .bits = 32, | ||
| 297 | } }); | ||
| 298 | const array_i32 = try ip.get(gpa, .{ .array_type = .{ | ||
| 299 | .len = 10, | ||
| 300 | .child = i32_type, | ||
| 301 | .sentinel = .none, | ||
| 302 | } }); | ||
| 303 | 260 | ||
| 304 | const another_i32_type = try ip.get(gpa, .{ .int_type = .{ | 261 | pub const TypeValue = extern struct { |
| 305 | .signedness = .signed, | 262 | ty: Index, |
| 306 | .bits = 32, | 263 | val: Index, |
| 307 | } }); | 264 | }; |
| 308 | try std.testing.expect(another_i32_type == i32_type); | ||
| 309 | 265 | ||
| 310 | const another_array_i32 = try ip.get(gpa, .{ .array_type = .{ | 266 | pub const IntType = std.builtin.Type.Int; |
| 311 | .len = 10, | 267 | |
| 312 | .child = i32_type, | 268 | /// Extern for hashing via memory reinterpretation. |
| 313 | .sentinel = .none, | 269 | pub const ErrorUnionType = extern struct { |
| 314 | } }); | 270 | error_set_type: Index, |
| 315 | try std.testing.expect(another_array_i32 == array_i32); | 271 | payload_type: Index, |
| 272 | }; | ||
| 273 | |||
| 274 | pub const ErrorSetType = struct { | ||
| 275 | /// Set of error names, sorted by null terminated string index. | ||
| 276 | names: []const NullTerminatedString, | ||
| 277 | /// This is ignored by `get` but will always be provided by `indexToKey`. | ||
| 278 | names_map: OptionalMapIndex = .none, | ||
| 279 | |||
| 280 | /// Look up field index based on field name. | ||
| 281 | pub fn nameIndex(self: ErrorSetType, ip: *const InternPool, name: NullTerminatedString) ?u32 { | ||
| 282 | const map = &ip.maps.items[@enumToInt(self.names_map.unwrap().?)]; | ||
| 283 | const adapter: NullTerminatedString.Adapter = .{ .strings = self.names }; | ||
| 284 | const field_index = map.getIndexAdapted(name, adapter) orelse return null; | ||
| 285 | return @intCast(u32, field_index); | ||
| 286 | } | ||
| 287 | }; | ||
| 288 | |||
| 289 | /// Extern layout so it can be hashed with `std.mem.asBytes`. | ||
| 290 | pub const PtrType = extern struct { | ||
| 291 | child: Index, | ||
| 292 | sentinel: Index = .none, | ||
| 293 | flags: Flags = .{}, | ||
| 294 | packed_offset: PackedOffset = .{ .bit_offset = 0, .host_size = 0 }, | ||
| 295 | |||
| 296 | pub const VectorIndex = enum(u16) { | ||
| 297 | none = std.math.maxInt(u16), | ||
| 298 | runtime = std.math.maxInt(u16) - 1, | ||
| 299 | _, | ||
| 300 | }; | ||
| 301 | |||
| 302 | pub const Flags = packed struct(u32) { | ||
| 303 | size: Size = .One, | ||
| 304 | /// `none` indicates the ABI alignment of the pointee_type. In this | ||
| 305 | /// case, this field *must* be set to `none`, otherwise the | ||
| 306 | /// `InternPool` equality and hashing functions will return incorrect | ||
| 307 | /// results. | ||
| 308 | alignment: Alignment = .none, | ||
| 309 | is_const: bool = false, | ||
| 310 | is_volatile: bool = false, | ||
| 311 | is_allowzero: bool = false, | ||
| 312 | /// See src/target.zig defaultAddressSpace function for how to obtain | ||
| 313 | /// an appropriate value for this field. | ||
| 314 | address_space: AddressSpace = .generic, | ||
| 315 | vector_index: VectorIndex = .none, | ||
| 316 | }; | ||
| 317 | |||
| 318 | pub const PackedOffset = packed struct(u32) { | ||
| 319 | /// If this is non-zero it means the pointer points to a sub-byte | ||
| 320 | /// range of data, which is backed by a "host integer" with this | ||
| 321 | /// number of bytes. | ||
| 322 | /// When host_size=pointee_abi_size and bit_offset=0, this must be | ||
| 323 | /// represented with host_size=0 instead. | ||
| 324 | host_size: u16, | ||
| 325 | bit_offset: u16, | ||
| 326 | }; | ||
| 327 | |||
| 328 | pub const Size = std.builtin.Type.Pointer.Size; | ||
| 329 | pub const AddressSpace = std.builtin.AddressSpace; | ||
| 330 | }; | ||
| 331 | |||
| 332 | /// Extern so that hashing can be done via memory reinterpreting. | ||
| 333 | pub const ArrayType = extern struct { | ||
| 334 | len: u64, | ||
| 335 | child: Index, | ||
| 336 | sentinel: Index = .none, | ||
| 337 | }; | ||
| 338 | |||
| 339 | /// Extern so that hashing can be done via memory reinterpreting. | ||
| 340 | pub const VectorType = extern struct { | ||
| 341 | len: u32, | ||
| 342 | child: Index, | ||
| 343 | }; | ||
| 344 | |||
| 345 | pub const OpaqueType = extern struct { | ||
| 346 | /// The Decl that corresponds to the opaque itself. | ||
| 347 | decl: Module.Decl.Index, | ||
| 348 | /// Represents the declarations inside this opaque. | ||
| 349 | namespace: Module.Namespace.Index, | ||
| 350 | }; | ||
| 351 | |||
| 352 | pub const StructType = extern struct { | ||
| 353 | /// The `none` tag is used to represent a struct with no fields. | ||
| 354 | index: Module.Struct.OptionalIndex, | ||
| 355 | /// May be `none` if the struct has no declarations. | ||
| 356 | namespace: Module.Namespace.OptionalIndex, | ||
| 357 | }; | ||
| 358 | |||
| 359 | pub const AnonStructType = struct { | ||
| 360 | types: []const Index, | ||
| 361 | /// This may be empty, indicating this is a tuple. | ||
| 362 | names: []const NullTerminatedString, | ||
| 363 | /// These elements may be `none`, indicating runtime-known. | ||
| 364 | values: []const Index, | ||
| 365 | |||
| 366 | pub fn isTuple(self: AnonStructType) bool { | ||
| 367 | return self.names.len == 0; | ||
| 368 | } | ||
| 369 | }; | ||
| 370 | |||
| 371 | pub const UnionType = struct { | ||
| 372 | index: Module.Union.Index, | ||
| 373 | runtime_tag: RuntimeTag, | ||
| 374 | |||
| 375 | pub const RuntimeTag = enum { none, safety, tagged }; | ||
| 376 | |||
| 377 | pub fn hasTag(self: UnionType) bool { | ||
| 378 | return switch (self.runtime_tag) { | ||
| 379 | .none => false, | ||
| 380 | .tagged, .safety => true, | ||
| 381 | }; | ||
| 382 | } | ||
| 383 | }; | ||
| 384 | |||
| 385 | pub const EnumType = struct { | ||
| 386 | /// The Decl that corresponds to the enum itself. | ||
| 387 | decl: Module.Decl.Index, | ||
| 388 | /// Represents the declarations inside this enum. | ||
| 389 | namespace: Module.Namespace.OptionalIndex, | ||
| 390 | /// An integer type which is used for the numerical value of the enum. | ||
| 391 | /// This field is present regardless of whether the enum has an | ||
| 392 | /// explicitly provided tag type or auto-numbered. | ||
| 393 | tag_ty: Index, | ||
| 394 | /// Set of field names in declaration order. | ||
| 395 | names: []const NullTerminatedString, | ||
| 396 | /// Maps integer tag value to field index. | ||
| 397 | /// Entries are in declaration order, same as `fields`. | ||
| 398 | /// If this is empty, it means the enum tags are auto-numbered. | ||
| 399 | values: []const Index, | ||
| 400 | tag_mode: TagMode, | ||
| 401 | /// This is ignored by `get` but will always be provided by `indexToKey`. | ||
| 402 | names_map: OptionalMapIndex = .none, | ||
| 403 | /// This is ignored by `get` but will be provided by `indexToKey` when | ||
| 404 | /// a value map exists. | ||
| 405 | values_map: OptionalMapIndex = .none, | ||
| 406 | |||
| 407 | pub const TagMode = enum { | ||
| 408 | /// The integer tag type was auto-numbered by zig. | ||
| 409 | auto, | ||
| 410 | /// The integer tag type was provided by the enum declaration, and the enum | ||
| 411 | /// is exhaustive. | ||
| 412 | explicit, | ||
| 413 | /// The integer tag type was provided by the enum declaration, and the enum | ||
| 414 | /// is non-exhaustive. | ||
| 415 | nonexhaustive, | ||
| 416 | }; | ||
| 417 | |||
| 418 | /// Look up field index based on field name. | ||
| 419 | pub fn nameIndex(self: EnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 { | ||
| 420 | const map = &ip.maps.items[@enumToInt(self.names_map.unwrap().?)]; | ||
| 421 | const adapter: NullTerminatedString.Adapter = .{ .strings = self.names }; | ||
| 422 | const field_index = map.getIndexAdapted(name, adapter) orelse return null; | ||
| 423 | return @intCast(u32, field_index); | ||
| 424 | } | ||
| 425 | |||
| 426 | /// Look up field index based on tag value. | ||
| 427 | /// Asserts that `values_map` is not `none`. | ||
| 428 | /// This function returns `null` when `tag_val` does not have the | ||
| 429 | /// integer tag type of the enum. | ||
| 430 | pub fn tagValueIndex(self: EnumType, ip: *const InternPool, tag_val: Index) ?u32 { | ||
| 431 | assert(tag_val != .none); | ||
| 432 | // TODO: we should probably decide a single interface for this function, but currently | ||
| 433 | // it's being called with both tag values and underlying ints. Fix this! | ||
| 434 | const int_tag_val = switch (ip.indexToKey(tag_val)) { | ||
| 435 | .enum_tag => |enum_tag| enum_tag.int, | ||
| 436 | .int => tag_val, | ||
| 437 | else => unreachable, | ||
| 438 | }; | ||
| 439 | if (self.values_map.unwrap()) |values_map| { | ||
| 440 | const map = &ip.maps.items[@enumToInt(values_map)]; | ||
| 441 | const adapter: Index.Adapter = .{ .indexes = self.values }; | ||
| 442 | const field_index = map.getIndexAdapted(int_tag_val, adapter) orelse return null; | ||
| 443 | return @intCast(u32, field_index); | ||
| 444 | } | ||
| 445 | // Auto-numbered enum. Convert `int_tag_val` to field index. | ||
| 446 | switch (ip.indexToKey(int_tag_val).int.storage) { | ||
| 447 | .u64 => |x| { | ||
| 448 | if (x >= self.names.len) return null; | ||
| 449 | return @intCast(u32, x); | ||
| 450 | }, | ||
| 451 | .i64, .big_int => return null, // out of range | ||
| 452 | .lazy_align, .lazy_size => unreachable, | ||
| 453 | } | ||
| 454 | } | ||
| 455 | }; | ||
| 456 | |||
| 457 | pub const IncompleteEnumType = struct { | ||
| 458 | /// Same as corresponding `EnumType` field. | ||
| 459 | decl: Module.Decl.Index, | ||
| 460 | /// Same as corresponding `EnumType` field. | ||
| 461 | namespace: Module.Namespace.OptionalIndex, | ||
| 462 | /// The field names and field values are not known yet, but | ||
| 463 | /// the number of fields must be known ahead of time. | ||
| 464 | fields_len: u32, | ||
| 465 | /// This information is needed so that the size does not change | ||
| 466 | /// later when populating field values. | ||
| 467 | has_values: bool, | ||
| 468 | /// Same as corresponding `EnumType` field. | ||
| 469 | tag_mode: EnumType.TagMode, | ||
| 470 | /// This may be updated via `setTagType` later. | ||
| 471 | tag_ty: Index = .none, | ||
| 472 | |||
| 473 | pub fn toEnumType(self: @This()) EnumType { | ||
| 474 | return .{ | ||
| 475 | .decl = self.decl, | ||
| 476 | .namespace = self.namespace, | ||
| 477 | .tag_ty = self.tag_ty, | ||
| 478 | .tag_mode = self.tag_mode, | ||
| 479 | .names = &.{}, | ||
| 480 | .values = &.{}, | ||
| 481 | }; | ||
| 482 | } | ||
| 483 | |||
| 484 | /// Only the decl is used for hashing and equality, so we can construct | ||
| 485 | /// this minimal key for use with `map`. | ||
| 486 | pub fn toKey(self: @This()) Key { | ||
| 487 | return .{ .enum_type = self.toEnumType() }; | ||
| 488 | } | ||
| 489 | }; | ||
| 490 | |||
| 491 | pub const FuncType = struct { | ||
| 492 | param_types: []Index, | ||
| 493 | return_type: Index, | ||
| 494 | /// Tells whether a parameter is comptime. See `paramIsComptime` helper | ||
| 495 | /// method for accessing this. | ||
| 496 | comptime_bits: u32, | ||
| 497 | /// Tells whether a parameter is noalias. See `paramIsNoalias` helper | ||
| 498 | /// method for accessing this. | ||
| 499 | noalias_bits: u32, | ||
| 500 | /// `none` indicates the function has the default alignment for | ||
| 501 | /// function code on the target. In this case, this field *must* be set | ||
| 502 | /// to `none`, otherwise the `InternPool` equality and hashing | ||
| 503 | /// functions will return incorrect results. | ||
| 504 | alignment: Alignment, | ||
| 505 | cc: std.builtin.CallingConvention, | ||
| 506 | is_var_args: bool, | ||
| 507 | is_generic: bool, | ||
| 508 | is_noinline: bool, | ||
| 509 | align_is_generic: bool, | ||
| 510 | cc_is_generic: bool, | ||
| 511 | section_is_generic: bool, | ||
| 512 | addrspace_is_generic: bool, | ||
| 513 | |||
| 514 | pub fn paramIsComptime(self: @This(), i: u5) bool { | ||
| 515 | assert(i < self.param_types.len); | ||
| 516 | return @truncate(u1, self.comptime_bits >> i) != 0; | ||
| 517 | } | ||
| 518 | |||
| 519 | pub fn paramIsNoalias(self: @This(), i: u5) bool { | ||
| 520 | assert(i < self.param_types.len); | ||
| 521 | return @truncate(u1, self.noalias_bits >> i) != 0; | ||
| 522 | } | ||
| 523 | }; | ||
| 524 | |||
| 525 | pub const Variable = struct { | ||
| 526 | ty: Index, | ||
| 527 | init: Index, | ||
| 528 | decl: Module.Decl.Index, | ||
| 529 | lib_name: OptionalNullTerminatedString = .none, | ||
| 530 | is_extern: bool = false, | ||
| 531 | is_const: bool = false, | ||
| 532 | is_threadlocal: bool = false, | ||
| 533 | is_weak_linkage: bool = false, | ||
| 534 | }; | ||
| 535 | |||
| 536 | pub const ExternFunc = struct { | ||
| 537 | ty: Index, | ||
| 538 | /// The Decl that corresponds to the function itself. | ||
| 539 | decl: Module.Decl.Index, | ||
| 540 | /// Library name if specified. | ||
| 541 | /// For example `extern "c" fn write(...) usize` would have 'c' as library name. | ||
| 542 | /// Index into the string table bytes. | ||
| 543 | lib_name: OptionalNullTerminatedString, | ||
| 544 | }; | ||
| 545 | |||
| 546 | /// Extern so it can be hashed by reinterpreting memory. | ||
| 547 | pub const Func = extern struct { | ||
| 548 | ty: Index, | ||
| 549 | index: Module.Fn.Index, | ||
| 550 | }; | ||
| 551 | |||
| 552 | pub const Int = struct { | ||
| 553 | ty: Index, | ||
| 554 | storage: Storage, | ||
| 555 | |||
| 556 | pub const Storage = union(enum) { | ||
| 557 | u64: u64, | ||
| 558 | i64: i64, | ||
| 559 | big_int: BigIntConst, | ||
| 560 | lazy_align: Index, | ||
| 561 | lazy_size: Index, | ||
| 562 | |||
| 563 | /// Big enough to fit any non-BigInt value | ||
| 564 | pub const BigIntSpace = struct { | ||
| 565 | /// The +1 is headroom so that operations such as incrementing once | ||
| 566 | /// or decrementing once are possible without using an allocator. | ||
| 567 | limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb, | ||
| 568 | }; | ||
| 569 | |||
| 570 | pub fn toBigInt(storage: Storage, space: *BigIntSpace) BigIntConst { | ||
| 571 | return switch (storage) { | ||
| 572 | .big_int => |x| x, | ||
| 573 | inline .u64, .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(), | ||
| 574 | .lazy_align, .lazy_size => unreachable, | ||
| 575 | }; | ||
| 576 | } | ||
| 577 | }; | ||
| 578 | }; | ||
| 579 | |||
| 580 | pub const Error = extern struct { | ||
| 581 | ty: Index, | ||
| 582 | name: NullTerminatedString, | ||
| 583 | }; | ||
| 584 | |||
| 585 | pub const ErrorUnion = struct { | ||
| 586 | ty: Index, | ||
| 587 | val: Value, | ||
| 588 | |||
| 589 | pub const Value = union(enum) { | ||
| 590 | err_name: NullTerminatedString, | ||
| 591 | payload: Index, | ||
| 592 | }; | ||
| 593 | }; | ||
| 594 | |||
| 595 | pub const EnumTag = extern struct { | ||
| 596 | /// The enum type. | ||
| 597 | ty: Index, | ||
| 598 | /// The integer tag value which has the integer tag type of the enum. | ||
| 599 | int: Index, | ||
| 600 | }; | ||
| 601 | |||
| 602 | pub const Float = struct { | ||
| 603 | ty: Index, | ||
| 604 | /// The storage used must match the size of the float type being represented. | ||
| 605 | storage: Storage, | ||
| 606 | |||
| 607 | pub const Storage = union(enum) { | ||
| 608 | f16: f16, | ||
| 609 | f32: f32, | ||
| 610 | f64: f64, | ||
| 611 | f80: f80, | ||
| 612 | f128: f128, | ||
| 613 | }; | ||
| 614 | }; | ||
| 615 | |||
| 616 | pub const Ptr = struct { | ||
| 617 | /// This is the pointer type, not the element type. | ||
| 618 | ty: Index, | ||
| 619 | /// The value of the address that the pointer points to. | ||
| 620 | addr: Addr, | ||
| 621 | /// This could be `none` if size is not a slice. | ||
| 622 | len: Index = .none, | ||
| 623 | |||
| 624 | pub const Addr = union(enum) { | ||
| 625 | decl: Module.Decl.Index, | ||
| 626 | mut_decl: MutDecl, | ||
| 627 | comptime_field: Index, | ||
| 628 | int: Index, | ||
| 629 | eu_payload: Index, | ||
| 630 | opt_payload: Index, | ||
| 631 | elem: BaseIndex, | ||
| 632 | field: BaseIndex, | ||
| 633 | |||
| 634 | pub const MutDecl = struct { | ||
| 635 | decl: Module.Decl.Index, | ||
| 636 | runtime_index: RuntimeIndex, | ||
| 637 | }; | ||
| 638 | pub const BaseIndex = struct { | ||
| 639 | base: Index, | ||
| 640 | index: u64, | ||
| 641 | }; | ||
| 642 | }; | ||
| 643 | }; | ||
| 644 | |||
| 645 | /// `null` is represented by the `val` field being `none`. | ||
| 646 | pub const Opt = extern struct { | ||
| 647 | /// This is the optional type; not the payload type. | ||
| 648 | ty: Index, | ||
| 649 | /// This could be `none`, indicating the optional is `null`. | ||
| 650 | val: Index, | ||
| 651 | }; | ||
| 652 | |||
| 653 | pub const Union = extern struct { | ||
| 654 | /// This is the union type; not the field type. | ||
| 655 | ty: Index, | ||
| 656 | /// Indicates the active field. | ||
| 657 | tag: Index, | ||
| 658 | /// The value of the active field. | ||
| 659 | val: Index, | ||
| 660 | }; | ||
| 661 | |||
| 662 | pub const Aggregate = struct { | ||
| 663 | ty: Index, | ||
| 664 | storage: Storage, | ||
| 665 | |||
| 666 | pub const Storage = union(enum) { | ||
| 667 | bytes: []const u8, | ||
| 668 | elems: []const Index, | ||
| 669 | repeated_elem: Index, | ||
| 670 | |||
| 671 | pub fn values(self: *const Storage) []const Index { | ||
| 672 | return switch (self.*) { | ||
| 673 | .bytes => &.{}, | ||
| 674 | .elems => |elems| elems, | ||
| 675 | .repeated_elem => |*elem| @as(*const [1]Index, elem), | ||
| 676 | }; | ||
| 677 | } | ||
| 678 | }; | ||
| 679 | }; | ||
| 680 | |||
| 681 | pub const MemoizedCall = struct { | ||
| 682 | func: Module.Fn.Index, | ||
| 683 | arg_values: []const Index, | ||
| 684 | result: Index, | ||
| 685 | }; | ||
| 686 | |||
| 687 | pub fn hash32(key: Key, ip: *const InternPool) u32 { | ||
| 688 | return @truncate(u32, key.hash64(ip)); | ||
| 689 | } | ||
| 690 | |||
| 691 | pub fn hash64(key: Key, ip: *const InternPool) u64 { | ||
| 692 | const asBytes = std.mem.asBytes; | ||
| 693 | const KeyTag = @typeInfo(Key).Union.tag_type.?; | ||
| 694 | const seed = @enumToInt(@as(KeyTag, key)); | ||
| 695 | return switch (key) { | ||
| 696 | // TODO: assert no padding in these types | ||
| 697 | inline .ptr_type, | ||
| 698 | .func, | ||
| 699 | .array_type, | ||
| 700 | .vector_type, | ||
| 701 | .opt_type, | ||
| 702 | .anyframe_type, | ||
| 703 | .error_union_type, | ||
| 704 | .simple_type, | ||
| 705 | .simple_value, | ||
| 706 | .opt, | ||
| 707 | .struct_type, | ||
| 708 | .undef, | ||
| 709 | .err, | ||
| 710 | .enum_literal, | ||
| 711 | .enum_tag, | ||
| 712 | .empty_enum_value, | ||
| 713 | .inferred_error_set_type, | ||
| 714 | .un, | ||
| 715 | => |x| Hash.hash(seed, asBytes(&x)), | ||
| 716 | |||
| 717 | .int_type => |x| Hash.hash(seed + @enumToInt(x.signedness), asBytes(&x.bits)), | ||
| 718 | .union_type => |x| Hash.hash(seed + @enumToInt(x.runtime_tag), asBytes(&x.index)), | ||
| 719 | |||
| 720 | .error_union => |x| switch (x.val) { | ||
| 721 | .err_name => |y| Hash.hash(seed + 0, asBytes(&x.ty) ++ asBytes(&y)), | ||
| 722 | .payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)), | ||
| 723 | }, | ||
| 724 | |||
| 725 | .runtime_value => |x| Hash.hash(seed, asBytes(&x.val)), | ||
| 726 | .opaque_type => |x| Hash.hash(seed, asBytes(&x.decl)), | ||
| 727 | |||
| 728 | .enum_type => |enum_type| { | ||
| 729 | var hasher = Hash.init(seed); | ||
| 730 | std.hash.autoHash(&hasher, enum_type.decl); | ||
| 731 | return hasher.final(); | ||
| 732 | }, | ||
| 733 | |||
| 734 | .variable => |variable| { | ||
| 735 | var hasher = Hash.init(seed); | ||
| 736 | std.hash.autoHash(&hasher, variable.decl); | ||
| 737 | return hasher.final(); | ||
| 738 | }, | ||
| 739 | .extern_func => |x| Hash.hash(seed, asBytes(&x.ty) ++ asBytes(&x.decl)), | ||
| 740 | |||
| 741 | .int => |int| { | ||
| 742 | var hasher = Hash.init(seed); | ||
| 743 | // Canonicalize all integers by converting them to BigIntConst. | ||
| 744 | switch (int.storage) { | ||
| 745 | .u64, .i64, .big_int => { | ||
| 746 | var buffer: Key.Int.Storage.BigIntSpace = undefined; | ||
| 747 | const big_int = int.storage.toBigInt(&buffer); | ||
| 748 | |||
| 749 | std.hash.autoHash(&hasher, int.ty); | ||
| 750 | std.hash.autoHash(&hasher, big_int.positive); | ||
| 751 | for (big_int.limbs) |limb| std.hash.autoHash(&hasher, limb); | ||
| 752 | }, | ||
| 753 | .lazy_align, .lazy_size => |lazy_ty| { | ||
| 754 | std.hash.autoHash( | ||
| 755 | &hasher, | ||
| 756 | @as(@typeInfo(Key.Int.Storage).Union.tag_type.?, int.storage), | ||
| 757 | ); | ||
| 758 | std.hash.autoHash(&hasher, lazy_ty); | ||
| 759 | }, | ||
| 760 | } | ||
| 761 | return hasher.final(); | ||
| 762 | }, | ||
| 763 | |||
| 764 | .float => |float| { | ||
| 765 | var hasher = Hash.init(seed); | ||
| 766 | std.hash.autoHash(&hasher, float.ty); | ||
| 767 | switch (float.storage) { | ||
| 768 | inline else => |val| std.hash.autoHash( | ||
| 769 | &hasher, | ||
| 770 | @bitCast(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(val))), val), | ||
| 771 | ), | ||
| 772 | } | ||
| 773 | return hasher.final(); | ||
| 774 | }, | ||
| 775 | |||
| 776 | .ptr => |ptr| { | ||
| 777 | // Int-to-ptr pointers are hashed separately than decl-referencing pointers. | ||
| 778 | // This is sound due to pointer provenance rules. | ||
| 779 | const addr: @typeInfo(Key.Ptr.Addr).Union.tag_type.? = ptr.addr; | ||
| 780 | const seed2 = seed + @enumToInt(addr); | ||
| 781 | const common = asBytes(&ptr.ty) ++ asBytes(&ptr.len); | ||
| 782 | return switch (ptr.addr) { | ||
| 783 | .decl => |x| Hash.hash(seed2, common ++ asBytes(&x)), | ||
| 784 | |||
| 785 | .mut_decl => |x| Hash.hash( | ||
| 786 | seed2, | ||
| 787 | asBytes(&x.decl) ++ asBytes(&x.runtime_index), | ||
| 788 | ), | ||
| 789 | |||
| 790 | .int, .eu_payload, .opt_payload, .comptime_field => |int| Hash.hash( | ||
| 791 | seed2, | ||
| 792 | asBytes(&int), | ||
| 793 | ), | ||
| 794 | |||
| 795 | .elem, .field => |x| Hash.hash( | ||
| 796 | seed2, | ||
| 797 | asBytes(&x.base) ++ asBytes(&x.index), | ||
| 798 | ), | ||
| 799 | }; | ||
| 800 | }, | ||
| 801 | |||
| 802 | .aggregate => |aggregate| { | ||
| 803 | var hasher = Hash.init(seed); | ||
| 804 | std.hash.autoHash(&hasher, aggregate.ty); | ||
| 805 | const len = ip.aggregateTypeLen(aggregate.ty); | ||
| 806 | const child = switch (ip.indexToKey(aggregate.ty)) { | ||
| 807 | .array_type => |array_type| array_type.child, | ||
| 808 | .vector_type => |vector_type| vector_type.child, | ||
| 809 | .anon_struct_type, .struct_type => .none, | ||
| 810 | else => unreachable, | ||
| 811 | }; | ||
| 812 | |||
| 813 | if (child == .u8_type) { | ||
| 814 | switch (aggregate.storage) { | ||
| 815 | .bytes => |bytes| for (bytes[0..@intCast(usize, len)]) |byte| { | ||
| 816 | std.hash.autoHash(&hasher, KeyTag.int); | ||
| 817 | std.hash.autoHash(&hasher, byte); | ||
| 818 | }, | ||
| 819 | .elems => |elems| for (elems[0..@intCast(usize, len)]) |elem| { | ||
| 820 | const elem_key = ip.indexToKey(elem); | ||
| 821 | std.hash.autoHash(&hasher, @as(KeyTag, elem_key)); | ||
| 822 | switch (elem_key) { | ||
| 823 | .undef => {}, | ||
| 824 | .int => |int| std.hash.autoHash( | ||
| 825 | &hasher, | ||
| 826 | @intCast(u8, int.storage.u64), | ||
| 827 | ), | ||
| 828 | else => unreachable, | ||
| 829 | } | ||
| 830 | }, | ||
| 831 | .repeated_elem => |elem| { | ||
| 832 | const elem_key = ip.indexToKey(elem); | ||
| 833 | var remaining = len; | ||
| 834 | while (remaining > 0) : (remaining -= 1) { | ||
| 835 | std.hash.autoHash(&hasher, @as(KeyTag, elem_key)); | ||
| 836 | switch (elem_key) { | ||
| 837 | .undef => {}, | ||
| 838 | .int => |int| std.hash.autoHash( | ||
| 839 | &hasher, | ||
| 840 | @intCast(u8, int.storage.u64), | ||
| 841 | ), | ||
| 842 | else => unreachable, | ||
| 843 | } | ||
| 844 | } | ||
| 845 | }, | ||
| 846 | } | ||
| 847 | return hasher.final(); | ||
| 848 | } | ||
| 849 | |||
| 850 | switch (aggregate.storage) { | ||
| 851 | .bytes => unreachable, | ||
| 852 | .elems => |elems| for (elems[0..@intCast(usize, len)]) |elem| | ||
| 853 | std.hash.autoHash(&hasher, elem), | ||
| 854 | .repeated_elem => |elem| { | ||
| 855 | var remaining = len; | ||
| 856 | while (remaining > 0) : (remaining -= 1) std.hash.autoHash(&hasher, elem); | ||
| 857 | }, | ||
| 858 | } | ||
| 859 | return hasher.final(); | ||
| 860 | }, | ||
| 861 | |||
| 862 | .error_set_type => |error_set_type| { | ||
| 863 | var hasher = Hash.init(seed); | ||
| 864 | for (error_set_type.names) |elem| std.hash.autoHash(&hasher, elem); | ||
| 865 | return hasher.final(); | ||
| 866 | }, | ||
| 867 | |||
| 868 | .anon_struct_type => |anon_struct_type| { | ||
| 869 | var hasher = Hash.init(seed); | ||
| 870 | for (anon_struct_type.types) |elem| std.hash.autoHash(&hasher, elem); | ||
| 871 | for (anon_struct_type.values) |elem| std.hash.autoHash(&hasher, elem); | ||
| 872 | for (anon_struct_type.names) |elem| std.hash.autoHash(&hasher, elem); | ||
| 873 | return hasher.final(); | ||
| 874 | }, | ||
| 875 | |||
| 876 | .func_type => |func_type| { | ||
| 877 | var hasher = Hash.init(seed); | ||
| 878 | for (func_type.param_types) |param_type| std.hash.autoHash(&hasher, param_type); | ||
| 879 | std.hash.autoHash(&hasher, func_type.return_type); | ||
| 880 | std.hash.autoHash(&hasher, func_type.comptime_bits); | ||
| 881 | std.hash.autoHash(&hasher, func_type.noalias_bits); | ||
| 882 | std.hash.autoHash(&hasher, func_type.alignment); | ||
| 883 | std.hash.autoHash(&hasher, func_type.cc); | ||
| 884 | std.hash.autoHash(&hasher, func_type.is_var_args); | ||
| 885 | std.hash.autoHash(&hasher, func_type.is_generic); | ||
| 886 | std.hash.autoHash(&hasher, func_type.is_noinline); | ||
| 887 | return hasher.final(); | ||
| 888 | }, | ||
| 889 | |||
| 890 | .memoized_call => |memoized_call| { | ||
| 891 | var hasher = Hash.init(seed); | ||
| 892 | std.hash.autoHash(&hasher, memoized_call.func); | ||
| 893 | for (memoized_call.arg_values) |arg| std.hash.autoHash(&hasher, arg); | ||
| 894 | return hasher.final(); | ||
| 895 | }, | ||
| 896 | }; | ||
| 897 | } | ||
| 898 | |||
| 899 | pub fn eql(a: Key, b: Key, ip: *const InternPool) bool { | ||
| 900 | const KeyTag = @typeInfo(Key).Union.tag_type.?; | ||
| 901 | const a_tag: KeyTag = a; | ||
| 902 | const b_tag: KeyTag = b; | ||
| 903 | if (a_tag != b_tag) return false; | ||
| 904 | switch (a) { | ||
| 905 | .int_type => |a_info| { | ||
| 906 | const b_info = b.int_type; | ||
| 907 | return std.meta.eql(a_info, b_info); | ||
| 908 | }, | ||
| 909 | .ptr_type => |a_info| { | ||
| 910 | const b_info = b.ptr_type; | ||
| 911 | return std.meta.eql(a_info, b_info); | ||
| 912 | }, | ||
| 913 | .array_type => |a_info| { | ||
| 914 | const b_info = b.array_type; | ||
| 915 | return std.meta.eql(a_info, b_info); | ||
| 916 | }, | ||
| 917 | .vector_type => |a_info| { | ||
| 918 | const b_info = b.vector_type; | ||
| 919 | return std.meta.eql(a_info, b_info); | ||
| 920 | }, | ||
| 921 | .opt_type => |a_info| { | ||
| 922 | const b_info = b.opt_type; | ||
| 923 | return a_info == b_info; | ||
| 924 | }, | ||
| 925 | .anyframe_type => |a_info| { | ||
| 926 | const b_info = b.anyframe_type; | ||
| 927 | return a_info == b_info; | ||
| 928 | }, | ||
| 929 | .error_union_type => |a_info| { | ||
| 930 | const b_info = b.error_union_type; | ||
| 931 | return std.meta.eql(a_info, b_info); | ||
| 932 | }, | ||
| 933 | .simple_type => |a_info| { | ||
| 934 | const b_info = b.simple_type; | ||
| 935 | return a_info == b_info; | ||
| 936 | }, | ||
| 937 | .simple_value => |a_info| { | ||
| 938 | const b_info = b.simple_value; | ||
| 939 | return a_info == b_info; | ||
| 940 | }, | ||
| 941 | .undef => |a_info| { | ||
| 942 | const b_info = b.undef; | ||
| 943 | return a_info == b_info; | ||
| 944 | }, | ||
| 945 | .runtime_value => |a_info| { | ||
| 946 | const b_info = b.runtime_value; | ||
| 947 | return a_info.val == b_info.val; | ||
| 948 | }, | ||
| 949 | .opt => |a_info| { | ||
| 950 | const b_info = b.opt; | ||
| 951 | return std.meta.eql(a_info, b_info); | ||
| 952 | }, | ||
| 953 | .struct_type => |a_info| { | ||
| 954 | const b_info = b.struct_type; | ||
| 955 | return std.meta.eql(a_info, b_info); | ||
| 956 | }, | ||
| 957 | .union_type => |a_info| { | ||
| 958 | const b_info = b.union_type; | ||
| 959 | return std.meta.eql(a_info, b_info); | ||
| 960 | }, | ||
| 961 | .un => |a_info| { | ||
| 962 | const b_info = b.un; | ||
| 963 | return std.meta.eql(a_info, b_info); | ||
| 964 | }, | ||
| 965 | .err => |a_info| { | ||
| 966 | const b_info = b.err; | ||
| 967 | return std.meta.eql(a_info, b_info); | ||
| 968 | }, | ||
| 969 | .error_union => |a_info| { | ||
| 970 | const b_info = b.error_union; | ||
| 971 | return std.meta.eql(a_info, b_info); | ||
| 972 | }, | ||
| 973 | .enum_literal => |a_info| { | ||
| 974 | const b_info = b.enum_literal; | ||
| 975 | return a_info == b_info; | ||
| 976 | }, | ||
| 977 | .enum_tag => |a_info| { | ||
| 978 | const b_info = b.enum_tag; | ||
| 979 | return std.meta.eql(a_info, b_info); | ||
| 980 | }, | ||
| 981 | .empty_enum_value => |a_info| { | ||
| 982 | const b_info = b.empty_enum_value; | ||
| 983 | return a_info == b_info; | ||
| 984 | }, | ||
| 985 | |||
| 986 | .variable => |a_info| { | ||
| 987 | const b_info = b.variable; | ||
| 988 | return a_info.decl == b_info.decl; | ||
| 989 | }, | ||
| 990 | .extern_func => |a_info| { | ||
| 991 | const b_info = b.extern_func; | ||
| 992 | return a_info.ty == b_info.ty and a_info.decl == b_info.decl; | ||
| 993 | }, | ||
| 994 | .func => |a_info| { | ||
| 995 | const b_info = b.func; | ||
| 996 | return a_info.ty == b_info.ty and a_info.index == b_info.index; | ||
| 997 | }, | ||
| 998 | |||
| 999 | .ptr => |a_info| { | ||
| 1000 | const b_info = b.ptr; | ||
| 1001 | if (a_info.ty != b_info.ty or a_info.len != b_info.len) return false; | ||
| 1002 | |||
| 1003 | const AddrTag = @typeInfo(Key.Ptr.Addr).Union.tag_type.?; | ||
| 1004 | if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false; | ||
| 1005 | |||
| 1006 | return switch (a_info.addr) { | ||
| 1007 | .decl => |a_decl| a_decl == b_info.addr.decl, | ||
| 1008 | .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl), | ||
| 1009 | .int => |a_int| a_int == b_info.addr.int, | ||
| 1010 | .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload, | ||
| 1011 | .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload, | ||
| 1012 | .comptime_field => |a_comptime_field| a_comptime_field == b_info.addr.comptime_field, | ||
| 1013 | .elem => |a_elem| std.meta.eql(a_elem, b_info.addr.elem), | ||
| 1014 | .field => |a_field| std.meta.eql(a_field, b_info.addr.field), | ||
| 1015 | }; | ||
| 1016 | }, | ||
| 1017 | |||
| 1018 | .int => |a_info| { | ||
| 1019 | const b_info = b.int; | ||
| 1020 | |||
| 1021 | if (a_info.ty != b_info.ty) | ||
| 1022 | return false; | ||
| 1023 | |||
| 1024 | return switch (a_info.storage) { | ||
| 1025 | .u64 => |aa| switch (b_info.storage) { | ||
| 1026 | .u64 => |bb| aa == bb, | ||
| 1027 | .i64 => |bb| aa == bb, | ||
| 1028 | .big_int => |bb| bb.orderAgainstScalar(aa) == .eq, | ||
| 1029 | .lazy_align, .lazy_size => false, | ||
| 1030 | }, | ||
| 1031 | .i64 => |aa| switch (b_info.storage) { | ||
| 1032 | .u64 => |bb| aa == bb, | ||
| 1033 | .i64 => |bb| aa == bb, | ||
| 1034 | .big_int => |bb| bb.orderAgainstScalar(aa) == .eq, | ||
| 1035 | .lazy_align, .lazy_size => false, | ||
| 1036 | }, | ||
| 1037 | .big_int => |aa| switch (b_info.storage) { | ||
| 1038 | .u64 => |bb| aa.orderAgainstScalar(bb) == .eq, | ||
| 1039 | .i64 => |bb| aa.orderAgainstScalar(bb) == .eq, | ||
| 1040 | .big_int => |bb| aa.eq(bb), | ||
| 1041 | .lazy_align, .lazy_size => false, | ||
| 1042 | }, | ||
| 1043 | .lazy_align => |aa| switch (b_info.storage) { | ||
| 1044 | .u64, .i64, .big_int, .lazy_size => false, | ||
| 1045 | .lazy_align => |bb| aa == bb, | ||
| 1046 | }, | ||
| 1047 | .lazy_size => |aa| switch (b_info.storage) { | ||
| 1048 | .u64, .i64, .big_int, .lazy_align => false, | ||
| 1049 | .lazy_size => |bb| aa == bb, | ||
| 1050 | }, | ||
| 1051 | }; | ||
| 1052 | }, | ||
| 1053 | |||
| 1054 | .float => |a_info| { | ||
| 1055 | const b_info = b.float; | ||
| 1056 | |||
| 1057 | if (a_info.ty != b_info.ty) | ||
| 1058 | return false; | ||
| 1059 | |||
| 1060 | if (a_info.ty == .c_longdouble_type and a_info.storage != .f80) { | ||
| 1061 | // These are strange: we'll sometimes represent them as f128, even if the | ||
| 1062 | // underlying type is smaller. f80 is an exception: see float_c_longdouble_f80. | ||
| 1063 | const a_val = switch (a_info.storage) { | ||
| 1064 | inline else => |val| @floatCast(f128, val), | ||
| 1065 | }; | ||
| 1066 | const b_val = switch (b_info.storage) { | ||
| 1067 | inline else => |val| @floatCast(f128, val), | ||
| 1068 | }; | ||
| 1069 | return a_val == b_val; | ||
| 1070 | } | ||
| 1071 | |||
| 1072 | const StorageTag = @typeInfo(Key.Float.Storage).Union.tag_type.?; | ||
| 1073 | assert(@as(StorageTag, a_info.storage) == @as(StorageTag, b_info.storage)); | ||
| 1074 | |||
| 1075 | return switch (a_info.storage) { | ||
| 1076 | inline else => |val, tag| val == @field(b_info.storage, @tagName(tag)), | ||
| 1077 | }; | ||
| 1078 | }, | ||
| 1079 | |||
| 1080 | .opaque_type => |a_info| { | ||
| 1081 | const b_info = b.opaque_type; | ||
| 1082 | return a_info.decl == b_info.decl; | ||
| 1083 | }, | ||
| 1084 | .enum_type => |a_info| { | ||
| 1085 | const b_info = b.enum_type; | ||
| 1086 | return a_info.decl == b_info.decl; | ||
| 1087 | }, | ||
| 1088 | .aggregate => |a_info| { | ||
| 1089 | const b_info = b.aggregate; | ||
| 1090 | if (a_info.ty != b_info.ty) return false; | ||
| 1091 | |||
| 1092 | const len = ip.aggregateTypeLen(a_info.ty); | ||
| 1093 | const StorageTag = @typeInfo(Key.Aggregate.Storage).Union.tag_type.?; | ||
| 1094 | if (@as(StorageTag, a_info.storage) != @as(StorageTag, b_info.storage)) { | ||
| 1095 | for (0..@intCast(usize, len)) |elem_index| { | ||
| 1096 | const a_elem = switch (a_info.storage) { | ||
| 1097 | .bytes => |bytes| ip.getIfExists(.{ .int = .{ | ||
| 1098 | .ty = .u8_type, | ||
| 1099 | .storage = .{ .u64 = bytes[elem_index] }, | ||
| 1100 | } }) orelse return false, | ||
| 1101 | .elems => |elems| elems[elem_index], | ||
| 1102 | .repeated_elem => |elem| elem, | ||
| 1103 | }; | ||
| 1104 | const b_elem = switch (b_info.storage) { | ||
| 1105 | .bytes => |bytes| ip.getIfExists(.{ .int = .{ | ||
| 1106 | .ty = .u8_type, | ||
| 1107 | .storage = .{ .u64 = bytes[elem_index] }, | ||
| 1108 | } }) orelse return false, | ||
| 1109 | .elems => |elems| elems[elem_index], | ||
| 1110 | .repeated_elem => |elem| elem, | ||
| 1111 | }; | ||
| 1112 | if (a_elem != b_elem) return false; | ||
| 1113 | } | ||
| 1114 | return true; | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | switch (a_info.storage) { | ||
| 1118 | .bytes => |a_bytes| { | ||
| 1119 | const b_bytes = b_info.storage.bytes; | ||
| 1120 | return std.mem.eql( | ||
| 1121 | u8, | ||
| 1122 | a_bytes[0..@intCast(usize, len)], | ||
| 1123 | b_bytes[0..@intCast(usize, len)], | ||
| 1124 | ); | ||
| 1125 | }, | ||
| 1126 | .elems => |a_elems| { | ||
| 1127 | const b_elems = b_info.storage.elems; | ||
| 1128 | return std.mem.eql( | ||
| 1129 | Index, | ||
| 1130 | a_elems[0..@intCast(usize, len)], | ||
| 1131 | b_elems[0..@intCast(usize, len)], | ||
| 1132 | ); | ||
| 1133 | }, | ||
| 1134 | .repeated_elem => |a_elem| { | ||
| 1135 | const b_elem = b_info.storage.repeated_elem; | ||
| 1136 | return a_elem == b_elem; | ||
| 1137 | }, | ||
| 1138 | } | ||
| 1139 | }, | ||
| 1140 | .anon_struct_type => |a_info| { | ||
| 1141 | const b_info = b.anon_struct_type; | ||
| 1142 | return std.mem.eql(Index, a_info.types, b_info.types) and | ||
| 1143 | std.mem.eql(Index, a_info.values, b_info.values) and | ||
| 1144 | std.mem.eql(NullTerminatedString, a_info.names, b_info.names); | ||
| 1145 | }, | ||
| 1146 | .error_set_type => |a_info| { | ||
| 1147 | const b_info = b.error_set_type; | ||
| 1148 | return std.mem.eql(NullTerminatedString, a_info.names, b_info.names); | ||
| 1149 | }, | ||
| 1150 | .inferred_error_set_type => |a_info| { | ||
| 1151 | const b_info = b.inferred_error_set_type; | ||
| 1152 | return a_info == b_info; | ||
| 1153 | }, | ||
| 1154 | |||
| 1155 | .func_type => |a_info| { | ||
| 1156 | const b_info = b.func_type; | ||
| 1157 | |||
| 1158 | return std.mem.eql(Index, a_info.param_types, b_info.param_types) and | ||
| 1159 | a_info.return_type == b_info.return_type and | ||
| 1160 | a_info.comptime_bits == b_info.comptime_bits and | ||
| 1161 | a_info.noalias_bits == b_info.noalias_bits and | ||
| 1162 | a_info.alignment == b_info.alignment and | ||
| 1163 | a_info.cc == b_info.cc and | ||
| 1164 | a_info.is_var_args == b_info.is_var_args and | ||
| 1165 | a_info.is_generic == b_info.is_generic and | ||
| 1166 | a_info.is_noinline == b_info.is_noinline; | ||
| 1167 | }, | ||
| 1168 | |||
| 1169 | .memoized_call => |a_info| { | ||
| 1170 | const b_info = b.memoized_call; | ||
| 1171 | return a_info.func == b_info.func and | ||
| 1172 | std.mem.eql(Index, a_info.arg_values, b_info.arg_values); | ||
| 1173 | }, | ||
| 1174 | } | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | pub fn typeOf(key: Key) Index { | ||
| 1178 | return switch (key) { | ||
| 1179 | .int_type, | ||
| 1180 | .ptr_type, | ||
| 1181 | .array_type, | ||
| 1182 | .vector_type, | ||
| 1183 | .opt_type, | ||
| 1184 | .anyframe_type, | ||
| 1185 | .error_union_type, | ||
| 1186 | .error_set_type, | ||
| 1187 | .inferred_error_set_type, | ||
| 1188 | .simple_type, | ||
| 1189 | .struct_type, | ||
| 1190 | .union_type, | ||
| 1191 | .opaque_type, | ||
| 1192 | .enum_type, | ||
| 1193 | .anon_struct_type, | ||
| 1194 | .func_type, | ||
| 1195 | => .type_type, | ||
| 1196 | |||
| 1197 | inline .runtime_value, | ||
| 1198 | .ptr, | ||
| 1199 | .int, | ||
| 1200 | .float, | ||
| 1201 | .opt, | ||
| 1202 | .variable, | ||
| 1203 | .extern_func, | ||
| 1204 | .func, | ||
| 1205 | .err, | ||
| 1206 | .error_union, | ||
| 1207 | .enum_tag, | ||
| 1208 | .aggregate, | ||
| 1209 | .un, | ||
| 1210 | => |x| x.ty, | ||
| 1211 | |||
| 1212 | .enum_literal => .enum_literal_type, | ||
| 1213 | |||
| 1214 | .undef => |x| x, | ||
| 1215 | .empty_enum_value => |x| x, | ||
| 1216 | |||
| 1217 | .simple_value => |s| switch (s) { | ||
| 1218 | .undefined => .undefined_type, | ||
| 1219 | .void => .void_type, | ||
| 1220 | .null => .null_type, | ||
| 1221 | .false, .true => .bool_type, | ||
| 1222 | .empty_struct => .empty_struct_type, | ||
| 1223 | .@"unreachable" => .noreturn_type, | ||
| 1224 | .generic_poison => .generic_poison_type, | ||
| 1225 | }, | ||
| 1226 | |||
| 1227 | .memoized_call => unreachable, | ||
| 1228 | }; | ||
| 1229 | } | ||
| 1230 | }; | ||
| 1231 | |||
| 1232 | pub const Item = struct { | ||
| 1233 | tag: Tag, | ||
| 1234 | /// The doc comments on the respective Tag explain how to interpret this. | ||
| 1235 | data: u32, | ||
| 1236 | }; | ||
| 1237 | |||
| 1238 | /// Represents an index into `map`. It represents the canonical index | ||
| 1239 | /// of a `Value` within this `InternPool`. The values are typed. | ||
| 1240 | /// Two values which have the same type can be equality compared simply | ||
| 1241 | /// by checking if their indexes are equal, provided they are both in | ||
| 1242 | /// the same `InternPool`. | ||
| 1243 | /// When adding a tag to this enum, consider adding a corresponding entry to | ||
| 1244 | /// `primitives` in AstGen.zig. | ||
| 1245 | pub const Index = enum(u32) { | ||
| 1246 | pub const first_type: Index = .u1_type; | ||
| 1247 | pub const last_type: Index = .empty_struct_type; | ||
| 1248 | pub const first_value: Index = .undef; | ||
| 1249 | pub const last_value: Index = .empty_struct; | ||
| 1250 | |||
| 1251 | u1_type, | ||
| 1252 | u8_type, | ||
| 1253 | i8_type, | ||
| 1254 | u16_type, | ||
| 1255 | i16_type, | ||
| 1256 | u29_type, | ||
| 1257 | u32_type, | ||
| 1258 | i32_type, | ||
| 1259 | u64_type, | ||
| 1260 | i64_type, | ||
| 1261 | u80_type, | ||
| 1262 | u128_type, | ||
| 1263 | i128_type, | ||
| 1264 | usize_type, | ||
| 1265 | isize_type, | ||
| 1266 | c_char_type, | ||
| 1267 | c_short_type, | ||
| 1268 | c_ushort_type, | ||
| 1269 | c_int_type, | ||
| 1270 | c_uint_type, | ||
| 1271 | c_long_type, | ||
| 1272 | c_ulong_type, | ||
| 1273 | c_longlong_type, | ||
| 1274 | c_ulonglong_type, | ||
| 1275 | c_longdouble_type, | ||
| 1276 | f16_type, | ||
| 1277 | f32_type, | ||
| 1278 | f64_type, | ||
| 1279 | f80_type, | ||
| 1280 | f128_type, | ||
| 1281 | anyopaque_type, | ||
| 1282 | bool_type, | ||
| 1283 | void_type, | ||
| 1284 | type_type, | ||
| 1285 | anyerror_type, | ||
| 1286 | comptime_int_type, | ||
| 1287 | comptime_float_type, | ||
| 1288 | noreturn_type, | ||
| 1289 | anyframe_type, | ||
| 1290 | null_type, | ||
| 1291 | undefined_type, | ||
| 1292 | enum_literal_type, | ||
| 1293 | atomic_order_type, | ||
| 1294 | atomic_rmw_op_type, | ||
| 1295 | calling_convention_type, | ||
| 1296 | address_space_type, | ||
| 1297 | float_mode_type, | ||
| 1298 | reduce_op_type, | ||
| 1299 | call_modifier_type, | ||
| 1300 | prefetch_options_type, | ||
| 1301 | export_options_type, | ||
| 1302 | extern_options_type, | ||
| 1303 | type_info_type, | ||
| 1304 | manyptr_u8_type, | ||
| 1305 | manyptr_const_u8_type, | ||
| 1306 | manyptr_const_u8_sentinel_0_type, | ||
| 1307 | single_const_pointer_to_comptime_int_type, | ||
| 1308 | slice_const_u8_type, | ||
| 1309 | slice_const_u8_sentinel_0_type, | ||
| 1310 | anyerror_void_error_union_type, | ||
| 1311 | generic_poison_type, | ||
| 1312 | /// `@TypeOf(.{})` | ||
| 1313 | empty_struct_type, | ||
| 1314 | |||
| 1315 | /// `undefined` (untyped) | ||
| 1316 | undef, | ||
| 1317 | /// `0` (comptime_int) | ||
| 1318 | zero, | ||
| 1319 | /// `0` (usize) | ||
| 1320 | zero_usize, | ||
| 1321 | /// `0` (u8) | ||
| 1322 | zero_u8, | ||
| 1323 | /// `1` (comptime_int) | ||
| 1324 | one, | ||
| 1325 | /// `1` (usize) | ||
| 1326 | one_usize, | ||
| 1327 | /// `1` (u8) | ||
| 1328 | one_u8, | ||
| 1329 | /// `4` (u8) | ||
| 1330 | four_u8, | ||
| 1331 | /// `-1` (comptime_int) | ||
| 1332 | negative_one, | ||
| 1333 | /// `std.builtin.CallingConvention.C` | ||
| 1334 | calling_convention_c, | ||
| 1335 | /// `std.builtin.CallingConvention.Inline` | ||
| 1336 | calling_convention_inline, | ||
| 1337 | /// `{}` | ||
| 1338 | void_value, | ||
| 1339 | /// `unreachable` (noreturn type) | ||
| 1340 | unreachable_value, | ||
| 1341 | /// `null` (untyped) | ||
| 1342 | null_value, | ||
| 1343 | /// `true` | ||
| 1344 | bool_true, | ||
| 1345 | /// `false` | ||
| 1346 | bool_false, | ||
| 1347 | /// `.{}` (untyped) | ||
| 1348 | empty_struct, | ||
| 1349 | |||
| 1350 | /// Used for generic parameters where the type and value | ||
| 1351 | /// is not known until generic function instantiation. | ||
| 1352 | generic_poison, | ||
| 1353 | |||
| 1354 | /// Used by Air/Sema only. | ||
| 1355 | var_args_param_type = std.math.maxInt(u32) - 1, | ||
| 1356 | none = std.math.maxInt(u32), | ||
| 1357 | |||
| 1358 | _, | ||
| 1359 | |||
| 1360 | pub fn toType(i: Index) @import("type.zig").Type { | ||
| 1361 | assert(i != .none); | ||
| 1362 | return .{ .ip_index = i }; | ||
| 1363 | } | ||
| 1364 | |||
| 1365 | pub fn toValue(i: Index) @import("value.zig").Value { | ||
| 1366 | assert(i != .none); | ||
| 1367 | return .{ | ||
| 1368 | .ip_index = i, | ||
| 1369 | .legacy = undefined, | ||
| 1370 | }; | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | /// Used for a map of `Index` values to the index within a list of `Index` values. | ||
| 1374 | const Adapter = struct { | ||
| 1375 | indexes: []const Index, | ||
| 1376 | |||
| 1377 | pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool { | ||
| 1378 | _ = b_void; | ||
| 1379 | return a == ctx.indexes[b_map_index]; | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | pub fn hash(ctx: @This(), a: Index) u32 { | ||
| 1383 | _ = ctx; | ||
| 1384 | return std.hash.uint32(@enumToInt(a)); | ||
| 1385 | } | ||
| 1386 | }; | ||
| 1387 | |||
| 1388 | /// This function is used in the debugger pretty formatters in tools/ to fetch the | ||
| 1389 | /// Tag to encoding mapping to facilitate fancy debug printing for this type. | ||
| 1390 | fn dbHelper(self: *Index, tag_to_encoding_map: *struct { | ||
| 1391 | const DataIsIndex = struct { data: Index }; | ||
| 1392 | const DataIsExtraIndexOfEnumExplicit = struct { | ||
| 1393 | const @"data.fields_len" = opaque {}; | ||
| 1394 | data: *EnumExplicit, | ||
| 1395 | @"trailing.names.len": *@"data.fields_len", | ||
| 1396 | @"trailing.values.len": *@"data.fields_len", | ||
| 1397 | trailing: struct { | ||
| 1398 | names: []NullTerminatedString, | ||
| 1399 | values: []Index, | ||
| 1400 | }, | ||
| 1401 | }; | ||
| 1402 | const DataIsExtraIndexOfTypeStructAnon = struct { | ||
| 1403 | const @"data.fields_len" = opaque {}; | ||
| 1404 | data: *TypeStructAnon, | ||
| 1405 | @"trailing.types.len": *@"data.fields_len", | ||
| 1406 | @"trailing.values.len": *@"data.fields_len", | ||
| 1407 | @"trailing.names.len": *@"data.fields_len", | ||
| 1408 | trailing: struct { | ||
| 1409 | types: []Index, | ||
| 1410 | values: []Index, | ||
| 1411 | names: []NullTerminatedString, | ||
| 1412 | }, | ||
| 1413 | }; | ||
| 1414 | |||
| 1415 | type_int_signed: struct { data: u32 }, | ||
| 1416 | type_int_unsigned: struct { data: u32 }, | ||
| 1417 | type_array_big: struct { data: *Array }, | ||
| 1418 | type_array_small: struct { data: *Vector }, | ||
| 1419 | type_vector: struct { data: *Vector }, | ||
| 1420 | type_pointer: struct { data: *Tag.TypePointer }, | ||
| 1421 | type_slice: DataIsIndex, | ||
| 1422 | type_optional: DataIsIndex, | ||
| 1423 | type_anyframe: DataIsIndex, | ||
| 1424 | type_error_union: struct { data: *Key.ErrorUnionType }, | ||
| 1425 | type_error_set: struct { | ||
| 1426 | const @"data.names_len" = opaque {}; | ||
| 1427 | data: *ErrorSet, | ||
| 1428 | @"trailing.names.len": *@"data.names_len", | ||
| 1429 | trailing: struct { names: []NullTerminatedString }, | ||
| 1430 | }, | ||
| 1431 | type_inferred_error_set: struct { data: Module.Fn.InferredErrorSet.Index }, | ||
| 1432 | type_enum_auto: struct { | ||
| 1433 | const @"data.fields_len" = opaque {}; | ||
| 1434 | data: *EnumAuto, | ||
| 1435 | @"trailing.names.len": *@"data.fields_len", | ||
| 1436 | trailing: struct { names: []NullTerminatedString }, | ||
| 1437 | }, | ||
| 1438 | type_enum_explicit: DataIsExtraIndexOfEnumExplicit, | ||
| 1439 | type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit, | ||
| 1440 | simple_type: struct { data: SimpleType }, | ||
| 1441 | type_opaque: struct { data: *Key.OpaqueType }, | ||
| 1442 | type_struct: struct { data: Module.Struct.OptionalIndex }, | ||
| 1443 | type_struct_ns: struct { data: Module.Namespace.Index }, | ||
| 1444 | type_struct_anon: DataIsExtraIndexOfTypeStructAnon, | ||
| 1445 | type_tuple_anon: DataIsExtraIndexOfTypeStructAnon, | ||
| 1446 | type_union_tagged: struct { data: Module.Union.Index }, | ||
| 1447 | type_union_untagged: struct { data: Module.Union.Index }, | ||
| 1448 | type_union_safety: struct { data: Module.Union.Index }, | ||
| 1449 | type_function: struct { | ||
| 1450 | const @"data.params_len" = opaque {}; | ||
| 1451 | data: *TypeFunction, | ||
| 1452 | @"trailing.param_types.len": *@"data.params_len", | ||
| 1453 | trailing: struct { param_types: []Index }, | ||
| 1454 | }, | ||
| 1455 | |||
| 1456 | undef: DataIsIndex, | ||
| 1457 | runtime_value: struct { data: *Tag.TypeValue }, | ||
| 1458 | simple_value: struct { data: SimpleValue }, | ||
| 1459 | ptr_decl: struct { data: *PtrDecl }, | ||
| 1460 | ptr_mut_decl: struct { data: *PtrMutDecl }, | ||
| 1461 | ptr_comptime_field: struct { data: *PtrComptimeField }, | ||
| 1462 | ptr_int: struct { data: *PtrBase }, | ||
| 1463 | ptr_eu_payload: struct { data: *PtrBase }, | ||
| 1464 | ptr_opt_payload: struct { data: *PtrBase }, | ||
| 1465 | ptr_elem: struct { data: *PtrBaseIndex }, | ||
| 1466 | ptr_field: struct { data: *PtrBaseIndex }, | ||
| 1467 | ptr_slice: struct { data: *PtrSlice }, | ||
| 1468 | opt_payload: struct { data: *Tag.TypeValue }, | ||
| 1469 | opt_null: DataIsIndex, | ||
| 1470 | int_u8: struct { data: u8 }, | ||
| 1471 | int_u16: struct { data: u16 }, | ||
| 1472 | int_u32: struct { data: u32 }, | ||
| 1473 | int_i32: struct { data: i32 }, | ||
| 1474 | int_usize: struct { data: u32 }, | ||
| 1475 | int_comptime_int_u32: struct { data: u32 }, | ||
| 1476 | int_comptime_int_i32: struct { data: i32 }, | ||
| 1477 | int_small: struct { data: *IntSmall }, | ||
| 1478 | int_positive: struct { data: u32 }, | ||
| 1479 | int_negative: struct { data: u32 }, | ||
| 1480 | int_lazy_align: struct { data: *IntLazy }, | ||
| 1481 | int_lazy_size: struct { data: *IntLazy }, | ||
| 1482 | error_set_error: struct { data: *Key.Error }, | ||
| 1483 | error_union_error: struct { data: *Key.Error }, | ||
| 1484 | error_union_payload: struct { data: *Tag.TypeValue }, | ||
| 1485 | enum_literal: struct { data: NullTerminatedString }, | ||
| 1486 | enum_tag: struct { data: *Tag.EnumTag }, | ||
| 1487 | float_f16: struct { data: f16 }, | ||
| 1488 | float_f32: struct { data: f32 }, | ||
| 1489 | float_f64: struct { data: *Float64 }, | ||
| 1490 | float_f80: struct { data: *Float80 }, | ||
| 1491 | float_f128: struct { data: *Float128 }, | ||
| 1492 | float_c_longdouble_f80: struct { data: *Float80 }, | ||
| 1493 | float_c_longdouble_f128: struct { data: *Float128 }, | ||
| 1494 | float_comptime_float: struct { data: *Float128 }, | ||
| 1495 | variable: struct { data: *Tag.Variable }, | ||
| 1496 | extern_func: struct { data: *Key.ExternFunc }, | ||
| 1497 | func: struct { data: *Tag.Func }, | ||
| 1498 | only_possible_value: DataIsIndex, | ||
| 1499 | union_value: struct { data: *Key.Union }, | ||
| 1500 | bytes: struct { data: *Bytes }, | ||
| 1501 | aggregate: struct { | ||
| 1502 | const @"data.ty.data.len orelse data.ty.data.fields_len" = opaque {}; | ||
| 1503 | data: *Tag.Aggregate, | ||
| 1504 | @"trailing.element_values.len": *@"data.ty.data.len orelse data.ty.data.fields_len", | ||
| 1505 | trailing: struct { element_values: []Index }, | ||
| 1506 | }, | ||
| 1507 | repeated: struct { data: *Repeated }, | ||
| 1508 | |||
| 1509 | memoized_call: struct { | ||
| 1510 | const @"data.args_len" = opaque {}; | ||
| 1511 | data: *MemoizedCall, | ||
| 1512 | @"trailing.arg_values.len": *@"data.args_len", | ||
| 1513 | trailing: struct { arg_values: []Index }, | ||
| 1514 | }, | ||
| 1515 | }) void { | ||
| 1516 | _ = self; | ||
| 1517 | const map_fields = @typeInfo(@typeInfo(@TypeOf(tag_to_encoding_map)).Pointer.child).Struct.fields; | ||
| 1518 | @setEvalBranchQuota(2_000); | ||
| 1519 | inline for (@typeInfo(Tag).Enum.fields, 0..) |tag, start| { | ||
| 1520 | inline for (0..map_fields.len) |offset| { | ||
| 1521 | if (comptime std.mem.eql(u8, tag.name, map_fields[(start + offset) % map_fields.len].name)) break; | ||
| 1522 | } else { | ||
| 1523 | @compileError(@typeName(Tag) ++ "." ++ tag.name ++ " missing dbHelper tag_to_encoding_map entry"); | ||
| 1524 | } | ||
| 1525 | } | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | comptime { | ||
| 1529 | if (builtin.mode == .Debug) { | ||
| 1530 | _ = &dbHelper; | ||
| 1531 | } | ||
| 1532 | } | ||
| 1533 | }; | ||
| 1534 | |||
| 1535 | pub const static_keys = [_]Key{ | ||
| 1536 | .{ .int_type = .{ | ||
| 1537 | .signedness = .unsigned, | ||
| 1538 | .bits = 1, | ||
| 1539 | } }, | ||
| 1540 | |||
| 1541 | .{ .int_type = .{ | ||
| 1542 | .signedness = .unsigned, | ||
| 1543 | .bits = 8, | ||
| 1544 | } }, | ||
| 1545 | |||
| 1546 | .{ .int_type = .{ | ||
| 1547 | .signedness = .signed, | ||
| 1548 | .bits = 8, | ||
| 1549 | } }, | ||
| 1550 | |||
| 1551 | .{ .int_type = .{ | ||
| 1552 | .signedness = .unsigned, | ||
| 1553 | .bits = 16, | ||
| 1554 | } }, | ||
| 1555 | |||
| 1556 | .{ .int_type = .{ | ||
| 1557 | .signedness = .signed, | ||
| 1558 | .bits = 16, | ||
| 1559 | } }, | ||
| 1560 | |||
| 1561 | .{ .int_type = .{ | ||
| 1562 | .signedness = .unsigned, | ||
| 1563 | .bits = 29, | ||
| 1564 | } }, | ||
| 1565 | |||
| 1566 | .{ .int_type = .{ | ||
| 1567 | .signedness = .unsigned, | ||
| 1568 | .bits = 32, | ||
| 1569 | } }, | ||
| 1570 | |||
| 1571 | .{ .int_type = .{ | ||
| 1572 | .signedness = .signed, | ||
| 1573 | .bits = 32, | ||
| 1574 | } }, | ||
| 1575 | |||
| 1576 | .{ .int_type = .{ | ||
| 1577 | .signedness = .unsigned, | ||
| 1578 | .bits = 64, | ||
| 1579 | } }, | ||
| 1580 | |||
| 1581 | .{ .int_type = .{ | ||
| 1582 | .signedness = .signed, | ||
| 1583 | .bits = 64, | ||
| 1584 | } }, | ||
| 1585 | |||
| 1586 | .{ .int_type = .{ | ||
| 1587 | .signedness = .unsigned, | ||
| 1588 | .bits = 80, | ||
| 1589 | } }, | ||
| 1590 | |||
| 1591 | .{ .int_type = .{ | ||
| 1592 | .signedness = .unsigned, | ||
| 1593 | .bits = 128, | ||
| 1594 | } }, | ||
| 1595 | |||
| 1596 | .{ .int_type = .{ | ||
| 1597 | .signedness = .signed, | ||
| 1598 | .bits = 128, | ||
| 1599 | } }, | ||
| 1600 | |||
| 1601 | .{ .simple_type = .usize }, | ||
| 1602 | .{ .simple_type = .isize }, | ||
| 1603 | .{ .simple_type = .c_char }, | ||
| 1604 | .{ .simple_type = .c_short }, | ||
| 1605 | .{ .simple_type = .c_ushort }, | ||
| 1606 | .{ .simple_type = .c_int }, | ||
| 1607 | .{ .simple_type = .c_uint }, | ||
| 1608 | .{ .simple_type = .c_long }, | ||
| 1609 | .{ .simple_type = .c_ulong }, | ||
| 1610 | .{ .simple_type = .c_longlong }, | ||
| 1611 | .{ .simple_type = .c_ulonglong }, | ||
| 1612 | .{ .simple_type = .c_longdouble }, | ||
| 1613 | .{ .simple_type = .f16 }, | ||
| 1614 | .{ .simple_type = .f32 }, | ||
| 1615 | .{ .simple_type = .f64 }, | ||
| 1616 | .{ .simple_type = .f80 }, | ||
| 1617 | .{ .simple_type = .f128 }, | ||
| 1618 | .{ .simple_type = .anyopaque }, | ||
| 1619 | .{ .simple_type = .bool }, | ||
| 1620 | .{ .simple_type = .void }, | ||
| 1621 | .{ .simple_type = .type }, | ||
| 1622 | .{ .simple_type = .anyerror }, | ||
| 1623 | .{ .simple_type = .comptime_int }, | ||
| 1624 | .{ .simple_type = .comptime_float }, | ||
| 1625 | .{ .simple_type = .noreturn }, | ||
| 1626 | .{ .anyframe_type = .none }, | ||
| 1627 | .{ .simple_type = .null }, | ||
| 1628 | .{ .simple_type = .undefined }, | ||
| 1629 | .{ .simple_type = .enum_literal }, | ||
| 1630 | .{ .simple_type = .atomic_order }, | ||
| 1631 | .{ .simple_type = .atomic_rmw_op }, | ||
| 1632 | .{ .simple_type = .calling_convention }, | ||
| 1633 | .{ .simple_type = .address_space }, | ||
| 1634 | .{ .simple_type = .float_mode }, | ||
| 1635 | .{ .simple_type = .reduce_op }, | ||
| 1636 | .{ .simple_type = .call_modifier }, | ||
| 1637 | .{ .simple_type = .prefetch_options }, | ||
| 1638 | .{ .simple_type = .export_options }, | ||
| 1639 | .{ .simple_type = .extern_options }, | ||
| 1640 | .{ .simple_type = .type_info }, | ||
| 1641 | |||
| 1642 | .{ .ptr_type = .{ | ||
| 1643 | .child = .u8_type, | ||
| 1644 | .flags = .{ | ||
| 1645 | .size = .Many, | ||
| 1646 | }, | ||
| 1647 | } }, | ||
| 1648 | |||
| 1649 | // manyptr_const_u8_type | ||
| 1650 | .{ .ptr_type = .{ | ||
| 1651 | .child = .u8_type, | ||
| 1652 | .flags = .{ | ||
| 1653 | .size = .Many, | ||
| 1654 | .is_const = true, | ||
| 1655 | }, | ||
| 1656 | } }, | ||
| 1657 | |||
| 1658 | // manyptr_const_u8_sentinel_0_type | ||
| 1659 | .{ .ptr_type = .{ | ||
| 1660 | .child = .u8_type, | ||
| 1661 | .sentinel = .zero_u8, | ||
| 1662 | .flags = .{ | ||
| 1663 | .size = .Many, | ||
| 1664 | .is_const = true, | ||
| 1665 | }, | ||
| 1666 | } }, | ||
| 1667 | |||
| 1668 | .{ .ptr_type = .{ | ||
| 1669 | .child = .comptime_int_type, | ||
| 1670 | .flags = .{ | ||
| 1671 | .size = .One, | ||
| 1672 | .is_const = true, | ||
| 1673 | }, | ||
| 1674 | } }, | ||
| 1675 | |||
| 1676 | // slice_const_u8_type | ||
| 1677 | .{ .ptr_type = .{ | ||
| 1678 | .child = .u8_type, | ||
| 1679 | .flags = .{ | ||
| 1680 | .size = .Slice, | ||
| 1681 | .is_const = true, | ||
| 1682 | }, | ||
| 1683 | } }, | ||
| 1684 | |||
| 1685 | // slice_const_u8_sentinel_0_type | ||
| 1686 | .{ .ptr_type = .{ | ||
| 1687 | .child = .u8_type, | ||
| 1688 | .sentinel = .zero_u8, | ||
| 1689 | .flags = .{ | ||
| 1690 | .size = .Slice, | ||
| 1691 | .is_const = true, | ||
| 1692 | }, | ||
| 1693 | } }, | ||
| 1694 | |||
| 1695 | // anyerror_void_error_union_type | ||
| 1696 | .{ .error_union_type = .{ | ||
| 1697 | .error_set_type = .anyerror_type, | ||
| 1698 | .payload_type = .void_type, | ||
| 1699 | } }, | ||
| 1700 | |||
| 1701 | // generic_poison_type | ||
| 1702 | .{ .simple_type = .generic_poison }, | ||
| 1703 | |||
| 1704 | // empty_struct_type | ||
| 1705 | .{ .anon_struct_type = .{ | ||
| 1706 | .types = &.{}, | ||
| 1707 | .names = &.{}, | ||
| 1708 | .values = &.{}, | ||
| 1709 | } }, | ||
| 1710 | |||
| 1711 | .{ .simple_value = .undefined }, | ||
| 1712 | |||
| 1713 | .{ .int = .{ | ||
| 1714 | .ty = .comptime_int_type, | ||
| 1715 | .storage = .{ .u64 = 0 }, | ||
| 1716 | } }, | ||
| 1717 | |||
| 1718 | .{ .int = .{ | ||
| 1719 | .ty = .usize_type, | ||
| 1720 | .storage = .{ .u64 = 0 }, | ||
| 1721 | } }, | ||
| 1722 | |||
| 1723 | .{ .int = .{ | ||
| 1724 | .ty = .u8_type, | ||
| 1725 | .storage = .{ .u64 = 0 }, | ||
| 1726 | } }, | ||
| 1727 | |||
| 1728 | .{ .int = .{ | ||
| 1729 | .ty = .comptime_int_type, | ||
| 1730 | .storage = .{ .u64 = 1 }, | ||
| 1731 | } }, | ||
| 1732 | |||
| 1733 | .{ .int = .{ | ||
| 1734 | .ty = .usize_type, | ||
| 1735 | .storage = .{ .u64 = 1 }, | ||
| 1736 | } }, | ||
| 1737 | |||
| 1738 | // one_u8 | ||
| 1739 | .{ .int = .{ | ||
| 1740 | .ty = .u8_type, | ||
| 1741 | .storage = .{ .u64 = 1 }, | ||
| 1742 | } }, | ||
| 1743 | // four_u8 | ||
| 1744 | .{ .int = .{ | ||
| 1745 | .ty = .u8_type, | ||
| 1746 | .storage = .{ .u64 = 4 }, | ||
| 1747 | } }, | ||
| 1748 | // negative_one | ||
| 1749 | .{ .int = .{ | ||
| 1750 | .ty = .comptime_int_type, | ||
| 1751 | .storage = .{ .i64 = -1 }, | ||
| 1752 | } }, | ||
| 1753 | // calling_convention_c | ||
| 1754 | .{ .enum_tag = .{ | ||
| 1755 | .ty = .calling_convention_type, | ||
| 1756 | .int = .one_u8, | ||
| 1757 | } }, | ||
| 1758 | // calling_convention_inline | ||
| 1759 | .{ .enum_tag = .{ | ||
| 1760 | .ty = .calling_convention_type, | ||
| 1761 | .int = .four_u8, | ||
| 1762 | } }, | ||
| 1763 | |||
| 1764 | .{ .simple_value = .void }, | ||
| 1765 | .{ .simple_value = .@"unreachable" }, | ||
| 1766 | .{ .simple_value = .null }, | ||
| 1767 | .{ .simple_value = .true }, | ||
| 1768 | .{ .simple_value = .false }, | ||
| 1769 | .{ .simple_value = .empty_struct }, | ||
| 1770 | .{ .simple_value = .generic_poison }, | ||
| 1771 | }; | ||
| 1772 | |||
| 1773 | /// How many items in the InternPool are statically known. | ||
| 1774 | pub const static_len: u32 = static_keys.len; | ||
| 1775 | |||
| 1776 | pub const Tag = enum(u8) { | ||
| 1777 | /// An integer type. | ||
| 1778 | /// data is number of bits | ||
| 1779 | type_int_signed, | ||
| 1780 | /// An integer type. | ||
| 1781 | /// data is number of bits | ||
| 1782 | type_int_unsigned, | ||
| 1783 | /// An array type whose length requires 64 bits or which has a sentinel. | ||
| 1784 | /// data is payload to Array. | ||
| 1785 | type_array_big, | ||
| 1786 | /// An array type that has no sentinel and whose length fits in 32 bits. | ||
| 1787 | /// data is payload to Vector. | ||
| 1788 | type_array_small, | ||
| 1789 | /// A vector type. | ||
| 1790 | /// data is payload to Vector. | ||
| 1791 | type_vector, | ||
| 1792 | /// A fully explicitly specified pointer type. | ||
| 1793 | type_pointer, | ||
| 1794 | /// A slice type. | ||
| 1795 | /// data is Index of underlying pointer type. | ||
| 1796 | type_slice, | ||
| 1797 | /// An optional type. | ||
| 1798 | /// data is the child type. | ||
| 1799 | type_optional, | ||
| 1800 | /// The type `anyframe->T`. | ||
| 1801 | /// data is the child type. | ||
| 1802 | /// If the child type is `none`, the type is `anyframe`. | ||
| 1803 | type_anyframe, | ||
| 1804 | /// An error union type. | ||
| 1805 | /// data is payload to `Key.ErrorUnionType`. | ||
| 1806 | type_error_union, | ||
| 1807 | /// An error set type. | ||
| 1808 | /// data is payload to `ErrorSet`. | ||
| 1809 | type_error_set, | ||
| 1810 | /// The inferred error set type of a function. | ||
| 1811 | /// data is `Module.Fn.InferredErrorSet.Index`. | ||
| 1812 | type_inferred_error_set, | ||
| 1813 | /// An enum type with auto-numbered tag values. | ||
| 1814 | /// The enum is exhaustive. | ||
| 1815 | /// data is payload index to `EnumAuto`. | ||
| 1816 | type_enum_auto, | ||
| 1817 | /// An enum type with an explicitly provided integer tag type. | ||
| 1818 | /// The enum is exhaustive. | ||
| 1819 | /// data is payload index to `EnumExplicit`. | ||
| 1820 | type_enum_explicit, | ||
| 1821 | /// An enum type with an explicitly provided integer tag type. | ||
| 1822 | /// The enum is non-exhaustive. | ||
| 1823 | /// data is payload index to `EnumExplicit`. | ||
| 1824 | type_enum_nonexhaustive, | ||
| 1825 | /// A type that can be represented with only an enum tag. | ||
| 1826 | /// data is SimpleType enum value. | ||
| 1827 | simple_type, | ||
| 1828 | /// An opaque type. | ||
| 1829 | /// data is index of Key.OpaqueType in extra. | ||
| 1830 | type_opaque, | ||
| 1831 | /// A struct type. | ||
| 1832 | /// data is Module.Struct.OptionalIndex | ||
| 1833 | /// The `none` tag is used to represent `@TypeOf(.{})`. | ||
| 1834 | type_struct, | ||
| 1835 | /// A struct type that has only a namespace; no fields, and there is no | ||
| 1836 | /// Module.Struct object allocated for it. | ||
| 1837 | /// data is Module.Namespace.Index. | ||
| 1838 | type_struct_ns, | ||
| 1839 | /// An AnonStructType which stores types, names, and values for fields. | ||
| 1840 | /// data is extra index of `TypeStructAnon`. | ||
| 1841 | type_struct_anon, | ||
| 1842 | /// An AnonStructType which has only types and values for fields. | ||
| 1843 | /// data is extra index of `TypeStructAnon`. | ||
| 1844 | type_tuple_anon, | ||
| 1845 | /// A tagged union type. | ||
| 1846 | /// `data` is `Module.Union.Index`. | ||
| 1847 | type_union_tagged, | ||
| 1848 | /// An untagged union type. It also has no safety tag. | ||
| 1849 | /// `data` is `Module.Union.Index`. | ||
| 1850 | type_union_untagged, | ||
| 1851 | /// An untagged union type which has a safety tag. | ||
| 1852 | /// `data` is `Module.Union.Index`. | ||
| 1853 | type_union_safety, | ||
| 1854 | /// A function body type. | ||
| 1855 | /// `data` is extra index to `TypeFunction`. | ||
| 1856 | type_function, | ||
| 1857 | |||
| 1858 | /// Typed `undefined`. | ||
| 1859 | /// `data` is `Index` of the type. | ||
| 1860 | /// Untyped `undefined` is stored instead via `simple_value`. | ||
| 1861 | undef, | ||
| 1862 | /// A wrapper for values which are comptime-known but should | ||
| 1863 | /// semantically be runtime-known. | ||
| 1864 | /// data is extra index of `TypeValue`. | ||
| 1865 | runtime_value, | ||
| 1866 | /// A value that can be represented with only an enum tag. | ||
| 1867 | /// data is SimpleValue enum value. | ||
| 1868 | simple_value, | ||
| 1869 | /// A pointer to a decl. | ||
| 1870 | /// data is extra index of `PtrDecl`, which contains the type and address. | ||
| 1871 | ptr_decl, | ||
| 1872 | /// A pointer to a decl that can be mutated at comptime. | ||
| 1873 | /// data is extra index of `PtrMutDecl`, which contains the type and address. | ||
| 1874 | ptr_mut_decl, | ||
| 1875 | /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value. | ||
| 1876 | ptr_comptime_field, | ||
| 1877 | /// A pointer with an integer value. | ||
| 1878 | /// data is extra index of `PtrBase`, which contains the type and address. | ||
| 1879 | /// Only pointer types are allowed to have this encoding. Optional types must use | ||
| 1880 | /// `opt_payload` or `opt_null`. | ||
| 1881 | ptr_int, | ||
| 1882 | /// A pointer to the payload of an error union. | ||
| 1883 | /// data is extra index of `PtrBase`, which contains the type and base pointer. | ||
| 1884 | ptr_eu_payload, | ||
| 1885 | /// A pointer to the payload of an optional. | ||
| 1886 | /// data is extra index of `PtrBase`, which contains the type and base pointer. | ||
| 1887 | ptr_opt_payload, | ||
| 1888 | /// A pointer to an array element. | ||
| 1889 | /// data is extra index of PtrBaseIndex, which contains the base array and element index. | ||
| 1890 | /// In order to use this encoding, one must ensure that the `InternPool` | ||
| 1891 | /// already contains the elem pointer type corresponding to this payload. | ||
| 1892 | ptr_elem, | ||
| 1893 | /// A pointer to a container field. | ||
| 1894 | /// data is extra index of PtrBaseIndex, which contains the base container and field index. | ||
| 1895 | ptr_field, | ||
| 1896 | /// A slice. | ||
| 1897 | /// data is extra index of PtrSlice, which contains the ptr and len values | ||
| 1898 | ptr_slice, | ||
| 1899 | /// An optional value that is non-null. | ||
| 1900 | /// data is extra index of `TypeValue`. | ||
| 1901 | /// The type is the optional type (not the payload type). | ||
| 1902 | opt_payload, | ||
| 1903 | /// An optional value that is null. | ||
| 1904 | /// data is Index of the optional type. | ||
| 1905 | opt_null, | ||
| 1906 | /// Type: u8 | ||
| 1907 | /// data is integer value | ||
| 1908 | int_u8, | ||
| 1909 | /// Type: u16 | ||
| 1910 | /// data is integer value | ||
| 1911 | int_u16, | ||
| 1912 | /// Type: u32 | ||
| 1913 | /// data is integer value | ||
| 1914 | int_u32, | ||
| 1915 | /// Type: i32 | ||
| 1916 | /// data is integer value bitcasted to u32. | ||
| 1917 | int_i32, | ||
| 1918 | /// A usize that fits in 32 bits. | ||
| 1919 | /// data is integer value. | ||
| 1920 | int_usize, | ||
| 1921 | /// A comptime_int that fits in a u32. | ||
| 1922 | /// data is integer value. | ||
| 1923 | int_comptime_int_u32, | ||
| 1924 | /// A comptime_int that fits in an i32. | ||
| 1925 | /// data is integer value bitcasted to u32. | ||
| 1926 | int_comptime_int_i32, | ||
| 1927 | /// An integer value that fits in 32 bits with an explicitly provided type. | ||
| 1928 | /// data is extra index of `IntSmall`. | ||
| 1929 | int_small, | ||
| 1930 | /// A positive integer value. | ||
| 1931 | /// data is a limbs index to `Int`. | ||
| 1932 | int_positive, | ||
| 1933 | /// A negative integer value. | ||
| 1934 | /// data is a limbs index to `Int`. | ||
| 1935 | int_negative, | ||
| 1936 | /// The ABI alignment of a lazy type. | ||
| 1937 | /// data is extra index of `IntLazy`. | ||
| 1938 | int_lazy_align, | ||
| 1939 | /// The ABI size of a lazy type. | ||
| 1940 | /// data is extra index of `IntLazy`. | ||
| 1941 | int_lazy_size, | ||
| 1942 | /// An error value. | ||
| 1943 | /// data is extra index of `Key.Error`. | ||
| 1944 | error_set_error, | ||
| 1945 | /// An error union error. | ||
| 1946 | /// data is extra index of `Key.Error`. | ||
| 1947 | error_union_error, | ||
| 1948 | /// An error union payload. | ||
| 1949 | /// data is extra index of `TypeValue`. | ||
| 1950 | error_union_payload, | ||
| 1951 | /// An enum literal value. | ||
| 1952 | /// data is `NullTerminatedString` of the error name. | ||
| 1953 | enum_literal, | ||
| 1954 | /// An enum tag value. | ||
| 1955 | /// data is extra index of `EnumTag`. | ||
| 1956 | enum_tag, | ||
| 1957 | /// An f16 value. | ||
| 1958 | /// data is float value bitcasted to u16 and zero-extended. | ||
| 1959 | float_f16, | ||
| 1960 | /// An f32 value. | ||
| 1961 | /// data is float value bitcasted to u32. | ||
| 1962 | float_f32, | ||
| 1963 | /// An f64 value. | ||
| 1964 | /// data is extra index to Float64. | ||
| 1965 | float_f64, | ||
| 1966 | /// An f80 value. | ||
| 1967 | /// data is extra index to Float80. | ||
| 1968 | float_f80, | ||
| 1969 | /// An f128 value. | ||
| 1970 | /// data is extra index to Float128. | ||
| 1971 | float_f128, | ||
| 1972 | /// A c_longdouble value of 80 bits. | ||
| 1973 | /// data is extra index to Float80. | ||
| 1974 | /// This is used when a c_longdouble value is provided as an f80, because f80 has unnormalized | ||
| 1975 | /// values which cannot be losslessly represented as f128. It should only be used when the type | ||
| 1976 | /// underlying c_longdouble for the target is 80 bits. | ||
| 1977 | float_c_longdouble_f80, | ||
| 1978 | /// A c_longdouble value of 128 bits. | ||
| 1979 | /// data is extra index to Float128. | ||
| 1980 | /// This is used when a c_longdouble value is provided as any type other than an f80, since all | ||
| 1981 | /// other float types can be losslessly converted to and from f128. | ||
| 1982 | float_c_longdouble_f128, | ||
| 1983 | /// A comptime_float value. | ||
| 1984 | /// data is extra index to Float128. | ||
| 1985 | float_comptime_float, | ||
| 1986 | /// A global variable. | ||
| 1987 | /// data is extra index to Variable. | ||
| 1988 | variable, | ||
| 1989 | /// An extern function. | ||
| 1990 | /// data is extra index to Key.ExternFunc. | ||
| 1991 | extern_func, | ||
| 1992 | /// A regular function. | ||
| 1993 | /// data is extra index to Func. | ||
| 1994 | func, | ||
| 1995 | /// This represents the only possible value for *some* types which have | ||
| 1996 | /// only one possible value. Not all only-possible-values are encoded this way; | ||
| 1997 | /// for example structs which have all comptime fields are not encoded this way. | ||
| 1998 | /// The set of values that are encoded this way is: | ||
| 1999 | /// * An array or vector which has length 0. | ||
| 2000 | /// * A struct which has all fields comptime-known. | ||
| 2001 | /// * An empty enum or union. TODO: this value's existence is strange, because such a type in reality has no values. See #15909 | ||
| 2002 | /// data is Index of the type, which is known to be zero bits at runtime. | ||
| 2003 | only_possible_value, | ||
| 2004 | /// data is extra index to Key.Union. | ||
| 2005 | union_value, | ||
| 2006 | /// An array of bytes. | ||
| 2007 | /// data is extra index to `Bytes`. | ||
| 2008 | bytes, | ||
| 2009 | /// An instance of a struct, array, or vector. | ||
| 2010 | /// data is extra index to `Aggregate`. | ||
| 2011 | aggregate, | ||
| 2012 | /// An instance of an array or vector with every element being the same value. | ||
| 2013 | /// data is extra index to `Repeated`. | ||
| 2014 | repeated, | ||
| 2015 | |||
| 2016 | /// A memoized comptime function call result. | ||
| 2017 | /// data is extra index to `MemoizedCall` | ||
| 2018 | memoized_call, | ||
| 2019 | |||
| 2020 | const ErrorUnionType = Key.ErrorUnionType; | ||
| 2021 | const OpaqueType = Key.OpaqueType; | ||
| 2022 | const TypeValue = Key.TypeValue; | ||
| 2023 | const Error = Key.Error; | ||
| 2024 | const EnumTag = Key.EnumTag; | ||
| 2025 | const ExternFunc = Key.ExternFunc; | ||
| 2026 | const Func = Key.Func; | ||
| 2027 | const Union = Key.Union; | ||
| 2028 | const TypePointer = Key.PtrType; | ||
| 2029 | |||
| 2030 | fn Payload(comptime tag: Tag) type { | ||
| 2031 | return switch (tag) { | ||
| 2032 | .type_int_signed => unreachable, | ||
| 2033 | .type_int_unsigned => unreachable, | ||
| 2034 | .type_array_big => Array, | ||
| 2035 | .type_array_small => Vector, | ||
| 2036 | .type_vector => Vector, | ||
| 2037 | .type_pointer => TypePointer, | ||
| 2038 | .type_slice => unreachable, | ||
| 2039 | .type_optional => unreachable, | ||
| 2040 | .type_anyframe => unreachable, | ||
| 2041 | .type_error_union => ErrorUnionType, | ||
| 2042 | .type_error_set => ErrorSet, | ||
| 2043 | .type_inferred_error_set => unreachable, | ||
| 2044 | .type_enum_auto => EnumAuto, | ||
| 2045 | .type_enum_explicit => EnumExplicit, | ||
| 2046 | .type_enum_nonexhaustive => EnumExplicit, | ||
| 2047 | .simple_type => unreachable, | ||
| 2048 | .type_opaque => OpaqueType, | ||
| 2049 | .type_struct => unreachable, | ||
| 2050 | .type_struct_ns => unreachable, | ||
| 2051 | .type_struct_anon => TypeStructAnon, | ||
| 2052 | .type_tuple_anon => TypeStructAnon, | ||
| 2053 | .type_union_tagged => unreachable, | ||
| 2054 | .type_union_untagged => unreachable, | ||
| 2055 | .type_union_safety => unreachable, | ||
| 2056 | .type_function => TypeFunction, | ||
| 2057 | |||
| 2058 | .undef => unreachable, | ||
| 2059 | .runtime_value => TypeValue, | ||
| 2060 | .simple_value => unreachable, | ||
| 2061 | .ptr_decl => PtrDecl, | ||
| 2062 | .ptr_mut_decl => PtrMutDecl, | ||
| 2063 | .ptr_comptime_field => PtrComptimeField, | ||
| 2064 | .ptr_int => PtrBase, | ||
| 2065 | .ptr_eu_payload => PtrBase, | ||
| 2066 | .ptr_opt_payload => PtrBase, | ||
| 2067 | .ptr_elem => PtrBaseIndex, | ||
| 2068 | .ptr_field => PtrBaseIndex, | ||
| 2069 | .ptr_slice => PtrSlice, | ||
| 2070 | .opt_payload => TypeValue, | ||
| 2071 | .opt_null => unreachable, | ||
| 2072 | .int_u8 => unreachable, | ||
| 2073 | .int_u16 => unreachable, | ||
| 2074 | .int_u32 => unreachable, | ||
| 2075 | .int_i32 => unreachable, | ||
| 2076 | .int_usize => unreachable, | ||
| 2077 | .int_comptime_int_u32 => unreachable, | ||
| 2078 | .int_comptime_int_i32 => unreachable, | ||
| 2079 | .int_small => IntSmall, | ||
| 2080 | .int_positive => unreachable, | ||
| 2081 | .int_negative => unreachable, | ||
| 2082 | .int_lazy_align => IntLazy, | ||
| 2083 | .int_lazy_size => IntLazy, | ||
| 2084 | .error_set_error => Error, | ||
| 2085 | .error_union_error => Error, | ||
| 2086 | .error_union_payload => TypeValue, | ||
| 2087 | .enum_literal => unreachable, | ||
| 2088 | .enum_tag => EnumTag, | ||
| 2089 | .float_f16 => unreachable, | ||
| 2090 | .float_f32 => unreachable, | ||
| 2091 | .float_f64 => unreachable, | ||
| 2092 | .float_f80 => unreachable, | ||
| 2093 | .float_f128 => unreachable, | ||
| 2094 | .float_c_longdouble_f80 => unreachable, | ||
| 2095 | .float_c_longdouble_f128 => unreachable, | ||
| 2096 | .float_comptime_float => unreachable, | ||
| 2097 | .variable => Variable, | ||
| 2098 | .extern_func => ExternFunc, | ||
| 2099 | .func => Func, | ||
| 2100 | .only_possible_value => unreachable, | ||
| 2101 | .union_value => Union, | ||
| 2102 | .bytes => Bytes, | ||
| 2103 | .aggregate => Aggregate, | ||
| 2104 | .repeated => Repeated, | ||
| 2105 | .memoized_call => MemoizedCall, | ||
| 2106 | }; | ||
| 2107 | } | ||
| 2108 | |||
| 2109 | pub const Variable = struct { | ||
| 2110 | ty: Index, | ||
| 2111 | /// May be `none`. | ||
| 2112 | init: Index, | ||
| 2113 | decl: Module.Decl.Index, | ||
| 2114 | /// Library name if specified. | ||
| 2115 | /// For example `extern "c" var stderrp = ...` would have 'c' as library name. | ||
| 2116 | lib_name: OptionalNullTerminatedString, | ||
| 2117 | flags: Flags, | ||
| 2118 | |||
| 2119 | pub const Flags = packed struct(u32) { | ||
| 2120 | is_extern: bool, | ||
| 2121 | is_const: bool, | ||
| 2122 | is_threadlocal: bool, | ||
| 2123 | is_weak_linkage: bool, | ||
| 2124 | _: u28 = 0, | ||
| 2125 | }; | ||
| 2126 | }; | ||
| 2127 | |||
| 2128 | /// Trailing: | ||
| 2129 | /// 0. element: Index for each len | ||
| 2130 | /// len is determined by the aggregate type. | ||
| 2131 | pub const Aggregate = struct { | ||
| 2132 | /// The type of the aggregate. | ||
| 2133 | ty: Index, | ||
| 2134 | }; | ||
| 2135 | }; | ||
| 2136 | |||
| 2137 | /// Trailing: | ||
| 2138 | /// 0. name: NullTerminatedString for each names_len | ||
| 2139 | pub const ErrorSet = struct { | ||
| 2140 | names_len: u32, | ||
| 2141 | /// Maps error names to declaration index. | ||
| 2142 | names_map: MapIndex, | ||
| 2143 | }; | ||
| 2144 | |||
| 2145 | /// Trailing: | ||
| 2146 | /// 0. param_type: Index for each params_len | ||
| 2147 | pub const TypeFunction = struct { | ||
| 2148 | params_len: u32, | ||
| 2149 | return_type: Index, | ||
| 2150 | comptime_bits: u32, | ||
| 2151 | noalias_bits: u32, | ||
| 2152 | flags: Flags, | ||
| 2153 | |||
| 2154 | pub const Flags = packed struct(u32) { | ||
| 2155 | alignment: Alignment, | ||
| 2156 | cc: std.builtin.CallingConvention, | ||
| 2157 | is_var_args: bool, | ||
| 2158 | is_generic: bool, | ||
| 2159 | is_noinline: bool, | ||
| 2160 | align_is_generic: bool, | ||
| 2161 | cc_is_generic: bool, | ||
| 2162 | section_is_generic: bool, | ||
| 2163 | addrspace_is_generic: bool, | ||
| 2164 | _: u11 = 0, | ||
| 2165 | }; | ||
| 2166 | }; | ||
| 2167 | |||
| 2168 | pub const Bytes = struct { | ||
| 2169 | /// The type of the aggregate | ||
| 2170 | ty: Index, | ||
| 2171 | /// Index into string_bytes, of len ip.aggregateTypeLen(ty) | ||
| 2172 | bytes: String, | ||
| 2173 | }; | ||
| 2174 | |||
| 2175 | pub const Repeated = struct { | ||
| 2176 | /// The type of the aggregate. | ||
| 2177 | ty: Index, | ||
| 2178 | /// The value of every element. | ||
| 2179 | elem_val: Index, | ||
| 2180 | }; | ||
| 2181 | |||
| 2182 | /// Trailing: | ||
| 2183 | /// 0. type: Index for each fields_len | ||
| 2184 | /// 1. value: Index for each fields_len | ||
| 2185 | /// 2. name: NullTerminatedString for each fields_len | ||
| 2186 | /// The set of field names is omitted when the `Tag` is `type_tuple_anon`. | ||
| 2187 | pub const TypeStructAnon = struct { | ||
| 2188 | fields_len: u32, | ||
| 2189 | }; | ||
| 2190 | |||
| 2191 | /// Having `SimpleType` and `SimpleValue` in separate enums makes it easier to | ||
| 2192 | /// implement logic that only wants to deal with types because the logic can | ||
| 2193 | /// ignore all simple values. Note that technically, types are values. | ||
| 2194 | pub const SimpleType = enum(u32) { | ||
| 2195 | f16, | ||
| 2196 | f32, | ||
| 2197 | f64, | ||
| 2198 | f80, | ||
| 2199 | f128, | ||
| 2200 | usize, | ||
| 2201 | isize, | ||
| 2202 | c_char, | ||
| 2203 | c_short, | ||
| 2204 | c_ushort, | ||
| 2205 | c_int, | ||
| 2206 | c_uint, | ||
| 2207 | c_long, | ||
| 2208 | c_ulong, | ||
| 2209 | c_longlong, | ||
| 2210 | c_ulonglong, | ||
| 2211 | c_longdouble, | ||
| 2212 | anyopaque, | ||
| 2213 | bool, | ||
| 2214 | void, | ||
| 2215 | type, | ||
| 2216 | anyerror, | ||
| 2217 | comptime_int, | ||
| 2218 | comptime_float, | ||
| 2219 | noreturn, | ||
| 2220 | null, | ||
| 2221 | undefined, | ||
| 2222 | enum_literal, | ||
| 2223 | |||
| 2224 | atomic_order, | ||
| 2225 | atomic_rmw_op, | ||
| 2226 | calling_convention, | ||
| 2227 | address_space, | ||
| 2228 | float_mode, | ||
| 2229 | reduce_op, | ||
| 2230 | call_modifier, | ||
| 2231 | prefetch_options, | ||
| 2232 | export_options, | ||
| 2233 | extern_options, | ||
| 2234 | type_info, | ||
| 2235 | |||
| 2236 | generic_poison, | ||
| 2237 | }; | ||
| 2238 | |||
| 2239 | pub const SimpleValue = enum(u32) { | ||
| 2240 | /// This is untyped `undefined`. | ||
| 2241 | undefined, | ||
| 2242 | void, | ||
| 2243 | /// This is untyped `null`. | ||
| 2244 | null, | ||
| 2245 | /// This is the untyped empty struct literal: `.{}` | ||
| 2246 | empty_struct, | ||
| 2247 | true, | ||
| 2248 | false, | ||
| 2249 | @"unreachable", | ||
| 2250 | |||
| 2251 | generic_poison, | ||
| 2252 | }; | ||
| 2253 | |||
| 2254 | /// Stored as a power-of-two, with one special value to indicate none. | ||
| 2255 | pub const Alignment = enum(u6) { | ||
| 2256 | none = std.math.maxInt(u6), | ||
| 2257 | _, | ||
| 2258 | |||
| 2259 | pub fn toByteUnitsOptional(a: Alignment) ?u64 { | ||
| 2260 | return switch (a) { | ||
| 2261 | .none => null, | ||
| 2262 | _ => @as(u64, 1) << @enumToInt(a), | ||
| 2263 | }; | ||
| 2264 | } | ||
| 2265 | |||
| 2266 | pub fn toByteUnits(a: Alignment, default: u64) u64 { | ||
| 2267 | return switch (a) { | ||
| 2268 | .none => default, | ||
| 2269 | _ => @as(u64, 1) << @enumToInt(a), | ||
| 2270 | }; | ||
| 2271 | } | ||
| 2272 | |||
| 2273 | pub fn fromByteUnits(n: u64) Alignment { | ||
| 2274 | if (n == 0) return .none; | ||
| 2275 | assert(std.math.isPowerOfTwo(n)); | ||
| 2276 | return @intToEnum(Alignment, @ctz(n)); | ||
| 2277 | } | ||
| 2278 | |||
| 2279 | pub fn fromNonzeroByteUnits(n: u64) Alignment { | ||
| 2280 | assert(n != 0); | ||
| 2281 | return fromByteUnits(n); | ||
| 2282 | } | ||
| 2283 | |||
| 2284 | pub fn min(a: Alignment, b: Alignment) Alignment { | ||
| 2285 | return @intToEnum(Alignment, @min(@enumToInt(a), @enumToInt(b))); | ||
| 2286 | } | ||
| 2287 | }; | ||
| 2288 | |||
| 2289 | /// Used for non-sentineled arrays that have length fitting in u32, as well as | ||
| 2290 | /// vectors. | ||
| 2291 | pub const Vector = struct { | ||
| 2292 | len: u32, | ||
| 2293 | child: Index, | ||
| 2294 | }; | ||
| 2295 | |||
| 2296 | pub const Array = struct { | ||
| 2297 | len0: u32, | ||
| 2298 | len1: u32, | ||
| 2299 | child: Index, | ||
| 2300 | sentinel: Index, | ||
| 2301 | |||
| 2302 | pub const Length = PackedU64; | ||
| 2303 | |||
| 2304 | pub fn getLength(a: Array) u64 { | ||
| 2305 | return (PackedU64{ | ||
| 2306 | .a = a.len0, | ||
| 2307 | .b = a.len1, | ||
| 2308 | }).get(); | ||
| 2309 | } | ||
| 2310 | }; | ||
| 2311 | |||
| 2312 | /// Trailing: | ||
| 2313 | /// 0. field name: NullTerminatedString for each fields_len; declaration order | ||
| 2314 | /// 1. tag value: Index for each fields_len; declaration order | ||
| 2315 | pub const EnumExplicit = struct { | ||
| 2316 | /// The Decl that corresponds to the enum itself. | ||
| 2317 | decl: Module.Decl.Index, | ||
| 2318 | /// This may be `none` if there are no declarations. | ||
| 2319 | namespace: Module.Namespace.OptionalIndex, | ||
| 2320 | /// An integer type which is used for the numerical value of the enum, which | ||
| 2321 | /// has been explicitly provided by the enum declaration. | ||
| 2322 | int_tag_type: Index, | ||
| 2323 | fields_len: u32, | ||
| 2324 | /// Maps field names to declaration index. | ||
| 2325 | names_map: MapIndex, | ||
| 2326 | /// Maps field values to declaration index. | ||
| 2327 | /// If this is `none`, it means the trailing tag values are absent because | ||
| 2328 | /// they are auto-numbered. | ||
| 2329 | values_map: OptionalMapIndex, | ||
| 2330 | }; | ||
| 2331 | |||
| 2332 | /// Trailing: | ||
| 2333 | /// 0. field name: NullTerminatedString for each fields_len; declaration order | ||
| 2334 | pub const EnumAuto = struct { | ||
| 2335 | /// The Decl that corresponds to the enum itself. | ||
| 2336 | decl: Module.Decl.Index, | ||
| 2337 | /// This may be `none` if there are no declarations. | ||
| 2338 | namespace: Module.Namespace.OptionalIndex, | ||
| 2339 | /// An integer type which is used for the numerical value of the enum, which | ||
| 2340 | /// was inferred by Zig based on the number of tags. | ||
| 2341 | int_tag_type: Index, | ||
| 2342 | fields_len: u32, | ||
| 2343 | /// Maps field names to declaration index. | ||
| 2344 | names_map: MapIndex, | ||
| 2345 | }; | ||
| 2346 | |||
| 2347 | pub const PackedU64 = packed struct(u64) { | ||
| 2348 | a: u32, | ||
| 2349 | b: u32, | ||
| 2350 | |||
| 2351 | pub fn get(x: PackedU64) u64 { | ||
| 2352 | return @bitCast(u64, x); | ||
| 2353 | } | ||
| 2354 | |||
| 2355 | pub fn init(x: u64) PackedU64 { | ||
| 2356 | return @bitCast(PackedU64, x); | ||
| 2357 | } | ||
| 2358 | }; | ||
| 2359 | |||
| 2360 | pub const PtrDecl = struct { | ||
| 2361 | ty: Index, | ||
| 2362 | decl: Module.Decl.Index, | ||
| 2363 | }; | ||
| 2364 | |||
| 2365 | pub const PtrMutDecl = struct { | ||
| 2366 | ty: Index, | ||
| 2367 | decl: Module.Decl.Index, | ||
| 2368 | runtime_index: RuntimeIndex, | ||
| 2369 | }; | ||
| 2370 | |||
| 2371 | pub const PtrComptimeField = struct { | ||
| 2372 | ty: Index, | ||
| 2373 | field_val: Index, | ||
| 2374 | }; | ||
| 2375 | |||
| 2376 | pub const PtrBase = struct { | ||
| 2377 | ty: Index, | ||
| 2378 | base: Index, | ||
| 2379 | }; | ||
| 2380 | |||
| 2381 | pub const PtrBaseIndex = struct { | ||
| 2382 | ty: Index, | ||
| 2383 | base: Index, | ||
| 2384 | index: Index, | ||
| 2385 | }; | ||
| 2386 | |||
| 2387 | pub const PtrSlice = struct { | ||
| 2388 | /// The slice type. | ||
| 2389 | ty: Index, | ||
| 2390 | /// A many pointer value. | ||
| 2391 | ptr: Index, | ||
| 2392 | /// A usize value. | ||
| 2393 | len: Index, | ||
| 2394 | }; | ||
| 2395 | |||
| 2396 | /// Trailing: Limb for every limbs_len | ||
| 2397 | pub const Int = struct { | ||
| 2398 | ty: Index, | ||
| 2399 | limbs_len: u32, | ||
| 2400 | }; | ||
| 2401 | |||
| 2402 | pub const IntSmall = struct { | ||
| 2403 | ty: Index, | ||
| 2404 | value: u32, | ||
| 2405 | }; | ||
| 2406 | |||
| 2407 | pub const IntLazy = struct { | ||
| 2408 | ty: Index, | ||
| 2409 | lazy_ty: Index, | ||
| 2410 | }; | ||
| 2411 | |||
| 2412 | /// A f64 value, broken up into 2 u32 parts. | ||
| 2413 | pub const Float64 = struct { | ||
| 2414 | piece0: u32, | ||
| 2415 | piece1: u32, | ||
| 2416 | |||
| 2417 | pub fn get(self: Float64) f64 { | ||
| 2418 | const int_bits = @as(u64, self.piece0) | (@as(u64, self.piece1) << 32); | ||
| 2419 | return @bitCast(f64, int_bits); | ||
| 2420 | } | ||
| 2421 | |||
| 2422 | fn pack(val: f64) Float64 { | ||
| 2423 | const bits = @bitCast(u64, val); | ||
| 2424 | return .{ | ||
| 2425 | .piece0 = @truncate(u32, bits), | ||
| 2426 | .piece1 = @truncate(u32, bits >> 32), | ||
| 2427 | }; | ||
| 2428 | } | ||
| 2429 | }; | ||
| 2430 | |||
| 2431 | /// A f80 value, broken up into 2 u32 parts and a u16 part zero-padded to a u32. | ||
| 2432 | pub const Float80 = struct { | ||
| 2433 | piece0: u32, | ||
| 2434 | piece1: u32, | ||
| 2435 | piece2: u32, // u16 part, top bits | ||
| 2436 | |||
| 2437 | pub fn get(self: Float80) f80 { | ||
| 2438 | const int_bits = @as(u80, self.piece0) | | ||
| 2439 | (@as(u80, self.piece1) << 32) | | ||
| 2440 | (@as(u80, self.piece2) << 64); | ||
| 2441 | return @bitCast(f80, int_bits); | ||
| 2442 | } | ||
| 2443 | |||
| 2444 | fn pack(val: f80) Float80 { | ||
| 2445 | const bits = @bitCast(u80, val); | ||
| 2446 | return .{ | ||
| 2447 | .piece0 = @truncate(u32, bits), | ||
| 2448 | .piece1 = @truncate(u32, bits >> 32), | ||
| 2449 | .piece2 = @truncate(u16, bits >> 64), | ||
| 2450 | }; | ||
| 2451 | } | ||
| 2452 | }; | ||
| 2453 | |||
| 2454 | /// A f128 value, broken up into 4 u32 parts. | ||
| 2455 | pub const Float128 = struct { | ||
| 2456 | piece0: u32, | ||
| 2457 | piece1: u32, | ||
| 2458 | piece2: u32, | ||
| 2459 | piece3: u32, | ||
| 2460 | |||
| 2461 | pub fn get(self: Float128) f128 { | ||
| 2462 | const int_bits = @as(u128, self.piece0) | | ||
| 2463 | (@as(u128, self.piece1) << 32) | | ||
| 2464 | (@as(u128, self.piece2) << 64) | | ||
| 2465 | (@as(u128, self.piece3) << 96); | ||
| 2466 | return @bitCast(f128, int_bits); | ||
| 2467 | } | ||
| 2468 | |||
| 2469 | fn pack(val: f128) Float128 { | ||
| 2470 | const bits = @bitCast(u128, val); | ||
| 2471 | return .{ | ||
| 2472 | .piece0 = @truncate(u32, bits), | ||
| 2473 | .piece1 = @truncate(u32, bits >> 32), | ||
| 2474 | .piece2 = @truncate(u32, bits >> 64), | ||
| 2475 | .piece3 = @truncate(u32, bits >> 96), | ||
| 2476 | }; | ||
| 2477 | } | ||
| 2478 | }; | ||
| 2479 | |||
| 2480 | /// Trailing: | ||
| 2481 | /// 0. arg value: Index for each args_len | ||
| 2482 | pub const MemoizedCall = struct { | ||
| 2483 | func: Module.Fn.Index, | ||
| 2484 | args_len: u32, | ||
| 2485 | result: Index, | ||
| 2486 | }; | ||
| 2487 | |||
| 2488 | pub fn init(ip: *InternPool, gpa: Allocator) !void { | ||
| 2489 | assert(ip.items.len == 0); | ||
| 2490 | |||
| 2491 | // Reserve string index 0 for an empty string. | ||
| 2492 | assert((try ip.getOrPutString(gpa, "")) == .empty); | ||
| 2493 | |||
| 2494 | // So that we can use `catch unreachable` below. | ||
| 2495 | try ip.items.ensureUnusedCapacity(gpa, static_keys.len); | ||
| 2496 | try ip.map.ensureUnusedCapacity(gpa, static_keys.len); | ||
| 2497 | try ip.extra.ensureUnusedCapacity(gpa, static_keys.len); | ||
| 2498 | |||
| 2499 | // This inserts all the statically-known values into the intern pool in the | ||
| 2500 | // order expected. | ||
| 2501 | for (static_keys) |key| _ = ip.get(gpa, key) catch unreachable; | ||
| 2502 | |||
| 2503 | if (std.debug.runtime_safety) { | ||
| 2504 | // Sanity check. | ||
| 2505 | assert(ip.indexToKey(.bool_true).simple_value == .true); | ||
| 2506 | assert(ip.indexToKey(.bool_false).simple_value == .false); | ||
| 2507 | |||
| 2508 | const cc_inline = ip.indexToKey(.calling_convention_inline).enum_tag.int; | ||
| 2509 | const cc_c = ip.indexToKey(.calling_convention_c).enum_tag.int; | ||
| 2510 | |||
| 2511 | assert(ip.indexToKey(cc_inline).int.storage.u64 == | ||
| 2512 | @enumToInt(std.builtin.CallingConvention.Inline)); | ||
| 2513 | |||
| 2514 | assert(ip.indexToKey(cc_c).int.storage.u64 == | ||
| 2515 | @enumToInt(std.builtin.CallingConvention.C)); | ||
| 2516 | |||
| 2517 | assert(ip.indexToKey(ip.typeOf(cc_inline)).int_type.bits == | ||
| 2518 | @typeInfo(@typeInfo(std.builtin.CallingConvention).Enum.tag_type).Int.bits); | ||
| 2519 | } | ||
| 2520 | |||
| 2521 | assert(ip.items.len == static_keys.len); | ||
| 2522 | } | ||
| 2523 | |||
| 2524 | pub fn deinit(ip: *InternPool, gpa: Allocator) void { | ||
| 2525 | ip.map.deinit(gpa); | ||
| 2526 | ip.items.deinit(gpa); | ||
| 2527 | ip.extra.deinit(gpa); | ||
| 2528 | ip.limbs.deinit(gpa); | ||
| 2529 | ip.string_bytes.deinit(gpa); | ||
| 2530 | |||
| 2531 | ip.structs_free_list.deinit(gpa); | ||
| 2532 | ip.allocated_structs.deinit(gpa); | ||
| 2533 | |||
| 2534 | ip.unions_free_list.deinit(gpa); | ||
| 2535 | ip.allocated_unions.deinit(gpa); | ||
| 2536 | |||
| 2537 | ip.funcs_free_list.deinit(gpa); | ||
| 2538 | ip.allocated_funcs.deinit(gpa); | ||
| 2539 | |||
| 2540 | ip.inferred_error_sets_free_list.deinit(gpa); | ||
| 2541 | ip.allocated_inferred_error_sets.deinit(gpa); | ||
| 2542 | |||
| 2543 | for (ip.maps.items) |*map| map.deinit(gpa); | ||
| 2544 | ip.maps.deinit(gpa); | ||
| 2545 | |||
| 2546 | ip.string_table.deinit(gpa); | ||
| 2547 | |||
| 2548 | ip.* = undefined; | ||
| 2549 | } | ||
| 2550 | |||
| 2551 | pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ||
| 2552 | assert(index != .none); | ||
| 2553 | const item = ip.items.get(@enumToInt(index)); | ||
| 2554 | const data = item.data; | ||
| 2555 | return switch (item.tag) { | ||
| 2556 | .type_int_signed => .{ | ||
| 2557 | .int_type = .{ | ||
| 2558 | .signedness = .signed, | ||
| 2559 | .bits = @intCast(u16, data), | ||
| 2560 | }, | ||
| 2561 | }, | ||
| 2562 | .type_int_unsigned => .{ | ||
| 2563 | .int_type = .{ | ||
| 2564 | .signedness = .unsigned, | ||
| 2565 | .bits = @intCast(u16, data), | ||
| 2566 | }, | ||
| 2567 | }, | ||
| 2568 | .type_array_big => { | ||
| 2569 | const array_info = ip.extraData(Array, data); | ||
| 2570 | return .{ .array_type = .{ | ||
| 2571 | .len = array_info.getLength(), | ||
| 2572 | .child = array_info.child, | ||
| 2573 | .sentinel = array_info.sentinel, | ||
| 2574 | } }; | ||
| 2575 | }, | ||
| 2576 | .type_array_small => { | ||
| 2577 | const array_info = ip.extraData(Vector, data); | ||
| 2578 | return .{ .array_type = .{ | ||
| 2579 | .len = array_info.len, | ||
| 2580 | .child = array_info.child, | ||
| 2581 | .sentinel = .none, | ||
| 2582 | } }; | ||
| 2583 | }, | ||
| 2584 | .simple_type => .{ .simple_type = @intToEnum(SimpleType, data) }, | ||
| 2585 | .simple_value => .{ .simple_value = @intToEnum(SimpleValue, data) }, | ||
| 2586 | |||
| 2587 | .type_vector => { | ||
| 2588 | const vector_info = ip.extraData(Vector, data); | ||
| 2589 | return .{ .vector_type = .{ | ||
| 2590 | .len = vector_info.len, | ||
| 2591 | .child = vector_info.child, | ||
| 2592 | } }; | ||
| 2593 | }, | ||
| 2594 | |||
| 2595 | .type_pointer => .{ .ptr_type = ip.extraData(Tag.TypePointer, data) }, | ||
| 2596 | |||
| 2597 | .type_slice => { | ||
| 2598 | assert(ip.items.items(.tag)[data] == .type_pointer); | ||
| 2599 | var ptr_info = ip.extraData(Tag.TypePointer, ip.items.items(.data)[data]); | ||
| 2600 | ptr_info.flags.size = .Slice; | ||
| 2601 | return .{ .ptr_type = ptr_info }; | ||
| 2602 | }, | ||
| 2603 | |||
| 2604 | .type_optional => .{ .opt_type = @intToEnum(Index, data) }, | ||
| 2605 | .type_anyframe => .{ .anyframe_type = @intToEnum(Index, data) }, | ||
| 2606 | |||
| 2607 | .type_error_union => .{ .error_union_type = ip.extraData(Key.ErrorUnionType, data) }, | ||
| 2608 | .type_error_set => { | ||
| 2609 | const error_set = ip.extraDataTrail(ErrorSet, data); | ||
| 2610 | const names_len = error_set.data.names_len; | ||
| 2611 | const names = ip.extra.items[error_set.end..][0..names_len]; | ||
| 2612 | return .{ .error_set_type = .{ | ||
| 2613 | .names = @ptrCast([]const NullTerminatedString, names), | ||
| 2614 | .names_map = error_set.data.names_map.toOptional(), | ||
| 2615 | } }; | ||
| 2616 | }, | ||
| 2617 | .type_inferred_error_set => .{ | ||
| 2618 | .inferred_error_set_type = @intToEnum(Module.Fn.InferredErrorSet.Index, data), | ||
| 2619 | }, | ||
| 2620 | |||
| 2621 | .type_opaque => .{ .opaque_type = ip.extraData(Key.OpaqueType, data) }, | ||
| 2622 | .type_struct => { | ||
| 2623 | const struct_index = @intToEnum(Module.Struct.OptionalIndex, data); | ||
| 2624 | const namespace = if (struct_index.unwrap()) |i| | ||
| 2625 | ip.structPtrConst(i).namespace.toOptional() | ||
| 2626 | else | ||
| 2627 | .none; | ||
| 2628 | return .{ .struct_type = .{ | ||
| 2629 | .index = struct_index, | ||
| 2630 | .namespace = namespace, | ||
| 2631 | } }; | ||
| 2632 | }, | ||
| 2633 | .type_struct_ns => .{ .struct_type = .{ | ||
| 2634 | .index = .none, | ||
| 2635 | .namespace = @intToEnum(Module.Namespace.Index, data).toOptional(), | ||
| 2636 | } }, | ||
| 2637 | |||
| 2638 | .type_struct_anon => { | ||
| 2639 | const type_struct_anon = ip.extraDataTrail(TypeStructAnon, data); | ||
| 2640 | const fields_len = type_struct_anon.data.fields_len; | ||
| 2641 | const types = ip.extra.items[type_struct_anon.end..][0..fields_len]; | ||
| 2642 | const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len]; | ||
| 2643 | const names = ip.extra.items[type_struct_anon.end + 2 * fields_len ..][0..fields_len]; | ||
| 2644 | return .{ .anon_struct_type = .{ | ||
| 2645 | .types = @ptrCast([]const Index, types), | ||
| 2646 | .values = @ptrCast([]const Index, values), | ||
| 2647 | .names = @ptrCast([]const NullTerminatedString, names), | ||
| 2648 | } }; | ||
| 2649 | }, | ||
| 2650 | .type_tuple_anon => { | ||
| 2651 | const type_struct_anon = ip.extraDataTrail(TypeStructAnon, data); | ||
| 2652 | const fields_len = type_struct_anon.data.fields_len; | ||
| 2653 | const types = ip.extra.items[type_struct_anon.end..][0..fields_len]; | ||
| 2654 | const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len]; | ||
| 2655 | return .{ .anon_struct_type = .{ | ||
| 2656 | .types = @ptrCast([]const Index, types), | ||
| 2657 | .values = @ptrCast([]const Index, values), | ||
| 2658 | .names = &.{}, | ||
| 2659 | } }; | ||
| 2660 | }, | ||
| 2661 | |||
| 2662 | .type_union_untagged => .{ .union_type = .{ | ||
| 2663 | .index = @intToEnum(Module.Union.Index, data), | ||
| 2664 | .runtime_tag = .none, | ||
| 2665 | } }, | ||
| 2666 | .type_union_tagged => .{ .union_type = .{ | ||
| 2667 | .index = @intToEnum(Module.Union.Index, data), | ||
| 2668 | .runtime_tag = .tagged, | ||
| 2669 | } }, | ||
| 2670 | .type_union_safety => .{ .union_type = .{ | ||
| 2671 | .index = @intToEnum(Module.Union.Index, data), | ||
| 2672 | .runtime_tag = .safety, | ||
| 2673 | } }, | ||
| 2674 | |||
| 2675 | .type_enum_auto => { | ||
| 2676 | const enum_auto = ip.extraDataTrail(EnumAuto, data); | ||
| 2677 | const names = @ptrCast( | ||
| 2678 | []const NullTerminatedString, | ||
| 2679 | ip.extra.items[enum_auto.end..][0..enum_auto.data.fields_len], | ||
| 2680 | ); | ||
| 2681 | return .{ .enum_type = .{ | ||
| 2682 | .decl = enum_auto.data.decl, | ||
| 2683 | .namespace = enum_auto.data.namespace, | ||
| 2684 | .tag_ty = enum_auto.data.int_tag_type, | ||
| 2685 | .names = names, | ||
| 2686 | .values = &.{}, | ||
| 2687 | .tag_mode = .auto, | ||
| 2688 | .names_map = enum_auto.data.names_map.toOptional(), | ||
| 2689 | .values_map = .none, | ||
| 2690 | } }; | ||
| 2691 | }, | ||
| 2692 | .type_enum_explicit => ip.indexToKeyEnum(data, .explicit), | ||
| 2693 | .type_enum_nonexhaustive => ip.indexToKeyEnum(data, .nonexhaustive), | ||
| 2694 | .type_function => .{ .func_type = ip.indexToKeyFuncType(data) }, | ||
| 2695 | |||
| 2696 | .undef => .{ .undef = @intToEnum(Index, data) }, | ||
| 2697 | .runtime_value => .{ .runtime_value = ip.extraData(Tag.TypeValue, data) }, | ||
| 2698 | .opt_null => .{ .opt = .{ | ||
| 2699 | .ty = @intToEnum(Index, data), | ||
| 2700 | .val = .none, | ||
| 2701 | } }, | ||
| 2702 | .opt_payload => { | ||
| 2703 | const extra = ip.extraData(Tag.TypeValue, data); | ||
| 2704 | return .{ .opt = .{ | ||
| 2705 | .ty = extra.ty, | ||
| 2706 | .val = extra.val, | ||
| 2707 | } }; | ||
| 2708 | }, | ||
| 2709 | .ptr_decl => { | ||
| 2710 | const info = ip.extraData(PtrDecl, data); | ||
| 2711 | return .{ .ptr = .{ | ||
| 2712 | .ty = info.ty, | ||
| 2713 | .addr = .{ .decl = info.decl }, | ||
| 2714 | } }; | ||
| 2715 | }, | ||
| 2716 | .ptr_mut_decl => { | ||
| 2717 | const info = ip.extraData(PtrMutDecl, data); | ||
| 2718 | return .{ .ptr = .{ | ||
| 2719 | .ty = info.ty, | ||
| 2720 | .addr = .{ .mut_decl = .{ | ||
| 2721 | .decl = info.decl, | ||
| 2722 | .runtime_index = info.runtime_index, | ||
| 2723 | } }, | ||
| 2724 | } }; | ||
| 2725 | }, | ||
| 2726 | .ptr_comptime_field => { | ||
| 2727 | const info = ip.extraData(PtrComptimeField, data); | ||
| 2728 | return .{ .ptr = .{ | ||
| 2729 | .ty = info.ty, | ||
| 2730 | .addr = .{ .comptime_field = info.field_val }, | ||
| 2731 | } }; | ||
| 2732 | }, | ||
| 2733 | .ptr_int => { | ||
| 2734 | const info = ip.extraData(PtrBase, data); | ||
| 2735 | return .{ .ptr = .{ | ||
| 2736 | .ty = info.ty, | ||
| 2737 | .addr = .{ .int = info.base }, | ||
| 2738 | } }; | ||
| 2739 | }, | ||
| 2740 | .ptr_eu_payload => { | ||
| 2741 | const info = ip.extraData(PtrBase, data); | ||
| 2742 | return .{ .ptr = .{ | ||
| 2743 | .ty = info.ty, | ||
| 2744 | .addr = .{ .eu_payload = info.base }, | ||
| 2745 | } }; | ||
| 2746 | }, | ||
| 2747 | .ptr_opt_payload => { | ||
| 2748 | const info = ip.extraData(PtrBase, data); | ||
| 2749 | return .{ .ptr = .{ | ||
| 2750 | .ty = info.ty, | ||
| 2751 | .addr = .{ .opt_payload = info.base }, | ||
| 2752 | } }; | ||
| 2753 | }, | ||
| 2754 | .ptr_elem => { | ||
| 2755 | // Avoid `indexToKey` recursion by asserting the tag encoding. | ||
| 2756 | const info = ip.extraData(PtrBaseIndex, data); | ||
| 2757 | const index_item = ip.items.get(@enumToInt(info.index)); | ||
| 2758 | return switch (index_item.tag) { | ||
| 2759 | .int_usize => .{ .ptr = .{ | ||
| 2760 | .ty = info.ty, | ||
| 2761 | .addr = .{ .elem = .{ | ||
| 2762 | .base = info.base, | ||
| 2763 | .index = index_item.data, | ||
| 2764 | } }, | ||
| 2765 | } }, | ||
| 2766 | .int_positive => @panic("TODO"), // implement along with behavior test coverage | ||
| 2767 | else => unreachable, | ||
| 2768 | }; | ||
| 2769 | }, | ||
| 2770 | .ptr_field => { | ||
| 2771 | // Avoid `indexToKey` recursion by asserting the tag encoding. | ||
| 2772 | const info = ip.extraData(PtrBaseIndex, data); | ||
| 2773 | const index_item = ip.items.get(@enumToInt(info.index)); | ||
| 2774 | return switch (index_item.tag) { | ||
| 2775 | .int_usize => .{ .ptr = .{ | ||
| 2776 | .ty = info.ty, | ||
| 2777 | .addr = .{ .field = .{ | ||
| 2778 | .base = info.base, | ||
| 2779 | .index = index_item.data, | ||
| 2780 | } }, | ||
| 2781 | } }, | ||
| 2782 | .int_positive => @panic("TODO"), // implement along with behavior test coverage | ||
| 2783 | else => unreachable, | ||
| 2784 | }; | ||
| 2785 | }, | ||
| 2786 | .ptr_slice => { | ||
| 2787 | const info = ip.extraData(PtrSlice, data); | ||
| 2788 | const ptr_item = ip.items.get(@enumToInt(info.ptr)); | ||
| 2789 | return .{ | ||
| 2790 | .ptr = .{ | ||
| 2791 | .ty = info.ty, | ||
| 2792 | .addr = switch (ptr_item.tag) { | ||
| 2793 | .ptr_decl => .{ | ||
| 2794 | .decl = ip.extraData(PtrDecl, ptr_item.data).decl, | ||
| 2795 | }, | ||
| 2796 | .ptr_mut_decl => b: { | ||
| 2797 | const sub_info = ip.extraData(PtrMutDecl, ptr_item.data); | ||
| 2798 | break :b .{ .mut_decl = .{ | ||
| 2799 | .decl = sub_info.decl, | ||
| 2800 | .runtime_index = sub_info.runtime_index, | ||
| 2801 | } }; | ||
| 2802 | }, | ||
| 2803 | .ptr_comptime_field => .{ | ||
| 2804 | .comptime_field = ip.extraData(PtrComptimeField, ptr_item.data).field_val, | ||
| 2805 | }, | ||
| 2806 | .ptr_int => .{ | ||
| 2807 | .int = ip.extraData(PtrBase, ptr_item.data).base, | ||
| 2808 | }, | ||
| 2809 | .ptr_eu_payload => .{ | ||
| 2810 | .eu_payload = ip.extraData(PtrBase, ptr_item.data).base, | ||
| 2811 | }, | ||
| 2812 | .ptr_opt_payload => .{ | ||
| 2813 | .opt_payload = ip.extraData(PtrBase, ptr_item.data).base, | ||
| 2814 | }, | ||
| 2815 | .ptr_elem => b: { | ||
| 2816 | // Avoid `indexToKey` recursion by asserting the tag encoding. | ||
| 2817 | const sub_info = ip.extraData(PtrBaseIndex, ptr_item.data); | ||
| 2818 | const index_item = ip.items.get(@enumToInt(sub_info.index)); | ||
| 2819 | break :b switch (index_item.tag) { | ||
| 2820 | .int_usize => .{ .elem = .{ | ||
| 2821 | .base = sub_info.base, | ||
| 2822 | .index = index_item.data, | ||
| 2823 | } }, | ||
| 2824 | .int_positive => @panic("TODO"), // implement along with behavior test coverage | ||
| 2825 | else => unreachable, | ||
| 2826 | }; | ||
| 2827 | }, | ||
| 2828 | .ptr_field => b: { | ||
| 2829 | // Avoid `indexToKey` recursion by asserting the tag encoding. | ||
| 2830 | const sub_info = ip.extraData(PtrBaseIndex, ptr_item.data); | ||
| 2831 | const index_item = ip.items.get(@enumToInt(sub_info.index)); | ||
| 2832 | break :b switch (index_item.tag) { | ||
| 2833 | .int_usize => .{ .field = .{ | ||
| 2834 | .base = sub_info.base, | ||
| 2835 | .index = index_item.data, | ||
| 2836 | } }, | ||
| 2837 | .int_positive => @panic("TODO"), // implement along with behavior test coverage | ||
| 2838 | else => unreachable, | ||
| 2839 | }; | ||
| 2840 | }, | ||
| 2841 | else => unreachable, | ||
| 2842 | }, | ||
| 2843 | .len = info.len, | ||
| 2844 | }, | ||
| 2845 | }; | ||
| 2846 | }, | ||
| 2847 | .int_u8 => .{ .int = .{ | ||
| 2848 | .ty = .u8_type, | ||
| 2849 | .storage = .{ .u64 = data }, | ||
| 2850 | } }, | ||
| 2851 | .int_u16 => .{ .int = .{ | ||
| 2852 | .ty = .u16_type, | ||
| 2853 | .storage = .{ .u64 = data }, | ||
| 2854 | } }, | ||
| 2855 | .int_u32 => .{ .int = .{ | ||
| 2856 | .ty = .u32_type, | ||
| 2857 | .storage = .{ .u64 = data }, | ||
| 2858 | } }, | ||
| 2859 | .int_i32 => .{ .int = .{ | ||
| 2860 | .ty = .i32_type, | ||
| 2861 | .storage = .{ .i64 = @bitCast(i32, data) }, | ||
| 2862 | } }, | ||
| 2863 | .int_usize => .{ .int = .{ | ||
| 2864 | .ty = .usize_type, | ||
| 2865 | .storage = .{ .u64 = data }, | ||
| 2866 | } }, | ||
| 2867 | .int_comptime_int_u32 => .{ .int = .{ | ||
| 2868 | .ty = .comptime_int_type, | ||
| 2869 | .storage = .{ .u64 = data }, | ||
| 2870 | } }, | ||
| 2871 | .int_comptime_int_i32 => .{ .int = .{ | ||
| 2872 | .ty = .comptime_int_type, | ||
| 2873 | .storage = .{ .i64 = @bitCast(i32, data) }, | ||
| 2874 | } }, | ||
| 2875 | .int_positive => ip.indexToKeyBigInt(data, true), | ||
| 2876 | .int_negative => ip.indexToKeyBigInt(data, false), | ||
| 2877 | .int_small => { | ||
| 2878 | const info = ip.extraData(IntSmall, data); | ||
| 2879 | return .{ .int = .{ | ||
| 2880 | .ty = info.ty, | ||
| 2881 | .storage = .{ .u64 = info.value }, | ||
| 2882 | } }; | ||
| 2883 | }, | ||
| 2884 | .int_lazy_align, .int_lazy_size => |tag| { | ||
| 2885 | const info = ip.extraData(IntLazy, data); | ||
| 2886 | return .{ .int = .{ | ||
| 2887 | .ty = info.ty, | ||
| 2888 | .storage = switch (tag) { | ||
| 2889 | .int_lazy_align => .{ .lazy_align = info.lazy_ty }, | ||
| 2890 | .int_lazy_size => .{ .lazy_size = info.lazy_ty }, | ||
| 2891 | else => unreachable, | ||
| 2892 | }, | ||
| 2893 | } }; | ||
| 2894 | }, | ||
| 2895 | .float_f16 => .{ .float = .{ | ||
| 2896 | .ty = .f16_type, | ||
| 2897 | .storage = .{ .f16 = @bitCast(f16, @intCast(u16, data)) }, | ||
| 2898 | } }, | ||
| 2899 | .float_f32 => .{ .float = .{ | ||
| 2900 | .ty = .f32_type, | ||
| 2901 | .storage = .{ .f32 = @bitCast(f32, data) }, | ||
| 2902 | } }, | ||
| 2903 | .float_f64 => .{ .float = .{ | ||
| 2904 | .ty = .f64_type, | ||
| 2905 | .storage = .{ .f64 = ip.extraData(Float64, data).get() }, | ||
| 2906 | } }, | ||
| 2907 | .float_f80 => .{ .float = .{ | ||
| 2908 | .ty = .f80_type, | ||
| 2909 | .storage = .{ .f80 = ip.extraData(Float80, data).get() }, | ||
| 2910 | } }, | ||
| 2911 | .float_f128 => .{ .float = .{ | ||
| 2912 | .ty = .f128_type, | ||
| 2913 | .storage = .{ .f128 = ip.extraData(Float128, data).get() }, | ||
| 2914 | } }, | ||
| 2915 | .float_c_longdouble_f80 => .{ .float = .{ | ||
| 2916 | .ty = .c_longdouble_type, | ||
| 2917 | .storage = .{ .f80 = ip.extraData(Float80, data).get() }, | ||
| 2918 | } }, | ||
| 2919 | .float_c_longdouble_f128 => .{ .float = .{ | ||
| 2920 | .ty = .c_longdouble_type, | ||
| 2921 | .storage = .{ .f128 = ip.extraData(Float128, data).get() }, | ||
| 2922 | } }, | ||
| 2923 | .float_comptime_float => .{ .float = .{ | ||
| 2924 | .ty = .comptime_float_type, | ||
| 2925 | .storage = .{ .f128 = ip.extraData(Float128, data).get() }, | ||
| 2926 | } }, | ||
| 2927 | .variable => { | ||
| 2928 | const extra = ip.extraData(Tag.Variable, data); | ||
| 2929 | return .{ .variable = .{ | ||
| 2930 | .ty = extra.ty, | ||
| 2931 | .init = extra.init, | ||
| 2932 | .decl = extra.decl, | ||
| 2933 | .lib_name = extra.lib_name, | ||
| 2934 | .is_extern = extra.flags.is_extern, | ||
| 2935 | .is_const = extra.flags.is_const, | ||
| 2936 | .is_threadlocal = extra.flags.is_threadlocal, | ||
| 2937 | .is_weak_linkage = extra.flags.is_weak_linkage, | ||
| 2938 | } }; | ||
| 2939 | }, | ||
| 2940 | .extern_func => .{ .extern_func = ip.extraData(Tag.ExternFunc, data) }, | ||
| 2941 | .func => .{ .func = ip.extraData(Tag.Func, data) }, | ||
| 2942 | .only_possible_value => { | ||
| 2943 | const ty = @intToEnum(Index, data); | ||
| 2944 | const ty_item = ip.items.get(@enumToInt(ty)); | ||
| 2945 | return switch (ty_item.tag) { | ||
| 2946 | .type_array_big => { | ||
| 2947 | const sentinel = @ptrCast( | ||
| 2948 | *const [1]Index, | ||
| 2949 | &ip.extra.items[ty_item.data + std.meta.fieldIndex(Array, "sentinel").?], | ||
| 2950 | ); | ||
| 2951 | return .{ .aggregate = .{ | ||
| 2952 | .ty = ty, | ||
| 2953 | .storage = .{ .elems = sentinel[0..@boolToInt(sentinel[0] != .none)] }, | ||
| 2954 | } }; | ||
| 2955 | }, | ||
| 2956 | .type_array_small, .type_vector => .{ .aggregate = .{ | ||
| 2957 | .ty = ty, | ||
| 2958 | .storage = .{ .elems = &.{} }, | ||
| 2959 | } }, | ||
| 2960 | // TODO: migrate structs to properly use the InternPool rather | ||
| 2961 | // than using the SegmentedList trick, then the struct type will | ||
| 2962 | // have a slice of comptime values that can be used here for when | ||
| 2963 | // the struct has one possible value due to all fields comptime (same | ||
| 2964 | // as the tuple case below). | ||
| 2965 | .type_struct, .type_struct_ns => .{ .aggregate = .{ | ||
| 2966 | .ty = ty, | ||
| 2967 | .storage = .{ .elems = &.{} }, | ||
| 2968 | } }, | ||
| 2969 | |||
| 2970 | // There is only one possible value precisely due to the | ||
| 2971 | // fact that this values slice is fully populated! | ||
| 2972 | .type_struct_anon, .type_tuple_anon => { | ||
| 2973 | const type_struct_anon = ip.extraDataTrail(TypeStructAnon, ty_item.data); | ||
| 2974 | const fields_len = type_struct_anon.data.fields_len; | ||
| 2975 | const values = ip.extra.items[type_struct_anon.end + fields_len ..][0..fields_len]; | ||
| 2976 | return .{ .aggregate = .{ | ||
| 2977 | .ty = ty, | ||
| 2978 | .storage = .{ .elems = @ptrCast([]const Index, values) }, | ||
| 2979 | } }; | ||
| 2980 | }, | ||
| 2981 | |||
| 2982 | .type_enum_auto, | ||
| 2983 | .type_enum_explicit, | ||
| 2984 | .type_union_tagged, | ||
| 2985 | .type_union_untagged, | ||
| 2986 | .type_union_safety, | ||
| 2987 | => .{ .empty_enum_value = ty }, | ||
| 2988 | |||
| 2989 | else => unreachable, | ||
| 2990 | }; | ||
| 2991 | }, | ||
| 2992 | .bytes => { | ||
| 2993 | const extra = ip.extraData(Bytes, data); | ||
| 2994 | const len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(extra.ty)); | ||
| 2995 | return .{ .aggregate = .{ | ||
| 2996 | .ty = extra.ty, | ||
| 2997 | .storage = .{ .bytes = ip.string_bytes.items[@enumToInt(extra.bytes)..][0..len] }, | ||
| 2998 | } }; | ||
| 2999 | }, | ||
| 3000 | .aggregate => { | ||
| 3001 | const extra = ip.extraDataTrail(Tag.Aggregate, data); | ||
| 3002 | const len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(extra.data.ty)); | ||
| 3003 | const fields = @ptrCast([]const Index, ip.extra.items[extra.end..][0..len]); | ||
| 3004 | return .{ .aggregate = .{ | ||
| 3005 | .ty = extra.data.ty, | ||
| 3006 | .storage = .{ .elems = fields }, | ||
| 3007 | } }; | ||
| 3008 | }, | ||
| 3009 | .repeated => { | ||
| 3010 | const extra = ip.extraData(Repeated, data); | ||
| 3011 | return .{ .aggregate = .{ | ||
| 3012 | .ty = extra.ty, | ||
| 3013 | .storage = .{ .repeated_elem = extra.elem_val }, | ||
| 3014 | } }; | ||
| 3015 | }, | ||
| 3016 | .union_value => .{ .un = ip.extraData(Key.Union, data) }, | ||
| 3017 | .error_set_error => .{ .err = ip.extraData(Key.Error, data) }, | ||
| 3018 | .error_union_error => { | ||
| 3019 | const extra = ip.extraData(Key.Error, data); | ||
| 3020 | return .{ .error_union = .{ | ||
| 3021 | .ty = extra.ty, | ||
| 3022 | .val = .{ .err_name = extra.name }, | ||
| 3023 | } }; | ||
| 3024 | }, | ||
| 3025 | .error_union_payload => { | ||
| 3026 | const extra = ip.extraData(Tag.TypeValue, data); | ||
| 3027 | return .{ .error_union = .{ | ||
| 3028 | .ty = extra.ty, | ||
| 3029 | .val = .{ .payload = extra.val }, | ||
| 3030 | } }; | ||
| 3031 | }, | ||
| 3032 | .enum_literal => .{ .enum_literal = @intToEnum(NullTerminatedString, data) }, | ||
| 3033 | .enum_tag => .{ .enum_tag = ip.extraData(Tag.EnumTag, data) }, | ||
| 3034 | |||
| 3035 | .memoized_call => { | ||
| 3036 | const extra = ip.extraDataTrail(MemoizedCall, data); | ||
| 3037 | return .{ .memoized_call = .{ | ||
| 3038 | .func = extra.data.func, | ||
| 3039 | .arg_values = @ptrCast([]const Index, ip.extra.items[extra.end..][0..extra.data.args_len]), | ||
| 3040 | .result = extra.data.result, | ||
| 3041 | } }; | ||
| 3042 | }, | ||
| 3043 | }; | ||
| 3044 | } | ||
| 3045 | |||
| 3046 | fn indexToKeyFuncType(ip: *const InternPool, data: u32) Key.FuncType { | ||
| 3047 | const type_function = ip.extraDataTrail(TypeFunction, data); | ||
| 3048 | const param_types = @ptrCast( | ||
| 3049 | []Index, | ||
| 3050 | ip.extra.items[type_function.end..][0..type_function.data.params_len], | ||
| 3051 | ); | ||
| 3052 | return .{ | ||
| 3053 | .param_types = param_types, | ||
| 3054 | .return_type = type_function.data.return_type, | ||
| 3055 | .comptime_bits = type_function.data.comptime_bits, | ||
| 3056 | .noalias_bits = type_function.data.noalias_bits, | ||
| 3057 | .alignment = type_function.data.flags.alignment, | ||
| 3058 | .cc = type_function.data.flags.cc, | ||
| 3059 | .is_var_args = type_function.data.flags.is_var_args, | ||
| 3060 | .is_generic = type_function.data.flags.is_generic, | ||
| 3061 | .is_noinline = type_function.data.flags.is_noinline, | ||
| 3062 | .align_is_generic = type_function.data.flags.align_is_generic, | ||
| 3063 | .cc_is_generic = type_function.data.flags.cc_is_generic, | ||
| 3064 | .section_is_generic = type_function.data.flags.section_is_generic, | ||
| 3065 | .addrspace_is_generic = type_function.data.flags.addrspace_is_generic, | ||
| 3066 | }; | ||
| 3067 | } | ||
| 3068 | |||
| 3069 | fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMode) Key { | ||
| 3070 | const enum_explicit = ip.extraDataTrail(EnumExplicit, data); | ||
| 3071 | const names = @ptrCast( | ||
| 3072 | []const NullTerminatedString, | ||
| 3073 | ip.extra.items[enum_explicit.end..][0..enum_explicit.data.fields_len], | ||
| 3074 | ); | ||
| 3075 | const values = if (enum_explicit.data.values_map != .none) @ptrCast( | ||
| 3076 | []const Index, | ||
| 3077 | ip.extra.items[enum_explicit.end + names.len ..][0..enum_explicit.data.fields_len], | ||
| 3078 | ) else &[0]Index{}; | ||
| 3079 | |||
| 3080 | return .{ .enum_type = .{ | ||
| 3081 | .decl = enum_explicit.data.decl, | ||
| 3082 | .namespace = enum_explicit.data.namespace, | ||
| 3083 | .tag_ty = enum_explicit.data.int_tag_type, | ||
| 3084 | .names = names, | ||
| 3085 | .values = values, | ||
| 3086 | .tag_mode = tag_mode, | ||
| 3087 | .names_map = enum_explicit.data.names_map.toOptional(), | ||
| 3088 | .values_map = enum_explicit.data.values_map, | ||
| 3089 | } }; | ||
| 3090 | } | ||
| 3091 | |||
| 3092 | fn indexToKeyBigInt(ip: *const InternPool, limb_index: u32, positive: bool) Key { | ||
| 3093 | const int_info = ip.limbData(Int, limb_index); | ||
| 3094 | return .{ .int = .{ | ||
| 3095 | .ty = int_info.ty, | ||
| 3096 | .storage = .{ .big_int = .{ | ||
| 3097 | .limbs = ip.limbSlice(Int, limb_index, int_info.limbs_len), | ||
| 3098 | .positive = positive, | ||
| 3099 | } }, | ||
| 3100 | } }; | ||
| 3101 | } | ||
| 3102 | |||
| 3103 | pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ||
| 3104 | const adapter: KeyAdapter = .{ .intern_pool = ip }; | ||
| 3105 | const gop = try ip.map.getOrPutAdapted(gpa, key, adapter); | ||
| 3106 | if (gop.found_existing) return @intToEnum(Index, gop.index); | ||
| 3107 | try ip.items.ensureUnusedCapacity(gpa, 1); | ||
| 3108 | switch (key) { | ||
| 3109 | .int_type => |int_type| { | ||
| 3110 | const t: Tag = switch (int_type.signedness) { | ||
| 3111 | .signed => .type_int_signed, | ||
| 3112 | .unsigned => .type_int_unsigned, | ||
| 3113 | }; | ||
| 3114 | ip.items.appendAssumeCapacity(.{ | ||
| 3115 | .tag = t, | ||
| 3116 | .data = int_type.bits, | ||
| 3117 | }); | ||
| 3118 | }, | ||
| 3119 | .ptr_type => |ptr_type| { | ||
| 3120 | assert(ptr_type.child != .none); | ||
| 3121 | assert(ptr_type.sentinel == .none or ip.typeOf(ptr_type.sentinel) == ptr_type.child); | ||
| 3122 | |||
| 3123 | if (ptr_type.flags.size == .Slice) { | ||
| 3124 | _ = ip.map.pop(); | ||
| 3125 | var new_key = key; | ||
| 3126 | new_key.ptr_type.flags.size = .Many; | ||
| 3127 | const ptr_type_index = try ip.get(gpa, new_key); | ||
| 3128 | assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing); | ||
| 3129 | try ip.items.ensureUnusedCapacity(gpa, 1); | ||
| 3130 | ip.items.appendAssumeCapacity(.{ | ||
| 3131 | .tag = .type_slice, | ||
| 3132 | .data = @enumToInt(ptr_type_index), | ||
| 3133 | }); | ||
| 3134 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3135 | } | ||
| 3136 | |||
| 3137 | var ptr_type_adjusted = ptr_type; | ||
| 3138 | if (ptr_type.flags.size == .C) ptr_type_adjusted.flags.is_allowzero = true; | ||
| 3139 | |||
| 3140 | ip.items.appendAssumeCapacity(.{ | ||
| 3141 | .tag = .type_pointer, | ||
| 3142 | .data = try ip.addExtra(gpa, ptr_type_adjusted), | ||
| 3143 | }); | ||
| 3144 | }, | ||
| 3145 | .array_type => |array_type| { | ||
| 3146 | assert(array_type.child != .none); | ||
| 3147 | assert(array_type.sentinel == .none or ip.typeOf(array_type.sentinel) == array_type.child); | ||
| 3148 | |||
| 3149 | if (std.math.cast(u32, array_type.len)) |len| { | ||
| 3150 | if (array_type.sentinel == .none) { | ||
| 3151 | ip.items.appendAssumeCapacity(.{ | ||
| 3152 | .tag = .type_array_small, | ||
| 3153 | .data = try ip.addExtra(gpa, Vector{ | ||
| 3154 | .len = len, | ||
| 3155 | .child = array_type.child, | ||
| 3156 | }), | ||
| 3157 | }); | ||
| 3158 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3159 | } | ||
| 3160 | } | ||
| 3161 | |||
| 3162 | const length = Array.Length.init(array_type.len); | ||
| 3163 | ip.items.appendAssumeCapacity(.{ | ||
| 3164 | .tag = .type_array_big, | ||
| 3165 | .data = try ip.addExtra(gpa, Array{ | ||
| 3166 | .len0 = length.a, | ||
| 3167 | .len1 = length.b, | ||
| 3168 | .child = array_type.child, | ||
| 3169 | .sentinel = array_type.sentinel, | ||
| 3170 | }), | ||
| 3171 | }); | ||
| 3172 | }, | ||
| 3173 | .vector_type => |vector_type| { | ||
| 3174 | ip.items.appendAssumeCapacity(.{ | ||
| 3175 | .tag = .type_vector, | ||
| 3176 | .data = try ip.addExtra(gpa, Vector{ | ||
| 3177 | .len = vector_type.len, | ||
| 3178 | .child = vector_type.child, | ||
| 3179 | }), | ||
| 3180 | }); | ||
| 3181 | }, | ||
| 3182 | .opt_type => |payload_type| { | ||
| 3183 | assert(payload_type != .none); | ||
| 3184 | ip.items.appendAssumeCapacity(.{ | ||
| 3185 | .tag = .type_optional, | ||
| 3186 | .data = @enumToInt(payload_type), | ||
| 3187 | }); | ||
| 3188 | }, | ||
| 3189 | .anyframe_type => |payload_type| { | ||
| 3190 | // payload_type might be none, indicating the type is `anyframe`. | ||
| 3191 | ip.items.appendAssumeCapacity(.{ | ||
| 3192 | .tag = .type_anyframe, | ||
| 3193 | .data = @enumToInt(payload_type), | ||
| 3194 | }); | ||
| 3195 | }, | ||
| 3196 | .error_union_type => |error_union_type| { | ||
| 3197 | ip.items.appendAssumeCapacity(.{ | ||
| 3198 | .tag = .type_error_union, | ||
| 3199 | .data = try ip.addExtra(gpa, error_union_type), | ||
| 3200 | }); | ||
| 3201 | }, | ||
| 3202 | .error_set_type => |error_set_type| { | ||
| 3203 | assert(error_set_type.names_map == .none); | ||
| 3204 | assert(std.sort.isSorted(NullTerminatedString, error_set_type.names, {}, NullTerminatedString.indexLessThan)); | ||
| 3205 | const names_map = try ip.addMap(gpa); | ||
| 3206 | try addStringsToMap(ip, gpa, names_map, error_set_type.names); | ||
| 3207 | const names_len = @intCast(u32, error_set_type.names.len); | ||
| 3208 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(ErrorSet).Struct.fields.len + names_len); | ||
| 3209 | ip.items.appendAssumeCapacity(.{ | ||
| 3210 | .tag = .type_error_set, | ||
| 3211 | .data = ip.addExtraAssumeCapacity(ErrorSet{ | ||
| 3212 | .names_len = names_len, | ||
| 3213 | .names_map = names_map, | ||
| 3214 | }), | ||
| 3215 | }); | ||
| 3216 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, error_set_type.names)); | ||
| 3217 | }, | ||
| 3218 | .inferred_error_set_type => |ies_index| { | ||
| 3219 | ip.items.appendAssumeCapacity(.{ | ||
| 3220 | .tag = .type_inferred_error_set, | ||
| 3221 | .data = @enumToInt(ies_index), | ||
| 3222 | }); | ||
| 3223 | }, | ||
| 3224 | .simple_type => |simple_type| { | ||
| 3225 | ip.items.appendAssumeCapacity(.{ | ||
| 3226 | .tag = .simple_type, | ||
| 3227 | .data = @enumToInt(simple_type), | ||
| 3228 | }); | ||
| 3229 | }, | ||
| 3230 | .simple_value => |simple_value| { | ||
| 3231 | ip.items.appendAssumeCapacity(.{ | ||
| 3232 | .tag = .simple_value, | ||
| 3233 | .data = @enumToInt(simple_value), | ||
| 3234 | }); | ||
| 3235 | }, | ||
| 3236 | .undef => |ty| { | ||
| 3237 | assert(ty != .none); | ||
| 3238 | ip.items.appendAssumeCapacity(.{ | ||
| 3239 | .tag = .undef, | ||
| 3240 | .data = @enumToInt(ty), | ||
| 3241 | }); | ||
| 3242 | }, | ||
| 3243 | .runtime_value => |runtime_value| { | ||
| 3244 | assert(runtime_value.ty == ip.typeOf(runtime_value.val)); | ||
| 3245 | ip.items.appendAssumeCapacity(.{ | ||
| 3246 | .tag = .runtime_value, | ||
| 3247 | .data = try ip.addExtra(gpa, runtime_value), | ||
| 3248 | }); | ||
| 3249 | }, | ||
| 3250 | |||
| 3251 | .struct_type => |struct_type| { | ||
| 3252 | ip.items.appendAssumeCapacity(if (struct_type.index.unwrap()) |i| .{ | ||
| 3253 | .tag = .type_struct, | ||
| 3254 | .data = @enumToInt(i), | ||
| 3255 | } else if (struct_type.namespace.unwrap()) |i| .{ | ||
| 3256 | .tag = .type_struct_ns, | ||
| 3257 | .data = @enumToInt(i), | ||
| 3258 | } else .{ | ||
| 3259 | .tag = .type_struct, | ||
| 3260 | .data = @enumToInt(Module.Struct.OptionalIndex.none), | ||
| 3261 | }); | ||
| 3262 | }, | ||
| 3263 | |||
| 3264 | .anon_struct_type => |anon_struct_type| { | ||
| 3265 | assert(anon_struct_type.types.len == anon_struct_type.values.len); | ||
| 3266 | for (anon_struct_type.types) |elem| assert(elem != .none); | ||
| 3267 | |||
| 3268 | const fields_len = @intCast(u32, anon_struct_type.types.len); | ||
| 3269 | if (anon_struct_type.names.len == 0) { | ||
| 3270 | try ip.extra.ensureUnusedCapacity( | ||
| 3271 | gpa, | ||
| 3272 | @typeInfo(TypeStructAnon).Struct.fields.len + (fields_len * 2), | ||
| 3273 | ); | ||
| 3274 | ip.items.appendAssumeCapacity(.{ | ||
| 3275 | .tag = .type_tuple_anon, | ||
| 3276 | .data = ip.addExtraAssumeCapacity(TypeStructAnon{ | ||
| 3277 | .fields_len = fields_len, | ||
| 3278 | }), | ||
| 3279 | }); | ||
| 3280 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, anon_struct_type.types)); | ||
| 3281 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, anon_struct_type.values)); | ||
| 3282 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3283 | } | ||
| 3284 | |||
| 3285 | assert(anon_struct_type.names.len == anon_struct_type.types.len); | ||
| 3286 | |||
| 3287 | try ip.extra.ensureUnusedCapacity( | ||
| 3288 | gpa, | ||
| 3289 | @typeInfo(TypeStructAnon).Struct.fields.len + (fields_len * 3), | ||
| 3290 | ); | ||
| 3291 | ip.items.appendAssumeCapacity(.{ | ||
| 3292 | .tag = .type_struct_anon, | ||
| 3293 | .data = ip.addExtraAssumeCapacity(TypeStructAnon{ | ||
| 3294 | .fields_len = fields_len, | ||
| 3295 | }), | ||
| 3296 | }); | ||
| 3297 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, anon_struct_type.types)); | ||
| 3298 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, anon_struct_type.values)); | ||
| 3299 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, anon_struct_type.names)); | ||
| 3300 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3301 | }, | ||
| 3302 | |||
| 3303 | .union_type => |union_type| { | ||
| 3304 | ip.items.appendAssumeCapacity(.{ | ||
| 3305 | .tag = switch (union_type.runtime_tag) { | ||
| 3306 | .none => .type_union_untagged, | ||
| 3307 | .safety => .type_union_safety, | ||
| 3308 | .tagged => .type_union_tagged, | ||
| 3309 | }, | ||
| 3310 | .data = @enumToInt(union_type.index), | ||
| 3311 | }); | ||
| 3312 | }, | ||
| 3313 | |||
| 3314 | .opaque_type => |opaque_type| { | ||
| 3315 | ip.items.appendAssumeCapacity(.{ | ||
| 3316 | .tag = .type_opaque, | ||
| 3317 | .data = try ip.addExtra(gpa, opaque_type), | ||
| 3318 | }); | ||
| 3319 | }, | ||
| 3320 | |||
| 3321 | .enum_type => |enum_type| { | ||
| 3322 | assert(enum_type.tag_ty == .noreturn_type or ip.isIntegerType(enum_type.tag_ty)); | ||
| 3323 | for (enum_type.values) |value| assert(ip.typeOf(value) == enum_type.tag_ty); | ||
| 3324 | assert(enum_type.names_map == .none); | ||
| 3325 | assert(enum_type.values_map == .none); | ||
| 3326 | |||
| 3327 | switch (enum_type.tag_mode) { | ||
| 3328 | .auto => { | ||
| 3329 | const names_map = try ip.addMap(gpa); | ||
| 3330 | try addStringsToMap(ip, gpa, names_map, enum_type.names); | ||
| 3331 | |||
| 3332 | const fields_len = @intCast(u32, enum_type.names.len); | ||
| 3333 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumAuto).Struct.fields.len + | ||
| 3334 | fields_len); | ||
| 3335 | ip.items.appendAssumeCapacity(.{ | ||
| 3336 | .tag = .type_enum_auto, | ||
| 3337 | .data = ip.addExtraAssumeCapacity(EnumAuto{ | ||
| 3338 | .decl = enum_type.decl, | ||
| 3339 | .namespace = enum_type.namespace, | ||
| 3340 | .int_tag_type = enum_type.tag_ty, | ||
| 3341 | .names_map = names_map, | ||
| 3342 | .fields_len = fields_len, | ||
| 3343 | }), | ||
| 3344 | }); | ||
| 3345 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.names)); | ||
| 3346 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3347 | }, | ||
| 3348 | .explicit => return finishGetEnum(ip, gpa, enum_type, .type_enum_explicit), | ||
| 3349 | .nonexhaustive => return finishGetEnum(ip, gpa, enum_type, .type_enum_nonexhaustive), | ||
| 3350 | } | ||
| 3351 | }, | ||
| 3352 | |||
| 3353 | .func_type => |func_type| { | ||
| 3354 | assert(func_type.return_type != .none); | ||
| 3355 | for (func_type.param_types) |param_type| assert(param_type != .none); | ||
| 3356 | |||
| 3357 | const params_len = @intCast(u32, func_type.param_types.len); | ||
| 3358 | |||
| 3359 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(TypeFunction).Struct.fields.len + | ||
| 3360 | params_len); | ||
| 3361 | ip.items.appendAssumeCapacity(.{ | ||
| 3362 | .tag = .type_function, | ||
| 3363 | .data = ip.addExtraAssumeCapacity(TypeFunction{ | ||
| 3364 | .params_len = params_len, | ||
| 3365 | .return_type = func_type.return_type, | ||
| 3366 | .comptime_bits = func_type.comptime_bits, | ||
| 3367 | .noalias_bits = func_type.noalias_bits, | ||
| 3368 | .flags = .{ | ||
| 3369 | .alignment = func_type.alignment, | ||
| 3370 | .cc = func_type.cc, | ||
| 3371 | .is_var_args = func_type.is_var_args, | ||
| 3372 | .is_generic = func_type.is_generic, | ||
| 3373 | .is_noinline = func_type.is_noinline, | ||
| 3374 | .align_is_generic = func_type.align_is_generic, | ||
| 3375 | .cc_is_generic = func_type.cc_is_generic, | ||
| 3376 | .section_is_generic = func_type.section_is_generic, | ||
| 3377 | .addrspace_is_generic = func_type.addrspace_is_generic, | ||
| 3378 | }, | ||
| 3379 | }), | ||
| 3380 | }); | ||
| 3381 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, func_type.param_types)); | ||
| 3382 | }, | ||
| 3383 | |||
| 3384 | .variable => |variable| { | ||
| 3385 | const has_init = variable.init != .none; | ||
| 3386 | if (has_init) assert(variable.ty == ip.typeOf(variable.init)); | ||
| 3387 | ip.items.appendAssumeCapacity(.{ | ||
| 3388 | .tag = .variable, | ||
| 3389 | .data = try ip.addExtra(gpa, Tag.Variable{ | ||
| 3390 | .ty = variable.ty, | ||
| 3391 | .init = variable.init, | ||
| 3392 | .decl = variable.decl, | ||
| 3393 | .lib_name = variable.lib_name, | ||
| 3394 | .flags = .{ | ||
| 3395 | .is_extern = variable.is_extern, | ||
| 3396 | .is_const = variable.is_const, | ||
| 3397 | .is_threadlocal = variable.is_threadlocal, | ||
| 3398 | .is_weak_linkage = variable.is_weak_linkage, | ||
| 3399 | }, | ||
| 3400 | }), | ||
| 3401 | }); | ||
| 3402 | }, | ||
| 3403 | |||
| 3404 | .extern_func => |extern_func| ip.items.appendAssumeCapacity(.{ | ||
| 3405 | .tag = .extern_func, | ||
| 3406 | .data = try ip.addExtra(gpa, @as(Tag.ExternFunc, extern_func)), | ||
| 3407 | }), | ||
| 3408 | |||
| 3409 | .func => |func| ip.items.appendAssumeCapacity(.{ | ||
| 3410 | .tag = .func, | ||
| 3411 | .data = try ip.addExtra(gpa, @as(Tag.Func, func)), | ||
| 3412 | }), | ||
| 3413 | |||
| 3414 | .ptr => |ptr| { | ||
| 3415 | const ptr_type = ip.indexToKey(ptr.ty).ptr_type; | ||
| 3416 | switch (ptr.len) { | ||
| 3417 | .none => { | ||
| 3418 | assert(ptr_type.flags.size != .Slice); | ||
| 3419 | switch (ptr.addr) { | ||
| 3420 | .decl => |decl| ip.items.appendAssumeCapacity(.{ | ||
| 3421 | .tag = .ptr_decl, | ||
| 3422 | .data = try ip.addExtra(gpa, PtrDecl{ | ||
| 3423 | .ty = ptr.ty, | ||
| 3424 | .decl = decl, | ||
| 3425 | }), | ||
| 3426 | }), | ||
| 3427 | .mut_decl => |mut_decl| ip.items.appendAssumeCapacity(.{ | ||
| 3428 | .tag = .ptr_mut_decl, | ||
| 3429 | .data = try ip.addExtra(gpa, PtrMutDecl{ | ||
| 3430 | .ty = ptr.ty, | ||
| 3431 | .decl = mut_decl.decl, | ||
| 3432 | .runtime_index = mut_decl.runtime_index, | ||
| 3433 | }), | ||
| 3434 | }), | ||
| 3435 | .comptime_field => |field_val| { | ||
| 3436 | assert(field_val != .none); | ||
| 3437 | ip.items.appendAssumeCapacity(.{ | ||
| 3438 | .tag = .ptr_comptime_field, | ||
| 3439 | .data = try ip.addExtra(gpa, PtrComptimeField{ | ||
| 3440 | .ty = ptr.ty, | ||
| 3441 | .field_val = field_val, | ||
| 3442 | }), | ||
| 3443 | }); | ||
| 3444 | }, | ||
| 3445 | .int, .eu_payload, .opt_payload => |base| { | ||
| 3446 | switch (ptr.addr) { | ||
| 3447 | .int => assert(ip.typeOf(base) == .usize_type), | ||
| 3448 | .eu_payload => assert(ip.indexToKey( | ||
| 3449 | ip.indexToKey(ip.typeOf(base)).ptr_type.child, | ||
| 3450 | ) == .error_union_type), | ||
| 3451 | .opt_payload => assert(ip.indexToKey( | ||
| 3452 | ip.indexToKey(ip.typeOf(base)).ptr_type.child, | ||
| 3453 | ) == .opt_type), | ||
| 3454 | else => unreachable, | ||
| 3455 | } | ||
| 3456 | ip.items.appendAssumeCapacity(.{ | ||
| 3457 | .tag = switch (ptr.addr) { | ||
| 3458 | .int => .ptr_int, | ||
| 3459 | .eu_payload => .ptr_eu_payload, | ||
| 3460 | .opt_payload => .ptr_opt_payload, | ||
| 3461 | else => unreachable, | ||
| 3462 | }, | ||
| 3463 | .data = try ip.addExtra(gpa, PtrBase{ | ||
| 3464 | .ty = ptr.ty, | ||
| 3465 | .base = base, | ||
| 3466 | }), | ||
| 3467 | }); | ||
| 3468 | }, | ||
| 3469 | .elem, .field => |base_index| { | ||
| 3470 | const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type; | ||
| 3471 | switch (ptr.addr) { | ||
| 3472 | .elem => assert(base_ptr_type.flags.size == .Many), | ||
| 3473 | .field => { | ||
| 3474 | assert(base_ptr_type.flags.size == .One); | ||
| 3475 | switch (ip.indexToKey(base_ptr_type.child)) { | ||
| 3476 | .anon_struct_type => |anon_struct_type| { | ||
| 3477 | assert(ptr.addr == .field); | ||
| 3478 | assert(base_index.index < anon_struct_type.types.len); | ||
| 3479 | }, | ||
| 3480 | .struct_type => |struct_type| { | ||
| 3481 | assert(ptr.addr == .field); | ||
| 3482 | assert(base_index.index < ip.structPtrUnwrapConst(struct_type.index).?.fields.count()); | ||
| 3483 | }, | ||
| 3484 | .union_type => |union_type| { | ||
| 3485 | assert(ptr.addr == .field); | ||
| 3486 | assert(base_index.index < ip.unionPtrConst(union_type.index).fields.count()); | ||
| 3487 | }, | ||
| 3488 | .ptr_type => |slice_type| { | ||
| 3489 | assert(ptr.addr == .field); | ||
| 3490 | assert(slice_type.flags.size == .Slice); | ||
| 3491 | assert(base_index.index < 2); | ||
| 3492 | }, | ||
| 3493 | else => unreachable, | ||
| 3494 | } | ||
| 3495 | }, | ||
| 3496 | else => unreachable, | ||
| 3497 | } | ||
| 3498 | _ = ip.map.pop(); | ||
| 3499 | const index_index = try ip.get(gpa, .{ .int = .{ | ||
| 3500 | .ty = .usize_type, | ||
| 3501 | .storage = .{ .u64 = base_index.index }, | ||
| 3502 | } }); | ||
| 3503 | assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing); | ||
| 3504 | try ip.items.ensureUnusedCapacity(gpa, 1); | ||
| 3505 | ip.items.appendAssumeCapacity(.{ | ||
| 3506 | .tag = switch (ptr.addr) { | ||
| 3507 | .elem => .ptr_elem, | ||
| 3508 | .field => .ptr_field, | ||
| 3509 | else => unreachable, | ||
| 3510 | }, | ||
| 3511 | .data = try ip.addExtra(gpa, PtrBaseIndex{ | ||
| 3512 | .ty = ptr.ty, | ||
| 3513 | .base = base_index.base, | ||
| 3514 | .index = index_index, | ||
| 3515 | }), | ||
| 3516 | }); | ||
| 3517 | }, | ||
| 3518 | } | ||
| 3519 | }, | ||
| 3520 | else => { | ||
| 3521 | // TODO: change Key.Ptr for slices to reference the manyptr value | ||
| 3522 | // rather than having an addr field directly. Then we can avoid | ||
| 3523 | // these problematic calls to pop(), get(), and getOrPutAdapted(). | ||
| 3524 | assert(ptr_type.flags.size == .Slice); | ||
| 3525 | _ = ip.map.pop(); | ||
| 3526 | var new_key = key; | ||
| 3527 | new_key.ptr.ty = ip.slicePtrType(ptr.ty); | ||
| 3528 | new_key.ptr.len = .none; | ||
| 3529 | assert(ip.indexToKey(new_key.ptr.ty).ptr_type.flags.size == .Many); | ||
| 3530 | const ptr_index = try ip.get(gpa, new_key); | ||
| 3531 | assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing); | ||
| 3532 | try ip.items.ensureUnusedCapacity(gpa, 1); | ||
| 3533 | ip.items.appendAssumeCapacity(.{ | ||
| 3534 | .tag = .ptr_slice, | ||
| 3535 | .data = try ip.addExtra(gpa, PtrSlice{ | ||
| 3536 | .ty = ptr.ty, | ||
| 3537 | .ptr = ptr_index, | ||
| 3538 | .len = ptr.len, | ||
| 3539 | }), | ||
| 3540 | }); | ||
| 3541 | }, | ||
| 3542 | } | ||
| 3543 | assert(ptr.ty == ip.indexToKey(@intToEnum(Index, ip.items.len - 1)).ptr.ty); | ||
| 3544 | }, | ||
| 3545 | |||
| 3546 | .opt => |opt| { | ||
| 3547 | assert(ip.isOptionalType(opt.ty)); | ||
| 3548 | assert(opt.val == .none or ip.indexToKey(opt.ty).opt_type == ip.typeOf(opt.val)); | ||
| 3549 | ip.items.appendAssumeCapacity(if (opt.val == .none) .{ | ||
| 3550 | .tag = .opt_null, | ||
| 3551 | .data = @enumToInt(opt.ty), | ||
| 3552 | } else .{ | ||
| 3553 | .tag = .opt_payload, | ||
| 3554 | .data = try ip.addExtra(gpa, Tag.TypeValue{ | ||
| 3555 | .ty = opt.ty, | ||
| 3556 | .val = opt.val, | ||
| 3557 | }), | ||
| 3558 | }); | ||
| 3559 | }, | ||
| 3560 | |||
| 3561 | .int => |int| b: { | ||
| 3562 | assert(ip.isIntegerType(int.ty)); | ||
| 3563 | switch (int.storage) { | ||
| 3564 | .u64, .i64, .big_int => {}, | ||
| 3565 | .lazy_align, .lazy_size => |lazy_ty| { | ||
| 3566 | ip.items.appendAssumeCapacity(.{ | ||
| 3567 | .tag = switch (int.storage) { | ||
| 3568 | else => unreachable, | ||
| 3569 | .lazy_align => .int_lazy_align, | ||
| 3570 | .lazy_size => .int_lazy_size, | ||
| 3571 | }, | ||
| 3572 | .data = try ip.addExtra(gpa, IntLazy{ | ||
| 3573 | .ty = int.ty, | ||
| 3574 | .lazy_ty = lazy_ty, | ||
| 3575 | }), | ||
| 3576 | }); | ||
| 3577 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3578 | }, | ||
| 3579 | } | ||
| 3580 | switch (int.ty) { | ||
| 3581 | .u8_type => switch (int.storage) { | ||
| 3582 | .big_int => |big_int| { | ||
| 3583 | ip.items.appendAssumeCapacity(.{ | ||
| 3584 | .tag = .int_u8, | ||
| 3585 | .data = big_int.to(u8) catch unreachable, | ||
| 3586 | }); | ||
| 3587 | break :b; | ||
| 3588 | }, | ||
| 3589 | inline .u64, .i64 => |x| { | ||
| 3590 | ip.items.appendAssumeCapacity(.{ | ||
| 3591 | .tag = .int_u8, | ||
| 3592 | .data = @intCast(u8, x), | ||
| 3593 | }); | ||
| 3594 | break :b; | ||
| 3595 | }, | ||
| 3596 | .lazy_align, .lazy_size => unreachable, | ||
| 3597 | }, | ||
| 3598 | .u16_type => switch (int.storage) { | ||
| 3599 | .big_int => |big_int| { | ||
| 3600 | ip.items.appendAssumeCapacity(.{ | ||
| 3601 | .tag = .int_u16, | ||
| 3602 | .data = big_int.to(u16) catch unreachable, | ||
| 3603 | }); | ||
| 3604 | break :b; | ||
| 3605 | }, | ||
| 3606 | inline .u64, .i64 => |x| { | ||
| 3607 | ip.items.appendAssumeCapacity(.{ | ||
| 3608 | .tag = .int_u16, | ||
| 3609 | .data = @intCast(u16, x), | ||
| 3610 | }); | ||
| 3611 | break :b; | ||
| 3612 | }, | ||
| 3613 | .lazy_align, .lazy_size => unreachable, | ||
| 3614 | }, | ||
| 3615 | .u32_type => switch (int.storage) { | ||
| 3616 | .big_int => |big_int| { | ||
| 3617 | ip.items.appendAssumeCapacity(.{ | ||
| 3618 | .tag = .int_u32, | ||
| 3619 | .data = big_int.to(u32) catch unreachable, | ||
| 3620 | }); | ||
| 3621 | break :b; | ||
| 3622 | }, | ||
| 3623 | inline .u64, .i64 => |x| { | ||
| 3624 | ip.items.appendAssumeCapacity(.{ | ||
| 3625 | .tag = .int_u32, | ||
| 3626 | .data = @intCast(u32, x), | ||
| 3627 | }); | ||
| 3628 | break :b; | ||
| 3629 | }, | ||
| 3630 | .lazy_align, .lazy_size => unreachable, | ||
| 3631 | }, | ||
| 3632 | .i32_type => switch (int.storage) { | ||
| 3633 | .big_int => |big_int| { | ||
| 3634 | const casted = big_int.to(i32) catch unreachable; | ||
| 3635 | ip.items.appendAssumeCapacity(.{ | ||
| 3636 | .tag = .int_i32, | ||
| 3637 | .data = @bitCast(u32, casted), | ||
| 3638 | }); | ||
| 3639 | break :b; | ||
| 3640 | }, | ||
| 3641 | inline .u64, .i64 => |x| { | ||
| 3642 | ip.items.appendAssumeCapacity(.{ | ||
| 3643 | .tag = .int_i32, | ||
| 3644 | .data = @bitCast(u32, @intCast(i32, x)), | ||
| 3645 | }); | ||
| 3646 | break :b; | ||
| 3647 | }, | ||
| 3648 | .lazy_align, .lazy_size => unreachable, | ||
| 3649 | }, | ||
| 3650 | .usize_type => switch (int.storage) { | ||
| 3651 | .big_int => |big_int| { | ||
| 3652 | if (big_int.to(u32)) |casted| { | ||
| 3653 | ip.items.appendAssumeCapacity(.{ | ||
| 3654 | .tag = .int_usize, | ||
| 3655 | .data = casted, | ||
| 3656 | }); | ||
| 3657 | break :b; | ||
| 3658 | } else |_| {} | ||
| 3659 | }, | ||
| 3660 | inline .u64, .i64 => |x| { | ||
| 3661 | if (std.math.cast(u32, x)) |casted| { | ||
| 3662 | ip.items.appendAssumeCapacity(.{ | ||
| 3663 | .tag = .int_usize, | ||
| 3664 | .data = casted, | ||
| 3665 | }); | ||
| 3666 | break :b; | ||
| 3667 | } | ||
| 3668 | }, | ||
| 3669 | .lazy_align, .lazy_size => unreachable, | ||
| 3670 | }, | ||
| 3671 | .comptime_int_type => switch (int.storage) { | ||
| 3672 | .big_int => |big_int| { | ||
| 3673 | if (big_int.to(u32)) |casted| { | ||
| 3674 | ip.items.appendAssumeCapacity(.{ | ||
| 3675 | .tag = .int_comptime_int_u32, | ||
| 3676 | .data = casted, | ||
| 3677 | }); | ||
| 3678 | break :b; | ||
| 3679 | } else |_| {} | ||
| 3680 | if (big_int.to(i32)) |casted| { | ||
| 3681 | ip.items.appendAssumeCapacity(.{ | ||
| 3682 | .tag = .int_comptime_int_i32, | ||
| 3683 | .data = @bitCast(u32, casted), | ||
| 3684 | }); | ||
| 3685 | break :b; | ||
| 3686 | } else |_| {} | ||
| 3687 | }, | ||
| 3688 | inline .u64, .i64 => |x| { | ||
| 3689 | if (std.math.cast(u32, x)) |casted| { | ||
| 3690 | ip.items.appendAssumeCapacity(.{ | ||
| 3691 | .tag = .int_comptime_int_u32, | ||
| 3692 | .data = casted, | ||
| 3693 | }); | ||
| 3694 | break :b; | ||
| 3695 | } | ||
| 3696 | if (std.math.cast(i32, x)) |casted| { | ||
| 3697 | ip.items.appendAssumeCapacity(.{ | ||
| 3698 | .tag = .int_comptime_int_i32, | ||
| 3699 | .data = @bitCast(u32, casted), | ||
| 3700 | }); | ||
| 3701 | break :b; | ||
| 3702 | } | ||
| 3703 | }, | ||
| 3704 | .lazy_align, .lazy_size => unreachable, | ||
| 3705 | }, | ||
| 3706 | else => {}, | ||
| 3707 | } | ||
| 3708 | switch (int.storage) { | ||
| 3709 | .big_int => |big_int| { | ||
| 3710 | if (big_int.to(u32)) |casted| { | ||
| 3711 | ip.items.appendAssumeCapacity(.{ | ||
| 3712 | .tag = .int_small, | ||
| 3713 | .data = try ip.addExtra(gpa, IntSmall{ | ||
| 3714 | .ty = int.ty, | ||
| 3715 | .value = casted, | ||
| 3716 | }), | ||
| 3717 | }); | ||
| 3718 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3719 | } else |_| {} | ||
| 3720 | |||
| 3721 | const tag: Tag = if (big_int.positive) .int_positive else .int_negative; | ||
| 3722 | try addInt(ip, gpa, int.ty, tag, big_int.limbs); | ||
| 3723 | }, | ||
| 3724 | inline .u64, .i64 => |x| { | ||
| 3725 | if (std.math.cast(u32, x)) |casted| { | ||
| 3726 | ip.items.appendAssumeCapacity(.{ | ||
| 3727 | .tag = .int_small, | ||
| 3728 | .data = try ip.addExtra(gpa, IntSmall{ | ||
| 3729 | .ty = int.ty, | ||
| 3730 | .value = casted, | ||
| 3731 | }), | ||
| 3732 | }); | ||
| 3733 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3734 | } | ||
| 3735 | |||
| 3736 | var buf: [2]Limb = undefined; | ||
| 3737 | const big_int = BigIntMutable.init(&buf, x).toConst(); | ||
| 3738 | const tag: Tag = if (big_int.positive) .int_positive else .int_negative; | ||
| 3739 | try addInt(ip, gpa, int.ty, tag, big_int.limbs); | ||
| 3740 | }, | ||
| 3741 | .lazy_align, .lazy_size => unreachable, | ||
| 3742 | } | ||
| 3743 | }, | ||
| 3744 | |||
| 3745 | .err => |err| { | ||
| 3746 | assert(ip.isErrorSetType(err.ty)); | ||
| 3747 | ip.items.appendAssumeCapacity(.{ | ||
| 3748 | .tag = .error_set_error, | ||
| 3749 | .data = try ip.addExtra(gpa, err), | ||
| 3750 | }); | ||
| 3751 | }, | ||
| 3752 | |||
| 3753 | .error_union => |error_union| { | ||
| 3754 | assert(ip.isErrorUnionType(error_union.ty)); | ||
| 3755 | ip.items.appendAssumeCapacity(switch (error_union.val) { | ||
| 3756 | .err_name => |err_name| .{ | ||
| 3757 | .tag = .error_union_error, | ||
| 3758 | .data = try ip.addExtra(gpa, Key.Error{ | ||
| 3759 | .ty = error_union.ty, | ||
| 3760 | .name = err_name, | ||
| 3761 | }), | ||
| 3762 | }, | ||
| 3763 | .payload => |payload| .{ | ||
| 3764 | .tag = .error_union_payload, | ||
| 3765 | .data = try ip.addExtra(gpa, Tag.TypeValue{ | ||
| 3766 | .ty = error_union.ty, | ||
| 3767 | .val = payload, | ||
| 3768 | }), | ||
| 3769 | }, | ||
| 3770 | }); | ||
| 3771 | }, | ||
| 3772 | |||
| 3773 | .enum_literal => |enum_literal| ip.items.appendAssumeCapacity(.{ | ||
| 3774 | .tag = .enum_literal, | ||
| 3775 | .data = @enumToInt(enum_literal), | ||
| 3776 | }), | ||
| 3777 | |||
| 3778 | .enum_tag => |enum_tag| { | ||
| 3779 | assert(ip.isEnumType(enum_tag.ty)); | ||
| 3780 | switch (ip.indexToKey(enum_tag.ty)) { | ||
| 3781 | .simple_type => assert(ip.isIntegerType(ip.typeOf(enum_tag.int))), | ||
| 3782 | .enum_type => |enum_type| assert(ip.typeOf(enum_tag.int) == enum_type.tag_ty), | ||
| 3783 | else => unreachable, | ||
| 3784 | } | ||
| 3785 | ip.items.appendAssumeCapacity(.{ | ||
| 3786 | .tag = .enum_tag, | ||
| 3787 | .data = try ip.addExtra(gpa, enum_tag), | ||
| 3788 | }); | ||
| 3789 | }, | ||
| 3790 | |||
| 3791 | .empty_enum_value => |enum_or_union_ty| ip.items.appendAssumeCapacity(.{ | ||
| 3792 | .tag = .only_possible_value, | ||
| 3793 | .data = @enumToInt(enum_or_union_ty), | ||
| 3794 | }), | ||
| 3795 | |||
| 3796 | .float => |float| { | ||
| 3797 | switch (float.ty) { | ||
| 3798 | .f16_type => ip.items.appendAssumeCapacity(.{ | ||
| 3799 | .tag = .float_f16, | ||
| 3800 | .data = @bitCast(u16, float.storage.f16), | ||
| 3801 | }), | ||
| 3802 | .f32_type => ip.items.appendAssumeCapacity(.{ | ||
| 3803 | .tag = .float_f32, | ||
| 3804 | .data = @bitCast(u32, float.storage.f32), | ||
| 3805 | }), | ||
| 3806 | .f64_type => ip.items.appendAssumeCapacity(.{ | ||
| 3807 | .tag = .float_f64, | ||
| 3808 | .data = try ip.addExtra(gpa, Float64.pack(float.storage.f64)), | ||
| 3809 | }), | ||
| 3810 | .f80_type => ip.items.appendAssumeCapacity(.{ | ||
| 3811 | .tag = .float_f80, | ||
| 3812 | .data = try ip.addExtra(gpa, Float80.pack(float.storage.f80)), | ||
| 3813 | }), | ||
| 3814 | .f128_type => ip.items.appendAssumeCapacity(.{ | ||
| 3815 | .tag = .float_f128, | ||
| 3816 | .data = try ip.addExtra(gpa, Float128.pack(float.storage.f128)), | ||
| 3817 | }), | ||
| 3818 | .c_longdouble_type => switch (float.storage) { | ||
| 3819 | .f80 => |x| ip.items.appendAssumeCapacity(.{ | ||
| 3820 | .tag = .float_c_longdouble_f80, | ||
| 3821 | .data = try ip.addExtra(gpa, Float80.pack(x)), | ||
| 3822 | }), | ||
| 3823 | inline .f16, .f32, .f64, .f128 => |x| ip.items.appendAssumeCapacity(.{ | ||
| 3824 | .tag = .float_c_longdouble_f128, | ||
| 3825 | .data = try ip.addExtra(gpa, Float128.pack(x)), | ||
| 3826 | }), | ||
| 3827 | }, | ||
| 3828 | .comptime_float_type => ip.items.appendAssumeCapacity(.{ | ||
| 3829 | .tag = .float_comptime_float, | ||
| 3830 | .data = try ip.addExtra(gpa, Float128.pack(float.storage.f128)), | ||
| 3831 | }), | ||
| 3832 | else => unreachable, | ||
| 3833 | } | ||
| 3834 | }, | ||
| 3835 | |||
| 3836 | .aggregate => |aggregate| { | ||
| 3837 | const ty_key = ip.indexToKey(aggregate.ty); | ||
| 3838 | const len = ip.aggregateTypeLen(aggregate.ty); | ||
| 3839 | const child = switch (ty_key) { | ||
| 3840 | .array_type => |array_type| array_type.child, | ||
| 3841 | .vector_type => |vector_type| vector_type.child, | ||
| 3842 | .anon_struct_type, .struct_type => .none, | ||
| 3843 | else => unreachable, | ||
| 3844 | }; | ||
| 3845 | const sentinel = switch (ty_key) { | ||
| 3846 | .array_type => |array_type| array_type.sentinel, | ||
| 3847 | .vector_type, .anon_struct_type, .struct_type => .none, | ||
| 3848 | else => unreachable, | ||
| 3849 | }; | ||
| 3850 | const len_including_sentinel = len + @boolToInt(sentinel != .none); | ||
| 3851 | switch (aggregate.storage) { | ||
| 3852 | .bytes => |bytes| { | ||
| 3853 | assert(child == .u8_type); | ||
| 3854 | if (bytes.len != len) { | ||
| 3855 | assert(bytes.len == len_including_sentinel); | ||
| 3856 | assert(bytes[@intCast(usize, len)] == ip.indexToKey(sentinel).int.storage.u64); | ||
| 3857 | } | ||
| 3858 | }, | ||
| 3859 | .elems => |elems| { | ||
| 3860 | if (elems.len != len) { | ||
| 3861 | assert(elems.len == len_including_sentinel); | ||
| 3862 | assert(elems[@intCast(usize, len)] == sentinel); | ||
| 3863 | } | ||
| 3864 | }, | ||
| 3865 | .repeated_elem => |elem| { | ||
| 3866 | assert(sentinel == .none or elem == sentinel); | ||
| 3867 | }, | ||
| 3868 | } | ||
| 3869 | switch (ty_key) { | ||
| 3870 | .array_type, .vector_type => { | ||
| 3871 | for (aggregate.storage.values()) |elem| { | ||
| 3872 | assert(ip.typeOf(elem) == child); | ||
| 3873 | } | ||
| 3874 | }, | ||
| 3875 | .struct_type => |struct_type| { | ||
| 3876 | for ( | ||
| 3877 | aggregate.storage.values(), | ||
| 3878 | ip.structPtrUnwrapConst(struct_type.index).?.fields.values(), | ||
| 3879 | ) |elem, field| { | ||
| 3880 | assert(ip.typeOf(elem) == field.ty.toIntern()); | ||
| 3881 | } | ||
| 3882 | }, | ||
| 3883 | .anon_struct_type => |anon_struct_type| { | ||
| 3884 | for (aggregate.storage.values(), anon_struct_type.types) |elem, ty| { | ||
| 3885 | assert(ip.typeOf(elem) == ty); | ||
| 3886 | } | ||
| 3887 | }, | ||
| 3888 | else => unreachable, | ||
| 3889 | } | ||
| 3890 | |||
| 3891 | if (len == 0) { | ||
| 3892 | ip.items.appendAssumeCapacity(.{ | ||
| 3893 | .tag = .only_possible_value, | ||
| 3894 | .data = @enumToInt(aggregate.ty), | ||
| 3895 | }); | ||
| 3896 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3897 | } | ||
| 3898 | |||
| 3899 | switch (ty_key) { | ||
| 3900 | .anon_struct_type => |anon_struct_type| opv: { | ||
| 3901 | switch (aggregate.storage) { | ||
| 3902 | .bytes => |bytes| for (anon_struct_type.values, bytes) |value, byte| { | ||
| 3903 | if (value != ip.getIfExists(.{ .int = .{ | ||
| 3904 | .ty = .u8_type, | ||
| 3905 | .storage = .{ .u64 = byte }, | ||
| 3906 | } })) break :opv; | ||
| 3907 | }, | ||
| 3908 | .elems => |elems| if (!std.mem.eql( | ||
| 3909 | Index, | ||
| 3910 | anon_struct_type.values, | ||
| 3911 | elems, | ||
| 3912 | )) break :opv, | ||
| 3913 | .repeated_elem => |elem| for (anon_struct_type.values) |value| { | ||
| 3914 | if (value != elem) break :opv; | ||
| 3915 | }, | ||
| 3916 | } | ||
| 3917 | // This encoding works thanks to the fact that, as we just verified, | ||
| 3918 | // the type itself contains a slice of values that can be provided | ||
| 3919 | // in the aggregate fields. | ||
| 3920 | ip.items.appendAssumeCapacity(.{ | ||
| 3921 | .tag = .only_possible_value, | ||
| 3922 | .data = @enumToInt(aggregate.ty), | ||
| 3923 | }); | ||
| 3924 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3925 | }, | ||
| 3926 | else => {}, | ||
| 3927 | } | ||
| 3928 | |||
| 3929 | repeated: { | ||
| 3930 | switch (aggregate.storage) { | ||
| 3931 | .bytes => |bytes| for (bytes[1..@intCast(usize, len)]) |byte| | ||
| 3932 | if (byte != bytes[0]) break :repeated, | ||
| 3933 | .elems => |elems| for (elems[1..@intCast(usize, len)]) |elem| | ||
| 3934 | if (elem != elems[0]) break :repeated, | ||
| 3935 | .repeated_elem => {}, | ||
| 3936 | } | ||
| 3937 | const elem = switch (aggregate.storage) { | ||
| 3938 | .bytes => |bytes| elem: { | ||
| 3939 | _ = ip.map.pop(); | ||
| 3940 | const elem = try ip.get(gpa, .{ .int = .{ | ||
| 3941 | .ty = .u8_type, | ||
| 3942 | .storage = .{ .u64 = bytes[0] }, | ||
| 3943 | } }); | ||
| 3944 | assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing); | ||
| 3945 | try ip.items.ensureUnusedCapacity(gpa, 1); | ||
| 3946 | break :elem elem; | ||
| 3947 | }, | ||
| 3948 | .elems => |elems| elems[0], | ||
| 3949 | .repeated_elem => |elem| elem, | ||
| 3950 | }; | ||
| 3951 | |||
| 3952 | try ip.extra.ensureUnusedCapacity( | ||
| 3953 | gpa, | ||
| 3954 | @typeInfo(Repeated).Struct.fields.len, | ||
| 3955 | ); | ||
| 3956 | ip.items.appendAssumeCapacity(.{ | ||
| 3957 | .tag = .repeated, | ||
| 3958 | .data = ip.addExtraAssumeCapacity(Repeated{ | ||
| 3959 | .ty = aggregate.ty, | ||
| 3960 | .elem_val = elem, | ||
| 3961 | }), | ||
| 3962 | }); | ||
| 3963 | return @intToEnum(Index, ip.items.len - 1); | ||
| 3964 | } | ||
| 3965 | |||
| 3966 | if (child == .u8_type) bytes: { | ||
| 3967 | const string_bytes_index = ip.string_bytes.items.len; | ||
| 3968 | try ip.string_bytes.ensureUnusedCapacity(gpa, @intCast(usize, len_including_sentinel + 1)); | ||
| 3969 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Bytes).Struct.fields.len); | ||
| 3970 | switch (aggregate.storage) { | ||
| 3971 | .bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes), | ||
| 3972 | .elems => |elems| for (elems) |elem| switch (ip.indexToKey(elem)) { | ||
| 3973 | .undef => { | ||
| 3974 | ip.string_bytes.shrinkRetainingCapacity(string_bytes_index); | ||
| 3975 | break :bytes; | ||
| 3976 | }, | ||
| 3977 | .int => |int| ip.string_bytes.appendAssumeCapacity( | ||
| 3978 | @intCast(u8, int.storage.u64), | ||
| 3979 | ), | ||
| 3980 | else => unreachable, | ||
| 3981 | }, | ||
| 3982 | .repeated_elem => |elem| switch (ip.indexToKey(elem)) { | ||
| 3983 | .undef => break :bytes, | ||
| 3984 | .int => |int| @memset( | ||
| 3985 | ip.string_bytes.addManyAsSliceAssumeCapacity(@intCast(usize, len)), | ||
| 3986 | @intCast(u8, int.storage.u64), | ||
| 3987 | ), | ||
| 3988 | else => unreachable, | ||
| 3989 | }, | ||
| 3990 | } | ||
| 3991 | const has_internal_null = | ||
| 3992 | std.mem.indexOfScalar(u8, ip.string_bytes.items[string_bytes_index..], 0) != null; | ||
| 3993 | if (sentinel != .none) ip.string_bytes.appendAssumeCapacity( | ||
| 3994 | @intCast(u8, ip.indexToKey(sentinel).int.storage.u64), | ||
| 3995 | ); | ||
| 3996 | const string = if (has_internal_null) | ||
| 3997 | @intToEnum(String, string_bytes_index) | ||
| 3998 | else | ||
| 3999 | (try ip.getOrPutTrailingString(gpa, @intCast(usize, len_including_sentinel))).toString(); | ||
| 4000 | ip.items.appendAssumeCapacity(.{ | ||
| 4001 | .tag = .bytes, | ||
| 4002 | .data = ip.addExtraAssumeCapacity(Bytes{ | ||
| 4003 | .ty = aggregate.ty, | ||
| 4004 | .bytes = string, | ||
| 4005 | }), | ||
| 4006 | }); | ||
| 4007 | return @intToEnum(Index, ip.items.len - 1); | ||
| 4008 | } | ||
| 4009 | |||
| 4010 | try ip.extra.ensureUnusedCapacity( | ||
| 4011 | gpa, | ||
| 4012 | @typeInfo(Tag.Aggregate).Struct.fields.len + @intCast(usize, len_including_sentinel), | ||
| 4013 | ); | ||
| 4014 | ip.items.appendAssumeCapacity(.{ | ||
| 4015 | .tag = .aggregate, | ||
| 4016 | .data = ip.addExtraAssumeCapacity(Tag.Aggregate{ | ||
| 4017 | .ty = aggregate.ty, | ||
| 4018 | }), | ||
| 4019 | }); | ||
| 4020 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, aggregate.storage.elems)); | ||
| 4021 | if (sentinel != .none) ip.extra.appendAssumeCapacity(@enumToInt(sentinel)); | ||
| 4022 | }, | ||
| 4023 | |||
| 4024 | .un => |un| { | ||
| 4025 | assert(un.ty != .none); | ||
| 4026 | assert(un.tag != .none); | ||
| 4027 | assert(un.val != .none); | ||
| 4028 | ip.items.appendAssumeCapacity(.{ | ||
| 4029 | .tag = .union_value, | ||
| 4030 | .data = try ip.addExtra(gpa, un), | ||
| 4031 | }); | ||
| 4032 | }, | ||
| 4033 | |||
| 4034 | .memoized_call => |memoized_call| { | ||
| 4035 | for (memoized_call.arg_values) |arg| assert(arg != .none); | ||
| 4036 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(MemoizedCall).Struct.fields.len + | ||
| 4037 | memoized_call.arg_values.len); | ||
| 4038 | ip.items.appendAssumeCapacity(.{ | ||
| 4039 | .tag = .memoized_call, | ||
| 4040 | .data = ip.addExtraAssumeCapacity(MemoizedCall{ | ||
| 4041 | .func = memoized_call.func, | ||
| 4042 | .args_len = @intCast(u32, memoized_call.arg_values.len), | ||
| 4043 | .result = memoized_call.result, | ||
| 4044 | }), | ||
| 4045 | }); | ||
| 4046 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, memoized_call.arg_values)); | ||
| 4047 | }, | ||
| 4048 | } | ||
| 4049 | return @intToEnum(Index, ip.items.len - 1); | ||
| 4050 | } | ||
| 4051 | |||
| 4052 | /// Provides API for completing an enum type after calling `getIncompleteEnum`. | ||
| 4053 | pub const IncompleteEnumType = struct { | ||
| 4054 | index: Index, | ||
| 4055 | tag_ty_index: u32, | ||
| 4056 | names_map: MapIndex, | ||
| 4057 | names_start: u32, | ||
| 4058 | values_map: OptionalMapIndex, | ||
| 4059 | values_start: u32, | ||
| 4060 | |||
| 4061 | pub fn setTagType(self: @This(), ip: *InternPool, tag_ty: Index) void { | ||
| 4062 | assert(tag_ty == .noreturn_type or ip.isIntegerType(tag_ty)); | ||
| 4063 | ip.extra.items[self.tag_ty_index] = @enumToInt(tag_ty); | ||
| 4064 | } | ||
| 4065 | |||
| 4066 | /// Returns the already-existing field with the same name, if any. | ||
| 4067 | pub fn addFieldName( | ||
| 4068 | self: @This(), | ||
| 4069 | ip: *InternPool, | ||
| 4070 | gpa: Allocator, | ||
| 4071 | name: NullTerminatedString, | ||
| 4072 | ) Allocator.Error!?u32 { | ||
| 4073 | const map = &ip.maps.items[@enumToInt(self.names_map)]; | ||
| 4074 | const field_index = map.count(); | ||
| 4075 | const strings = ip.extra.items[self.names_start..][0..field_index]; | ||
| 4076 | const adapter: NullTerminatedString.Adapter = .{ | ||
| 4077 | .strings = @ptrCast([]const NullTerminatedString, strings), | ||
| 4078 | }; | ||
| 4079 | const gop = try map.getOrPutAdapted(gpa, name, adapter); | ||
| 4080 | if (gop.found_existing) return @intCast(u32, gop.index); | ||
| 4081 | ip.extra.items[self.names_start + field_index] = @enumToInt(name); | ||
| 4082 | return null; | ||
| 4083 | } | ||
| 4084 | |||
| 4085 | /// Returns the already-existing field with the same value, if any. | ||
| 4086 | /// Make sure the type of the value has the integer tag type of the enum. | ||
| 4087 | pub fn addFieldValue( | ||
| 4088 | self: @This(), | ||
| 4089 | ip: *InternPool, | ||
| 4090 | gpa: Allocator, | ||
| 4091 | value: Index, | ||
| 4092 | ) Allocator.Error!?u32 { | ||
| 4093 | assert(ip.typeOf(value) == @intToEnum(Index, ip.extra.items[self.tag_ty_index])); | ||
| 4094 | const map = &ip.maps.items[@enumToInt(self.values_map.unwrap().?)]; | ||
| 4095 | const field_index = map.count(); | ||
| 4096 | const indexes = ip.extra.items[self.values_start..][0..field_index]; | ||
| 4097 | const adapter: Index.Adapter = .{ | ||
| 4098 | .indexes = @ptrCast([]const Index, indexes), | ||
| 4099 | }; | ||
| 4100 | const gop = try map.getOrPutAdapted(gpa, value, adapter); | ||
| 4101 | if (gop.found_existing) return @intCast(u32, gop.index); | ||
| 4102 | ip.extra.items[self.values_start + field_index] = @enumToInt(value); | ||
| 4103 | return null; | ||
| 4104 | } | ||
| 4105 | }; | ||
| 4106 | |||
| 4107 | /// This is used to create an enum type in the `InternPool`, with the ability | ||
| 4108 | /// to update the tag type, field names, and field values later. | ||
| 4109 | pub fn getIncompleteEnum( | ||
| 4110 | ip: *InternPool, | ||
| 4111 | gpa: Allocator, | ||
| 4112 | enum_type: Key.IncompleteEnumType, | ||
| 4113 | ) Allocator.Error!IncompleteEnumType { | ||
| 4114 | switch (enum_type.tag_mode) { | ||
| 4115 | .auto => return getIncompleteEnumAuto(ip, gpa, enum_type), | ||
| 4116 | .explicit => return getIncompleteEnumExplicit(ip, gpa, enum_type, .type_enum_explicit), | ||
| 4117 | .nonexhaustive => return getIncompleteEnumExplicit(ip, gpa, enum_type, .type_enum_nonexhaustive), | ||
| 4118 | } | ||
| 4119 | } | ||
| 4120 | |||
| 4121 | fn getIncompleteEnumAuto( | ||
| 4122 | ip: *InternPool, | ||
| 4123 | gpa: Allocator, | ||
| 4124 | enum_type: Key.IncompleteEnumType, | ||
| 4125 | ) Allocator.Error!IncompleteEnumType { | ||
| 4126 | const int_tag_type = if (enum_type.tag_ty != .none) | ||
| 4127 | enum_type.tag_ty | ||
| 4128 | else | ||
| 4129 | try ip.get(gpa, .{ .int_type = .{ | ||
| 4130 | .bits = if (enum_type.fields_len == 0) 0 else std.math.log2_int_ceil(u32, enum_type.fields_len), | ||
| 4131 | .signedness = .unsigned, | ||
| 4132 | } }); | ||
| 4133 | |||
| 4134 | // We must keep the map in sync with `items`. The hash and equality functions | ||
| 4135 | // for enum types only look at the decl field, which is present even in | ||
| 4136 | // an `IncompleteEnumType`. | ||
| 4137 | const adapter: KeyAdapter = .{ .intern_pool = ip }; | ||
| 4138 | const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter); | ||
| 4139 | assert(!gop.found_existing); | ||
| 4140 | |||
| 4141 | const names_map = try ip.addMap(gpa); | ||
| 4142 | |||
| 4143 | const extra_fields_len: u32 = @typeInfo(EnumAuto).Struct.fields.len; | ||
| 4144 | try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + enum_type.fields_len); | ||
| 4145 | try ip.items.ensureUnusedCapacity(gpa, 1); | ||
| 4146 | |||
| 4147 | const extra_index = ip.addExtraAssumeCapacity(EnumAuto{ | ||
| 4148 | .decl = enum_type.decl, | ||
| 4149 | .namespace = enum_type.namespace, | ||
| 4150 | .int_tag_type = int_tag_type, | ||
| 4151 | .names_map = names_map, | ||
| 4152 | .fields_len = enum_type.fields_len, | ||
| 4153 | }); | ||
| 4154 | |||
| 4155 | ip.items.appendAssumeCapacity(.{ | ||
| 4156 | .tag = .type_enum_auto, | ||
| 4157 | .data = extra_index, | ||
| 4158 | }); | ||
| 4159 | ip.extra.appendNTimesAssumeCapacity(@enumToInt(Index.none), enum_type.fields_len); | ||
| 4160 | return .{ | ||
| 4161 | .index = @intToEnum(Index, ip.items.len - 1), | ||
| 4162 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?, | ||
| 4163 | .names_map = names_map, | ||
| 4164 | .names_start = extra_index + extra_fields_len, | ||
| 4165 | .values_map = .none, | ||
| 4166 | .values_start = undefined, | ||
| 4167 | }; | ||
| 4168 | } | ||
| 4169 | |||
| 4170 | fn getIncompleteEnumExplicit( | ||
| 4171 | ip: *InternPool, | ||
| 4172 | gpa: Allocator, | ||
| 4173 | enum_type: Key.IncompleteEnumType, | ||
| 4174 | tag: Tag, | ||
| 4175 | ) Allocator.Error!IncompleteEnumType { | ||
| 4176 | // We must keep the map in sync with `items`. The hash and equality functions | ||
| 4177 | // for enum types only look at the decl field, which is present even in | ||
| 4178 | // an `IncompleteEnumType`. | ||
| 4179 | const adapter: KeyAdapter = .{ .intern_pool = ip }; | ||
| 4180 | const gop = try ip.map.getOrPutAdapted(gpa, enum_type.toKey(), adapter); | ||
| 4181 | assert(!gop.found_existing); | ||
| 4182 | |||
| 4183 | const names_map = try ip.addMap(gpa); | ||
| 4184 | const values_map: OptionalMapIndex = if (!enum_type.has_values) .none else m: { | ||
| 4185 | const values_map = try ip.addMap(gpa); | ||
| 4186 | break :m values_map.toOptional(); | ||
| 4187 | }; | ||
| 4188 | |||
| 4189 | const reserved_len = enum_type.fields_len + | ||
| 4190 | if (enum_type.has_values) enum_type.fields_len else 0; | ||
| 4191 | |||
| 4192 | const extra_fields_len: u32 = @typeInfo(EnumExplicit).Struct.fields.len; | ||
| 4193 | try ip.extra.ensureUnusedCapacity(gpa, extra_fields_len + reserved_len); | ||
| 4194 | try ip.items.ensureUnusedCapacity(gpa, 1); | ||
| 4195 | |||
| 4196 | const extra_index = ip.addExtraAssumeCapacity(EnumExplicit{ | ||
| 4197 | .decl = enum_type.decl, | ||
| 4198 | .namespace = enum_type.namespace, | ||
| 4199 | .int_tag_type = enum_type.tag_ty, | ||
| 4200 | .fields_len = enum_type.fields_len, | ||
| 4201 | .names_map = names_map, | ||
| 4202 | .values_map = values_map, | ||
| 4203 | }); | ||
| 4204 | |||
| 4205 | ip.items.appendAssumeCapacity(.{ | ||
| 4206 | .tag = tag, | ||
| 4207 | .data = extra_index, | ||
| 4208 | }); | ||
| 4209 | // This is both fields and values (if present). | ||
| 4210 | ip.extra.appendNTimesAssumeCapacity(@enumToInt(Index.none), reserved_len); | ||
| 4211 | return .{ | ||
| 4212 | .index = @intToEnum(Index, ip.items.len - 1), | ||
| 4213 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?, | ||
| 4214 | .names_map = names_map, | ||
| 4215 | .names_start = extra_index + extra_fields_len, | ||
| 4216 | .values_map = values_map, | ||
| 4217 | .values_start = extra_index + extra_fields_len + enum_type.fields_len, | ||
| 4218 | }; | ||
| 4219 | } | ||
| 4220 | |||
| 4221 | pub fn finishGetEnum( | ||
| 4222 | ip: *InternPool, | ||
| 4223 | gpa: Allocator, | ||
| 4224 | enum_type: Key.EnumType, | ||
| 4225 | tag: Tag, | ||
| 4226 | ) Allocator.Error!Index { | ||
| 4227 | const names_map = try ip.addMap(gpa); | ||
| 4228 | try addStringsToMap(ip, gpa, names_map, enum_type.names); | ||
| 4229 | |||
| 4230 | const values_map: OptionalMapIndex = if (enum_type.values.len == 0) .none else m: { | ||
| 4231 | const values_map = try ip.addMap(gpa); | ||
| 4232 | try addIndexesToMap(ip, gpa, values_map, enum_type.values); | ||
| 4233 | break :m values_map.toOptional(); | ||
| 4234 | }; | ||
| 4235 | const fields_len = @intCast(u32, enum_type.names.len); | ||
| 4236 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(EnumExplicit).Struct.fields.len + | ||
| 4237 | fields_len); | ||
| 4238 | ip.items.appendAssumeCapacity(.{ | ||
| 4239 | .tag = tag, | ||
| 4240 | .data = ip.addExtraAssumeCapacity(EnumExplicit{ | ||
| 4241 | .decl = enum_type.decl, | ||
| 4242 | .namespace = enum_type.namespace, | ||
| 4243 | .int_tag_type = enum_type.tag_ty, | ||
| 4244 | .fields_len = fields_len, | ||
| 4245 | .names_map = names_map, | ||
| 4246 | .values_map = values_map, | ||
| 4247 | }), | ||
| 4248 | }); | ||
| 4249 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.names)); | ||
| 4250 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, enum_type.values)); | ||
| 4251 | return @intToEnum(Index, ip.items.len - 1); | ||
| 4252 | } | ||
| 4253 | |||
| 4254 | pub fn getIfExists(ip: *const InternPool, key: Key) ?Index { | ||
| 4255 | const adapter: KeyAdapter = .{ .intern_pool = ip }; | ||
| 4256 | const index = ip.map.getIndexAdapted(key, adapter) orelse return null; | ||
| 4257 | return @intToEnum(Index, index); | ||
| 4258 | } | ||
| 4259 | |||
| 4260 | pub fn getAssumeExists(ip: *const InternPool, key: Key) Index { | ||
| 4261 | return ip.getIfExists(key).?; | ||
| 4262 | } | ||
| 4263 | |||
| 4264 | fn addStringsToMap( | ||
| 4265 | ip: *InternPool, | ||
| 4266 | gpa: Allocator, | ||
| 4267 | map_index: MapIndex, | ||
| 4268 | strings: []const NullTerminatedString, | ||
| 4269 | ) Allocator.Error!void { | ||
| 4270 | const map = &ip.maps.items[@enumToInt(map_index)]; | ||
| 4271 | const adapter: NullTerminatedString.Adapter = .{ .strings = strings }; | ||
| 4272 | for (strings) |string| { | ||
| 4273 | const gop = try map.getOrPutAdapted(gpa, string, adapter); | ||
| 4274 | assert(!gop.found_existing); | ||
| 4275 | } | ||
| 4276 | } | ||
| 4277 | |||
| 4278 | fn addIndexesToMap( | ||
| 4279 | ip: *InternPool, | ||
| 4280 | gpa: Allocator, | ||
| 4281 | map_index: MapIndex, | ||
| 4282 | indexes: []const Index, | ||
| 4283 | ) Allocator.Error!void { | ||
| 4284 | const map = &ip.maps.items[@enumToInt(map_index)]; | ||
| 4285 | const adapter: Index.Adapter = .{ .indexes = indexes }; | ||
| 4286 | for (indexes) |index| { | ||
| 4287 | const gop = try map.getOrPutAdapted(gpa, index, adapter); | ||
| 4288 | assert(!gop.found_existing); | ||
| 4289 | } | ||
| 4290 | } | ||
| 4291 | |||
| 4292 | fn addMap(ip: *InternPool, gpa: Allocator) Allocator.Error!MapIndex { | ||
| 4293 | const ptr = try ip.maps.addOne(gpa); | ||
| 4294 | ptr.* = .{}; | ||
| 4295 | return @intToEnum(MapIndex, ip.maps.items.len - 1); | ||
| 4296 | } | ||
| 4297 | |||
| 4298 | /// This operation only happens under compile error conditions. | ||
| 4299 | /// Leak the index until the next garbage collection. | ||
| 4300 | /// TODO: this is a bit problematic to implement, can we get away without it? | ||
| 4301 | pub const remove = @compileError("InternPool.remove is not currently a supported operation; put a TODO there instead"); | ||
| 4302 | |||
| 4303 | fn addInt(ip: *InternPool, gpa: Allocator, ty: Index, tag: Tag, limbs: []const Limb) !void { | ||
| 4304 | const limbs_len = @intCast(u32, limbs.len); | ||
| 4305 | try ip.reserveLimbs(gpa, @typeInfo(Int).Struct.fields.len + limbs_len); | ||
| 4306 | ip.items.appendAssumeCapacity(.{ | ||
| 4307 | .tag = tag, | ||
| 4308 | .data = ip.addLimbsExtraAssumeCapacity(Int{ | ||
| 4309 | .ty = ty, | ||
| 4310 | .limbs_len = limbs_len, | ||
| 4311 | }), | ||
| 4312 | }); | ||
| 4313 | ip.addLimbsAssumeCapacity(limbs); | ||
| 4314 | } | ||
| 4315 | |||
| 4316 | fn addExtra(ip: *InternPool, gpa: Allocator, extra: anytype) Allocator.Error!u32 { | ||
| 4317 | const fields = @typeInfo(@TypeOf(extra)).Struct.fields; | ||
| 4318 | try ip.extra.ensureUnusedCapacity(gpa, fields.len); | ||
| 4319 | return ip.addExtraAssumeCapacity(extra); | ||
| 4320 | } | ||
| 4321 | |||
| 4322 | fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { | ||
| 4323 | const result = @intCast(u32, ip.extra.items.len); | ||
| 4324 | inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| { | ||
| 4325 | ip.extra.appendAssumeCapacity(switch (field.type) { | ||
| 4326 | u32 => @field(extra, field.name), | ||
| 4327 | Index => @enumToInt(@field(extra, field.name)), | ||
| 4328 | Module.Decl.Index => @enumToInt(@field(extra, field.name)), | ||
| 4329 | Module.Namespace.Index => @enumToInt(@field(extra, field.name)), | ||
| 4330 | Module.Namespace.OptionalIndex => @enumToInt(@field(extra, field.name)), | ||
| 4331 | Module.Fn.Index => @enumToInt(@field(extra, field.name)), | ||
| 4332 | MapIndex => @enumToInt(@field(extra, field.name)), | ||
| 4333 | OptionalMapIndex => @enumToInt(@field(extra, field.name)), | ||
| 4334 | RuntimeIndex => @enumToInt(@field(extra, field.name)), | ||
| 4335 | String => @enumToInt(@field(extra, field.name)), | ||
| 4336 | NullTerminatedString => @enumToInt(@field(extra, field.name)), | ||
| 4337 | OptionalNullTerminatedString => @enumToInt(@field(extra, field.name)), | ||
| 4338 | i32 => @bitCast(u32, @field(extra, field.name)), | ||
| 4339 | Tag.TypePointer.Flags => @bitCast(u32, @field(extra, field.name)), | ||
| 4340 | TypeFunction.Flags => @bitCast(u32, @field(extra, field.name)), | ||
| 4341 | Tag.TypePointer.PackedOffset => @bitCast(u32, @field(extra, field.name)), | ||
| 4342 | Tag.TypePointer.VectorIndex => @enumToInt(@field(extra, field.name)), | ||
| 4343 | Tag.Variable.Flags => @bitCast(u32, @field(extra, field.name)), | ||
| 4344 | else => @compileError("bad field type: " ++ @typeName(field.type)), | ||
| 4345 | }); | ||
| 4346 | } | ||
| 4347 | return result; | ||
| 4348 | } | ||
| 4349 | |||
| 4350 | fn reserveLimbs(ip: *InternPool, gpa: Allocator, n: usize) !void { | ||
| 4351 | switch (@sizeOf(Limb)) { | ||
| 4352 | @sizeOf(u32) => try ip.extra.ensureUnusedCapacity(gpa, n), | ||
| 4353 | @sizeOf(u64) => try ip.limbs.ensureUnusedCapacity(gpa, n), | ||
| 4354 | else => @compileError("unsupported host"), | ||
| 4355 | } | ||
| 4356 | } | ||
| 4357 | |||
| 4358 | fn addLimbsExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { | ||
| 4359 | switch (@sizeOf(Limb)) { | ||
| 4360 | @sizeOf(u32) => return addExtraAssumeCapacity(ip, extra), | ||
| 4361 | @sizeOf(u64) => {}, | ||
| 4362 | else => @compileError("unsupported host"), | ||
| 4363 | } | ||
| 4364 | const result = @intCast(u32, ip.limbs.items.len); | ||
| 4365 | inline for (@typeInfo(@TypeOf(extra)).Struct.fields, 0..) |field, i| { | ||
| 4366 | const new: u32 = switch (field.type) { | ||
| 4367 | u32 => @field(extra, field.name), | ||
| 4368 | Index => @enumToInt(@field(extra, field.name)), | ||
| 4369 | else => @compileError("bad field type: " ++ @typeName(field.type)), | ||
| 4370 | }; | ||
| 4371 | if (i % 2 == 0) { | ||
| 4372 | ip.limbs.appendAssumeCapacity(new); | ||
| 4373 | } else { | ||
| 4374 | ip.limbs.items[ip.limbs.items.len - 1] |= @as(u64, new) << 32; | ||
| 4375 | } | ||
| 4376 | } | ||
| 4377 | return result; | ||
| 4378 | } | ||
| 4379 | |||
| 4380 | fn addLimbsAssumeCapacity(ip: *InternPool, limbs: []const Limb) void { | ||
| 4381 | switch (@sizeOf(Limb)) { | ||
| 4382 | @sizeOf(u32) => ip.extra.appendSliceAssumeCapacity(limbs), | ||
| 4383 | @sizeOf(u64) => ip.limbs.appendSliceAssumeCapacity(limbs), | ||
| 4384 | else => @compileError("unsupported host"), | ||
| 4385 | } | ||
| 4386 | } | ||
| 4387 | |||
| 4388 | fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct { data: T, end: usize } { | ||
| 4389 | var result: T = undefined; | ||
| 4390 | const fields = @typeInfo(T).Struct.fields; | ||
| 4391 | inline for (fields, 0..) |field, i| { | ||
| 4392 | const int32 = ip.extra.items[i + index]; | ||
| 4393 | @field(result, field.name) = switch (field.type) { | ||
| 4394 | u32 => int32, | ||
| 4395 | Index => @intToEnum(Index, int32), | ||
| 4396 | Module.Decl.Index => @intToEnum(Module.Decl.Index, int32), | ||
| 4397 | Module.Namespace.Index => @intToEnum(Module.Namespace.Index, int32), | ||
| 4398 | Module.Namespace.OptionalIndex => @intToEnum(Module.Namespace.OptionalIndex, int32), | ||
| 4399 | Module.Fn.Index => @intToEnum(Module.Fn.Index, int32), | ||
| 4400 | MapIndex => @intToEnum(MapIndex, int32), | ||
| 4401 | OptionalMapIndex => @intToEnum(OptionalMapIndex, int32), | ||
| 4402 | RuntimeIndex => @intToEnum(RuntimeIndex, int32), | ||
| 4403 | String => @intToEnum(String, int32), | ||
| 4404 | NullTerminatedString => @intToEnum(NullTerminatedString, int32), | ||
| 4405 | OptionalNullTerminatedString => @intToEnum(OptionalNullTerminatedString, int32), | ||
| 4406 | i32 => @bitCast(i32, int32), | ||
| 4407 | Tag.TypePointer.Flags => @bitCast(Tag.TypePointer.Flags, int32), | ||
| 4408 | TypeFunction.Flags => @bitCast(TypeFunction.Flags, int32), | ||
| 4409 | Tag.TypePointer.PackedOffset => @bitCast(Tag.TypePointer.PackedOffset, int32), | ||
| 4410 | Tag.TypePointer.VectorIndex => @intToEnum(Tag.TypePointer.VectorIndex, int32), | ||
| 4411 | Tag.Variable.Flags => @bitCast(Tag.Variable.Flags, int32), | ||
| 4412 | else => @compileError("bad field type: " ++ @typeName(field.type)), | ||
| 4413 | }; | ||
| 4414 | } | ||
| 4415 | return .{ | ||
| 4416 | .data = result, | ||
| 4417 | .end = index + fields.len, | ||
| 4418 | }; | ||
| 4419 | } | ||
| 4420 | |||
| 4421 | fn extraData(ip: *const InternPool, comptime T: type, index: usize) T { | ||
| 4422 | return extraDataTrail(ip, T, index).data; | ||
| 4423 | } | ||
| 4424 | |||
| 4425 | /// Asserts the struct has 32-bit fields and the number of fields is evenly divisible by 2. | ||
| 4426 | fn limbData(ip: *const InternPool, comptime T: type, index: usize) T { | ||
| 4427 | switch (@sizeOf(Limb)) { | ||
| 4428 | @sizeOf(u32) => return extraData(ip, T, index), | ||
| 4429 | @sizeOf(u64) => {}, | ||
| 4430 | else => @compileError("unsupported host"), | ||
| 4431 | } | ||
| 4432 | var result: T = undefined; | ||
| 4433 | inline for (@typeInfo(T).Struct.fields, 0..) |field, i| { | ||
| 4434 | const host_int = ip.limbs.items[index + i / 2]; | ||
| 4435 | const int32 = if (i % 2 == 0) | ||
| 4436 | @truncate(u32, host_int) | ||
| 4437 | else | ||
| 4438 | @truncate(u32, host_int >> 32); | ||
| 4439 | |||
| 4440 | @field(result, field.name) = switch (field.type) { | ||
| 4441 | u32 => int32, | ||
| 4442 | Index => @intToEnum(Index, int32), | ||
| 4443 | else => @compileError("bad field type: " ++ @typeName(field.type)), | ||
| 4444 | }; | ||
| 4445 | } | ||
| 4446 | return result; | ||
| 4447 | } | ||
| 4448 | |||
| 4449 | /// This function returns the Limb slice that is trailing data after a payload. | ||
| 4450 | fn limbSlice(ip: *const InternPool, comptime S: type, limb_index: u32, len: u32) []const Limb { | ||
| 4451 | const field_count = @typeInfo(S).Struct.fields.len; | ||
| 4452 | switch (@sizeOf(Limb)) { | ||
| 4453 | @sizeOf(u32) => { | ||
| 4454 | const start = limb_index + field_count; | ||
| 4455 | return ip.extra.items[start..][0..len]; | ||
| 4456 | }, | ||
| 4457 | @sizeOf(u64) => { | ||
| 4458 | const start = limb_index + @divExact(field_count, 2); | ||
| 4459 | return ip.limbs.items[start..][0..len]; | ||
| 4460 | }, | ||
| 4461 | else => @compileError("unsupported host"), | ||
| 4462 | } | ||
| 4463 | } | ||
| 4464 | |||
| 4465 | const LimbsAsIndexes = struct { | ||
| 4466 | start: u32, | ||
| 4467 | len: u32, | ||
| 4468 | }; | ||
| 4469 | |||
| 4470 | fn limbsSliceToIndex(ip: *const InternPool, limbs: []const Limb) LimbsAsIndexes { | ||
| 4471 | const host_slice = switch (@sizeOf(Limb)) { | ||
| 4472 | @sizeOf(u32) => ip.extra.items, | ||
| 4473 | @sizeOf(u64) => ip.limbs.items, | ||
| 4474 | else => @compileError("unsupported host"), | ||
| 4475 | }; | ||
| 4476 | // TODO: https://github.com/ziglang/zig/issues/1738 | ||
| 4477 | return .{ | ||
| 4478 | .start = @intCast(u32, @divExact(@ptrToInt(limbs.ptr) - @ptrToInt(host_slice.ptr), @sizeOf(Limb))), | ||
| 4479 | .len = @intCast(u32, limbs.len), | ||
| 4480 | }; | ||
| 4481 | } | ||
| 4482 | |||
| 4483 | /// This function converts Limb array indexes to a primitive slice type. | ||
| 4484 | fn limbsIndexToSlice(ip: *const InternPool, limbs: LimbsAsIndexes) []const Limb { | ||
| 4485 | return switch (@sizeOf(Limb)) { | ||
| 4486 | @sizeOf(u32) => ip.extra.items[limbs.start..][0..limbs.len], | ||
| 4487 | @sizeOf(u64) => ip.limbs.items[limbs.start..][0..limbs.len], | ||
| 4488 | else => @compileError("unsupported host"), | ||
| 4489 | }; | ||
| 4490 | } | ||
| 4491 | |||
| 4492 | test "basic usage" { | ||
| 4493 | const gpa = std.testing.allocator; | ||
| 4494 | |||
| 4495 | var ip: InternPool = .{}; | ||
| 4496 | defer ip.deinit(gpa); | ||
| 4497 | |||
| 4498 | const i32_type = try ip.get(gpa, .{ .int_type = .{ | ||
| 4499 | .signedness = .signed, | ||
| 4500 | .bits = 32, | ||
| 4501 | } }); | ||
| 4502 | const array_i32 = try ip.get(gpa, .{ .array_type = .{ | ||
| 4503 | .len = 10, | ||
| 4504 | .child = i32_type, | ||
| 4505 | .sentinel = .none, | ||
| 4506 | } }); | ||
| 4507 | |||
| 4508 | const another_i32_type = try ip.get(gpa, .{ .int_type = .{ | ||
| 4509 | .signedness = .signed, | ||
| 4510 | .bits = 32, | ||
| 4511 | } }); | ||
| 4512 | try std.testing.expect(another_i32_type == i32_type); | ||
| 4513 | |||
| 4514 | const another_array_i32 = try ip.get(gpa, .{ .array_type = .{ | ||
| 4515 | .len = 10, | ||
| 4516 | .child = i32_type, | ||
| 4517 | .sentinel = .none, | ||
| 4518 | } }); | ||
| 4519 | try std.testing.expect(another_array_i32 == array_i32); | ||
| 4520 | } | ||
| 4521 | |||
| 4522 | pub fn childType(ip: *const InternPool, i: Index) Index { | ||
| 4523 | return switch (ip.indexToKey(i)) { | ||
| 4524 | .ptr_type => |ptr_type| ptr_type.child, | ||
| 4525 | .vector_type => |vector_type| vector_type.child, | ||
| 4526 | .array_type => |array_type| array_type.child, | ||
| 4527 | .opt_type, .anyframe_type => |child| child, | ||
| 4528 | else => unreachable, | ||
| 4529 | }; | ||
| 4530 | } | ||
| 4531 | |||
| 4532 | /// Given a slice type, returns the type of the ptr field. | ||
| 4533 | pub fn slicePtrType(ip: *const InternPool, i: Index) Index { | ||
| 4534 | switch (i) { | ||
| 4535 | .slice_const_u8_type => return .manyptr_const_u8_type, | ||
| 4536 | .slice_const_u8_sentinel_0_type => return .manyptr_const_u8_sentinel_0_type, | ||
| 4537 | else => {}, | ||
| 4538 | } | ||
| 4539 | const item = ip.items.get(@enumToInt(i)); | ||
| 4540 | switch (item.tag) { | ||
| 4541 | .type_slice => return @intToEnum(Index, item.data), | ||
| 4542 | else => unreachable, // not a slice type | ||
| 4543 | } | ||
| 4544 | } | ||
| 4545 | |||
| 4546 | /// Given a slice value, returns the value of the ptr field. | ||
| 4547 | pub fn slicePtr(ip: *const InternPool, i: Index) Index { | ||
| 4548 | const item = ip.items.get(@enumToInt(i)); | ||
| 4549 | switch (item.tag) { | ||
| 4550 | .ptr_slice => return ip.extraData(PtrSlice, item.data).ptr, | ||
| 4551 | else => unreachable, // not a slice value | ||
| 4552 | } | ||
| 4553 | } | ||
| 4554 | |||
| 4555 | /// Given a slice value, returns the value of the len field. | ||
| 4556 | pub fn sliceLen(ip: *const InternPool, i: Index) Index { | ||
| 4557 | const item = ip.items.get(@enumToInt(i)); | ||
| 4558 | switch (item.tag) { | ||
| 4559 | .ptr_slice => return ip.extraData(PtrSlice, item.data).len, | ||
| 4560 | else => unreachable, // not a slice value | ||
| 4561 | } | ||
| 4562 | } | ||
| 4563 | |||
| 4564 | /// Given an existing value, returns the same value but with the supplied type. | ||
| 4565 | /// Only some combinations are allowed: | ||
| 4566 | /// * identity coercion | ||
| 4567 | /// * undef => any | ||
| 4568 | /// * int <=> int | ||
| 4569 | /// * int <=> enum | ||
| 4570 | /// * enum_literal => enum | ||
| 4571 | /// * ptr <=> ptr | ||
| 4572 | /// * opt ptr <=> ptr | ||
| 4573 | /// * opt ptr <=> opt ptr | ||
| 4574 | /// * int <=> ptr | ||
| 4575 | /// * null_value => opt | ||
| 4576 | /// * payload => opt | ||
| 4577 | /// * error set <=> error set | ||
| 4578 | /// * error union <=> error union | ||
| 4579 | /// * error set => error union | ||
| 4580 | /// * payload => error union | ||
| 4581 | /// * fn <=> fn | ||
| 4582 | pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index { | ||
| 4583 | const old_ty = ip.typeOf(val); | ||
| 4584 | if (old_ty == new_ty) return val; | ||
| 4585 | switch (val) { | ||
| 4586 | .undef => return ip.get(gpa, .{ .undef = new_ty }), | ||
| 4587 | .null_value => if (ip.isOptionalType(new_ty)) | ||
| 4588 | return ip.get(gpa, .{ .opt = .{ | ||
| 4589 | .ty = new_ty, | ||
| 4590 | .val = .none, | ||
| 4591 | } }) | ||
| 4592 | else if (ip.isPointerType(new_ty)) | ||
| 4593 | return ip.get(gpa, .{ .ptr = .{ | ||
| 4594 | .ty = new_ty, | ||
| 4595 | .addr = .{ .int = .zero_usize }, | ||
| 4596 | .len = switch (ip.indexToKey(new_ty).ptr_type.flags.size) { | ||
| 4597 | .One, .Many, .C => .none, | ||
| 4598 | .Slice => try ip.get(gpa, .{ .undef = .usize_type }), | ||
| 4599 | }, | ||
| 4600 | } }), | ||
| 4601 | else => switch (ip.indexToKey(val)) { | ||
| 4602 | .undef => return ip.get(gpa, .{ .undef = new_ty }), | ||
| 4603 | .extern_func => |extern_func| if (ip.isFunctionType(new_ty)) | ||
| 4604 | return ip.get(gpa, .{ .extern_func = .{ | ||
| 4605 | .ty = new_ty, | ||
| 4606 | .decl = extern_func.decl, | ||
| 4607 | .lib_name = extern_func.lib_name, | ||
| 4608 | } }), | ||
| 4609 | .func => |func| if (ip.isFunctionType(new_ty)) | ||
| 4610 | return ip.get(gpa, .{ .func = .{ | ||
| 4611 | .ty = new_ty, | ||
| 4612 | .index = func.index, | ||
| 4613 | } }), | ||
| 4614 | .int => |int| switch (ip.indexToKey(new_ty)) { | ||
| 4615 | .enum_type => |enum_type| return ip.get(gpa, .{ .enum_tag = .{ | ||
| 4616 | .ty = new_ty, | ||
| 4617 | .int = try ip.getCoerced(gpa, val, enum_type.tag_ty), | ||
| 4618 | } }), | ||
| 4619 | .ptr_type => return ip.get(gpa, .{ .ptr = .{ | ||
| 4620 | .ty = new_ty, | ||
| 4621 | .addr = .{ .int = try ip.getCoerced(gpa, val, .usize_type) }, | ||
| 4622 | } }), | ||
| 4623 | else => if (ip.isIntegerType(new_ty)) | ||
| 4624 | return getCoercedInts(ip, gpa, int, new_ty), | ||
| 4625 | }, | ||
| 4626 | .enum_tag => |enum_tag| if (ip.isIntegerType(new_ty)) | ||
| 4627 | return getCoercedInts(ip, gpa, ip.indexToKey(enum_tag.int).int, new_ty), | ||
| 4628 | .enum_literal => |enum_literal| switch (ip.indexToKey(new_ty)) { | ||
| 4629 | .enum_type => |enum_type| { | ||
| 4630 | const index = enum_type.nameIndex(ip, enum_literal).?; | ||
| 4631 | return ip.get(gpa, .{ .enum_tag = .{ | ||
| 4632 | .ty = new_ty, | ||
| 4633 | .int = if (enum_type.values.len != 0) | ||
| 4634 | enum_type.values[index] | ||
| 4635 | else | ||
| 4636 | try ip.get(gpa, .{ .int = .{ | ||
| 4637 | .ty = enum_type.tag_ty, | ||
| 4638 | .storage = .{ .u64 = index }, | ||
| 4639 | } }), | ||
| 4640 | } }); | ||
| 4641 | }, | ||
| 4642 | else => {}, | ||
| 4643 | }, | ||
| 4644 | .ptr => |ptr| if (ip.isPointerType(new_ty)) | ||
| 4645 | return ip.get(gpa, .{ .ptr = .{ | ||
| 4646 | .ty = new_ty, | ||
| 4647 | .addr = ptr.addr, | ||
| 4648 | .len = ptr.len, | ||
| 4649 | } }) | ||
| 4650 | else if (ip.isIntegerType(new_ty)) | ||
| 4651 | switch (ptr.addr) { | ||
| 4652 | .int => |int| return ip.getCoerced(gpa, int, new_ty), | ||
| 4653 | else => {}, | ||
| 4654 | }, | ||
| 4655 | .opt => |opt| switch (ip.indexToKey(new_ty)) { | ||
| 4656 | .ptr_type => |ptr_type| return switch (opt.val) { | ||
| 4657 | .none => try ip.get(gpa, .{ .ptr = .{ | ||
| 4658 | .ty = new_ty, | ||
| 4659 | .addr = .{ .int = .zero_usize }, | ||
| 4660 | .len = switch (ptr_type.flags.size) { | ||
| 4661 | .One, .Many, .C => .none, | ||
| 4662 | .Slice => try ip.get(gpa, .{ .undef = .usize_type }), | ||
| 4663 | }, | ||
| 4664 | } }), | ||
| 4665 | else => |payload| try ip.getCoerced(gpa, payload, new_ty), | ||
| 4666 | }, | ||
| 4667 | .opt_type => |child_type| return try ip.get(gpa, .{ .opt = .{ | ||
| 4668 | .ty = new_ty, | ||
| 4669 | .val = switch (opt.val) { | ||
| 4670 | .none => .none, | ||
| 4671 | else => try ip.getCoerced(gpa, opt.val, child_type), | ||
| 4672 | }, | ||
| 4673 | } }), | ||
| 4674 | else => {}, | ||
| 4675 | }, | ||
| 4676 | .err => |err| if (ip.isErrorSetType(new_ty)) | ||
| 4677 | return ip.get(gpa, .{ .err = .{ | ||
| 4678 | .ty = new_ty, | ||
| 4679 | .name = err.name, | ||
| 4680 | } }) | ||
| 4681 | else if (ip.isErrorUnionType(new_ty)) | ||
| 4682 | return ip.get(gpa, .{ .error_union = .{ | ||
| 4683 | .ty = new_ty, | ||
| 4684 | .val = .{ .err_name = err.name }, | ||
| 4685 | } }), | ||
| 4686 | .error_union => |error_union| if (ip.isErrorUnionType(new_ty)) | ||
| 4687 | return ip.get(gpa, .{ .error_union = .{ | ||
| 4688 | .ty = new_ty, | ||
| 4689 | .val = error_union.val, | ||
| 4690 | } }), | ||
| 4691 | else => {}, | ||
| 4692 | }, | ||
| 4693 | } | ||
| 4694 | switch (ip.indexToKey(new_ty)) { | ||
| 4695 | .opt_type => |child_type| switch (val) { | ||
| 4696 | .null_value => return ip.get(gpa, .{ .opt = .{ | ||
| 4697 | .ty = new_ty, | ||
| 4698 | .val = .none, | ||
| 4699 | } }), | ||
| 4700 | else => return ip.get(gpa, .{ .opt = .{ | ||
| 4701 | .ty = new_ty, | ||
| 4702 | .val = try ip.getCoerced(gpa, val, child_type), | ||
| 4703 | } }), | ||
| 4704 | }, | ||
| 4705 | .error_union_type => |error_union_type| return ip.get(gpa, .{ .error_union = .{ | ||
| 4706 | .ty = new_ty, | ||
| 4707 | .val = .{ .payload = try ip.getCoerced(gpa, val, error_union_type.payload_type) }, | ||
| 4708 | } }), | ||
| 4709 | else => {}, | ||
| 4710 | } | ||
| 4711 | if (std.debug.runtime_safety) { | ||
| 4712 | std.debug.panic("InternPool.getCoerced of {s} not implemented from {s} to {s}", .{ | ||
| 4713 | @tagName(ip.indexToKey(val)), | ||
| 4714 | @tagName(ip.indexToKey(old_ty)), | ||
| 4715 | @tagName(ip.indexToKey(new_ty)), | ||
| 4716 | }); | ||
| 4717 | } | ||
| 4718 | unreachable; | ||
| 4719 | } | ||
| 4720 | |||
| 4721 | /// Asserts `val` has an integer type. | ||
| 4722 | /// Assumes `new_ty` is an integer type. | ||
| 4723 | pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, int: Key.Int, new_ty: Index) Allocator.Error!Index { | ||
| 4724 | // The key cannot be passed directly to `get`, otherwise in the case of | ||
| 4725 | // big_int storage, the limbs would be invalidated before they are read. | ||
| 4726 | // Here we pre-reserve the limbs to ensure that the logic in `addInt` will | ||
| 4727 | // not use an invalidated limbs pointer. | ||
| 4728 | const new_storage: Key.Int.Storage = switch (int.storage) { | ||
| 4729 | .u64, .i64, .lazy_align, .lazy_size => int.storage, | ||
| 4730 | .big_int => |big_int| storage: { | ||
| 4731 | const positive = big_int.positive; | ||
| 4732 | const limbs = ip.limbsSliceToIndex(big_int.limbs); | ||
| 4733 | // This line invalidates the limbs slice, but the indexes computed in the | ||
| 4734 | // previous line are still correct. | ||
| 4735 | try reserveLimbs(ip, gpa, @typeInfo(Int).Struct.fields.len + big_int.limbs.len); | ||
| 4736 | break :storage .{ .big_int = .{ | ||
| 4737 | .limbs = ip.limbsIndexToSlice(limbs), | ||
| 4738 | .positive = positive, | ||
| 4739 | } }; | ||
| 4740 | }, | ||
| 4741 | }; | ||
| 4742 | return ip.get(gpa, .{ .int = .{ | ||
| 4743 | .ty = new_ty, | ||
| 4744 | .storage = new_storage, | ||
| 4745 | } }); | ||
| 4746 | } | ||
| 4747 | |||
| 4748 | pub fn indexToStructType(ip: *const InternPool, val: Index) Module.Struct.OptionalIndex { | ||
| 4749 | assert(val != .none); | ||
| 4750 | const tags = ip.items.items(.tag); | ||
| 4751 | if (tags[@enumToInt(val)] != .type_struct) return .none; | ||
| 4752 | const datas = ip.items.items(.data); | ||
| 4753 | return @intToEnum(Module.Struct.Index, datas[@enumToInt(val)]).toOptional(); | ||
| 4754 | } | ||
| 4755 | |||
| 4756 | pub fn indexToUnionType(ip: *const InternPool, val: Index) Module.Union.OptionalIndex { | ||
| 4757 | assert(val != .none); | ||
| 4758 | const tags = ip.items.items(.tag); | ||
| 4759 | switch (tags[@enumToInt(val)]) { | ||
| 4760 | .type_union_tagged, .type_union_untagged, .type_union_safety => {}, | ||
| 4761 | else => return .none, | ||
| 4762 | } | ||
| 4763 | const datas = ip.items.items(.data); | ||
| 4764 | return @intToEnum(Module.Union.Index, datas[@enumToInt(val)]).toOptional(); | ||
| 4765 | } | ||
| 4766 | |||
| 4767 | pub fn indexToFuncType(ip: *const InternPool, val: Index) ?Key.FuncType { | ||
| 4768 | assert(val != .none); | ||
| 4769 | const tags = ip.items.items(.tag); | ||
| 4770 | const datas = ip.items.items(.data); | ||
| 4771 | switch (tags[@enumToInt(val)]) { | ||
| 4772 | .type_function => return indexToKeyFuncType(ip, datas[@enumToInt(val)]), | ||
| 4773 | else => return null, | ||
| 4774 | } | ||
| 4775 | } | ||
| 4776 | |||
| 4777 | pub fn indexToFunc(ip: *const InternPool, val: Index) Module.Fn.OptionalIndex { | ||
| 4778 | assert(val != .none); | ||
| 4779 | const tags = ip.items.items(.tag); | ||
| 4780 | if (tags[@enumToInt(val)] != .func) return .none; | ||
| 4781 | const datas = ip.items.items(.data); | ||
| 4782 | return ip.extraData(Tag.Func, datas[@enumToInt(val)]).index.toOptional(); | ||
| 4783 | } | ||
| 4784 | |||
| 4785 | pub fn indexToInferredErrorSetType(ip: *const InternPool, val: Index) Module.Fn.InferredErrorSet.OptionalIndex { | ||
| 4786 | assert(val != .none); | ||
| 4787 | const tags = ip.items.items(.tag); | ||
| 4788 | if (tags[@enumToInt(val)] != .type_inferred_error_set) return .none; | ||
| 4789 | const datas = ip.items.items(.data); | ||
| 4790 | return @intToEnum(Module.Fn.InferredErrorSet.Index, datas[@enumToInt(val)]).toOptional(); | ||
| 4791 | } | ||
| 4792 | |||
| 4793 | /// includes .comptime_int_type | ||
| 4794 | pub fn isIntegerType(ip: *const InternPool, ty: Index) bool { | ||
| 4795 | return switch (ty) { | ||
| 4796 | .usize_type, | ||
| 4797 | .isize_type, | ||
| 4798 | .c_char_type, | ||
| 4799 | .c_short_type, | ||
| 4800 | .c_ushort_type, | ||
| 4801 | .c_int_type, | ||
| 4802 | .c_uint_type, | ||
| 4803 | .c_long_type, | ||
| 4804 | .c_ulong_type, | ||
| 4805 | .c_longlong_type, | ||
| 4806 | .c_ulonglong_type, | ||
| 4807 | .c_longdouble_type, | ||
| 4808 | .comptime_int_type, | ||
| 4809 | => true, | ||
| 4810 | else => ip.indexToKey(ty) == .int_type, | ||
| 4811 | }; | ||
| 4812 | } | ||
| 4813 | |||
| 4814 | /// does not include .enum_literal_type | ||
| 4815 | pub fn isEnumType(ip: *const InternPool, ty: Index) bool { | ||
| 4816 | return switch (ty) { | ||
| 4817 | .atomic_order_type, | ||
| 4818 | .atomic_rmw_op_type, | ||
| 4819 | .calling_convention_type, | ||
| 4820 | .address_space_type, | ||
| 4821 | .float_mode_type, | ||
| 4822 | .reduce_op_type, | ||
| 4823 | .call_modifier_type, | ||
| 4824 | => true, | ||
| 4825 | else => ip.indexToKey(ty) == .enum_type, | ||
| 4826 | }; | ||
| 4827 | } | ||
| 4828 | |||
| 4829 | pub fn isFunctionType(ip: *const InternPool, ty: Index) bool { | ||
| 4830 | return ip.indexToKey(ty) == .func_type; | ||
| 4831 | } | ||
| 4832 | |||
| 4833 | pub fn isPointerType(ip: *const InternPool, ty: Index) bool { | ||
| 4834 | return ip.indexToKey(ty) == .ptr_type; | ||
| 4835 | } | ||
| 4836 | |||
| 4837 | pub fn isOptionalType(ip: *const InternPool, ty: Index) bool { | ||
| 4838 | return ip.indexToKey(ty) == .opt_type; | ||
| 4839 | } | ||
| 4840 | |||
| 4841 | /// includes .inferred_error_set_type | ||
| 4842 | pub fn isErrorSetType(ip: *const InternPool, ty: Index) bool { | ||
| 4843 | return ty == .anyerror_type or switch (ip.indexToKey(ty)) { | ||
| 4844 | .error_set_type, .inferred_error_set_type => true, | ||
| 4845 | else => false, | ||
| 4846 | }; | ||
| 4847 | } | ||
| 4848 | |||
| 4849 | pub fn isInferredErrorSetType(ip: *const InternPool, ty: Index) bool { | ||
| 4850 | return ip.indexToKey(ty) == .inferred_error_set_type; | ||
| 4851 | } | ||
| 4852 | |||
| 4853 | pub fn isErrorUnionType(ip: *const InternPool, ty: Index) bool { | ||
| 4854 | return ip.indexToKey(ty) == .error_union_type; | ||
| 4855 | } | ||
| 4856 | |||
| 4857 | pub fn isAggregateType(ip: *const InternPool, ty: Index) bool { | ||
| 4858 | return switch (ip.indexToKey(ty)) { | ||
| 4859 | .array_type, .vector_type, .anon_struct_type, .struct_type => true, | ||
| 4860 | else => false, | ||
| 4861 | }; | ||
| 4862 | } | ||
| 4863 | |||
| 4864 | /// The is only legal because the initializer is not part of the hash. | ||
| 4865 | pub fn mutateVarInit(ip: *InternPool, index: Index, init_index: Index) void { | ||
| 4866 | const item = ip.items.get(@enumToInt(index)); | ||
| 4867 | assert(item.tag == .variable); | ||
| 4868 | ip.extra.items[item.data + std.meta.fieldIndex(Tag.Variable, "init").?] = @enumToInt(init_index); | ||
| 4869 | } | ||
| 4870 | |||
| 4871 | pub fn dump(ip: *const InternPool) void { | ||
| 4872 | dumpStatsFallible(ip, std.heap.page_allocator) catch return; | ||
| 4873 | dumpAllFallible(ip) catch return; | ||
| 4874 | } | ||
| 4875 | |||
| 4876 | fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { | ||
| 4877 | const items_size = (1 + 4) * ip.items.len; | ||
| 4878 | const extra_size = 4 * ip.extra.items.len; | ||
| 4879 | const limbs_size = 8 * ip.limbs.items.len; | ||
| 4880 | // TODO: fields size is not taken into account | ||
| 4881 | const structs_size = ip.allocated_structs.len * | ||
| 4882 | (@sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl)); | ||
| 4883 | const unions_size = ip.allocated_unions.len * | ||
| 4884 | (@sizeOf(Module.Union) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl)); | ||
| 4885 | const funcs_size = ip.allocated_funcs.len * | ||
| 4886 | (@sizeOf(Module.Fn) + @sizeOf(Module.Decl)); | ||
| 4887 | |||
| 4888 | // TODO: map overhead size is not taken into account | ||
| 4889 | const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size + | ||
| 4890 | structs_size + unions_size + funcs_size; | ||
| 4891 | |||
| 4892 | std.debug.print( | ||
| 4893 | \\InternPool size: {d} bytes | ||
| 4894 | \\ {d} items: {d} bytes | ||
| 4895 | \\ {d} extra: {d} bytes | ||
| 4896 | \\ {d} limbs: {d} bytes | ||
| 4897 | \\ {d} structs: {d} bytes | ||
| 4898 | \\ {d} unions: {d} bytes | ||
| 4899 | \\ {d} funcs: {d} bytes | ||
| 4900 | \\ | ||
| 4901 | , .{ | ||
| 4902 | total_size, | ||
| 4903 | ip.items.len, | ||
| 4904 | items_size, | ||
| 4905 | ip.extra.items.len, | ||
| 4906 | extra_size, | ||
| 4907 | ip.limbs.items.len, | ||
| 4908 | limbs_size, | ||
| 4909 | ip.allocated_structs.len, | ||
| 4910 | structs_size, | ||
| 4911 | ip.allocated_unions.len, | ||
| 4912 | unions_size, | ||
| 4913 | ip.allocated_funcs.len, | ||
| 4914 | funcs_size, | ||
| 4915 | }); | ||
| 4916 | |||
| 4917 | const tags = ip.items.items(.tag); | ||
| 4918 | const datas = ip.items.items(.data); | ||
| 4919 | const TagStats = struct { | ||
| 4920 | count: usize = 0, | ||
| 4921 | bytes: usize = 0, | ||
| 4922 | }; | ||
| 4923 | var counts = std.AutoArrayHashMap(Tag, TagStats).init(arena); | ||
| 4924 | for (tags, datas) |tag, data| { | ||
| 4925 | const gop = try counts.getOrPut(tag); | ||
| 4926 | if (!gop.found_existing) gop.value_ptr.* = .{}; | ||
| 4927 | gop.value_ptr.count += 1; | ||
| 4928 | gop.value_ptr.bytes += 1 + 4 + @as(usize, switch (tag) { | ||
| 4929 | .type_int_signed => 0, | ||
| 4930 | .type_int_unsigned => 0, | ||
| 4931 | .type_array_small => @sizeOf(Vector), | ||
| 4932 | .type_array_big => @sizeOf(Array), | ||
| 4933 | .type_vector => @sizeOf(Vector), | ||
| 4934 | .type_pointer => @sizeOf(Tag.TypePointer), | ||
| 4935 | .type_slice => 0, | ||
| 4936 | .type_optional => 0, | ||
| 4937 | .type_anyframe => 0, | ||
| 4938 | .type_error_union => @sizeOf(Key.ErrorUnionType), | ||
| 4939 | .type_error_set => b: { | ||
| 4940 | const info = ip.extraData(ErrorSet, data); | ||
| 4941 | break :b @sizeOf(ErrorSet) + (@sizeOf(u32) * info.names_len); | ||
| 4942 | }, | ||
| 4943 | .type_inferred_error_set => @sizeOf(Module.Fn.InferredErrorSet), | ||
| 4944 | .type_enum_explicit, .type_enum_nonexhaustive => @sizeOf(EnumExplicit), | ||
| 4945 | .type_enum_auto => @sizeOf(EnumAuto), | ||
| 4946 | .type_opaque => @sizeOf(Key.OpaqueType), | ||
| 4947 | .type_struct => b: { | ||
| 4948 | const struct_index = @intToEnum(Module.Struct.Index, data); | ||
| 4949 | const struct_obj = ip.structPtrConst(struct_index); | ||
| 4950 | break :b @sizeOf(Module.Struct) + | ||
| 4951 | @sizeOf(Module.Namespace) + | ||
| 4952 | @sizeOf(Module.Decl) + | ||
| 4953 | (struct_obj.fields.count() * @sizeOf(Module.Struct.Field)); | ||
| 4954 | }, | ||
| 4955 | .type_struct_ns => @sizeOf(Module.Namespace), | ||
| 4956 | .type_struct_anon => b: { | ||
| 4957 | const info = ip.extraData(TypeStructAnon, data); | ||
| 4958 | break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 3 * info.fields_len); | ||
| 4959 | }, | ||
| 4960 | .type_tuple_anon => b: { | ||
| 4961 | const info = ip.extraData(TypeStructAnon, data); | ||
| 4962 | break :b @sizeOf(TypeStructAnon) + (@sizeOf(u32) * 2 * info.fields_len); | ||
| 4963 | }, | ||
| 4964 | |||
| 4965 | .type_union_tagged, | ||
| 4966 | .type_union_untagged, | ||
| 4967 | .type_union_safety, | ||
| 4968 | => @sizeOf(Module.Union) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl), | ||
| 4969 | |||
| 4970 | .type_function => b: { | ||
| 4971 | const info = ip.extraData(TypeFunction, data); | ||
| 4972 | break :b @sizeOf(TypeFunction) + (@sizeOf(Index) * info.params_len); | ||
| 4973 | }, | ||
| 4974 | |||
| 4975 | .undef => 0, | ||
| 4976 | .runtime_value => @sizeOf(Tag.TypeValue), | ||
| 4977 | .simple_type => 0, | ||
| 4978 | .simple_value => 0, | ||
| 4979 | .ptr_decl => @sizeOf(PtrDecl), | ||
| 4980 | .ptr_mut_decl => @sizeOf(PtrMutDecl), | ||
| 4981 | .ptr_comptime_field => @sizeOf(PtrComptimeField), | ||
| 4982 | .ptr_int => @sizeOf(PtrBase), | ||
| 4983 | .ptr_eu_payload => @sizeOf(PtrBase), | ||
| 4984 | .ptr_opt_payload => @sizeOf(PtrBase), | ||
| 4985 | .ptr_elem => @sizeOf(PtrBaseIndex), | ||
| 4986 | .ptr_field => @sizeOf(PtrBaseIndex), | ||
| 4987 | .ptr_slice => @sizeOf(PtrSlice), | ||
| 4988 | .opt_null => 0, | ||
| 4989 | .opt_payload => @sizeOf(Tag.TypeValue), | ||
| 4990 | .int_u8 => 0, | ||
| 4991 | .int_u16 => 0, | ||
| 4992 | .int_u32 => 0, | ||
| 4993 | .int_i32 => 0, | ||
| 4994 | .int_usize => 0, | ||
| 4995 | .int_comptime_int_u32 => 0, | ||
| 4996 | .int_comptime_int_i32 => 0, | ||
| 4997 | .int_small => @sizeOf(IntSmall), | ||
| 4998 | |||
| 4999 | .int_positive, | ||
| 5000 | .int_negative, | ||
| 5001 | => b: { | ||
| 5002 | const int = ip.limbData(Int, data); | ||
| 5003 | break :b @sizeOf(Int) + int.limbs_len * 8; | ||
| 5004 | }, | ||
| 5005 | |||
| 5006 | .int_lazy_align, .int_lazy_size => @sizeOf(IntLazy), | ||
| 5007 | |||
| 5008 | .error_set_error, .error_union_error => @sizeOf(Key.Error), | ||
| 5009 | .error_union_payload => @sizeOf(Tag.TypeValue), | ||
| 5010 | .enum_literal => 0, | ||
| 5011 | .enum_tag => @sizeOf(Tag.EnumTag), | ||
| 5012 | |||
| 5013 | .bytes => b: { | ||
| 5014 | const info = ip.extraData(Bytes, data); | ||
| 5015 | const len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(info.ty)); | ||
| 5016 | break :b @sizeOf(Bytes) + len + | ||
| 5017 | @boolToInt(ip.string_bytes.items[@enumToInt(info.bytes) + len - 1] != 0); | ||
| 5018 | }, | ||
| 5019 | .aggregate => b: { | ||
| 5020 | const info = ip.extraData(Tag.Aggregate, data); | ||
| 5021 | const fields_len = @intCast(u32, ip.aggregateTypeLenIncludingSentinel(info.ty)); | ||
| 5022 | break :b @sizeOf(Tag.Aggregate) + (@sizeOf(Index) * fields_len); | ||
| 5023 | }, | ||
| 5024 | .repeated => @sizeOf(Repeated), | ||
| 5025 | |||
| 5026 | .float_f16 => 0, | ||
| 5027 | .float_f32 => 0, | ||
| 5028 | .float_f64 => @sizeOf(Float64), | ||
| 5029 | .float_f80 => @sizeOf(Float80), | ||
| 5030 | .float_f128 => @sizeOf(Float128), | ||
| 5031 | .float_c_longdouble_f80 => @sizeOf(Float80), | ||
| 5032 | .float_c_longdouble_f128 => @sizeOf(Float128), | ||
| 5033 | .float_comptime_float => @sizeOf(Float128), | ||
| 5034 | .variable => @sizeOf(Tag.Variable) + @sizeOf(Module.Decl), | ||
| 5035 | .extern_func => @sizeOf(Tag.ExternFunc) + @sizeOf(Module.Decl), | ||
| 5036 | .func => @sizeOf(Tag.Func) + @sizeOf(Module.Fn) + @sizeOf(Module.Decl), | ||
| 5037 | .only_possible_value => 0, | ||
| 5038 | .union_value => @sizeOf(Key.Union), | ||
| 5039 | |||
| 5040 | .memoized_call => b: { | ||
| 5041 | const info = ip.extraData(MemoizedCall, data); | ||
| 5042 | break :b @sizeOf(MemoizedCall) + (@sizeOf(Index) * info.args_len); | ||
| 5043 | }, | ||
| 5044 | }); | ||
| 5045 | } | ||
| 5046 | const SortContext = struct { | ||
| 5047 | map: *std.AutoArrayHashMap(Tag, TagStats), | ||
| 5048 | pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool { | ||
| 5049 | const values = ctx.map.values(); | ||
| 5050 | return values[a_index].bytes > values[b_index].bytes; | ||
| 5051 | //return values[a_index].count > values[b_index].count; | ||
| 5052 | } | ||
| 5053 | }; | ||
| 5054 | counts.sort(SortContext{ .map = &counts }); | ||
| 5055 | const len = @min(50, counts.count()); | ||
| 5056 | std.debug.print(" top 50 tags:\n", .{}); | ||
| 5057 | for (counts.keys()[0..len], counts.values()[0..len]) |tag, stats| { | ||
| 5058 | std.debug.print(" {s}: {d} occurrences, {d} total bytes\n", .{ | ||
| 5059 | @tagName(tag), stats.count, stats.bytes, | ||
| 5060 | }); | ||
| 5061 | } | ||
| 5062 | } | ||
| 5063 | |||
| 5064 | fn dumpAllFallible(ip: *const InternPool) anyerror!void { | ||
| 5065 | const tags = ip.items.items(.tag); | ||
| 5066 | const datas = ip.items.items(.data); | ||
| 5067 | var bw = std.io.bufferedWriter(std.io.getStdErr().writer()); | ||
| 5068 | const w = bw.writer(); | ||
| 5069 | for (tags, datas, 0..) |tag, data, i| { | ||
| 5070 | try w.print("${d} = {s}(", .{ i, @tagName(tag) }); | ||
| 5071 | switch (tag) { | ||
| 5072 | .simple_type => try w.print("{s}", .{@tagName(@intToEnum(SimpleType, data))}), | ||
| 5073 | .simple_value => try w.print("{s}", .{@tagName(@intToEnum(SimpleValue, data))}), | ||
| 5074 | |||
| 5075 | .type_int_signed, | ||
| 5076 | .type_int_unsigned, | ||
| 5077 | .type_array_small, | ||
| 5078 | .type_array_big, | ||
| 5079 | .type_vector, | ||
| 5080 | .type_pointer, | ||
| 5081 | .type_optional, | ||
| 5082 | .type_anyframe, | ||
| 5083 | .type_error_union, | ||
| 5084 | .type_error_set, | ||
| 5085 | .type_inferred_error_set, | ||
| 5086 | .type_enum_explicit, | ||
| 5087 | .type_enum_nonexhaustive, | ||
| 5088 | .type_enum_auto, | ||
| 5089 | .type_opaque, | ||
| 5090 | .type_struct, | ||
| 5091 | .type_struct_ns, | ||
| 5092 | .type_struct_anon, | ||
| 5093 | .type_tuple_anon, | ||
| 5094 | .type_union_tagged, | ||
| 5095 | .type_union_untagged, | ||
| 5096 | .type_union_safety, | ||
| 5097 | .type_function, | ||
| 5098 | .undef, | ||
| 5099 | .runtime_value, | ||
| 5100 | .ptr_decl, | ||
| 5101 | .ptr_mut_decl, | ||
| 5102 | .ptr_comptime_field, | ||
| 5103 | .ptr_int, | ||
| 5104 | .ptr_eu_payload, | ||
| 5105 | .ptr_opt_payload, | ||
| 5106 | .ptr_elem, | ||
| 5107 | .ptr_field, | ||
| 5108 | .ptr_slice, | ||
| 5109 | .opt_payload, | ||
| 5110 | .int_u8, | ||
| 5111 | .int_u16, | ||
| 5112 | .int_u32, | ||
| 5113 | .int_i32, | ||
| 5114 | .int_usize, | ||
| 5115 | .int_comptime_int_u32, | ||
| 5116 | .int_comptime_int_i32, | ||
| 5117 | .int_small, | ||
| 5118 | .int_positive, | ||
| 5119 | .int_negative, | ||
| 5120 | .int_lazy_align, | ||
| 5121 | .int_lazy_size, | ||
| 5122 | .error_set_error, | ||
| 5123 | .error_union_error, | ||
| 5124 | .error_union_payload, | ||
| 5125 | .enum_literal, | ||
| 5126 | .enum_tag, | ||
| 5127 | .bytes, | ||
| 5128 | .aggregate, | ||
| 5129 | .repeated, | ||
| 5130 | .float_f16, | ||
| 5131 | .float_f32, | ||
| 5132 | .float_f64, | ||
| 5133 | .float_f80, | ||
| 5134 | .float_f128, | ||
| 5135 | .float_c_longdouble_f80, | ||
| 5136 | .float_c_longdouble_f128, | ||
| 5137 | .float_comptime_float, | ||
| 5138 | .variable, | ||
| 5139 | .extern_func, | ||
| 5140 | .func, | ||
| 5141 | .union_value, | ||
| 5142 | .memoized_call, | ||
| 5143 | => try w.print("{d}", .{data}), | ||
| 5144 | |||
| 5145 | .opt_null, | ||
| 5146 | .type_slice, | ||
| 5147 | .only_possible_value, | ||
| 5148 | => try w.print("${d}", .{data}), | ||
| 5149 | } | ||
| 5150 | try w.writeAll(")\n"); | ||
| 5151 | } | ||
| 5152 | try bw.flush(); | ||
| 5153 | } | ||
| 5154 | |||
| 5155 | pub fn structPtr(ip: *InternPool, index: Module.Struct.Index) *Module.Struct { | ||
| 5156 | return ip.allocated_structs.at(@enumToInt(index)); | ||
| 5157 | } | ||
| 5158 | |||
| 5159 | pub fn structPtrConst(ip: *const InternPool, index: Module.Struct.Index) *const Module.Struct { | ||
| 5160 | return ip.allocated_structs.at(@enumToInt(index)); | ||
| 5161 | } | ||
| 5162 | |||
| 5163 | pub fn structPtrUnwrapConst(ip: *const InternPool, index: Module.Struct.OptionalIndex) ?*const Module.Struct { | ||
| 5164 | return structPtrConst(ip, index.unwrap() orelse return null); | ||
| 5165 | } | ||
| 5166 | |||
| 5167 | pub fn unionPtr(ip: *InternPool, index: Module.Union.Index) *Module.Union { | ||
| 5168 | return ip.allocated_unions.at(@enumToInt(index)); | ||
| 5169 | } | ||
| 5170 | |||
| 5171 | pub fn unionPtrConst(ip: *const InternPool, index: Module.Union.Index) *const Module.Union { | ||
| 5172 | return ip.allocated_unions.at(@enumToInt(index)); | ||
| 5173 | } | ||
| 5174 | |||
| 5175 | pub fn funcPtr(ip: *InternPool, index: Module.Fn.Index) *Module.Fn { | ||
| 5176 | return ip.allocated_funcs.at(@enumToInt(index)); | ||
| 5177 | } | ||
| 5178 | |||
| 5179 | pub fn funcPtrConst(ip: *const InternPool, index: Module.Fn.Index) *const Module.Fn { | ||
| 5180 | return ip.allocated_funcs.at(@enumToInt(index)); | ||
| 5181 | } | ||
| 5182 | |||
| 5183 | pub fn inferredErrorSetPtr(ip: *InternPool, index: Module.Fn.InferredErrorSet.Index) *Module.Fn.InferredErrorSet { | ||
| 5184 | return ip.allocated_inferred_error_sets.at(@enumToInt(index)); | ||
| 5185 | } | ||
| 5186 | |||
| 5187 | pub fn inferredErrorSetPtrConst(ip: *const InternPool, index: Module.Fn.InferredErrorSet.Index) *const Module.Fn.InferredErrorSet { | ||
| 5188 | return ip.allocated_inferred_error_sets.at(@enumToInt(index)); | ||
| 5189 | } | ||
| 5190 | |||
| 5191 | pub fn createStruct( | ||
| 5192 | ip: *InternPool, | ||
| 5193 | gpa: Allocator, | ||
| 5194 | initialization: Module.Struct, | ||
| 5195 | ) Allocator.Error!Module.Struct.Index { | ||
| 5196 | if (ip.structs_free_list.popOrNull()) |index| { | ||
| 5197 | ip.allocated_structs.at(@enumToInt(index)).* = initialization; | ||
| 5198 | return index; | ||
| 5199 | } | ||
| 5200 | const ptr = try ip.allocated_structs.addOne(gpa); | ||
| 5201 | ptr.* = initialization; | ||
| 5202 | return @intToEnum(Module.Struct.Index, ip.allocated_structs.len - 1); | ||
| 5203 | } | ||
| 5204 | |||
| 5205 | pub fn destroyStruct(ip: *InternPool, gpa: Allocator, index: Module.Struct.Index) void { | ||
| 5206 | ip.structPtr(index).* = undefined; | ||
| 5207 | ip.structs_free_list.append(gpa, index) catch { | ||
| 5208 | // In order to keep `destroyStruct` a non-fallible function, we ignore memory | ||
| 5209 | // allocation failures here, instead leaking the Struct until garbage collection. | ||
| 5210 | }; | ||
| 5211 | } | ||
| 5212 | |||
| 5213 | pub fn createUnion( | ||
| 5214 | ip: *InternPool, | ||
| 5215 | gpa: Allocator, | ||
| 5216 | initialization: Module.Union, | ||
| 5217 | ) Allocator.Error!Module.Union.Index { | ||
| 5218 | if (ip.unions_free_list.popOrNull()) |index| { | ||
| 5219 | ip.allocated_unions.at(@enumToInt(index)).* = initialization; | ||
| 5220 | return index; | ||
| 5221 | } | ||
| 5222 | const ptr = try ip.allocated_unions.addOne(gpa); | ||
| 5223 | ptr.* = initialization; | ||
| 5224 | return @intToEnum(Module.Union.Index, ip.allocated_unions.len - 1); | ||
| 5225 | } | ||
| 5226 | |||
| 5227 | pub fn destroyUnion(ip: *InternPool, gpa: Allocator, index: Module.Union.Index) void { | ||
| 5228 | ip.unionPtr(index).* = undefined; | ||
| 5229 | ip.unions_free_list.append(gpa, index) catch { | ||
| 5230 | // In order to keep `destroyUnion` a non-fallible function, we ignore memory | ||
| 5231 | // allocation failures here, instead leaking the Union until garbage collection. | ||
| 5232 | }; | ||
| 5233 | } | ||
| 5234 | |||
| 5235 | pub fn createFunc( | ||
| 5236 | ip: *InternPool, | ||
| 5237 | gpa: Allocator, | ||
| 5238 | initialization: Module.Fn, | ||
| 5239 | ) Allocator.Error!Module.Fn.Index { | ||
| 5240 | if (ip.funcs_free_list.popOrNull()) |index| { | ||
| 5241 | ip.allocated_funcs.at(@enumToInt(index)).* = initialization; | ||
| 5242 | return index; | ||
| 5243 | } | ||
| 5244 | const ptr = try ip.allocated_funcs.addOne(gpa); | ||
| 5245 | ptr.* = initialization; | ||
| 5246 | return @intToEnum(Module.Fn.Index, ip.allocated_funcs.len - 1); | ||
| 5247 | } | ||
| 5248 | |||
| 5249 | pub fn destroyFunc(ip: *InternPool, gpa: Allocator, index: Module.Fn.Index) void { | ||
| 5250 | ip.funcPtr(index).* = undefined; | ||
| 5251 | ip.funcs_free_list.append(gpa, index) catch { | ||
| 5252 | // In order to keep `destroyFunc` a non-fallible function, we ignore memory | ||
| 5253 | // allocation failures here, instead leaking the Fn until garbage collection. | ||
| 5254 | }; | ||
| 5255 | } | ||
| 5256 | |||
| 5257 | pub fn createInferredErrorSet( | ||
| 5258 | ip: *InternPool, | ||
| 5259 | gpa: Allocator, | ||
| 5260 | initialization: Module.Fn.InferredErrorSet, | ||
| 5261 | ) Allocator.Error!Module.Fn.InferredErrorSet.Index { | ||
| 5262 | if (ip.inferred_error_sets_free_list.popOrNull()) |index| { | ||
| 5263 | ip.allocated_inferred_error_sets.at(@enumToInt(index)).* = initialization; | ||
| 5264 | return index; | ||
| 5265 | } | ||
| 5266 | const ptr = try ip.allocated_inferred_error_sets.addOne(gpa); | ||
| 5267 | ptr.* = initialization; | ||
| 5268 | return @intToEnum(Module.Fn.InferredErrorSet.Index, ip.allocated_inferred_error_sets.len - 1); | ||
| 5269 | } | ||
| 5270 | |||
| 5271 | pub fn destroyInferredErrorSet(ip: *InternPool, gpa: Allocator, index: Module.Fn.InferredErrorSet.Index) void { | ||
| 5272 | ip.inferredErrorSetPtr(index).* = undefined; | ||
| 5273 | ip.inferred_error_sets_free_list.append(gpa, index) catch { | ||
| 5274 | // In order to keep `destroyInferredErrorSet` a non-fallible function, we ignore memory | ||
| 5275 | // allocation failures here, instead leaking the InferredErrorSet until garbage collection. | ||
| 5276 | }; | ||
| 5277 | } | ||
| 5278 | |||
| 5279 | pub fn getOrPutString( | ||
| 5280 | ip: *InternPool, | ||
| 5281 | gpa: Allocator, | ||
| 5282 | s: []const u8, | ||
| 5283 | ) Allocator.Error!NullTerminatedString { | ||
| 5284 | try ip.string_bytes.ensureUnusedCapacity(gpa, s.len + 1); | ||
| 5285 | ip.string_bytes.appendSliceAssumeCapacity(s); | ||
| 5286 | ip.string_bytes.appendAssumeCapacity(0); | ||
| 5287 | return ip.getOrPutTrailingString(gpa, s.len + 1); | ||
| 5288 | } | ||
| 5289 | |||
| 5290 | pub fn getOrPutStringFmt( | ||
| 5291 | ip: *InternPool, | ||
| 5292 | gpa: Allocator, | ||
| 5293 | comptime format: []const u8, | ||
| 5294 | args: anytype, | ||
| 5295 | ) Allocator.Error!NullTerminatedString { | ||
| 5296 | // ensure that references to string_bytes in args do not get invalidated | ||
| 5297 | const len = @intCast(usize, std.fmt.count(format, args) + 1); | ||
| 5298 | try ip.string_bytes.ensureUnusedCapacity(gpa, len); | ||
| 5299 | ip.string_bytes.writer(undefined).print(format, args) catch unreachable; | ||
| 5300 | ip.string_bytes.appendAssumeCapacity(0); | ||
| 5301 | return ip.getOrPutTrailingString(gpa, len); | ||
| 5302 | } | ||
| 5303 | |||
| 5304 | pub fn getOrPutStringOpt( | ||
| 5305 | ip: *InternPool, | ||
| 5306 | gpa: Allocator, | ||
| 5307 | optional_string: ?[]const u8, | ||
| 5308 | ) Allocator.Error!OptionalNullTerminatedString { | ||
| 5309 | const s = optional_string orelse return .none; | ||
| 5310 | const interned = try getOrPutString(ip, gpa, s); | ||
| 5311 | return interned.toOptional(); | ||
| 5312 | } | ||
| 5313 | |||
| 5314 | /// Uses the last len bytes of ip.string_bytes as the key. | ||
| 5315 | pub fn getOrPutTrailingString( | ||
| 5316 | ip: *InternPool, | ||
| 5317 | gpa: Allocator, | ||
| 5318 | len: usize, | ||
| 5319 | ) Allocator.Error!NullTerminatedString { | ||
| 5320 | const string_bytes = &ip.string_bytes; | ||
| 5321 | const str_index = @intCast(u32, string_bytes.items.len - len); | ||
| 5322 | if (len > 0 and string_bytes.getLast() == 0) { | ||
| 5323 | _ = string_bytes.pop(); | ||
| 5324 | } else { | ||
| 5325 | try string_bytes.ensureUnusedCapacity(gpa, 1); | ||
| 5326 | } | ||
| 5327 | const key: []const u8 = string_bytes.items[str_index..]; | ||
| 5328 | const gop = try ip.string_table.getOrPutContextAdapted(gpa, key, std.hash_map.StringIndexAdapter{ | ||
| 5329 | .bytes = string_bytes, | ||
| 5330 | }, std.hash_map.StringIndexContext{ | ||
| 5331 | .bytes = string_bytes, | ||
| 5332 | }); | ||
| 5333 | if (gop.found_existing) { | ||
| 5334 | string_bytes.shrinkRetainingCapacity(str_index); | ||
| 5335 | return @intToEnum(NullTerminatedString, gop.key_ptr.*); | ||
| 5336 | } else { | ||
| 5337 | gop.key_ptr.* = str_index; | ||
| 5338 | string_bytes.appendAssumeCapacity(0); | ||
| 5339 | return @intToEnum(NullTerminatedString, str_index); | ||
| 5340 | } | ||
| 5341 | } | ||
| 5342 | |||
| 5343 | pub fn getString(ip: *InternPool, s: []const u8) OptionalNullTerminatedString { | ||
| 5344 | if (ip.string_table.getKeyAdapted(s, std.hash_map.StringIndexAdapter{ | ||
| 5345 | .bytes = &ip.string_bytes, | ||
| 5346 | })) |index| { | ||
| 5347 | return @intToEnum(NullTerminatedString, index).toOptional(); | ||
| 5348 | } else { | ||
| 5349 | return .none; | ||
| 5350 | } | ||
| 5351 | } | ||
| 5352 | |||
| 5353 | pub fn stringToSlice(ip: *const InternPool, s: NullTerminatedString) [:0]const u8 { | ||
| 5354 | const string_bytes = ip.string_bytes.items; | ||
| 5355 | const start = @enumToInt(s); | ||
| 5356 | var end: usize = start; | ||
| 5357 | while (string_bytes[end] != 0) end += 1; | ||
| 5358 | return string_bytes[start..end :0]; | ||
| 5359 | } | ||
| 5360 | |||
| 5361 | pub fn stringToSliceUnwrap(ip: *const InternPool, s: OptionalNullTerminatedString) ?[:0]const u8 { | ||
| 5362 | return ip.stringToSlice(s.unwrap() orelse return null); | ||
| 5363 | } | ||
| 5364 | |||
| 5365 | pub fn stringEqlSlice(ip: *const InternPool, a: NullTerminatedString, b: []const u8) bool { | ||
| 5366 | return std.mem.eql(u8, stringToSlice(ip, a), b); | ||
| 5367 | } | ||
| 5368 | |||
| 5369 | pub fn typeOf(ip: *const InternPool, index: Index) Index { | ||
| 5370 | // This optimization of static keys is required so that typeOf can be called | ||
| 5371 | // on static keys that haven't been added yet during static key initialization. | ||
| 5372 | // An alternative would be to topological sort the static keys, but this would | ||
| 5373 | // mean that the range of type indices would not be dense. | ||
| 5374 | return switch (index) { | ||
| 5375 | .u1_type, | ||
| 5376 | .u8_type, | ||
| 5377 | .i8_type, | ||
| 5378 | .u16_type, | ||
| 5379 | .i16_type, | ||
| 5380 | .u29_type, | ||
| 5381 | .u32_type, | ||
| 5382 | .i32_type, | ||
| 5383 | .u64_type, | ||
| 5384 | .i64_type, | ||
| 5385 | .u80_type, | ||
| 5386 | .u128_type, | ||
| 5387 | .i128_type, | ||
| 5388 | .usize_type, | ||
| 5389 | .isize_type, | ||
| 5390 | .c_char_type, | ||
| 5391 | .c_short_type, | ||
| 5392 | .c_ushort_type, | ||
| 5393 | .c_int_type, | ||
| 5394 | .c_uint_type, | ||
| 5395 | .c_long_type, | ||
| 5396 | .c_ulong_type, | ||
| 5397 | .c_longlong_type, | ||
| 5398 | .c_ulonglong_type, | ||
| 5399 | .c_longdouble_type, | ||
| 5400 | .f16_type, | ||
| 5401 | .f32_type, | ||
| 5402 | .f64_type, | ||
| 5403 | .f80_type, | ||
| 5404 | .f128_type, | ||
| 5405 | .anyopaque_type, | ||
| 5406 | .bool_type, | ||
| 5407 | .void_type, | ||
| 5408 | .type_type, | ||
| 5409 | .anyerror_type, | ||
| 5410 | .comptime_int_type, | ||
| 5411 | .comptime_float_type, | ||
| 5412 | .noreturn_type, | ||
| 5413 | .anyframe_type, | ||
| 5414 | .null_type, | ||
| 5415 | .undefined_type, | ||
| 5416 | .enum_literal_type, | ||
| 5417 | .atomic_order_type, | ||
| 5418 | .atomic_rmw_op_type, | ||
| 5419 | .calling_convention_type, | ||
| 5420 | .address_space_type, | ||
| 5421 | .float_mode_type, | ||
| 5422 | .reduce_op_type, | ||
| 5423 | .call_modifier_type, | ||
| 5424 | .prefetch_options_type, | ||
| 5425 | .export_options_type, | ||
| 5426 | .extern_options_type, | ||
| 5427 | .type_info_type, | ||
| 5428 | .manyptr_u8_type, | ||
| 5429 | .manyptr_const_u8_type, | ||
| 5430 | .manyptr_const_u8_sentinel_0_type, | ||
| 5431 | .single_const_pointer_to_comptime_int_type, | ||
| 5432 | .slice_const_u8_type, | ||
| 5433 | .slice_const_u8_sentinel_0_type, | ||
| 5434 | .anyerror_void_error_union_type, | ||
| 5435 | .generic_poison_type, | ||
| 5436 | .empty_struct_type, | ||
| 5437 | => .type_type, | ||
| 5438 | |||
| 5439 | .undef => .undefined_type, | ||
| 5440 | .zero, .one, .negative_one => .comptime_int_type, | ||
| 5441 | .zero_usize, .one_usize => .usize_type, | ||
| 5442 | .zero_u8, .one_u8, .four_u8 => .u8_type, | ||
| 5443 | .calling_convention_c, .calling_convention_inline => .calling_convention_type, | ||
| 5444 | .void_value => .void_type, | ||
| 5445 | .unreachable_value => .noreturn_type, | ||
| 5446 | .null_value => .null_type, | ||
| 5447 | .bool_true, .bool_false => .bool_type, | ||
| 5448 | .empty_struct => .empty_struct_type, | ||
| 5449 | .generic_poison => .generic_poison_type, | ||
| 5450 | |||
| 5451 | // This optimization on tags is needed so that indexToKey can call | ||
| 5452 | // typeOf without being recursive. | ||
| 5453 | _ => switch (ip.items.items(.tag)[@enumToInt(index)]) { | ||
| 5454 | .type_int_signed, | ||
| 5455 | .type_int_unsigned, | ||
| 5456 | .type_array_big, | ||
| 5457 | .type_array_small, | ||
| 5458 | .type_vector, | ||
| 5459 | .type_pointer, | ||
| 5460 | .type_slice, | ||
| 5461 | .type_optional, | ||
| 5462 | .type_anyframe, | ||
| 5463 | .type_error_union, | ||
| 5464 | .type_error_set, | ||
| 5465 | .type_inferred_error_set, | ||
| 5466 | .type_enum_auto, | ||
| 5467 | .type_enum_explicit, | ||
| 5468 | .type_enum_nonexhaustive, | ||
| 5469 | .simple_type, | ||
| 5470 | .type_opaque, | ||
| 5471 | .type_struct, | ||
| 5472 | .type_struct_ns, | ||
| 5473 | .type_struct_anon, | ||
| 5474 | .type_tuple_anon, | ||
| 5475 | .type_union_tagged, | ||
| 5476 | .type_union_untagged, | ||
| 5477 | .type_union_safety, | ||
| 5478 | .type_function, | ||
| 5479 | => .type_type, | ||
| 5480 | |||
| 5481 | .undef, | ||
| 5482 | .opt_null, | ||
| 5483 | .only_possible_value, | ||
| 5484 | => @intToEnum(Index, ip.items.items(.data)[@enumToInt(index)]), | ||
| 5485 | |||
| 5486 | .simple_value => unreachable, // handled via Index above | ||
| 5487 | |||
| 5488 | inline .ptr_decl, | ||
| 5489 | .ptr_mut_decl, | ||
| 5490 | .ptr_comptime_field, | ||
| 5491 | .ptr_int, | ||
| 5492 | .ptr_eu_payload, | ||
| 5493 | .ptr_opt_payload, | ||
| 5494 | .ptr_elem, | ||
| 5495 | .ptr_field, | ||
| 5496 | .ptr_slice, | ||
| 5497 | .opt_payload, | ||
| 5498 | .error_union_payload, | ||
| 5499 | .runtime_value, | ||
| 5500 | .int_small, | ||
| 5501 | .int_lazy_align, | ||
| 5502 | .int_lazy_size, | ||
| 5503 | .error_set_error, | ||
| 5504 | .error_union_error, | ||
| 5505 | .enum_tag, | ||
| 5506 | .variable, | ||
| 5507 | .extern_func, | ||
| 5508 | .func, | ||
| 5509 | .union_value, | ||
| 5510 | .bytes, | ||
| 5511 | .aggregate, | ||
| 5512 | .repeated, | ||
| 5513 | => |t| { | ||
| 5514 | const extra_index = ip.items.items(.data)[@enumToInt(index)]; | ||
| 5515 | const field_index = std.meta.fieldIndex(t.Payload(), "ty").?; | ||
| 5516 | return @intToEnum(Index, ip.extra.items[extra_index + field_index]); | ||
| 5517 | }, | ||
| 5518 | |||
| 5519 | .int_u8 => .u8_type, | ||
| 5520 | .int_u16 => .u16_type, | ||
| 5521 | .int_u32 => .u32_type, | ||
| 5522 | .int_i32 => .i32_type, | ||
| 5523 | .int_usize => .usize_type, | ||
| 5524 | |||
| 5525 | .int_comptime_int_u32, | ||
| 5526 | .int_comptime_int_i32, | ||
| 5527 | => .comptime_int_type, | ||
| 5528 | |||
| 5529 | // Note these are stored in limbs data, not extra data. | ||
| 5530 | .int_positive, | ||
| 5531 | .int_negative, | ||
| 5532 | => ip.limbData(Int, ip.items.items(.data)[@enumToInt(index)]).ty, | ||
| 5533 | |||
| 5534 | .enum_literal => .enum_literal_type, | ||
| 5535 | .float_f16 => .f16_type, | ||
| 5536 | .float_f32 => .f32_type, | ||
| 5537 | .float_f64 => .f64_type, | ||
| 5538 | .float_f80 => .f80_type, | ||
| 5539 | .float_f128 => .f128_type, | ||
| 5540 | |||
| 5541 | .float_c_longdouble_f80, | ||
| 5542 | .float_c_longdouble_f128, | ||
| 5543 | => .c_longdouble_type, | ||
| 5544 | |||
| 5545 | .float_comptime_float => .comptime_float_type, | ||
| 5546 | |||
| 5547 | .memoized_call => unreachable, | ||
| 5548 | }, | ||
| 5549 | |||
| 5550 | .var_args_param_type => unreachable, | ||
| 5551 | .none => unreachable, | ||
| 5552 | }; | ||
| 5553 | } | ||
| 5554 | |||
| 5555 | /// Assumes that the enum's field indexes equal its value tags. | ||
| 5556 | pub fn toEnum(ip: *const InternPool, comptime E: type, i: Index) E { | ||
| 5557 | const int = ip.indexToKey(i).enum_tag.int; | ||
| 5558 | return @intToEnum(E, ip.indexToKey(int).int.storage.u64); | ||
| 5559 | } | ||
| 5560 | |||
| 5561 | pub fn aggregateTypeLen(ip: *const InternPool, ty: Index) u64 { | ||
| 5562 | return switch (ip.indexToKey(ty)) { | ||
| 5563 | .struct_type => |struct_type| ip.structPtrConst(struct_type.index.unwrap() orelse return 0).fields.count(), | ||
| 5564 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, | ||
| 5565 | .array_type => |array_type| array_type.len, | ||
| 5566 | .vector_type => |vector_type| vector_type.len, | ||
| 5567 | else => unreachable, | ||
| 5568 | }; | ||
| 5569 | } | ||
| 5570 | |||
| 5571 | pub fn aggregateTypeLenIncludingSentinel(ip: *const InternPool, ty: Index) u64 { | ||
| 5572 | return switch (ip.indexToKey(ty)) { | ||
| 5573 | .struct_type => |struct_type| ip.structPtrConst(struct_type.index.unwrap() orelse return 0).fields.count(), | ||
| 5574 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, | ||
| 5575 | .array_type => |array_type| array_type.len + @boolToInt(array_type.sentinel != .none), | ||
| 5576 | .vector_type => |vector_type| vector_type.len, | ||
| 5577 | else => unreachable, | ||
| 5578 | }; | ||
| 5579 | } | ||
| 5580 | |||
| 5581 | pub fn isNoReturn(ip: *const InternPool, ty: Index) bool { | ||
| 5582 | return switch (ty) { | ||
| 5583 | .noreturn_type => true, | ||
| 5584 | else => switch (ip.indexToKey(ty)) { | ||
| 5585 | .error_set_type => |error_set_type| error_set_type.names.len == 0, | ||
| 5586 | else => false, | ||
| 5587 | }, | ||
| 5588 | }; | ||
| 5589 | } | ||
| 5590 | |||
| 5591 | /// This is a particularly hot function, so we operate directly on encodings | ||
| 5592 | /// rather than the more straightforward implementation of calling `indexToKey`. | ||
| 5593 | pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPoison}!std.builtin.TypeId { | ||
| 5594 | return switch (index) { | ||
| 5595 | .u1_type, | ||
| 5596 | .u8_type, | ||
| 5597 | .i8_type, | ||
| 5598 | .u16_type, | ||
| 5599 | .i16_type, | ||
| 5600 | .u29_type, | ||
| 5601 | .u32_type, | ||
| 5602 | .i32_type, | ||
| 5603 | .u64_type, | ||
| 5604 | .i64_type, | ||
| 5605 | .u80_type, | ||
| 5606 | .u128_type, | ||
| 5607 | .i128_type, | ||
| 5608 | .usize_type, | ||
| 5609 | .isize_type, | ||
| 5610 | .c_char_type, | ||
| 5611 | .c_short_type, | ||
| 5612 | .c_ushort_type, | ||
| 5613 | .c_int_type, | ||
| 5614 | .c_uint_type, | ||
| 5615 | .c_long_type, | ||
| 5616 | .c_ulong_type, | ||
| 5617 | .c_longlong_type, | ||
| 5618 | .c_ulonglong_type, | ||
| 5619 | => .Int, | ||
| 5620 | |||
| 5621 | .c_longdouble_type, | ||
| 5622 | .f16_type, | ||
| 5623 | .f32_type, | ||
| 5624 | .f64_type, | ||
| 5625 | .f80_type, | ||
| 5626 | .f128_type, | ||
| 5627 | => .Float, | ||
| 5628 | |||
| 5629 | .anyopaque_type => .Opaque, | ||
| 5630 | .bool_type => .Bool, | ||
| 5631 | .void_type => .Void, | ||
| 5632 | .type_type => .Type, | ||
| 5633 | .anyerror_type => .ErrorSet, | ||
| 5634 | .comptime_int_type => .ComptimeInt, | ||
| 5635 | .comptime_float_type => .ComptimeFloat, | ||
| 5636 | .noreturn_type => .NoReturn, | ||
| 5637 | .anyframe_type => .AnyFrame, | ||
| 5638 | .null_type => .Null, | ||
| 5639 | .undefined_type => .Undefined, | ||
| 5640 | .enum_literal_type => .EnumLiteral, | ||
| 5641 | |||
| 5642 | .atomic_order_type, | ||
| 5643 | .atomic_rmw_op_type, | ||
| 5644 | .calling_convention_type, | ||
| 5645 | .address_space_type, | ||
| 5646 | .float_mode_type, | ||
| 5647 | .reduce_op_type, | ||
| 5648 | .call_modifier_type, | ||
| 5649 | => .Enum, | ||
| 5650 | |||
| 5651 | .prefetch_options_type, | ||
| 5652 | .export_options_type, | ||
| 5653 | .extern_options_type, | ||
| 5654 | => .Struct, | ||
| 5655 | |||
| 5656 | .type_info_type => .Union, | ||
| 5657 | |||
| 5658 | .manyptr_u8_type, | ||
| 5659 | .manyptr_const_u8_type, | ||
| 5660 | .manyptr_const_u8_sentinel_0_type, | ||
| 5661 | .single_const_pointer_to_comptime_int_type, | ||
| 5662 | .slice_const_u8_type, | ||
| 5663 | .slice_const_u8_sentinel_0_type, | ||
| 5664 | => .Pointer, | ||
| 5665 | |||
| 5666 | .anyerror_void_error_union_type => .ErrorUnion, | ||
| 5667 | .empty_struct_type => .Struct, | ||
| 5668 | |||
| 5669 | .generic_poison_type => return error.GenericPoison, | ||
| 5670 | |||
| 5671 | // values, not types | ||
| 5672 | .undef => unreachable, | ||
| 5673 | .zero => unreachable, | ||
| 5674 | .zero_usize => unreachable, | ||
| 5675 | .zero_u8 => unreachable, | ||
| 5676 | .one => unreachable, | ||
| 5677 | .one_usize => unreachable, | ||
| 5678 | .one_u8 => unreachable, | ||
| 5679 | .four_u8 => unreachable, | ||
| 5680 | .negative_one => unreachable, | ||
| 5681 | .calling_convention_c => unreachable, | ||
| 5682 | .calling_convention_inline => unreachable, | ||
| 5683 | .void_value => unreachable, | ||
| 5684 | .unreachable_value => unreachable, | ||
| 5685 | .null_value => unreachable, | ||
| 5686 | .bool_true => unreachable, | ||
| 5687 | .bool_false => unreachable, | ||
| 5688 | .empty_struct => unreachable, | ||
| 5689 | .generic_poison => unreachable, | ||
| 5690 | |||
| 5691 | .var_args_param_type => unreachable, // special tag | ||
| 5692 | |||
| 5693 | _ => switch (ip.items.items(.tag)[@enumToInt(index)]) { | ||
| 5694 | .type_int_signed, | ||
| 5695 | .type_int_unsigned, | ||
| 5696 | => .Int, | ||
| 5697 | |||
| 5698 | .type_array_big, | ||
| 5699 | .type_array_small, | ||
| 5700 | => .Array, | ||
| 5701 | |||
| 5702 | .type_vector => .Vector, | ||
| 5703 | |||
| 5704 | .type_pointer, | ||
| 5705 | .type_slice, | ||
| 5706 | => .Pointer, | ||
| 5707 | |||
| 5708 | .type_optional => .Optional, | ||
| 5709 | .type_anyframe => .AnyFrame, | ||
| 5710 | .type_error_union => .ErrorUnion, | ||
| 5711 | |||
| 5712 | .type_error_set, | ||
| 5713 | .type_inferred_error_set, | ||
| 5714 | => .ErrorSet, | ||
| 5715 | |||
| 5716 | .type_enum_auto, | ||
| 5717 | .type_enum_explicit, | ||
| 5718 | .type_enum_nonexhaustive, | ||
| 5719 | => .Enum, | ||
| 5720 | |||
| 5721 | .simple_type => unreachable, // handled via Index tag above | ||
| 5722 | |||
| 5723 | .type_opaque => .Opaque, | ||
| 5724 | |||
| 5725 | .type_struct, | ||
| 5726 | .type_struct_ns, | ||
| 5727 | .type_struct_anon, | ||
| 5728 | .type_tuple_anon, | ||
| 5729 | => .Struct, | ||
| 5730 | |||
| 5731 | .type_union_tagged, | ||
| 5732 | .type_union_untagged, | ||
| 5733 | .type_union_safety, | ||
| 5734 | => .Union, | ||
| 5735 | |||
| 5736 | .type_function => .Fn, | ||
| 5737 | |||
| 5738 | // values, not types | ||
| 5739 | .undef, | ||
| 5740 | .runtime_value, | ||
| 5741 | .simple_value, | ||
| 5742 | .ptr_decl, | ||
| 5743 | .ptr_mut_decl, | ||
| 5744 | .ptr_comptime_field, | ||
| 5745 | .ptr_int, | ||
| 5746 | .ptr_eu_payload, | ||
| 5747 | .ptr_opt_payload, | ||
| 5748 | .ptr_elem, | ||
| 5749 | .ptr_field, | ||
| 5750 | .ptr_slice, | ||
| 5751 | .opt_payload, | ||
| 5752 | .opt_null, | ||
| 5753 | .int_u8, | ||
| 5754 | .int_u16, | ||
| 5755 | .int_u32, | ||
| 5756 | .int_i32, | ||
| 5757 | .int_usize, | ||
| 5758 | .int_comptime_int_u32, | ||
| 5759 | .int_comptime_int_i32, | ||
| 5760 | .int_small, | ||
| 5761 | .int_positive, | ||
| 5762 | .int_negative, | ||
| 5763 | .int_lazy_align, | ||
| 5764 | .int_lazy_size, | ||
| 5765 | .error_set_error, | ||
| 5766 | .error_union_error, | ||
| 5767 | .error_union_payload, | ||
| 5768 | .enum_literal, | ||
| 5769 | .enum_tag, | ||
| 5770 | .float_f16, | ||
| 5771 | .float_f32, | ||
| 5772 | .float_f64, | ||
| 5773 | .float_f80, | ||
| 5774 | .float_f128, | ||
| 5775 | .float_c_longdouble_f80, | ||
| 5776 | .float_c_longdouble_f128, | ||
| 5777 | .float_comptime_float, | ||
| 5778 | .variable, | ||
| 5779 | .extern_func, | ||
| 5780 | .func, | ||
| 5781 | .only_possible_value, | ||
| 5782 | .union_value, | ||
| 5783 | .bytes, | ||
| 5784 | .aggregate, | ||
| 5785 | .repeated, | ||
| 5786 | // memoization, not types | ||
| 5787 | .memoized_call, | ||
| 5788 | => unreachable, | ||
| 5789 | }, | ||
| 5790 | .none => unreachable, // special tag | ||
| 5791 | }; | ||
| 316 | } | 5792 | } |
src/Liveness.zig+27-29| ... | @@ -5,15 +5,17 @@ | ... | @@ -5,15 +5,17 @@ |
| 5 | //! Some instructions are special, such as: | 5 | //! Some instructions are special, such as: |
| 6 | //! * Conditional Branches | 6 | //! * Conditional Branches |
| 7 | //! * Switch Branches | 7 | //! * Switch Branches |
| 8 | const Liveness = @This(); | ||
| 9 | const std = @import("std"); | 8 | const std = @import("std"); |
| 10 | const trace = @import("tracy.zig").trace; | ||
| 11 | const log = std.log.scoped(.liveness); | 9 | const log = std.log.scoped(.liveness); |
| 12 | const assert = std.debug.assert; | 10 | const assert = std.debug.assert; |
| 13 | const Allocator = std.mem.Allocator; | 11 | const Allocator = std.mem.Allocator; |
| 14 | const Air = @import("Air.zig"); | ||
| 15 | const Log2Int = std.math.Log2Int; | 12 | const Log2Int = std.math.Log2Int; |
| 16 | 13 | ||
| 14 | const Liveness = @This(); | ||
| 15 | const trace = @import("tracy.zig").trace; | ||
| 16 | const Air = @import("Air.zig"); | ||
| 17 | const InternPool = @import("InternPool.zig"); | ||
| 18 | |||
| 17 | pub const Verify = @import("Liveness/Verify.zig"); | 19 | pub const Verify = @import("Liveness/Verify.zig"); |
| 18 | 20 | ||
| 19 | /// This array is split into sets of 4 bits per AIR instruction. | 21 | /// This array is split into sets of 4 bits per AIR instruction. |
| ... | @@ -129,7 +131,7 @@ fn LivenessPassData(comptime pass: LivenessPass) type { | ... | @@ -129,7 +131,7 @@ fn LivenessPassData(comptime pass: LivenessPass) type { |
| 129 | }; | 131 | }; |
| 130 | } | 132 | } |
| 131 | 133 | ||
| 132 | pub fn analyze(gpa: Allocator, air: Air) Allocator.Error!Liveness { | 134 | pub fn analyze(gpa: Allocator, air: Air, intern_pool: *const InternPool) Allocator.Error!Liveness { |
| 133 | const tracy = trace(@src()); | 135 | const tracy = trace(@src()); |
| 134 | defer tracy.end(); | 136 | defer tracy.end(); |
| 135 | 137 | ||
| ... | @@ -142,6 +144,7 @@ pub fn analyze(gpa: Allocator, air: Air) Allocator.Error!Liveness { | ... | @@ -142,6 +144,7 @@ pub fn analyze(gpa: Allocator, air: Air) Allocator.Error!Liveness { |
| 142 | ), | 144 | ), |
| 143 | .extra = .{}, | 145 | .extra = .{}, |
| 144 | .special = .{}, | 146 | .special = .{}, |
| 147 | .intern_pool = intern_pool, | ||
| 145 | }; | 148 | }; |
| 146 | errdefer gpa.free(a.tomb_bits); | 149 | errdefer gpa.free(a.tomb_bits); |
| 147 | errdefer a.special.deinit(gpa); | 150 | errdefer a.special.deinit(gpa); |
| ... | @@ -222,6 +225,7 @@ pub fn categorizeOperand( | ... | @@ -222,6 +225,7 @@ pub fn categorizeOperand( |
| 222 | air: Air, | 225 | air: Air, |
| 223 | inst: Air.Inst.Index, | 226 | inst: Air.Inst.Index, |
| 224 | operand: Air.Inst.Index, | 227 | operand: Air.Inst.Index, |
| 228 | ip: *const InternPool, | ||
| 225 | ) OperandCategory { | 229 | ) OperandCategory { |
| 226 | const air_tags = air.instructions.items(.tag); | 230 | const air_tags = air.instructions.items(.tag); |
| 227 | const air_datas = air.instructions.items(.data); | 231 | const air_datas = air.instructions.items(.data); |
| ... | @@ -317,9 +321,10 @@ pub fn categorizeOperand( | ... | @@ -317,9 +321,10 @@ pub fn categorizeOperand( |
| 317 | 321 | ||
| 318 | .arg, | 322 | .arg, |
| 319 | .alloc, | 323 | .alloc, |
| 324 | .inferred_alloc, | ||
| 325 | .inferred_alloc_comptime, | ||
| 320 | .ret_ptr, | 326 | .ret_ptr, |
| 321 | .constant, | 327 | .interned, |
| 322 | .const_ty, | ||
| 323 | .trap, | 328 | .trap, |
| 324 | .breakpoint, | 329 | .breakpoint, |
| 325 | .dbg_stmt, | 330 | .dbg_stmt, |
| ... | @@ -530,7 +535,7 @@ pub fn categorizeOperand( | ... | @@ -530,7 +535,7 @@ pub fn categorizeOperand( |
| 530 | .aggregate_init => { | 535 | .aggregate_init => { |
| 531 | const ty_pl = air_datas[inst].ty_pl; | 536 | const ty_pl = air_datas[inst].ty_pl; |
| 532 | const aggregate_ty = air.getRefType(ty_pl.ty); | 537 | const aggregate_ty = air.getRefType(ty_pl.ty); |
| 533 | const len = @intCast(usize, aggregate_ty.arrayLen()); | 538 | const len = @intCast(usize, aggregate_ty.arrayLenIp(ip)); |
| 534 | const elements = @ptrCast([]const Air.Inst.Ref, air.extra[ty_pl.payload..][0..len]); | 539 | const elements = @ptrCast([]const Air.Inst.Ref, air.extra[ty_pl.payload..][0..len]); |
| 535 | 540 | ||
| 536 | if (elements.len <= bpi - 1) { | 541 | if (elements.len <= bpi - 1) { |
| ... | @@ -621,7 +626,7 @@ pub fn categorizeOperand( | ... | @@ -621,7 +626,7 @@ pub fn categorizeOperand( |
| 621 | 626 | ||
| 622 | var operand_live: bool = true; | 627 | var operand_live: bool = true; |
| 623 | for (air.extra[cond_extra.end..][0..2]) |cond_inst| { | 628 | for (air.extra[cond_extra.end..][0..2]) |cond_inst| { |
| 624 | if (l.categorizeOperand(air, cond_inst, operand) == .tomb) | 629 | if (l.categorizeOperand(air, cond_inst, operand, ip) == .tomb) |
| 625 | operand_live = false; | 630 | operand_live = false; |
| 626 | 631 | ||
| 627 | switch (air_tags[cond_inst]) { | 632 | switch (air_tags[cond_inst]) { |
| ... | @@ -818,6 +823,7 @@ pub const BigTomb = struct { | ... | @@ -818,6 +823,7 @@ pub const BigTomb = struct { |
| 818 | const Analysis = struct { | 823 | const Analysis = struct { |
| 819 | gpa: Allocator, | 824 | gpa: Allocator, |
| 820 | air: Air, | 825 | air: Air, |
| 826 | intern_pool: *const InternPool, | ||
| 821 | tomb_bits: []usize, | 827 | tomb_bits: []usize, |
| 822 | special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32), | 828 | special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32), |
| 823 | extra: std.ArrayListUnmanaged(u32), | 829 | extra: std.ArrayListUnmanaged(u32), |
| ... | @@ -867,6 +873,7 @@ fn analyzeInst( | ... | @@ -867,6 +873,7 @@ fn analyzeInst( |
| 867 | data: *LivenessPassData(pass), | 873 | data: *LivenessPassData(pass), |
| 868 | inst: Air.Inst.Index, | 874 | inst: Air.Inst.Index, |
| 869 | ) Allocator.Error!void { | 875 | ) Allocator.Error!void { |
| 876 | const ip = a.intern_pool; | ||
| 870 | const inst_tags = a.air.instructions.items(.tag); | 877 | const inst_tags = a.air.instructions.items(.tag); |
| 871 | const inst_datas = a.air.instructions.items(.data); | 878 | const inst_datas = a.air.instructions.items(.data); |
| 872 | 879 | ||
| ... | @@ -967,9 +974,7 @@ fn analyzeInst( | ... | @@ -967,9 +974,7 @@ fn analyzeInst( |
| 967 | .work_group_id, | 974 | .work_group_id, |
| 968 | => return analyzeOperands(a, pass, data, inst, .{ .none, .none, .none }), | 975 | => return analyzeOperands(a, pass, data, inst, .{ .none, .none, .none }), |
| 969 | 976 | ||
| 970 | .constant, | 977 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, |
| 971 | .const_ty, | ||
| 972 | => unreachable, | ||
| 973 | 978 | ||
| 974 | .trap, | 979 | .trap, |
| 975 | .unreach, | 980 | .unreach, |
| ... | @@ -1134,7 +1139,7 @@ fn analyzeInst( | ... | @@ -1134,7 +1139,7 @@ fn analyzeInst( |
| 1134 | .aggregate_init => { | 1139 | .aggregate_init => { |
| 1135 | const ty_pl = inst_datas[inst].ty_pl; | 1140 | const ty_pl = inst_datas[inst].ty_pl; |
| 1136 | const aggregate_ty = a.air.getRefType(ty_pl.ty); | 1141 | const aggregate_ty = a.air.getRefType(ty_pl.ty); |
| 1137 | const len = @intCast(usize, aggregate_ty.arrayLen()); | 1142 | const len = @intCast(usize, aggregate_ty.arrayLenIp(ip)); |
| 1138 | const elements = @ptrCast([]const Air.Inst.Ref, a.air.extra[ty_pl.payload..][0..len]); | 1143 | const elements = @ptrCast([]const Air.Inst.Ref, a.air.extra[ty_pl.payload..][0..len]); |
| 1139 | 1144 | ||
| 1140 | if (elements.len <= bpi - 1) { | 1145 | if (elements.len <= bpi - 1) { |
| ... | @@ -1253,19 +1258,17 @@ fn analyzeOperands( | ... | @@ -1253,19 +1258,17 @@ fn analyzeOperands( |
| 1253 | ) Allocator.Error!void { | 1258 | ) Allocator.Error!void { |
| 1254 | const gpa = a.gpa; | 1259 | const gpa = a.gpa; |
| 1255 | const inst_tags = a.air.instructions.items(.tag); | 1260 | const inst_tags = a.air.instructions.items(.tag); |
| 1261 | const ip = a.intern_pool; | ||
| 1256 | 1262 | ||
| 1257 | switch (pass) { | 1263 | switch (pass) { |
| 1258 | .loop_analysis => { | 1264 | .loop_analysis => { |
| 1259 | _ = data.live_set.remove(inst); | 1265 | _ = data.live_set.remove(inst); |
| 1260 | 1266 | ||
| 1261 | for (operands) |op_ref| { | 1267 | for (operands) |op_ref| { |
| 1262 | const operand = Air.refToIndex(op_ref) orelse continue; | 1268 | const operand = Air.refToIndexAllowNone(op_ref) orelse continue; |
| 1263 | 1269 | ||
| 1264 | // Don't compute any liveness for constants | 1270 | // Don't compute any liveness for constants |
| 1265 | switch (inst_tags[operand]) { | 1271 | if (inst_tags[operand] == .interned) continue; |
| 1266 | .constant, .const_ty => continue, | ||
| 1267 | else => {}, | ||
| 1268 | } | ||
| 1269 | 1272 | ||
| 1270 | _ = try data.live_set.put(gpa, operand, {}); | 1273 | _ = try data.live_set.put(gpa, operand, {}); |
| 1271 | } | 1274 | } |
| ... | @@ -1288,20 +1291,17 @@ fn analyzeOperands( | ... | @@ -1288,20 +1291,17 @@ fn analyzeOperands( |
| 1288 | // If our result is unused and the instruction doesn't need to be lowered, backends will | 1291 | // If our result is unused and the instruction doesn't need to be lowered, backends will |
| 1289 | // skip the lowering of this instruction, so we don't want to record uses of operands. | 1292 | // skip the lowering of this instruction, so we don't want to record uses of operands. |
| 1290 | // That way, we can mark as many instructions as possible unused. | 1293 | // That way, we can mark as many instructions as possible unused. |
| 1291 | if (!immediate_death or a.air.mustLower(inst)) { | 1294 | if (!immediate_death or a.air.mustLower(inst, ip)) { |
| 1292 | // Note that it's important we iterate over the operands backwards, so that if a dying | 1295 | // Note that it's important we iterate over the operands backwards, so that if a dying |
| 1293 | // operand is used multiple times we mark its last use as its death. | 1296 | // operand is used multiple times we mark its last use as its death. |
| 1294 | var i = operands.len; | 1297 | var i = operands.len; |
| 1295 | while (i > 0) { | 1298 | while (i > 0) { |
| 1296 | i -= 1; | 1299 | i -= 1; |
| 1297 | const op_ref = operands[i]; | 1300 | const op_ref = operands[i]; |
| 1298 | const operand = Air.refToIndex(op_ref) orelse continue; | 1301 | const operand = Air.refToIndexAllowNone(op_ref) orelse continue; |
| 1299 | 1302 | ||
| 1300 | // Don't compute any liveness for constants | 1303 | // Don't compute any liveness for constants |
| 1301 | switch (inst_tags[operand]) { | 1304 | if (inst_tags[operand] == .interned) continue; |
| 1302 | .constant, .const_ty => continue, | ||
| 1303 | else => {}, | ||
| 1304 | } | ||
| 1305 | 1305 | ||
| 1306 | const mask = @as(Bpi, 1) << @intCast(OperandInt, i); | 1306 | const mask = @as(Bpi, 1) << @intCast(OperandInt, i); |
| 1307 | 1307 | ||
| ... | @@ -1407,7 +1407,7 @@ fn analyzeInstBlock( | ... | @@ -1407,7 +1407,7 @@ fn analyzeInstBlock( |
| 1407 | 1407 | ||
| 1408 | // If the block is noreturn, block deaths not only aren't useful, they're impossible to | 1408 | // If the block is noreturn, block deaths not only aren't useful, they're impossible to |
| 1409 | // find: there could be more stuff alive after the block than before it! | 1409 | // find: there could be more stuff alive after the block than before it! |
| 1410 | if (!a.air.getRefType(ty_pl.ty).isNoReturn()) { | 1410 | if (!a.intern_pool.isNoReturn(a.air.getRefType(ty_pl.ty).ip_index)) { |
| 1411 | // The block kills the difference in the live sets | 1411 | // The block kills the difference in the live sets |
| 1412 | const block_scope = data.block_scopes.get(inst).?; | 1412 | const block_scope = data.block_scopes.get(inst).?; |
| 1413 | const num_deaths = data.live_set.count() - block_scope.live_set.count(); | 1413 | const num_deaths = data.live_set.count() - block_scope.live_set.count(); |
| ... | @@ -1819,6 +1819,7 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type { | ... | @@ -1819,6 +1819,7 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type { |
| 1819 | 1819 | ||
| 1820 | /// Must be called with operands in reverse order. | 1820 | /// Must be called with operands in reverse order. |
| 1821 | fn feed(big: *Self, op_ref: Air.Inst.Ref) !void { | 1821 | fn feed(big: *Self, op_ref: Air.Inst.Ref) !void { |
| 1822 | const ip = big.a.intern_pool; | ||
| 1822 | // Note that after this, `operands_remaining` becomes the index of the current operand | 1823 | // Note that after this, `operands_remaining` becomes the index of the current operand |
| 1823 | big.operands_remaining -= 1; | 1824 | big.operands_remaining -= 1; |
| 1824 | 1825 | ||
| ... | @@ -1831,15 +1832,12 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type { | ... | @@ -1831,15 +1832,12 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type { |
| 1831 | 1832 | ||
| 1832 | // Don't compute any liveness for constants | 1833 | // Don't compute any liveness for constants |
| 1833 | const inst_tags = big.a.air.instructions.items(.tag); | 1834 | const inst_tags = big.a.air.instructions.items(.tag); |
| 1834 | switch (inst_tags[operand]) { | 1835 | if (inst_tags[operand] == .interned) return |
| 1835 | .constant, .const_ty => return, | ||
| 1836 | else => {}, | ||
| 1837 | } | ||
| 1838 | 1836 | ||
| 1839 | // If our result is unused and the instruction doesn't need to be lowered, backends will | 1837 | // If our result is unused and the instruction doesn't need to be lowered, backends will |
| 1840 | // skip the lowering of this instruction, so we don't want to record uses of operands. | 1838 | // skip the lowering of this instruction, so we don't want to record uses of operands. |
| 1841 | // That way, we can mark as many instructions as possible unused. | 1839 | // That way, we can mark as many instructions as possible unused. |
| 1842 | if (big.will_die_immediately and !big.a.air.mustLower(big.inst)) return; | 1840 | if (big.will_die_immediately and !big.a.air.mustLower(big.inst, ip)) return; |
| 1843 | 1841 | ||
| 1844 | const extra_byte = (big.operands_remaining - (bpi - 1)) / 31; | 1842 | const extra_byte = (big.operands_remaining - (bpi - 1)) / 31; |
| 1845 | const extra_bit = @intCast(u5, big.operands_remaining - (bpi - 1) - extra_byte * 31); | 1843 | const extra_bit = @intCast(u5, big.operands_remaining - (bpi - 1) - extra_byte * 31); |
src/Liveness/Verify.zig+62-57| ... | @@ -5,6 +5,7 @@ air: Air, | ... | @@ -5,6 +5,7 @@ air: Air, |
| 5 | liveness: Liveness, | 5 | liveness: Liveness, |
| 6 | live: LiveMap = .{}, | 6 | live: LiveMap = .{}, |
| 7 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, LiveMap) = .{}, | 7 | blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, LiveMap) = .{}, |
| 8 | intern_pool: *const InternPool, | ||
| 8 | 9 | ||
| 9 | pub const Error = error{ LivenessInvalid, OutOfMemory }; | 10 | pub const Error = error{ LivenessInvalid, OutOfMemory }; |
| 10 | 11 | ||
| ... | @@ -27,10 +28,11 @@ pub fn verify(self: *Verify) Error!void { | ... | @@ -27,10 +28,11 @@ pub fn verify(self: *Verify) Error!void { |
| 27 | const LiveMap = std.AutoHashMapUnmanaged(Air.Inst.Index, void); | 28 | const LiveMap = std.AutoHashMapUnmanaged(Air.Inst.Index, void); |
| 28 | 29 | ||
| 29 | fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | 30 | fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 31 | const ip = self.intern_pool; | ||
| 30 | const tag = self.air.instructions.items(.tag); | 32 | const tag = self.air.instructions.items(.tag); |
| 31 | const data = self.air.instructions.items(.data); | 33 | const data = self.air.instructions.items(.data); |
| 32 | for (body) |inst| { | 34 | for (body) |inst| { |
| 33 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) { | 35 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) { |
| 34 | // This instruction will not be lowered and should be ignored. | 36 | // This instruction will not be lowered and should be ignored. |
| 35 | continue; | 37 | continue; |
| 36 | } | 38 | } |
| ... | @@ -39,9 +41,10 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -39,9 +41,10 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 39 | // no operands | 41 | // no operands |
| 40 | .arg, | 42 | .arg, |
| 41 | .alloc, | 43 | .alloc, |
| 44 | .inferred_alloc, | ||
| 45 | .inferred_alloc_comptime, | ||
| 42 | .ret_ptr, | 46 | .ret_ptr, |
| 43 | .constant, | 47 | .interned, |
| 44 | .const_ty, | ||
| 45 | .breakpoint, | 48 | .breakpoint, |
| 46 | .dbg_stmt, | 49 | .dbg_stmt, |
| 47 | .dbg_inline_begin, | 50 | .dbg_inline_begin, |
| ... | @@ -58,10 +61,10 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -58,10 +61,10 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 58 | .work_item_id, | 61 | .work_item_id, |
| 59 | .work_group_size, | 62 | .work_group_size, |
| 60 | .work_group_id, | 63 | .work_group_id, |
| 61 | => try self.verifyInst(inst, .{ .none, .none, .none }), | 64 | => try self.verifyInstOperands(inst, .{ .none, .none, .none }), |
| 62 | 65 | ||
| 63 | .trap, .unreach => { | 66 | .trap, .unreach => { |
| 64 | try self.verifyInst(inst, .{ .none, .none, .none }); | 67 | try self.verifyInstOperands(inst, .{ .none, .none, .none }); |
| 65 | // This instruction terminates the function, so everything should be dead | 68 | // This instruction terminates the function, so everything should be dead |
| 66 | if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst}); | 69 | if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst}); |
| 67 | }, | 70 | }, |
| ... | @@ -110,7 +113,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -110,7 +113,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 110 | .c_va_copy, | 113 | .c_va_copy, |
| 111 | => { | 114 | => { |
| 112 | const ty_op = data[inst].ty_op; | 115 | const ty_op = data[inst].ty_op; |
| 113 | try self.verifyInst(inst, .{ ty_op.operand, .none, .none }); | 116 | try self.verifyInstOperands(inst, .{ ty_op.operand, .none, .none }); |
| 114 | }, | 117 | }, |
| 115 | .is_null, | 118 | .is_null, |
| 116 | .is_non_null, | 119 | .is_non_null, |
| ... | @@ -146,13 +149,13 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -146,13 +149,13 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 146 | .c_va_end, | 149 | .c_va_end, |
| 147 | => { | 150 | => { |
| 148 | const un_op = data[inst].un_op; | 151 | const un_op = data[inst].un_op; |
| 149 | try self.verifyInst(inst, .{ un_op, .none, .none }); | 152 | try self.verifyInstOperands(inst, .{ un_op, .none, .none }); |
| 150 | }, | 153 | }, |
| 151 | .ret, | 154 | .ret, |
| 152 | .ret_load, | 155 | .ret_load, |
| 153 | => { | 156 | => { |
| 154 | const un_op = data[inst].un_op; | 157 | const un_op = data[inst].un_op; |
| 155 | try self.verifyInst(inst, .{ un_op, .none, .none }); | 158 | try self.verifyInstOperands(inst, .{ un_op, .none, .none }); |
| 156 | // This instruction terminates the function, so everything should be dead | 159 | // This instruction terminates the function, so everything should be dead |
| 157 | if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst}); | 160 | if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst}); |
| 158 | }, | 161 | }, |
| ... | @@ -161,36 +164,36 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -161,36 +164,36 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 161 | .wasm_memory_grow, | 164 | .wasm_memory_grow, |
| 162 | => { | 165 | => { |
| 163 | const pl_op = data[inst].pl_op; | 166 | const pl_op = data[inst].pl_op; |
| 164 | try self.verifyInst(inst, .{ pl_op.operand, .none, .none }); | 167 | try self.verifyInstOperands(inst, .{ pl_op.operand, .none, .none }); |
| 165 | }, | 168 | }, |
| 166 | .prefetch => { | 169 | .prefetch => { |
| 167 | const prefetch = data[inst].prefetch; | 170 | const prefetch = data[inst].prefetch; |
| 168 | try self.verifyInst(inst, .{ prefetch.ptr, .none, .none }); | 171 | try self.verifyInstOperands(inst, .{ prefetch.ptr, .none, .none }); |
| 169 | }, | 172 | }, |
| 170 | .reduce, | 173 | .reduce, |
| 171 | .reduce_optimized, | 174 | .reduce_optimized, |
| 172 | => { | 175 | => { |
| 173 | const reduce = data[inst].reduce; | 176 | const reduce = data[inst].reduce; |
| 174 | try self.verifyInst(inst, .{ reduce.operand, .none, .none }); | 177 | try self.verifyInstOperands(inst, .{ reduce.operand, .none, .none }); |
| 175 | }, | 178 | }, |
| 176 | .union_init => { | 179 | .union_init => { |
| 177 | const ty_pl = data[inst].ty_pl; | 180 | const ty_pl = data[inst].ty_pl; |
| 178 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; | 181 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 179 | try self.verifyInst(inst, .{ extra.init, .none, .none }); | 182 | try self.verifyInstOperands(inst, .{ extra.init, .none, .none }); |
| 180 | }, | 183 | }, |
| 181 | .struct_field_ptr, .struct_field_val => { | 184 | .struct_field_ptr, .struct_field_val => { |
| 182 | const ty_pl = data[inst].ty_pl; | 185 | const ty_pl = data[inst].ty_pl; |
| 183 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 186 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 184 | try self.verifyInst(inst, .{ extra.struct_operand, .none, .none }); | 187 | try self.verifyInstOperands(inst, .{ extra.struct_operand, .none, .none }); |
| 185 | }, | 188 | }, |
| 186 | .field_parent_ptr => { | 189 | .field_parent_ptr => { |
| 187 | const ty_pl = data[inst].ty_pl; | 190 | const ty_pl = data[inst].ty_pl; |
| 188 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; | 191 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 189 | try self.verifyInst(inst, .{ extra.field_ptr, .none, .none }); | 192 | try self.verifyInstOperands(inst, .{ extra.field_ptr, .none, .none }); |
| 190 | }, | 193 | }, |
| 191 | .atomic_load => { | 194 | .atomic_load => { |
| 192 | const atomic_load = data[inst].atomic_load; | 195 | const atomic_load = data[inst].atomic_load; |
| 193 | try self.verifyInst(inst, .{ atomic_load.ptr, .none, .none }); | 196 | try self.verifyInstOperands(inst, .{ atomic_load.ptr, .none, .none }); |
| 194 | }, | 197 | }, |
| 195 | 198 | ||
| 196 | // binary | 199 | // binary |
| ... | @@ -260,7 +263,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -260,7 +263,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 260 | .memcpy, | 263 | .memcpy, |
| 261 | => { | 264 | => { |
| 262 | const bin_op = data[inst].bin_op; | 265 | const bin_op = data[inst].bin_op; |
| 263 | try self.verifyInst(inst, .{ bin_op.lhs, bin_op.rhs, .none }); | 266 | try self.verifyInstOperands(inst, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 264 | }, | 267 | }, |
| 265 | .add_with_overflow, | 268 | .add_with_overflow, |
| 266 | .sub_with_overflow, | 269 | .sub_with_overflow, |
| ... | @@ -274,62 +277,62 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -274,62 +277,62 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 274 | => { | 277 | => { |
| 275 | const ty_pl = data[inst].ty_pl; | 278 | const ty_pl = data[inst].ty_pl; |
| 276 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 279 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 277 | try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none }); | 280 | try self.verifyInstOperands(inst, .{ extra.lhs, extra.rhs, .none }); |
| 278 | }, | 281 | }, |
| 279 | .shuffle => { | 282 | .shuffle => { |
| 280 | const ty_pl = data[inst].ty_pl; | 283 | const ty_pl = data[inst].ty_pl; |
| 281 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; | 284 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 282 | try self.verifyInst(inst, .{ extra.a, extra.b, .none }); | 285 | try self.verifyInstOperands(inst, .{ extra.a, extra.b, .none }); |
| 283 | }, | 286 | }, |
| 284 | .cmp_vector, | 287 | .cmp_vector, |
| 285 | .cmp_vector_optimized, | 288 | .cmp_vector_optimized, |
| 286 | => { | 289 | => { |
| 287 | const ty_pl = data[inst].ty_pl; | 290 | const ty_pl = data[inst].ty_pl; |
| 288 | const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data; | 291 | const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data; |
| 289 | try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none }); | 292 | try self.verifyInstOperands(inst, .{ extra.lhs, extra.rhs, .none }); |
| 290 | }, | 293 | }, |
| 291 | .atomic_rmw => { | 294 | .atomic_rmw => { |
| 292 | const pl_op = data[inst].pl_op; | 295 | const pl_op = data[inst].pl_op; |
| 293 | const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data; | 296 | const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 294 | try self.verifyInst(inst, .{ pl_op.operand, extra.operand, .none }); | 297 | try self.verifyInstOperands(inst, .{ pl_op.operand, extra.operand, .none }); |
| 295 | }, | 298 | }, |
| 296 | 299 | ||
| 297 | // ternary | 300 | // ternary |
| 298 | .select => { | 301 | .select => { |
| 299 | const pl_op = data[inst].pl_op; | 302 | const pl_op = data[inst].pl_op; |
| 300 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; | 303 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 301 | try self.verifyInst(inst, .{ pl_op.operand, extra.lhs, extra.rhs }); | 304 | try self.verifyInstOperands(inst, .{ pl_op.operand, extra.lhs, extra.rhs }); |
| 302 | }, | 305 | }, |
| 303 | .mul_add => { | 306 | .mul_add => { |
| 304 | const pl_op = data[inst].pl_op; | 307 | const pl_op = data[inst].pl_op; |
| 305 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; | 308 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 306 | try self.verifyInst(inst, .{ extra.lhs, extra.rhs, pl_op.operand }); | 309 | try self.verifyInstOperands(inst, .{ extra.lhs, extra.rhs, pl_op.operand }); |
| 307 | }, | 310 | }, |
| 308 | .vector_store_elem => { | 311 | .vector_store_elem => { |
| 309 | const vector_store_elem = data[inst].vector_store_elem; | 312 | const vector_store_elem = data[inst].vector_store_elem; |
| 310 | const extra = self.air.extraData(Air.Bin, vector_store_elem.payload).data; | 313 | const extra = self.air.extraData(Air.Bin, vector_store_elem.payload).data; |
| 311 | try self.verifyInst(inst, .{ vector_store_elem.vector_ptr, extra.lhs, extra.rhs }); | 314 | try self.verifyInstOperands(inst, .{ vector_store_elem.vector_ptr, extra.lhs, extra.rhs }); |
| 312 | }, | 315 | }, |
| 313 | .cmpxchg_strong, | 316 | .cmpxchg_strong, |
| 314 | .cmpxchg_weak, | 317 | .cmpxchg_weak, |
| 315 | => { | 318 | => { |
| 316 | const ty_pl = data[inst].ty_pl; | 319 | const ty_pl = data[inst].ty_pl; |
| 317 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; | 320 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 318 | try self.verifyInst(inst, .{ extra.ptr, extra.expected_value, extra.new_value }); | 321 | try self.verifyInstOperands(inst, .{ extra.ptr, extra.expected_value, extra.new_value }); |
| 319 | }, | 322 | }, |
| 320 | 323 | ||
| 321 | // big tombs | 324 | // big tombs |
| 322 | .aggregate_init => { | 325 | .aggregate_init => { |
| 323 | const ty_pl = data[inst].ty_pl; | 326 | const ty_pl = data[inst].ty_pl; |
| 324 | const aggregate_ty = self.air.getRefType(ty_pl.ty); | 327 | const aggregate_ty = self.air.getRefType(ty_pl.ty); |
| 325 | const len = @intCast(usize, aggregate_ty.arrayLen()); | 328 | const len = @intCast(usize, aggregate_ty.arrayLenIp(ip)); |
| 326 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); | 329 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 327 | 330 | ||
| 328 | var bt = self.liveness.iterateBigTomb(inst); | 331 | var bt = self.liveness.iterateBigTomb(inst); |
| 329 | for (elements) |element| { | 332 | for (elements) |element| { |
| 330 | try self.verifyOperand(inst, element, bt.feed()); | 333 | try self.verifyOperand(inst, element, bt.feed()); |
| 331 | } | 334 | } |
| 332 | try self.verifyInst(inst, .{ .none, .none, .none }); | 335 | try self.verifyInst(inst); |
| 333 | }, | 336 | }, |
| 334 | .call, .call_always_tail, .call_never_tail, .call_never_inline => { | 337 | .call, .call_always_tail, .call_never_tail, .call_never_inline => { |
| 335 | const pl_op = data[inst].pl_op; | 338 | const pl_op = data[inst].pl_op; |
| ... | @@ -344,7 +347,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -344,7 +347,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 344 | for (args) |arg| { | 347 | for (args) |arg| { |
| 345 | try self.verifyOperand(inst, arg, bt.feed()); | 348 | try self.verifyOperand(inst, arg, bt.feed()); |
| 346 | } | 349 | } |
| 347 | try self.verifyInst(inst, .{ .none, .none, .none }); | 350 | try self.verifyInst(inst); |
| 348 | }, | 351 | }, |
| 349 | .assembly => { | 352 | .assembly => { |
| 350 | const ty_pl = data[inst].ty_pl; | 353 | const ty_pl = data[inst].ty_pl; |
| ... | @@ -370,7 +373,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -370,7 +373,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 370 | for (inputs) |input| { | 373 | for (inputs) |input| { |
| 371 | try self.verifyOperand(inst, input, bt.feed()); | 374 | try self.verifyOperand(inst, input, bt.feed()); |
| 372 | } | 375 | } |
| 373 | try self.verifyInst(inst, .{ .none, .none, .none }); | 376 | try self.verifyInst(inst); |
| 374 | }, | 377 | }, |
| 375 | 378 | ||
| 376 | // control flow | 379 | // control flow |
| ... | @@ -394,7 +397,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -394,7 +397,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 394 | 397 | ||
| 395 | for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death); | 398 | for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death); |
| 396 | 399 | ||
| 397 | try self.verifyInst(inst, .{ .none, .none, .none }); | 400 | try self.verifyInst(inst); |
| 398 | }, | 401 | }, |
| 399 | .try_ptr => { | 402 | .try_ptr => { |
| 400 | const ty_pl = data[inst].ty_pl; | 403 | const ty_pl = data[inst].ty_pl; |
| ... | @@ -416,7 +419,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -416,7 +419,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 416 | 419 | ||
| 417 | for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death); | 420 | for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death); |
| 418 | 421 | ||
| 419 | try self.verifyInst(inst, .{ .none, .none, .none }); | 422 | try self.verifyInst(inst); |
| 420 | }, | 423 | }, |
| 421 | .br => { | 424 | .br => { |
| 422 | const br = data[inst].br; | 425 | const br = data[inst].br; |
| ... | @@ -428,7 +431,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -428,7 +431,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 428 | } else { | 431 | } else { |
| 429 | gop.value_ptr.* = try self.live.clone(self.gpa); | 432 | gop.value_ptr.* = try self.live.clone(self.gpa); |
| 430 | } | 433 | } |
| 431 | try self.verifyInst(inst, .{ .none, .none, .none }); | 434 | try self.verifyInst(inst); |
| 432 | }, | 435 | }, |
| 433 | .block => { | 436 | .block => { |
| 434 | const ty_pl = data[inst].ty_pl; | 437 | const ty_pl = data[inst].ty_pl; |
| ... | @@ -450,7 +453,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -450,7 +453,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 450 | 453 | ||
| 451 | for (block_liveness.deaths) |death| try self.verifyDeath(inst, death); | 454 | for (block_liveness.deaths) |death| try self.verifyDeath(inst, death); |
| 452 | 455 | ||
| 453 | if (block_ty.isNoReturn()) { | 456 | if (ip.isNoReturn(block_ty.toIntern())) { |
| 454 | assert(!self.blocks.contains(inst)); | 457 | assert(!self.blocks.contains(inst)); |
| 455 | } else { | 458 | } else { |
| 456 | var live = self.blocks.fetchRemove(inst).?.value; | 459 | var live = self.blocks.fetchRemove(inst).?.value; |
| ... | @@ -459,7 +462,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -459,7 +462,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 459 | try self.verifyMatchingLiveness(inst, live); | 462 | try self.verifyMatchingLiveness(inst, live); |
| 460 | } | 463 | } |
| 461 | 464 | ||
| 462 | try self.verifyInst(inst, .{ .none, .none, .none }); | 465 | try self.verifyInstOperands(inst, .{ .none, .none, .none }); |
| 463 | }, | 466 | }, |
| 464 | .loop => { | 467 | .loop => { |
| 465 | const ty_pl = data[inst].ty_pl; | 468 | const ty_pl = data[inst].ty_pl; |
| ... | @@ -474,7 +477,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -474,7 +477,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 474 | // The same stuff should be alive after the loop as before it | 477 | // The same stuff should be alive after the loop as before it |
| 475 | try self.verifyMatchingLiveness(inst, live); | 478 | try self.verifyMatchingLiveness(inst, live); |
| 476 | 479 | ||
| 477 | try self.verifyInst(inst, .{ .none, .none, .none }); | 480 | try self.verifyInstOperands(inst, .{ .none, .none, .none }); |
| 478 | }, | 481 | }, |
| 479 | .cond_br => { | 482 | .cond_br => { |
| 480 | const pl_op = data[inst].pl_op; | 483 | const pl_op = data[inst].pl_op; |
| ... | @@ -497,7 +500,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -497,7 +500,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 497 | for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death); | 500 | for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death); |
| 498 | try self.verifyBody(else_body); | 501 | try self.verifyBody(else_body); |
| 499 | 502 | ||
| 500 | try self.verifyInst(inst, .{ .none, .none, .none }); | 503 | try self.verifyInst(inst); |
| 501 | }, | 504 | }, |
| 502 | .switch_br => { | 505 | .switch_br => { |
| 503 | const pl_op = data[inst].pl_op; | 506 | const pl_op = data[inst].pl_op; |
| ... | @@ -541,7 +544,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -541,7 +544,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 541 | try self.verifyBody(else_body); | 544 | try self.verifyBody(else_body); |
| 542 | } | 545 | } |
| 543 | 546 | ||
| 544 | try self.verifyInst(inst, .{ .none, .none, .none }); | 547 | try self.verifyInst(inst); |
| 545 | }, | 548 | }, |
| 546 | } | 549 | } |
| 547 | } | 550 | } |
| ... | @@ -552,20 +555,22 @@ fn verifyDeath(self: *Verify, inst: Air.Inst.Index, operand: Air.Inst.Index) Err | ... | @@ -552,20 +555,22 @@ fn verifyDeath(self: *Verify, inst: Air.Inst.Index, operand: Air.Inst.Index) Err |
| 552 | } | 555 | } |
| 553 | 556 | ||
| 554 | fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies: bool) Error!void { | 557 | fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies: bool) Error!void { |
| 555 | const operand = Air.refToIndex(op_ref) orelse return; | 558 | const operand = Air.refToIndexAllowNone(op_ref) orelse { |
| 556 | switch (self.air.instructions.items(.tag)[operand]) { | 559 | assert(!dies); |
| 557 | .constant, .const_ty => {}, | 560 | return; |
| 558 | else => { | 561 | }; |
| 559 | if (dies) { | 562 | if (self.air.instructions.items(.tag)[operand] == .interned) { |
| 560 | if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand }); | 563 | assert(!dies); |
| 561 | } else { | 564 | return; |
| 562 | if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand }); | 565 | } |
| 563 | } | 566 | if (dies) { |
| 564 | }, | 567 | if (!self.live.remove(operand)) return invalid("%{}: dead operand %{} reused and killed again", .{ inst, operand }); |
| 568 | } else { | ||
| 569 | if (!self.live.contains(operand)) return invalid("%{}: dead operand %{} reused", .{ inst, operand }); | ||
| 565 | } | 570 | } |
| 566 | } | 571 | } |
| 567 | 572 | ||
| 568 | fn verifyInst( | 573 | fn verifyInstOperands( |
| 569 | self: *Verify, | 574 | self: *Verify, |
| 570 | inst: Air.Inst.Index, | 575 | inst: Air.Inst.Index, |
| 571 | operands: [Liveness.bpi - 1]Air.Inst.Ref, | 576 | operands: [Liveness.bpi - 1]Air.Inst.Ref, |
| ... | @@ -574,16 +579,15 @@ fn verifyInst( | ... | @@ -574,16 +579,15 @@ fn verifyInst( |
| 574 | const dies = self.liveness.operandDies(inst, @intCast(Liveness.OperandInt, operand_index)); | 579 | const dies = self.liveness.operandDies(inst, @intCast(Liveness.OperandInt, operand_index)); |
| 575 | try self.verifyOperand(inst, operand, dies); | 580 | try self.verifyOperand(inst, operand, dies); |
| 576 | } | 581 | } |
| 577 | const tag = self.air.instructions.items(.tag); | 582 | try self.verifyInst(inst); |
| 578 | switch (tag[inst]) { | 583 | } |
| 579 | .constant, .const_ty => unreachable, | 584 | |
| 580 | else => { | 585 | fn verifyInst(self: *Verify, inst: Air.Inst.Index) Error!void { |
| 581 | if (self.liveness.isUnused(inst)) { | 586 | if (self.air.instructions.items(.tag)[inst] == .interned) return; |
| 582 | assert(!self.live.contains(inst)); | 587 | if (self.liveness.isUnused(inst)) { |
| 583 | } else { | 588 | assert(!self.live.contains(inst)); |
| 584 | try self.live.putNoClobber(self.gpa, inst, {}); | 589 | } else { |
| 585 | } | 590 | try self.live.putNoClobber(self.gpa, inst, {}); |
| 586 | }, | ||
| 587 | } | 591 | } |
| 588 | } | 592 | } |
| 589 | 593 | ||
| ... | @@ -604,4 +608,5 @@ const log = std.log.scoped(.liveness_verify); | ... | @@ -604,4 +608,5 @@ const log = std.log.scoped(.liveness_verify); |
| 604 | 608 | ||
| 605 | const Air = @import("../Air.zig"); | 609 | const Air = @import("../Air.zig"); |
| 606 | const Liveness = @import("../Liveness.zig"); | 610 | const Liveness = @import("../Liveness.zig"); |
| 611 | const InternPool = @import("../InternPool.zig"); | ||
| 607 | const Verify = @This(); | 612 | const Verify = @This(); |
src/Module.zig+1440-1086| ... | @@ -32,6 +32,19 @@ const build_options = @import("build_options"); | ... | @@ -32,6 +32,19 @@ const build_options = @import("build_options"); |
| 32 | const Liveness = @import("Liveness.zig"); | 32 | const Liveness = @import("Liveness.zig"); |
| 33 | const isUpDir = @import("introspect.zig").isUpDir; | 33 | const isUpDir = @import("introspect.zig").isUpDir; |
| 34 | const clang = @import("clang.zig"); | 34 | const clang = @import("clang.zig"); |
| 35 | const InternPool = @import("InternPool.zig"); | ||
| 36 | |||
| 37 | comptime { | ||
| 38 | @setEvalBranchQuota(4000); | ||
| 39 | for ( | ||
| 40 | @typeInfo(Zir.Inst.Ref).Enum.fields, | ||
| 41 | @typeInfo(Air.Inst.Ref).Enum.fields, | ||
| 42 | @typeInfo(InternPool.Index).Enum.fields, | ||
| 43 | ) |zir_field, air_field, ip_field| { | ||
| 44 | assert(mem.eql(u8, zir_field.name, ip_field.name)); | ||
| 45 | assert(mem.eql(u8, air_field.name, ip_field.name)); | ||
| 46 | } | ||
| 47 | } | ||
| 35 | 48 | ||
| 36 | /// General-purpose allocator. Used for both temporary and long-term storage. | 49 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 37 | gpa: Allocator, | 50 | gpa: Allocator, |
| ... | @@ -72,28 +85,29 @@ import_table: std.StringArrayHashMapUnmanaged(*File) = .{}, | ... | @@ -72,28 +85,29 @@ import_table: std.StringArrayHashMapUnmanaged(*File) = .{}, |
| 72 | /// Keys are fully resolved file paths. This table owns the keys and values. | 85 | /// Keys are fully resolved file paths. This table owns the keys and values. |
| 73 | embed_table: std.StringHashMapUnmanaged(*EmbedFile) = .{}, | 86 | embed_table: std.StringHashMapUnmanaged(*EmbedFile) = .{}, |
| 74 | 87 | ||
| 75 | /// This is a temporary addition to stage2 in order to match legacy behavior, | 88 | /// Stores all Type and Value objects; periodically garbage collected. |
| 76 | /// however the end-game once the lang spec is settled will be to use a global | 89 | intern_pool: InternPool = .{}, |
| 77 | /// InternPool for comptime memoized objects, making this behavior consistent across all types, | ||
| 78 | /// not only string literals. Or, we might decide to not guarantee string literals | ||
| 79 | /// to have equal comptime pointers, in which case this field can be deleted (perhaps | ||
| 80 | /// the commit that introduced it can simply be reverted). | ||
| 81 | /// This table uses an optional index so that when a Decl is destroyed, the string literal | ||
| 82 | /// is still reclaimable by a future Decl. | ||
| 83 | string_literal_table: std.HashMapUnmanaged(StringLiteralContext.Key, Decl.OptionalIndex, StringLiteralContext, std.hash_map.default_max_load_percentage) = .{}, | ||
| 84 | string_literal_bytes: ArrayListUnmanaged(u8) = .{}, | ||
| 85 | 90 | ||
| 91 | /// To be eliminated in a future commit by moving more data into InternPool. | ||
| 92 | /// Current uses that must be eliminated: | ||
| 93 | /// * Struct comptime_args | ||
| 94 | /// * Struct optimized_order | ||
| 95 | /// * Union fields | ||
| 96 | /// This memory lives until the Module is destroyed. | ||
| 97 | tmp_hack_arena: std.heap.ArenaAllocator, | ||
| 98 | |||
| 99 | /// This is currently only used for string literals. | ||
| 100 | memoized_decls: std.AutoHashMapUnmanaged(InternPool.Index, Decl.Index) = .{}, | ||
| 101 | |||
| 102 | monomorphed_func_keys: std.ArrayListUnmanaged(InternPool.Index) = .{}, | ||
| 86 | /// The set of all the generic function instantiations. This is used so that when a generic | 103 | /// The set of all the generic function instantiations. This is used so that when a generic |
| 87 | /// function is called twice with the same comptime parameter arguments, both calls dispatch | 104 | /// function is called twice with the same comptime parameter arguments, both calls dispatch |
| 88 | /// to the same function. | 105 | /// to the same function. |
| 89 | monomorphed_funcs: MonomorphedFuncsSet = .{}, | 106 | monomorphed_funcs: MonomorphedFuncsSet = .{}, |
| 90 | /// The set of all comptime function calls that have been cached so that future calls | ||
| 91 | /// with the same parameters will get the same return value. | ||
| 92 | memoized_calls: MemoizedCallSet = .{}, | ||
| 93 | /// Contains the values from `@setAlignStack`. A sparse table is used here | 107 | /// Contains the values from `@setAlignStack`. A sparse table is used here |
| 94 | /// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while | 108 | /// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while |
| 95 | /// functions are many. | 109 | /// functions are many. |
| 96 | align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{}, | 110 | align_stack_fns: std.AutoHashMapUnmanaged(Fn.Index, SetAlignStack) = .{}, |
| 97 | 111 | ||
| 98 | /// We optimize memory usage for a compilation with no compile errors by storing the | 112 | /// We optimize memory usage for a compilation with no compile errors by storing the |
| 99 | /// error messages and mapping outside of `Decl`. | 113 | /// error messages and mapping outside of `Decl`. |
| ... | @@ -120,13 +134,8 @@ cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, []CImportError) = .{}, | ... | @@ -120,13 +134,8 @@ cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, []CImportError) = .{}, |
| 120 | /// contains Decls that need to be deleted if they end up having no references to them. | 134 | /// contains Decls that need to be deleted if they end up having no references to them. |
| 121 | deletion_set: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, | 135 | deletion_set: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, |
| 122 | 136 | ||
| 123 | /// Error tags and their values, tag names are duped with mod.gpa. | 137 | /// Key is the error name, index is the error tag value. Index 0 has a length-0 string. |
| 124 | /// Corresponds with `error_name_list`. | 138 | global_error_set: GlobalErrorSet = .{}, |
| 125 | global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{}, | ||
| 126 | |||
| 127 | /// ErrorInt -> []const u8 for fast lookups for @intToError at comptime | ||
| 128 | /// Corresponds with `global_error_set`. | ||
| 129 | error_name_list: ArrayListUnmanaged([]const u8), | ||
| 130 | 139 | ||
| 131 | /// Incrementing integer used to compare against the corresponding Decl | 140 | /// Incrementing integer used to compare against the corresponding Decl |
| 132 | /// field to determine whether a Decl's status applies to an ongoing update, or a | 141 | /// field to determine whether a Decl's status applies to an ongoing update, or a |
| ... | @@ -165,6 +174,11 @@ allocated_decls: std.SegmentedList(Decl, 0) = .{}, | ... | @@ -165,6 +174,11 @@ allocated_decls: std.SegmentedList(Decl, 0) = .{}, |
| 165 | /// When a Decl object is freed from `allocated_decls`, it is pushed into this stack. | 174 | /// When a Decl object is freed from `allocated_decls`, it is pushed into this stack. |
| 166 | decls_free_list: ArrayListUnmanaged(Decl.Index) = .{}, | 175 | decls_free_list: ArrayListUnmanaged(Decl.Index) = .{}, |
| 167 | 176 | ||
| 177 | /// Same pattern as with `allocated_decls`. | ||
| 178 | allocated_namespaces: std.SegmentedList(Namespace, 0) = .{}, | ||
| 179 | /// Same pattern as with `decls_free_list`. | ||
| 180 | namespaces_free_list: ArrayListUnmanaged(Namespace.Index) = .{}, | ||
| 181 | |||
| 168 | global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{}, | 182 | global_assembly: std.AutoHashMapUnmanaged(Decl.Index, []u8) = .{}, |
| 169 | 183 | ||
| 170 | reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct { | 184 | reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct { |
| ... | @@ -172,6 +186,8 @@ reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct { | ... | @@ -172,6 +186,8 @@ reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct { |
| 172 | src: LazySrcLoc, | 186 | src: LazySrcLoc, |
| 173 | }) = .{}, | 187 | }) = .{}, |
| 174 | 188 | ||
| 189 | pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void); | ||
| 190 | |||
| 175 | pub const CImportError = struct { | 191 | pub const CImportError = struct { |
| 176 | offset: u32, | 192 | offset: u32, |
| 177 | line: u32, | 193 | line: u32, |
| ... | @@ -187,108 +203,40 @@ pub const CImportError = struct { | ... | @@ -187,108 +203,40 @@ pub const CImportError = struct { |
| 187 | } | 203 | } |
| 188 | }; | 204 | }; |
| 189 | 205 | ||
| 190 | pub const StringLiteralContext = struct { | 206 | pub const MonomorphedFuncKey = struct { func: Fn.Index, args_index: u32, args_len: u32 }; |
| 191 | bytes: *ArrayListUnmanaged(u8), | ||
| 192 | |||
| 193 | pub const Key = struct { | ||
| 194 | index: u32, | ||
| 195 | len: u32, | ||
| 196 | }; | ||
| 197 | |||
| 198 | pub fn eql(self: @This(), a: Key, b: Key) bool { | ||
| 199 | _ = self; | ||
| 200 | return a.index == b.index and a.len == b.len; | ||
| 201 | } | ||
| 202 | |||
| 203 | pub fn hash(self: @This(), x: Key) u64 { | ||
| 204 | const x_slice = self.bytes.items[x.index..][0..x.len]; | ||
| 205 | return std.hash_map.hashString(x_slice); | ||
| 206 | } | ||
| 207 | }; | ||
| 208 | |||
| 209 | pub const StringLiteralAdapter = struct { | ||
| 210 | bytes: *ArrayListUnmanaged(u8), | ||
| 211 | 207 | ||
| 212 | pub fn eql(self: @This(), a_slice: []const u8, b: StringLiteralContext.Key) bool { | 208 | pub const MonomorphedFuncAdaptedKey = struct { func: Fn.Index, args: []const InternPool.Index }; |
| 213 | const b_slice = self.bytes.items[b.index..][0..b.len]; | ||
| 214 | return mem.eql(u8, a_slice, b_slice); | ||
| 215 | } | ||
| 216 | 209 | ||
| 217 | pub fn hash(self: @This(), adapted_key: []const u8) u64 { | 210 | pub const MonomorphedFuncsSet = std.HashMapUnmanaged( |
| 218 | _ = self; | 211 | MonomorphedFuncKey, |
| 219 | return std.hash_map.hashString(adapted_key); | 212 | InternPool.Index, |
| 220 | } | ||
| 221 | }; | ||
| 222 | |||
| 223 | const MonomorphedFuncsSet = std.HashMapUnmanaged( | ||
| 224 | *Fn, | ||
| 225 | void, | ||
| 226 | MonomorphedFuncsContext, | 213 | MonomorphedFuncsContext, |
| 227 | std.hash_map.default_max_load_percentage, | 214 | std.hash_map.default_max_load_percentage, |
| 228 | ); | 215 | ); |
| 229 | 216 | ||
| 230 | const MonomorphedFuncsContext = struct { | 217 | pub const MonomorphedFuncsContext = struct { |
| 231 | pub fn eql(ctx: @This(), a: *Fn, b: *Fn) bool { | 218 | mod: *Module, |
| 232 | _ = ctx; | 219 | |
| 233 | return a == b; | 220 | pub fn eql(_: @This(), a: MonomorphedFuncKey, b: MonomorphedFuncKey) bool { |
| 221 | return std.meta.eql(a, b); | ||
| 234 | } | 222 | } |
| 235 | 223 | ||
| 236 | /// Must match `Sema.GenericCallAdapter.hash`. | 224 | pub fn hash(ctx: @This(), key: MonomorphedFuncKey) u64 { |
| 237 | pub fn hash(ctx: @This(), key: *Fn) u64 { | 225 | const key_args = ctx.mod.monomorphed_func_keys.items[key.args_index..][0..key.args_len]; |
| 238 | _ = ctx; | 226 | return std.hash.Wyhash.hash(@enumToInt(key.func), std.mem.sliceAsBytes(key_args)); |
| 239 | return key.hash; | ||
| 240 | } | 227 | } |
| 241 | }; | 228 | }; |
| 242 | 229 | ||
| 243 | pub const MemoizedCallSet = std.HashMapUnmanaged( | 230 | pub const MonomorphedFuncsAdaptedContext = struct { |
| 244 | MemoizedCall.Key, | 231 | mod: *Module, |
| 245 | MemoizedCall.Result, | ||
| 246 | MemoizedCall, | ||
| 247 | std.hash_map.default_max_load_percentage, | ||
| 248 | ); | ||
| 249 | |||
| 250 | pub const MemoizedCall = struct { | ||
| 251 | module: *Module, | ||
| 252 | |||
| 253 | pub const Key = struct { | ||
| 254 | func: *Fn, | ||
| 255 | args: []TypedValue, | ||
| 256 | }; | ||
| 257 | |||
| 258 | pub const Result = struct { | ||
| 259 | val: Value, | ||
| 260 | arena: std.heap.ArenaAllocator.State, | ||
| 261 | }; | ||
| 262 | |||
| 263 | pub fn eql(ctx: @This(), a: Key, b: Key) bool { | ||
| 264 | if (a.func != b.func) return false; | ||
| 265 | |||
| 266 | assert(a.args.len == b.args.len); | ||
| 267 | for (a.args, 0..) |a_arg, arg_i| { | ||
| 268 | const b_arg = b.args[arg_i]; | ||
| 269 | if (!a_arg.eql(b_arg, ctx.module)) { | ||
| 270 | return false; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | 232 | ||
| 274 | return true; | 233 | pub fn eql(ctx: @This(), adapted_key: MonomorphedFuncAdaptedKey, other_key: MonomorphedFuncKey) bool { |
| 234 | const other_key_args = ctx.mod.monomorphed_func_keys.items[other_key.args_index..][0..other_key.args_len]; | ||
| 235 | return adapted_key.func == other_key.func and std.mem.eql(InternPool.Index, adapted_key.args, other_key_args); | ||
| 275 | } | 236 | } |
| 276 | 237 | ||
| 277 | /// Must match `Sema.GenericCallAdapter.hash`. | 238 | pub fn hash(_: @This(), adapted_key: MonomorphedFuncAdaptedKey) u64 { |
| 278 | pub fn hash(ctx: @This(), key: Key) u64 { | 239 | return std.hash.Wyhash.hash(@enumToInt(adapted_key.func), std.mem.sliceAsBytes(adapted_key.args)); |
| 279 | var hasher = std.hash.Wyhash.init(0); | ||
| 280 | |||
| 281 | // The generic function Decl is guaranteed to be the first dependency | ||
| 282 | // of each of its instantiations. | ||
| 283 | std.hash.autoHash(&hasher, key.func); | ||
| 284 | |||
| 285 | // This logic must be kept in sync with the logic in `analyzeCall` that | ||
| 286 | // computes the hash. | ||
| 287 | for (key.args) |arg| { | ||
| 288 | arg.hash(&hasher, ctx.module); | ||
| 289 | } | ||
| 290 | |||
| 291 | return hasher.final(); | ||
| 292 | } | 240 | } |
| 293 | }; | 241 | }; |
| 294 | 242 | ||
| ... | @@ -322,7 +270,7 @@ pub const GlobalEmitH = struct { | ... | @@ -322,7 +270,7 @@ pub const GlobalEmitH = struct { |
| 322 | pub const ErrorInt = u32; | 270 | pub const ErrorInt = u32; |
| 323 | 271 | ||
| 324 | pub const Export = struct { | 272 | pub const Export = struct { |
| 325 | options: std.builtin.ExportOptions, | 273 | opts: Options, |
| 326 | src: LazySrcLoc, | 274 | src: LazySrcLoc, |
| 327 | /// The Decl that performs the export. Note that this is *not* the Decl being exported. | 275 | /// The Decl that performs the export. Note that this is *not* the Decl being exported. |
| 328 | owner_decl: Decl.Index, | 276 | owner_decl: Decl.Index, |
| ... | @@ -340,10 +288,17 @@ pub const Export = struct { | ... | @@ -340,10 +288,17 @@ pub const Export = struct { |
| 340 | complete, | 288 | complete, |
| 341 | }, | 289 | }, |
| 342 | 290 | ||
| 291 | pub const Options = struct { | ||
| 292 | name: InternPool.NullTerminatedString, | ||
| 293 | linkage: std.builtin.GlobalLinkage = .Strong, | ||
| 294 | section: InternPool.OptionalNullTerminatedString = .none, | ||
| 295 | visibility: std.builtin.SymbolVisibility = .default, | ||
| 296 | }; | ||
| 297 | |||
| 343 | pub fn getSrcLoc(exp: Export, mod: *Module) SrcLoc { | 298 | pub fn getSrcLoc(exp: Export, mod: *Module) SrcLoc { |
| 344 | const src_decl = mod.declPtr(exp.src_decl); | 299 | const src_decl = mod.declPtr(exp.src_decl); |
| 345 | return .{ | 300 | return .{ |
| 346 | .file_scope = src_decl.getFileScope(), | 301 | .file_scope = src_decl.getFileScope(mod), |
| 347 | .parent_decl_node = src_decl.src_node, | 302 | .parent_decl_node = src_decl.src_node, |
| 348 | .lazy = exp.src, | 303 | .lazy = exp.src, |
| 349 | }; | 304 | }; |
| ... | @@ -351,61 +306,76 @@ pub const Export = struct { | ... | @@ -351,61 +306,76 @@ pub const Export = struct { |
| 351 | }; | 306 | }; |
| 352 | 307 | ||
| 353 | pub const CaptureScope = struct { | 308 | pub const CaptureScope = struct { |
| 309 | refs: u32, | ||
| 354 | parent: ?*CaptureScope, | 310 | parent: ?*CaptureScope, |
| 355 | 311 | ||
| 356 | /// Values from this decl's evaluation that will be closed over in | 312 | /// Values from this decl's evaluation that will be closed over in |
| 357 | /// child decls. Values stored in the value_arena of the linked decl. | 313 | /// child decls. This map is backed by the gpa, and deinited when |
| 358 | /// During sema, this map is backed by the gpa. Once sema completes, | 314 | /// the refcount reaches 0. |
| 359 | /// it is reallocated using the value_arena. | 315 | captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Capture) = .{}, |
| 360 | captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, TypedValue) = .{}, | ||
| 361 | 316 | ||
| 362 | pub fn failed(noalias self: *const @This()) bool { | 317 | pub const Capture = union(enum) { |
| 318 | comptime_val: InternPool.Index, // index of value | ||
| 319 | runtime_val: InternPool.Index, // index of type | ||
| 320 | }; | ||
| 321 | |||
| 322 | pub fn failed(noalias self: *const CaptureScope) bool { | ||
| 363 | return self.captures.available == 0 and self.captures.size == std.math.maxInt(u32); | 323 | return self.captures.available == 0 and self.captures.size == std.math.maxInt(u32); |
| 364 | } | 324 | } |
| 365 | 325 | ||
| 366 | pub fn fail(noalias self: *@This()) void { | 326 | pub fn fail(noalias self: *CaptureScope, gpa: Allocator) void { |
| 327 | self.captures.deinit(gpa); | ||
| 367 | self.captures.available = 0; | 328 | self.captures.available = 0; |
| 368 | self.captures.size = std.math.maxInt(u32); | 329 | self.captures.size = std.math.maxInt(u32); |
| 369 | } | 330 | } |
| 331 | |||
| 332 | pub fn incRef(self: *CaptureScope) void { | ||
| 333 | self.refs += 1; | ||
| 334 | } | ||
| 335 | |||
| 336 | pub fn decRef(self: *CaptureScope, gpa: Allocator) void { | ||
| 337 | self.refs -= 1; | ||
| 338 | if (self.refs > 0) return; | ||
| 339 | if (self.parent) |p| p.decRef(gpa); | ||
| 340 | if (!self.failed()) { | ||
| 341 | self.captures.deinit(gpa); | ||
| 342 | } | ||
| 343 | gpa.destroy(self); | ||
| 344 | } | ||
| 370 | }; | 345 | }; |
| 371 | 346 | ||
| 372 | pub const WipCaptureScope = struct { | 347 | pub const WipCaptureScope = struct { |
| 373 | scope: *CaptureScope, | 348 | scope: *CaptureScope, |
| 374 | finalized: bool, | 349 | finalized: bool, |
| 375 | gpa: Allocator, | 350 | gpa: Allocator, |
| 376 | perm_arena: Allocator, | ||
| 377 | 351 | ||
| 378 | pub fn init(gpa: Allocator, perm_arena: Allocator, parent: ?*CaptureScope) !@This() { | 352 | pub fn init(gpa: Allocator, parent: ?*CaptureScope) !WipCaptureScope { |
| 379 | const scope = try perm_arena.create(CaptureScope); | 353 | const scope = try gpa.create(CaptureScope); |
| 380 | scope.* = .{ .parent = parent }; | 354 | if (parent) |p| p.incRef(); |
| 381 | return @This(){ | 355 | scope.* = .{ .refs = 1, .parent = parent }; |
| 356 | return .{ | ||
| 382 | .scope = scope, | 357 | .scope = scope, |
| 383 | .finalized = false, | 358 | .finalized = false, |
| 384 | .gpa = gpa, | 359 | .gpa = gpa, |
| 385 | .perm_arena = perm_arena, | ||
| 386 | }; | 360 | }; |
| 387 | } | 361 | } |
| 388 | 362 | ||
| 389 | pub fn finalize(noalias self: *@This()) !void { | 363 | pub fn finalize(noalias self: *WipCaptureScope) !void { |
| 390 | assert(!self.finalized); | ||
| 391 | // use a temp to avoid unintentional aliasing due to RLS | ||
| 392 | const tmp = try self.scope.captures.clone(self.perm_arena); | ||
| 393 | self.scope.captures.deinit(self.gpa); | ||
| 394 | self.scope.captures = tmp; | ||
| 395 | self.finalized = true; | 364 | self.finalized = true; |
| 396 | } | 365 | } |
| 397 | 366 | ||
| 398 | pub fn reset(noalias self: *@This(), parent: ?*CaptureScope) !void { | 367 | pub fn reset(noalias self: *WipCaptureScope, parent: ?*CaptureScope) !void { |
| 399 | if (!self.finalized) try self.finalize(); | 368 | self.scope.decRef(self.gpa); |
| 400 | self.scope = try self.perm_arena.create(CaptureScope); | 369 | self.scope = try self.gpa.create(CaptureScope); |
| 401 | self.scope.* = .{ .parent = parent }; | 370 | if (parent) |p| p.incRef(); |
| 402 | self.finalized = false; | 371 | self.scope.* = .{ .refs = 1, .parent = parent }; |
| 403 | } | 372 | } |
| 404 | 373 | ||
| 405 | pub fn deinit(noalias self: *@This()) void { | 374 | pub fn deinit(noalias self: *WipCaptureScope) void { |
| 406 | if (!self.finalized) { | 375 | if (self.finalized) { |
| 407 | self.scope.captures.deinit(self.gpa); | 376 | self.scope.decRef(self.gpa); |
| 408 | self.scope.fail(); | 377 | } else { |
| 378 | self.scope.fail(self.gpa); | ||
| 409 | } | 379 | } |
| 410 | self.* = undefined; | 380 | self.* = undefined; |
| 411 | } | 381 | } |
| ... | @@ -452,8 +422,7 @@ const ValueArena = struct { | ... | @@ -452,8 +422,7 @@ const ValueArena = struct { |
| 452 | }; | 422 | }; |
| 453 | 423 | ||
| 454 | pub const Decl = struct { | 424 | pub const Decl = struct { |
| 455 | /// Allocated with Module's allocator; outlives the ZIR code. | 425 | name: InternPool.NullTerminatedString, |
| 456 | name: [*:0]const u8, | ||
| 457 | /// The most recent Type of the Decl after a successful semantic analysis. | 426 | /// The most recent Type of the Decl after a successful semantic analysis. |
| 458 | /// Populated when `has_tv`. | 427 | /// Populated when `has_tv`. |
| 459 | ty: Type, | 428 | ty: Type, |
| ... | @@ -461,20 +430,16 @@ pub const Decl = struct { | ... | @@ -461,20 +430,16 @@ pub const Decl = struct { |
| 461 | /// Populated when `has_tv`. | 430 | /// Populated when `has_tv`. |
| 462 | val: Value, | 431 | val: Value, |
| 463 | /// Populated when `has_tv`. | 432 | /// Populated when `has_tv`. |
| 464 | /// Points to memory inside value_arena. | 433 | @"linksection": InternPool.OptionalNullTerminatedString, |
| 465 | @"linksection": ?[*:0]const u8, | ||
| 466 | /// Populated when `has_tv`. | 434 | /// Populated when `has_tv`. |
| 467 | @"align": u32, | 435 | @"align": u32, |
| 468 | /// Populated when `has_tv`. | 436 | /// Populated when `has_tv`. |
| 469 | @"addrspace": std.builtin.AddressSpace, | 437 | @"addrspace": std.builtin.AddressSpace, |
| 470 | /// The memory for ty, val, align, linksection, and captures. | ||
| 471 | /// If this is `null` then there is no memory management needed. | ||
| 472 | value_arena: ?*ValueArena = null, | ||
| 473 | /// The direct parent namespace of the Decl. | 438 | /// The direct parent namespace of the Decl. |
| 474 | /// Reference to externally owned memory. | 439 | /// Reference to externally owned memory. |
| 475 | /// In the case of the Decl corresponding to a file, this is | 440 | /// In the case of the Decl corresponding to a file, this is |
| 476 | /// the namespace of the struct, since there is no parent. | 441 | /// the namespace of the struct, since there is no parent. |
| 477 | src_namespace: *Namespace, | 442 | src_namespace: Namespace.Index, |
| 478 | 443 | ||
| 479 | /// The scope which lexically contains this decl. A decl must depend | 444 | /// The scope which lexically contains this decl. A decl must depend |
| 480 | /// on its lexical parent, in order to ensure that this pointer is valid. | 445 | /// on its lexical parent, in order to ensure that this pointer is valid. |
| ... | @@ -624,55 +589,17 @@ pub const Decl = struct { | ... | @@ -624,55 +589,17 @@ pub const Decl = struct { |
| 624 | function_body, | 589 | function_body, |
| 625 | }; | 590 | }; |
| 626 | 591 | ||
| 627 | pub fn clearName(decl: *Decl, gpa: Allocator) void { | ||
| 628 | gpa.free(mem.sliceTo(decl.name, 0)); | ||
| 629 | decl.name = undefined; | ||
| 630 | } | ||
| 631 | |||
| 632 | pub fn clearValues(decl: *Decl, mod: *Module) void { | 592 | pub fn clearValues(decl: *Decl, mod: *Module) void { |
| 633 | const gpa = mod.gpa; | 593 | if (decl.getOwnedFunctionIndex(mod).unwrap()) |func| { |
| 634 | if (decl.getExternFn()) |extern_fn| { | ||
| 635 | extern_fn.deinit(gpa); | ||
| 636 | gpa.destroy(extern_fn); | ||
| 637 | } | ||
| 638 | if (decl.getFunction()) |func| { | ||
| 639 | _ = mod.align_stack_fns.remove(func); | 594 | _ = mod.align_stack_fns.remove(func); |
| 640 | if (func.comptime_args != null) { | 595 | mod.destroyFunc(func); |
| 641 | _ = mod.monomorphed_funcs.remove(func); | ||
| 642 | } | ||
| 643 | func.deinit(gpa); | ||
| 644 | gpa.destroy(func); | ||
| 645 | } | ||
| 646 | if (decl.getVariable()) |variable| { | ||
| 647 | variable.deinit(gpa); | ||
| 648 | gpa.destroy(variable); | ||
| 649 | } | ||
| 650 | if (decl.value_arena) |value_arena| { | ||
| 651 | if (decl.owns_tv) { | ||
| 652 | if (decl.val.castTag(.str_lit)) |str_lit| { | ||
| 653 | mod.string_literal_table.getPtrContext(str_lit.data, .{ | ||
| 654 | .bytes = &mod.string_literal_bytes, | ||
| 655 | }).?.* = .none; | ||
| 656 | } | ||
| 657 | } | ||
| 658 | value_arena.deinit(gpa); | ||
| 659 | decl.value_arena = null; | ||
| 660 | decl.has_tv = false; | ||
| 661 | decl.owns_tv = false; | ||
| 662 | } | 596 | } |
| 663 | } | 597 | } |
| 664 | 598 | ||
| 665 | pub fn finalizeNewArena(decl: *Decl, arena: *std.heap.ArenaAllocator) !void { | ||
| 666 | assert(decl.value_arena == null); | ||
| 667 | const value_arena = try arena.allocator().create(ValueArena); | ||
| 668 | value_arena.* = .{ .state = arena.state }; | ||
| 669 | decl.value_arena = value_arena; | ||
| 670 | } | ||
| 671 | |||
| 672 | /// This name is relative to the containing namespace of the decl. | 599 | /// This name is relative to the containing namespace of the decl. |
| 673 | /// The memory is owned by the containing File ZIR. | 600 | /// The memory is owned by the containing File ZIR. |
| 674 | pub fn getName(decl: Decl) ?[:0]const u8 { | 601 | pub fn getName(decl: Decl, mod: *Module) ?[:0]const u8 { |
| 675 | const zir = decl.getFileScope().zir; | 602 | const zir = decl.getFileScope(mod).zir; |
| 676 | return decl.getNameZir(zir); | 603 | return decl.getNameZir(zir); |
| 677 | } | 604 | } |
| 678 | 605 | ||
| ... | @@ -683,8 +610,8 @@ pub const Decl = struct { | ... | @@ -683,8 +610,8 @@ pub const Decl = struct { |
| 683 | return zir.nullTerminatedString(name_index); | 610 | return zir.nullTerminatedString(name_index); |
| 684 | } | 611 | } |
| 685 | 612 | ||
| 686 | pub fn contentsHash(decl: Decl) std.zig.SrcHash { | 613 | pub fn contentsHash(decl: Decl, mod: *Module) std.zig.SrcHash { |
| 687 | const zir = decl.getFileScope().zir; | 614 | const zir = decl.getFileScope(mod).zir; |
| 688 | return decl.contentsHashZir(zir); | 615 | return decl.contentsHashZir(zir); |
| 689 | } | 616 | } |
| 690 | 617 | ||
| ... | @@ -695,31 +622,31 @@ pub const Decl = struct { | ... | @@ -695,31 +622,31 @@ pub const Decl = struct { |
| 695 | return contents_hash; | 622 | return contents_hash; |
| 696 | } | 623 | } |
| 697 | 624 | ||
| 698 | pub fn zirBlockIndex(decl: *const Decl) Zir.Inst.Index { | 625 | pub fn zirBlockIndex(decl: *const Decl, mod: *Module) Zir.Inst.Index { |
| 699 | assert(decl.zir_decl_index != 0); | 626 | assert(decl.zir_decl_index != 0); |
| 700 | const zir = decl.getFileScope().zir; | 627 | const zir = decl.getFileScope(mod).zir; |
| 701 | return zir.extra[decl.zir_decl_index + 6]; | 628 | return zir.extra[decl.zir_decl_index + 6]; |
| 702 | } | 629 | } |
| 703 | 630 | ||
| 704 | pub fn zirAlignRef(decl: Decl) Zir.Inst.Ref { | 631 | pub fn zirAlignRef(decl: Decl, mod: *Module) Zir.Inst.Ref { |
| 705 | if (!decl.has_align) return .none; | 632 | if (!decl.has_align) return .none; |
| 706 | assert(decl.zir_decl_index != 0); | 633 | assert(decl.zir_decl_index != 0); |
| 707 | const zir = decl.getFileScope().zir; | 634 | const zir = decl.getFileScope(mod).zir; |
| 708 | return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 8]); | 635 | return @intToEnum(Zir.Inst.Ref, zir.extra[decl.zir_decl_index + 8]); |
| 709 | } | 636 | } |
| 710 | 637 | ||
| 711 | pub fn zirLinksectionRef(decl: Decl) Zir.Inst.Ref { | 638 | pub fn zirLinksectionRef(decl: Decl, mod: *Module) Zir.Inst.Ref { |
| 712 | if (!decl.has_linksection_or_addrspace) return .none; | 639 | if (!decl.has_linksection_or_addrspace) return .none; |
| 713 | assert(decl.zir_decl_index != 0); | 640 | assert(decl.zir_decl_index != 0); |
| 714 | const zir = decl.getFileScope().zir; | 641 | const zir = decl.getFileScope(mod).zir; |
| 715 | const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align); | 642 | const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align); |
| 716 | return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | 643 | return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); |
| 717 | } | 644 | } |
| 718 | 645 | ||
| 719 | pub fn zirAddrspaceRef(decl: Decl) Zir.Inst.Ref { | 646 | pub fn zirAddrspaceRef(decl: Decl, mod: *Module) Zir.Inst.Ref { |
| 720 | if (!decl.has_linksection_or_addrspace) return .none; | 647 | if (!decl.has_linksection_or_addrspace) return .none; |
| 721 | assert(decl.zir_decl_index != 0); | 648 | assert(decl.zir_decl_index != 0); |
| 722 | const zir = decl.getFileScope().zir; | 649 | const zir = decl.getFileScope(mod).zir; |
| 723 | const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align) + 1; | 650 | const extra_index = decl.zir_decl_index + 8 + @boolToInt(decl.has_align) + 1; |
| 724 | return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | 651 | return @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); |
| 725 | } | 652 | } |
| ... | @@ -744,154 +671,167 @@ pub const Decl = struct { | ... | @@ -744,154 +671,167 @@ pub const Decl = struct { |
| 744 | return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(node_index)); | 671 | return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(node_index)); |
| 745 | } | 672 | } |
| 746 | 673 | ||
| 747 | pub fn srcLoc(decl: Decl) SrcLoc { | 674 | pub fn srcLoc(decl: Decl, mod: *Module) SrcLoc { |
| 748 | return decl.nodeOffsetSrcLoc(0); | 675 | return decl.nodeOffsetSrcLoc(0, mod); |
| 749 | } | 676 | } |
| 750 | 677 | ||
| 751 | pub fn nodeOffsetSrcLoc(decl: Decl, node_offset: i32) SrcLoc { | 678 | pub fn nodeOffsetSrcLoc(decl: Decl, node_offset: i32, mod: *Module) SrcLoc { |
| 752 | return .{ | 679 | return .{ |
| 753 | .file_scope = decl.getFileScope(), | 680 | .file_scope = decl.getFileScope(mod), |
| 754 | .parent_decl_node = decl.src_node, | 681 | .parent_decl_node = decl.src_node, |
| 755 | .lazy = LazySrcLoc.nodeOffset(node_offset), | 682 | .lazy = LazySrcLoc.nodeOffset(node_offset), |
| 756 | }; | 683 | }; |
| 757 | } | 684 | } |
| 758 | 685 | ||
| 759 | pub fn srcToken(decl: Decl) Ast.TokenIndex { | 686 | pub fn srcToken(decl: Decl, mod: *Module) Ast.TokenIndex { |
| 760 | const tree = &decl.getFileScope().tree; | 687 | const tree = &decl.getFileScope(mod).tree; |
| 761 | return tree.firstToken(decl.src_node); | 688 | return tree.firstToken(decl.src_node); |
| 762 | } | 689 | } |
| 763 | 690 | ||
| 764 | pub fn srcByteOffset(decl: Decl) u32 { | 691 | pub fn srcByteOffset(decl: Decl, mod: *Module) u32 { |
| 765 | const tree = &decl.getFileScope().tree; | 692 | const tree = &decl.getFileScope(mod).tree; |
| 766 | return tree.tokens.items(.start)[decl.srcToken()]; | 693 | return tree.tokens.items(.start)[decl.srcToken()]; |
| 767 | } | 694 | } |
| 768 | 695 | ||
| 769 | pub fn renderFullyQualifiedName(decl: Decl, mod: *Module, writer: anytype) !void { | 696 | pub fn renderFullyQualifiedName(decl: Decl, mod: *Module, writer: anytype) !void { |
| 770 | const unqualified_name = mem.sliceTo(decl.name, 0); | ||
| 771 | if (decl.name_fully_qualified) { | 697 | if (decl.name_fully_qualified) { |
| 772 | return writer.writeAll(unqualified_name); | 698 | try writer.print("{}", .{decl.name.fmt(&mod.intern_pool)}); |
| 699 | } else { | ||
| 700 | try mod.namespacePtr(decl.src_namespace).renderFullyQualifiedName(mod, decl.name, writer); | ||
| 773 | } | 701 | } |
| 774 | return decl.src_namespace.renderFullyQualifiedName(mod, unqualified_name, writer); | ||
| 775 | } | 702 | } |
| 776 | 703 | ||
| 777 | pub fn renderFullyQualifiedDebugName(decl: Decl, mod: *Module, writer: anytype) !void { | 704 | pub fn renderFullyQualifiedDebugName(decl: Decl, mod: *Module, writer: anytype) !void { |
| 778 | const unqualified_name = mem.sliceTo(decl.name, 0); | 705 | return mod.namespacePtr(decl.src_namespace).renderFullyQualifiedDebugName(mod, decl.name, writer); |
| 779 | return decl.src_namespace.renderFullyQualifiedDebugName(mod, unqualified_name, writer); | ||
| 780 | } | 706 | } |
| 781 | 707 | ||
| 782 | pub fn getFullyQualifiedName(decl: Decl, mod: *Module) ![:0]u8 { | 708 | pub fn getFullyQualifiedName(decl: Decl, mod: *Module) !InternPool.NullTerminatedString { |
| 783 | var buffer = std.ArrayList(u8).init(mod.gpa); | 709 | if (decl.name_fully_qualified) return decl.name; |
| 784 | defer buffer.deinit(); | 710 | |
| 785 | try decl.renderFullyQualifiedName(mod, buffer.writer()); | 711 | const ip = &mod.intern_pool; |
| 712 | const count = count: { | ||
| 713 | var count: usize = ip.stringToSlice(decl.name).len + 1; | ||
| 714 | var ns: Namespace.Index = decl.src_namespace; | ||
| 715 | while (true) { | ||
| 716 | const namespace = mod.namespacePtr(ns); | ||
| 717 | const ns_decl = mod.declPtr(namespace.getDeclIndex(mod)); | ||
| 718 | count += ip.stringToSlice(ns_decl.name).len + 1; | ||
| 719 | ns = namespace.parent.unwrap() orelse { | ||
| 720 | count += namespace.file_scope.sub_file_path.len; | ||
| 721 | break :count count; | ||
| 722 | }; | ||
| 723 | } | ||
| 724 | }; | ||
| 725 | |||
| 726 | const gpa = mod.gpa; | ||
| 727 | const start = ip.string_bytes.items.len; | ||
| 728 | // Protects reads of interned strings from being reallocated during the call to | ||
| 729 | // renderFullyQualifiedName. | ||
| 730 | try ip.string_bytes.ensureUnusedCapacity(gpa, count); | ||
| 731 | decl.renderFullyQualifiedName(mod, ip.string_bytes.writer(gpa)) catch unreachable; | ||
| 786 | 732 | ||
| 787 | // Sanitize the name for nvptx which is more restrictive. | 733 | // Sanitize the name for nvptx which is more restrictive. |
| 734 | // TODO This should be handled by the backend, not the frontend. Have a | ||
| 735 | // look at how the C backend does it for inspiration. | ||
| 788 | if (mod.comp.bin_file.options.target.cpu.arch.isNvptx()) { | 736 | if (mod.comp.bin_file.options.target.cpu.arch.isNvptx()) { |
| 789 | for (buffer.items) |*byte| switch (byte.*) { | 737 | for (ip.string_bytes.items[start..]) |*byte| switch (byte.*) { |
| 790 | '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_', | 738 | '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_', |
| 791 | else => {}, | 739 | else => {}, |
| 792 | }; | 740 | }; |
| 793 | } | 741 | } |
| 794 | 742 | ||
| 795 | return buffer.toOwnedSliceSentinel(0); | 743 | return ip.getOrPutTrailingString(gpa, ip.string_bytes.items.len - start); |
| 796 | } | 744 | } |
| 797 | 745 | ||
| 798 | pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue { | 746 | pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue { |
| 799 | if (!decl.has_tv) return error.AnalysisFail; | 747 | if (!decl.has_tv) return error.AnalysisFail; |
| 800 | return TypedValue{ | 748 | return TypedValue{ .ty = decl.ty, .val = decl.val }; |
| 801 | .ty = decl.ty, | ||
| 802 | .val = decl.val, | ||
| 803 | }; | ||
| 804 | } | 749 | } |
| 805 | 750 | ||
| 806 | pub fn value(decl: *Decl) error{AnalysisFail}!Value { | 751 | pub fn internValue(decl: *Decl, mod: *Module) Allocator.Error!InternPool.Index { |
| 807 | return (try decl.typedValue()).val; | 752 | assert(decl.has_tv); |
| 753 | const ip_index = try decl.val.intern(decl.ty, mod); | ||
| 754 | decl.val = ip_index.toValue(); | ||
| 755 | return ip_index; | ||
| 808 | } | 756 | } |
| 809 | 757 | ||
| 810 | pub fn isFunction(decl: Decl) !bool { | 758 | pub fn isFunction(decl: Decl, mod: *const Module) !bool { |
| 811 | const tv = try decl.typedValue(); | 759 | const tv = try decl.typedValue(); |
| 812 | return tv.ty.zigTypeTag() == .Fn; | 760 | return tv.ty.zigTypeTag(mod) == .Fn; |
| 813 | } | 761 | } |
| 814 | 762 | ||
| 815 | /// If the Decl has a value and it is a struct, return it, | 763 | /// If the Decl owns its value and it is a struct, return it, |
| 816 | /// otherwise null. | 764 | /// otherwise null. |
| 817 | pub fn getStruct(decl: *Decl) ?*Struct { | 765 | pub fn getOwnedStruct(decl: Decl, mod: *Module) ?*Struct { |
| 818 | if (!decl.owns_tv) return null; | 766 | return mod.structPtrUnwrap(decl.getOwnedStructIndex(mod)); |
| 819 | const ty = (decl.val.castTag(.ty) orelse return null).data; | 767 | } |
| 820 | const struct_obj = (ty.castTag(.@"struct") orelse return null).data; | 768 | |
| 821 | return struct_obj; | 769 | pub fn getOwnedStructIndex(decl: Decl, mod: *Module) Struct.OptionalIndex { |
| 770 | if (!decl.owns_tv) return .none; | ||
| 771 | if (decl.val.ip_index == .none) return .none; | ||
| 772 | return mod.intern_pool.indexToStructType(decl.val.toIntern()); | ||
| 822 | } | 773 | } |
| 823 | 774 | ||
| 824 | /// If the Decl has a value and it is a union, return it, | 775 | /// If the Decl owns its value and it is a union, return it, |
| 825 | /// otherwise null. | 776 | /// otherwise null. |
| 826 | pub fn getUnion(decl: *Decl) ?*Union { | 777 | pub fn getOwnedUnion(decl: Decl, mod: *Module) ?*Union { |
| 827 | if (!decl.owns_tv) return null; | 778 | if (!decl.owns_tv) return null; |
| 828 | const ty = (decl.val.castTag(.ty) orelse return null).data; | 779 | if (decl.val.ip_index == .none) return null; |
| 829 | const union_obj = (ty.cast(Type.Payload.Union) orelse return null).data; | 780 | return mod.typeToUnion(decl.val.toType()); |
| 830 | return union_obj; | ||
| 831 | } | 781 | } |
| 832 | 782 | ||
| 833 | /// If the Decl has a value and it is a function, return it, | 783 | /// If the Decl owns its value and it is a function, return it, |
| 834 | /// otherwise null. | 784 | /// otherwise null. |
| 835 | pub fn getFunction(decl: *const Decl) ?*Fn { | 785 | pub fn getOwnedFunction(decl: Decl, mod: *Module) ?*Fn { |
| 836 | if (!decl.owns_tv) return null; | 786 | return mod.funcPtrUnwrap(decl.getOwnedFunctionIndex(mod)); |
| 837 | const func = (decl.val.castTag(.function) orelse return null).data; | ||
| 838 | return func; | ||
| 839 | } | 787 | } |
| 840 | 788 | ||
| 841 | /// If the Decl has a value and it is an extern function, returns it, | 789 | pub fn getOwnedFunctionIndex(decl: Decl, mod: *Module) Fn.OptionalIndex { |
| 790 | return if (decl.owns_tv) decl.val.getFunctionIndex(mod) else .none; | ||
| 791 | } | ||
| 792 | |||
| 793 | /// If the Decl owns its value and it is an extern function, returns it, | ||
| 842 | /// otherwise null. | 794 | /// otherwise null. |
| 843 | pub fn getExternFn(decl: *const Decl) ?*ExternFn { | 795 | pub fn getOwnedExternFunc(decl: Decl, mod: *Module) ?InternPool.Key.ExternFunc { |
| 844 | if (!decl.owns_tv) return null; | 796 | return if (decl.owns_tv) decl.val.getExternFunc(mod) else null; |
| 845 | const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data; | ||
| 846 | return extern_fn; | ||
| 847 | } | 797 | } |
| 848 | 798 | ||
| 849 | /// If the Decl has a value and it is a variable, returns it, | 799 | /// If the Decl owns its value and it is a variable, returns it, |
| 850 | /// otherwise null. | 800 | /// otherwise null. |
| 851 | pub fn getVariable(decl: *const Decl) ?*Var { | 801 | pub fn getOwnedVariable(decl: Decl, mod: *Module) ?InternPool.Key.Variable { |
| 852 | if (!decl.owns_tv) return null; | 802 | return if (decl.owns_tv) decl.val.getVariable(mod) else null; |
| 853 | const variable = (decl.val.castTag(.variable) orelse return null).data; | ||
| 854 | return variable; | ||
| 855 | } | 803 | } |
| 856 | 804 | ||
| 857 | /// Gets the namespace that this Decl creates by being a struct, union, | 805 | /// Gets the namespace that this Decl creates by being a struct, union, |
| 858 | /// enum, or opaque. | 806 | /// enum, or opaque. |
| 859 | /// Only returns it if the Decl is the owner. | 807 | /// Only returns it if the Decl is the owner. |
| 860 | pub fn getInnerNamespace(decl: *Decl) ?*Namespace { | 808 | pub fn getOwnedInnerNamespaceIndex(decl: Decl, mod: *Module) Namespace.OptionalIndex { |
| 861 | if (!decl.owns_tv) return null; | 809 | if (!decl.owns_tv) return .none; |
| 862 | const ty = (decl.val.castTag(.ty) orelse return null).data; | 810 | return switch (decl.val.ip_index) { |
| 863 | switch (ty.tag()) { | 811 | .empty_struct_type => .none, |
| 864 | .@"struct" => { | 812 | .none => .none, |
| 865 | const struct_obj = ty.castTag(.@"struct").?.data; | 813 | else => switch (mod.intern_pool.indexToKey(decl.val.toIntern())) { |
| 866 | return &struct_obj.namespace; | 814 | .opaque_type => |opaque_type| opaque_type.namespace.toOptional(), |
| 867 | }, | 815 | .struct_type => |struct_type| struct_type.namespace, |
| 868 | .enum_full, .enum_nonexhaustive => { | 816 | .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(), |
| 869 | const enum_obj = ty.cast(Type.Payload.EnumFull).?.data; | 817 | .enum_type => |enum_type| enum_type.namespace, |
| 870 | return &enum_obj.namespace; | 818 | else => .none, |
| 871 | }, | ||
| 872 | .empty_struct => { | ||
| 873 | return ty.castTag(.empty_struct).?.data; | ||
| 874 | }, | ||
| 875 | .@"opaque" => { | ||
| 876 | const opaque_obj = ty.cast(Type.Payload.Opaque).?.data; | ||
| 877 | return &opaque_obj.namespace; | ||
| 878 | }, | ||
| 879 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 880 | const union_obj = ty.cast(Type.Payload.Union).?.data; | ||
| 881 | return &union_obj.namespace; | ||
| 882 | }, | 819 | }, |
| 820 | }; | ||
| 821 | } | ||
| 883 | 822 | ||
| 884 | else => return null, | 823 | /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer. |
| 885 | } | 824 | pub fn getOwnedInnerNamespace(decl: Decl, mod: *Module) ?*Namespace { |
| 825 | return mod.namespacePtrUnwrap(decl.getOwnedInnerNamespaceIndex(mod)); | ||
| 886 | } | 826 | } |
| 887 | 827 | ||
| 888 | pub fn dump(decl: *Decl) void { | 828 | pub fn dump(decl: *Decl) void { |
| 889 | const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src); | 829 | const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src); |
| 890 | std.debug.print("{s}:{d}:{d} name={s} status={s}", .{ | 830 | std.debug.print("{s}:{d}:{d} name={d} status={s}", .{ |
| 891 | decl.scope.sub_file_path, | 831 | decl.scope.sub_file_path, |
| 892 | loc.line + 1, | 832 | loc.line + 1, |
| 893 | loc.column + 1, | 833 | loc.column + 1, |
| 894 | mem.sliceTo(decl.name, 0), | 834 | @enumToInt(decl.name), |
| 895 | @tagName(decl.analysis), | 835 | @tagName(decl.analysis), |
| 896 | }); | 836 | }); |
| 897 | if (decl.has_tv) { | 837 | if (decl.has_tv) { |
| ... | @@ -900,8 +840,8 @@ pub const Decl = struct { | ... | @@ -900,8 +840,8 @@ pub const Decl = struct { |
| 900 | std.debug.print("\n", .{}); | 840 | std.debug.print("\n", .{}); |
| 901 | } | 841 | } |
| 902 | 842 | ||
| 903 | pub fn getFileScope(decl: Decl) *File { | 843 | pub fn getFileScope(decl: Decl, mod: *Module) *File { |
| 904 | return decl.src_namespace.file_scope; | 844 | return mod.namespacePtr(decl.src_namespace).file_scope; |
| 905 | } | 845 | } |
| 906 | 846 | ||
| 907 | pub fn removeDependant(decl: *Decl, other: Decl.Index) void { | 847 | pub fn removeDependant(decl: *Decl, other: Decl.Index) void { |
| ... | @@ -912,25 +852,29 @@ pub const Decl = struct { | ... | @@ -912,25 +852,29 @@ pub const Decl = struct { |
| 912 | assert(decl.dependencies.swapRemove(other)); | 852 | assert(decl.dependencies.swapRemove(other)); |
| 913 | } | 853 | } |
| 914 | 854 | ||
| 915 | pub fn isExtern(decl: Decl) bool { | 855 | pub fn isExtern(decl: Decl, mod: *Module) bool { |
| 916 | assert(decl.has_tv); | 856 | assert(decl.has_tv); |
| 917 | return switch (decl.val.tag()) { | 857 | return switch (mod.intern_pool.indexToKey(decl.val.toIntern())) { |
| 918 | .extern_fn => true, | 858 | .variable => |variable| variable.is_extern, |
| 919 | .variable => decl.val.castTag(.variable).?.data.init.tag() == .unreachable_value, | 859 | .extern_func => true, |
| 920 | else => false, | 860 | else => false, |
| 921 | }; | 861 | }; |
| 922 | } | 862 | } |
| 923 | 863 | ||
| 924 | pub fn getAlignment(decl: Decl, target: Target) u32 { | 864 | pub fn getAlignment(decl: Decl, mod: *Module) u32 { |
| 925 | assert(decl.has_tv); | 865 | assert(decl.has_tv); |
| 926 | if (decl.@"align" != 0) { | 866 | if (decl.@"align" != 0) { |
| 927 | // Explicit alignment. | 867 | // Explicit alignment. |
| 928 | return decl.@"align"; | 868 | return decl.@"align"; |
| 929 | } else { | 869 | } else { |
| 930 | // Natural alignment. | 870 | // Natural alignment. |
| 931 | return decl.ty.abiAlignment(target); | 871 | return decl.ty.abiAlignment(mod); |
| 932 | } | 872 | } |
| 933 | } | 873 | } |
| 874 | |||
| 875 | pub fn intern(decl: *Decl, mod: *Module) Allocator.Error!void { | ||
| 876 | decl.val = (try decl.val.intern(decl.ty, mod)).toValue(); | ||
| 877 | } | ||
| 934 | }; | 878 | }; |
| 935 | 879 | ||
| 936 | /// This state is attached to every Decl when Module emit_h is non-null. | 880 | /// This state is attached to every Decl when Module emit_h is non-null. |
| ... | @@ -938,38 +882,6 @@ pub const EmitH = struct { | ... | @@ -938,38 +882,6 @@ pub const EmitH = struct { |
| 938 | fwd_decl: ArrayListUnmanaged(u8) = .{}, | 882 | fwd_decl: ArrayListUnmanaged(u8) = .{}, |
| 939 | }; | 883 | }; |
| 940 | 884 | ||
| 941 | /// Represents the data that an explicit error set syntax provides. | ||
| 942 | pub const ErrorSet = struct { | ||
| 943 | /// The Decl that corresponds to the error set itself. | ||
| 944 | owner_decl: Decl.Index, | ||
| 945 | /// The string bytes are stored in the owner Decl arena. | ||
| 946 | /// These must be in sorted order. See sortNames. | ||
| 947 | names: NameMap, | ||
| 948 | |||
| 949 | pub const NameMap = std.StringArrayHashMapUnmanaged(void); | ||
| 950 | |||
| 951 | pub fn srcLoc(self: ErrorSet, mod: *Module) SrcLoc { | ||
| 952 | const owner_decl = mod.declPtr(self.owner_decl); | ||
| 953 | return .{ | ||
| 954 | .file_scope = owner_decl.getFileScope(), | ||
| 955 | .parent_decl_node = owner_decl.src_node, | ||
| 956 | .lazy = LazySrcLoc.nodeOffset(0), | ||
| 957 | }; | ||
| 958 | } | ||
| 959 | |||
| 960 | /// sort the NameMap. This should be called whenever the map is modified. | ||
| 961 | /// alloc should be the allocator used for the NameMap data. | ||
| 962 | pub fn sortNames(names: *NameMap) void { | ||
| 963 | const Context = struct { | ||
| 964 | keys: [][]const u8, | ||
| 965 | pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool { | ||
| 966 | return std.mem.lessThan(u8, ctx.keys[a_index], ctx.keys[b_index]); | ||
| 967 | } | ||
| 968 | }; | ||
| 969 | names.sort(Context{ .keys = names.keys() }); | ||
| 970 | } | ||
| 971 | }; | ||
| 972 | |||
| 973 | pub const PropertyBoolean = enum { no, yes, unknown, wip }; | 885 | pub const PropertyBoolean = enum { no, yes, unknown, wip }; |
| 974 | 886 | ||
| 975 | /// Represents the data that a struct declaration provides. | 887 | /// Represents the data that a struct declaration provides. |
| ... | @@ -977,7 +889,7 @@ pub const Struct = struct { | ... | @@ -977,7 +889,7 @@ pub const Struct = struct { |
| 977 | /// Set of field names in declaration order. | 889 | /// Set of field names in declaration order. |
| 978 | fields: Fields, | 890 | fields: Fields, |
| 979 | /// Represents the declarations inside this struct. | 891 | /// Represents the declarations inside this struct. |
| 980 | namespace: Namespace, | 892 | namespace: Namespace.Index, |
| 981 | /// The Decl that corresponds to the struct itself. | 893 | /// The Decl that corresponds to the struct itself. |
| 982 | owner_decl: Decl.Index, | 894 | owner_decl: Decl.Index, |
| 983 | /// Index of the struct_decl ZIR instruction. | 895 | /// Index of the struct_decl ZIR instruction. |
| ... | @@ -989,7 +901,7 @@ pub const Struct = struct { | ... | @@ -989,7 +901,7 @@ pub const Struct = struct { |
| 989 | /// If the layout is packed, this is the backing integer type of the packed struct. | 901 | /// If the layout is packed, this is the backing integer type of the packed struct. |
| 990 | /// Whether zig chooses this type or the user specifies it, it is stored here. | 902 | /// Whether zig chooses this type or the user specifies it, it is stored here. |
| 991 | /// This will be set to the noreturn type until status is `have_layout`. | 903 | /// This will be set to the noreturn type until status is `have_layout`. |
| 992 | backing_int_ty: Type = Type.initTag(.noreturn), | 904 | backing_int_ty: Type = Type.noreturn, |
| 993 | status: enum { | 905 | status: enum { |
| 994 | none, | 906 | none, |
| 995 | field_types_wip, | 907 | field_types_wip, |
| ... | @@ -1011,15 +923,37 @@ pub const Struct = struct { | ... | @@ -1011,15 +923,37 @@ pub const Struct = struct { |
| 1011 | is_tuple: bool, | 923 | is_tuple: bool, |
| 1012 | assumed_runtime_bits: bool = false, | 924 | assumed_runtime_bits: bool = false, |
| 1013 | 925 | ||
| 1014 | pub const Fields = std.StringArrayHashMapUnmanaged(Field); | 926 | pub const Index = enum(u32) { |
| 927 | _, | ||
| 928 | |||
| 929 | pub fn toOptional(i: Index) OptionalIndex { | ||
| 930 | return @intToEnum(OptionalIndex, @enumToInt(i)); | ||
| 931 | } | ||
| 932 | }; | ||
| 933 | |||
| 934 | pub const OptionalIndex = enum(u32) { | ||
| 935 | none = std.math.maxInt(u32), | ||
| 936 | _, | ||
| 937 | |||
| 938 | pub fn init(oi: ?Index) OptionalIndex { | ||
| 939 | return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none)); | ||
| 940 | } | ||
| 941 | |||
| 942 | pub fn unwrap(oi: OptionalIndex) ?Index { | ||
| 943 | if (oi == .none) return null; | ||
| 944 | return @intToEnum(Index, @enumToInt(oi)); | ||
| 945 | } | ||
| 946 | }; | ||
| 947 | |||
| 948 | pub const Fields = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Field); | ||
| 1015 | 949 | ||
| 1016 | /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl. | 950 | /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl. |
| 1017 | pub const Field = struct { | 951 | pub const Field = struct { |
| 1018 | /// Uses `noreturn` to indicate `anytype`. | 952 | /// Uses `noreturn` to indicate `anytype`. |
| 1019 | /// undefined until `status` is >= `have_field_types`. | 953 | /// undefined until `status` is >= `have_field_types`. |
| 1020 | ty: Type, | 954 | ty: Type, |
| 1021 | /// Uses `unreachable_value` to indicate no default. | 955 | /// Uses `none` to indicate no default. |
| 1022 | default_val: Value, | 956 | default_val: InternPool.Index, |
| 1023 | /// Zero means to use the ABI alignment of the type. | 957 | /// Zero means to use the ABI alignment of the type. |
| 1024 | abi_align: u32, | 958 | abi_align: u32, |
| 1025 | /// undefined until `status` is `have_layout`. | 959 | /// undefined until `status` is `have_layout`. |
| ... | @@ -1030,7 +964,7 @@ pub const Struct = struct { | ... | @@ -1030,7 +964,7 @@ pub const Struct = struct { |
| 1030 | /// Returns the field alignment. If the struct is packed, returns 0. | 964 | /// Returns the field alignment. If the struct is packed, returns 0. |
| 1031 | pub fn alignment( | 965 | pub fn alignment( |
| 1032 | field: Field, | 966 | field: Field, |
| 1033 | target: Target, | 967 | mod: *Module, |
| 1034 | layout: std.builtin.Type.ContainerLayout, | 968 | layout: std.builtin.Type.ContainerLayout, |
| 1035 | ) u32 { | 969 | ) u32 { |
| 1036 | if (field.abi_align != 0) { | 970 | if (field.abi_align != 0) { |
| ... | @@ -1038,24 +972,26 @@ pub const Struct = struct { | ... | @@ -1038,24 +972,26 @@ pub const Struct = struct { |
| 1038 | return field.abi_align; | 972 | return field.abi_align; |
| 1039 | } | 973 | } |
| 1040 | 974 | ||
| 975 | const target = mod.getTarget(); | ||
| 976 | |||
| 1041 | switch (layout) { | 977 | switch (layout) { |
| 1042 | .Packed => return 0, | 978 | .Packed => return 0, |
| 1043 | .Auto => { | 979 | .Auto => { |
| 1044 | if (target.ofmt == .c) { | 980 | if (target.ofmt == .c) { |
| 1045 | return alignmentExtern(field, target); | 981 | return alignmentExtern(field, mod); |
| 1046 | } else { | 982 | } else { |
| 1047 | return field.ty.abiAlignment(target); | 983 | return field.ty.abiAlignment(mod); |
| 1048 | } | 984 | } |
| 1049 | }, | 985 | }, |
| 1050 | .Extern => return alignmentExtern(field, target), | 986 | .Extern => return alignmentExtern(field, mod), |
| 1051 | } | 987 | } |
| 1052 | } | 988 | } |
| 1053 | 989 | ||
| 1054 | pub fn alignmentExtern(field: Field, target: Target) u32 { | 990 | pub fn alignmentExtern(field: Field, mod: *Module) u32 { |
| 1055 | // This logic is duplicated in Type.abiAlignmentAdvanced. | 991 | // This logic is duplicated in Type.abiAlignmentAdvanced. |
| 1056 | const ty_abi_align = field.ty.abiAlignment(target); | 992 | const ty_abi_align = field.ty.abiAlignment(mod); |
| 1057 | 993 | ||
| 1058 | if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) { | 994 | if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { |
| 1059 | // The C ABI requires 128 bit integer fields of structs | 995 | // The C ABI requires 128 bit integer fields of structs |
| 1060 | // to be 16-bytes aligned. | 996 | // to be 16-bytes aligned. |
| 1061 | return @max(ty_abi_align, 16); | 997 | return @max(ty_abi_align, 16); |
| ... | @@ -1069,39 +1005,12 @@ pub const Struct = struct { | ... | @@ -1069,39 +1005,12 @@ pub const Struct = struct { |
| 1069 | /// runtime version of the struct. | 1005 | /// runtime version of the struct. |
| 1070 | pub const omitted_field = std.math.maxInt(u32); | 1006 | pub const omitted_field = std.math.maxInt(u32); |
| 1071 | 1007 | ||
| 1072 | pub fn getFullyQualifiedName(s: *Struct, mod: *Module) ![:0]u8 { | 1008 | pub fn getFullyQualifiedName(s: *Struct, mod: *Module) !InternPool.NullTerminatedString { |
| 1073 | return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); | 1009 | return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); |
| 1074 | } | 1010 | } |
| 1075 | 1011 | ||
| 1076 | pub fn srcLoc(s: Struct, mod: *Module) SrcLoc { | 1012 | pub fn srcLoc(s: Struct, mod: *Module) SrcLoc { |
| 1077 | const owner_decl = mod.declPtr(s.owner_decl); | 1013 | return mod.declPtr(s.owner_decl).srcLoc(mod); |
| 1078 | return .{ | ||
| 1079 | .file_scope = owner_decl.getFileScope(), | ||
| 1080 | .parent_decl_node = owner_decl.src_node, | ||
| 1081 | .lazy = LazySrcLoc.nodeOffset(0), | ||
| 1082 | }; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | pub fn fieldSrcLoc(s: Struct, mod: *Module, query: FieldSrcQuery) SrcLoc { | ||
| 1086 | @setCold(true); | ||
| 1087 | const owner_decl = mod.declPtr(s.owner_decl); | ||
| 1088 | const file = owner_decl.getFileScope(); | ||
| 1089 | const tree = file.getTree(mod.gpa) catch |err| { | ||
| 1090 | // In this case we emit a warning + a less precise source location. | ||
| 1091 | log.warn("unable to load {s}: {s}", .{ | ||
| 1092 | file.sub_file_path, @errorName(err), | ||
| 1093 | }); | ||
| 1094 | return s.srcLoc(mod); | ||
| 1095 | }; | ||
| 1096 | const node = owner_decl.relativeToNodeIndex(0); | ||
| 1097 | |||
| 1098 | var buf: [2]Ast.Node.Index = undefined; | ||
| 1099 | if (tree.fullContainerDecl(&buf, node)) |container_decl| { | ||
| 1100 | return queryFieldSrc(tree.*, query, file, container_decl); | ||
| 1101 | } else { | ||
| 1102 | // This struct was generated using @Type | ||
| 1103 | return s.srcLoc(mod); | ||
| 1104 | } | ||
| 1105 | } | 1014 | } |
| 1106 | 1015 | ||
| 1107 | pub fn haveFieldTypes(s: Struct) bool { | 1016 | pub fn haveFieldTypes(s: Struct) bool { |
| ... | @@ -1132,7 +1041,7 @@ pub const Struct = struct { | ... | @@ -1132,7 +1041,7 @@ pub const Struct = struct { |
| 1132 | }; | 1041 | }; |
| 1133 | } | 1042 | } |
| 1134 | 1043 | ||
| 1135 | pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 { | 1044 | pub fn packedFieldBitOffset(s: Struct, mod: *Module, index: usize) u16 { |
| 1136 | assert(s.layout == .Packed); | 1045 | assert(s.layout == .Packed); |
| 1137 | assert(s.haveLayout()); | 1046 | assert(s.haveLayout()); |
| 1138 | var bit_sum: u64 = 0; | 1047 | var bit_sum: u64 = 0; |
| ... | @@ -1140,12 +1049,13 @@ pub const Struct = struct { | ... | @@ -1140,12 +1049,13 @@ pub const Struct = struct { |
| 1140 | if (i == index) { | 1049 | if (i == index) { |
| 1141 | return @intCast(u16, bit_sum); | 1050 | return @intCast(u16, bit_sum); |
| 1142 | } | 1051 | } |
| 1143 | bit_sum += field.ty.bitSize(target); | 1052 | bit_sum += field.ty.bitSize(mod); |
| 1144 | } | 1053 | } |
| 1145 | unreachable; // index out of bounds | 1054 | unreachable; // index out of bounds |
| 1146 | } | 1055 | } |
| 1147 | 1056 | ||
| 1148 | pub const RuntimeFieldIterator = struct { | 1057 | pub const RuntimeFieldIterator = struct { |
| 1058 | module: *Module, | ||
| 1149 | struct_obj: *const Struct, | 1059 | struct_obj: *const Struct, |
| 1150 | index: u32 = 0, | 1060 | index: u32 = 0, |
| 1151 | 1061 | ||
| ... | @@ -1155,6 +1065,7 @@ pub const Struct = struct { | ... | @@ -1155,6 +1065,7 @@ pub const Struct = struct { |
| 1155 | }; | 1065 | }; |
| 1156 | 1066 | ||
| 1157 | pub fn next(it: *RuntimeFieldIterator) ?FieldAndIndex { | 1067 | pub fn next(it: *RuntimeFieldIterator) ?FieldAndIndex { |
| 1068 | const mod = it.module; | ||
| 1158 | while (true) { | 1069 | while (true) { |
| 1159 | var i = it.index; | 1070 | var i = it.index; |
| 1160 | it.index += 1; | 1071 | it.index += 1; |
| ... | @@ -1167,120 +1078,19 @@ pub const Struct = struct { | ... | @@ -1167,120 +1078,19 @@ pub const Struct = struct { |
| 1167 | } | 1078 | } |
| 1168 | const field = it.struct_obj.fields.values()[i]; | 1079 | const field = it.struct_obj.fields.values()[i]; |
| 1169 | 1080 | ||
| 1170 | if (!field.is_comptime and field.ty.hasRuntimeBits()) { | 1081 | if (!field.is_comptime and field.ty.hasRuntimeBits(mod)) { |
| 1171 | return FieldAndIndex{ .index = i, .field = field }; | 1082 | return FieldAndIndex{ .index = i, .field = field }; |
| 1172 | } | 1083 | } |
| 1173 | } | 1084 | } |
| 1174 | } | 1085 | } |
| 1175 | }; | 1086 | }; |
| 1176 | 1087 | ||
| 1177 | pub fn runtimeFieldIterator(s: *const Struct) RuntimeFieldIterator { | 1088 | pub fn runtimeFieldIterator(s: *const Struct, module: *Module) RuntimeFieldIterator { |
| 1178 | return .{ .struct_obj = s }; | ||
| 1179 | } | ||
| 1180 | }; | ||
| 1181 | |||
| 1182 | /// Represents the data that an enum declaration provides, when the fields | ||
| 1183 | /// are auto-numbered, and there are no declarations. The integer tag type | ||
| 1184 | /// is inferred to be the smallest power of two unsigned int that fits | ||
| 1185 | /// the number of fields. | ||
| 1186 | pub const EnumSimple = struct { | ||
| 1187 | /// The Decl that corresponds to the enum itself. | ||
| 1188 | owner_decl: Decl.Index, | ||
| 1189 | /// Set of field names in declaration order. | ||
| 1190 | fields: NameMap, | ||
| 1191 | |||
| 1192 | pub const NameMap = EnumFull.NameMap; | ||
| 1193 | |||
| 1194 | pub fn srcLoc(self: EnumSimple, mod: *Module) SrcLoc { | ||
| 1195 | const owner_decl = mod.declPtr(self.owner_decl); | ||
| 1196 | return .{ | ||
| 1197 | .file_scope = owner_decl.getFileScope(), | ||
| 1198 | .parent_decl_node = owner_decl.src_node, | ||
| 1199 | .lazy = LazySrcLoc.nodeOffset(0), | ||
| 1200 | }; | ||
| 1201 | } | ||
| 1202 | }; | ||
| 1203 | |||
| 1204 | /// Represents the data that an enum declaration provides, when there are no | ||
| 1205 | /// declarations. However an integer tag type is provided, and the enum tag values | ||
| 1206 | /// are explicitly provided. | ||
| 1207 | pub const EnumNumbered = struct { | ||
| 1208 | /// The Decl that corresponds to the enum itself. | ||
| 1209 | owner_decl: Decl.Index, | ||
| 1210 | /// An integer type which is used for the numerical value of the enum. | ||
| 1211 | /// Whether zig chooses this type or the user specifies it, it is stored here. | ||
| 1212 | tag_ty: Type, | ||
| 1213 | /// Set of field names in declaration order. | ||
| 1214 | fields: NameMap, | ||
| 1215 | /// Maps integer tag value to field index. | ||
| 1216 | /// Entries are in declaration order, same as `fields`. | ||
| 1217 | /// If this hash map is empty, it means the enum tags are auto-numbered. | ||
| 1218 | values: ValueMap, | ||
| 1219 | |||
| 1220 | pub const NameMap = EnumFull.NameMap; | ||
| 1221 | pub const ValueMap = EnumFull.ValueMap; | ||
| 1222 | |||
| 1223 | pub fn srcLoc(self: EnumNumbered, mod: *Module) SrcLoc { | ||
| 1224 | const owner_decl = mod.declPtr(self.owner_decl); | ||
| 1225 | return .{ | ||
| 1226 | .file_scope = owner_decl.getFileScope(), | ||
| 1227 | .parent_decl_node = owner_decl.src_node, | ||
| 1228 | .lazy = LazySrcLoc.nodeOffset(0), | ||
| 1229 | }; | ||
| 1230 | } | ||
| 1231 | }; | ||
| 1232 | |||
| 1233 | /// Represents the data that an enum declaration provides, when there is | ||
| 1234 | /// at least one tag value explicitly specified, or at least one declaration. | ||
| 1235 | pub const EnumFull = struct { | ||
| 1236 | /// The Decl that corresponds to the enum itself. | ||
| 1237 | owner_decl: Decl.Index, | ||
| 1238 | /// An integer type which is used for the numerical value of the enum. | ||
| 1239 | /// Whether zig chooses this type or the user specifies it, it is stored here. | ||
| 1240 | tag_ty: Type, | ||
| 1241 | /// Set of field names in declaration order. | ||
| 1242 | fields: NameMap, | ||
| 1243 | /// Maps integer tag value to field index. | ||
| 1244 | /// Entries are in declaration order, same as `fields`. | ||
| 1245 | /// If this hash map is empty, it means the enum tags are auto-numbered. | ||
| 1246 | values: ValueMap, | ||
| 1247 | /// Represents the declarations inside this enum. | ||
| 1248 | namespace: Namespace, | ||
| 1249 | /// true if zig inferred this tag type, false if user specified it | ||
| 1250 | tag_ty_inferred: bool, | ||
| 1251 | |||
| 1252 | pub const NameMap = std.StringArrayHashMapUnmanaged(void); | ||
| 1253 | pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.ArrayHashContext, false); | ||
| 1254 | |||
| 1255 | pub fn srcLoc(self: EnumFull, mod: *Module) SrcLoc { | ||
| 1256 | const owner_decl = mod.declPtr(self.owner_decl); | ||
| 1257 | return .{ | 1089 | return .{ |
| 1258 | .file_scope = owner_decl.getFileScope(), | 1090 | .struct_obj = s, |
| 1259 | .parent_decl_node = owner_decl.src_node, | 1091 | .module = module, |
| 1260 | .lazy = LazySrcLoc.nodeOffset(0), | ||
| 1261 | }; | 1092 | }; |
| 1262 | } | 1093 | } |
| 1263 | |||
| 1264 | pub fn fieldSrcLoc(e: EnumFull, mod: *Module, query: FieldSrcQuery) SrcLoc { | ||
| 1265 | @setCold(true); | ||
| 1266 | const owner_decl = mod.declPtr(e.owner_decl); | ||
| 1267 | const file = owner_decl.getFileScope(); | ||
| 1268 | const tree = file.getTree(mod.gpa) catch |err| { | ||
| 1269 | // In this case we emit a warning + a less precise source location. | ||
| 1270 | log.warn("unable to load {s}: {s}", .{ | ||
| 1271 | file.sub_file_path, @errorName(err), | ||
| 1272 | }); | ||
| 1273 | return e.srcLoc(mod); | ||
| 1274 | }; | ||
| 1275 | const node = owner_decl.relativeToNodeIndex(0); | ||
| 1276 | var buf: [2]Ast.Node.Index = undefined; | ||
| 1277 | if (tree.fullContainerDecl(&buf, node)) |container_decl| { | ||
| 1278 | return queryFieldSrc(tree.*, query, file, container_decl); | ||
| 1279 | } else { | ||
| 1280 | // This enum was generated using @Type | ||
| 1281 | return e.srcLoc(mod); | ||
| 1282 | } | ||
| 1283 | } | ||
| 1284 | }; | 1094 | }; |
| 1285 | 1095 | ||
| 1286 | pub const Union = struct { | 1096 | pub const Union = struct { |
| ... | @@ -1293,7 +1103,7 @@ pub const Union = struct { | ... | @@ -1293,7 +1103,7 @@ pub const Union = struct { |
| 1293 | /// Set of field names in declaration order. | 1103 | /// Set of field names in declaration order. |
| 1294 | fields: Fields, | 1104 | fields: Fields, |
| 1295 | /// Represents the declarations inside this union. | 1105 | /// Represents the declarations inside this union. |
| 1296 | namespace: Namespace, | 1106 | namespace: Namespace.Index, |
| 1297 | /// The Decl that corresponds to the union itself. | 1107 | /// The Decl that corresponds to the union itself. |
| 1298 | owner_decl: Decl.Index, | 1108 | owner_decl: Decl.Index, |
| 1299 | /// Index of the union_decl ZIR instruction. | 1109 | /// Index of the union_decl ZIR instruction. |
| ... | @@ -1314,6 +1124,28 @@ pub const Union = struct { | ... | @@ -1314,6 +1124,28 @@ pub const Union = struct { |
| 1314 | requires_comptime: PropertyBoolean = .unknown, | 1124 | requires_comptime: PropertyBoolean = .unknown, |
| 1315 | assumed_runtime_bits: bool = false, | 1125 | assumed_runtime_bits: bool = false, |
| 1316 | 1126 | ||
| 1127 | pub const Index = enum(u32) { | ||
| 1128 | _, | ||
| 1129 | |||
| 1130 | pub fn toOptional(i: Index) OptionalIndex { | ||
| 1131 | return @intToEnum(OptionalIndex, @enumToInt(i)); | ||
| 1132 | } | ||
| 1133 | }; | ||
| 1134 | |||
| 1135 | pub const OptionalIndex = enum(u32) { | ||
| 1136 | none = std.math.maxInt(u32), | ||
| 1137 | _, | ||
| 1138 | |||
| 1139 | pub fn init(oi: ?Index) OptionalIndex { | ||
| 1140 | return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none)); | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | pub fn unwrap(oi: OptionalIndex) ?Index { | ||
| 1144 | if (oi == .none) return null; | ||
| 1145 | return @intToEnum(Index, @enumToInt(oi)); | ||
| 1146 | } | ||
| 1147 | }; | ||
| 1148 | |||
| 1317 | pub const Field = struct { | 1149 | pub const Field = struct { |
| 1318 | /// undefined until `status` is `have_field_types` or `have_layout`. | 1150 | /// undefined until `status` is `have_field_types` or `have_layout`. |
| 1319 | ty: Type, | 1151 | ty: Type, |
| ... | @@ -1323,52 +1155,30 @@ pub const Union = struct { | ... | @@ -1323,52 +1155,30 @@ pub const Union = struct { |
| 1323 | /// Returns the field alignment, assuming the union is not packed. | 1155 | /// Returns the field alignment, assuming the union is not packed. |
| 1324 | /// Keep implementation in sync with `Sema.unionFieldAlignment`. | 1156 | /// Keep implementation in sync with `Sema.unionFieldAlignment`. |
| 1325 | /// Prefer to call that function instead of this one during Sema. | 1157 | /// Prefer to call that function instead of this one during Sema. |
| 1326 | pub fn normalAlignment(field: Field, target: Target) u32 { | 1158 | pub fn normalAlignment(field: Field, mod: *Module) u32 { |
| 1327 | if (field.abi_align == 0) { | 1159 | if (field.abi_align == 0) { |
| 1328 | return field.ty.abiAlignment(target); | 1160 | return field.ty.abiAlignment(mod); |
| 1329 | } else { | 1161 | } else { |
| 1330 | return field.abi_align; | 1162 | return field.abi_align; |
| 1331 | } | 1163 | } |
| 1332 | } | 1164 | } |
| 1333 | }; | 1165 | }; |
| 1334 | 1166 | ||
| 1335 | pub const Fields = std.StringArrayHashMapUnmanaged(Field); | 1167 | pub const Fields = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Field); |
| 1336 | 1168 | ||
| 1337 | pub fn getFullyQualifiedName(s: *Union, mod: *Module) ![:0]u8 { | 1169 | pub fn getFullyQualifiedName(s: *Union, mod: *Module) !InternPool.NullTerminatedString { |
| 1338 | return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); | 1170 | return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); |
| 1339 | } | 1171 | } |
| 1340 | 1172 | ||
| 1341 | pub fn srcLoc(self: Union, mod: *Module) SrcLoc { | 1173 | pub fn srcLoc(self: Union, mod: *Module) SrcLoc { |
| 1342 | const owner_decl = mod.declPtr(self.owner_decl); | 1174 | const owner_decl = mod.declPtr(self.owner_decl); |
| 1343 | return .{ | 1175 | return .{ |
| 1344 | .file_scope = owner_decl.getFileScope(), | 1176 | .file_scope = owner_decl.getFileScope(mod), |
| 1345 | .parent_decl_node = owner_decl.src_node, | 1177 | .parent_decl_node = owner_decl.src_node, |
| 1346 | .lazy = LazySrcLoc.nodeOffset(0), | 1178 | .lazy = LazySrcLoc.nodeOffset(0), |
| 1347 | }; | 1179 | }; |
| 1348 | } | 1180 | } |
| 1349 | 1181 | ||
| 1350 | pub fn fieldSrcLoc(u: Union, mod: *Module, query: FieldSrcQuery) SrcLoc { | ||
| 1351 | @setCold(true); | ||
| 1352 | const owner_decl = mod.declPtr(u.owner_decl); | ||
| 1353 | const file = owner_decl.getFileScope(); | ||
| 1354 | const tree = file.getTree(mod.gpa) catch |err| { | ||
| 1355 | // In this case we emit a warning + a less precise source location. | ||
| 1356 | log.warn("unable to load {s}: {s}", .{ | ||
| 1357 | file.sub_file_path, @errorName(err), | ||
| 1358 | }); | ||
| 1359 | return u.srcLoc(mod); | ||
| 1360 | }; | ||
| 1361 | const node = owner_decl.relativeToNodeIndex(0); | ||
| 1362 | |||
| 1363 | var buf: [2]Ast.Node.Index = undefined; | ||
| 1364 | if (tree.fullContainerDecl(&buf, node)) |container_decl| { | ||
| 1365 | return queryFieldSrc(tree.*, query, file, container_decl); | ||
| 1366 | } else { | ||
| 1367 | // This union was generated using @Type | ||
| 1368 | return u.srcLoc(mod); | ||
| 1369 | } | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | pub fn haveFieldTypes(u: Union) bool { | 1182 | pub fn haveFieldTypes(u: Union) bool { |
| 1373 | return switch (u.status) { | 1183 | return switch (u.status) { |
| 1374 | .none, | 1184 | .none, |
| ... | @@ -1383,22 +1193,22 @@ pub const Union = struct { | ... | @@ -1383,22 +1193,22 @@ pub const Union = struct { |
| 1383 | }; | 1193 | }; |
| 1384 | } | 1194 | } |
| 1385 | 1195 | ||
| 1386 | pub fn hasAllZeroBitFieldTypes(u: Union) bool { | 1196 | pub fn hasAllZeroBitFieldTypes(u: Union, mod: *Module) bool { |
| 1387 | assert(u.haveFieldTypes()); | 1197 | assert(u.haveFieldTypes()); |
| 1388 | for (u.fields.values()) |field| { | 1198 | for (u.fields.values()) |field| { |
| 1389 | if (field.ty.hasRuntimeBits()) return false; | 1199 | if (field.ty.hasRuntimeBits(mod)) return false; |
| 1390 | } | 1200 | } |
| 1391 | return true; | 1201 | return true; |
| 1392 | } | 1202 | } |
| 1393 | 1203 | ||
| 1394 | pub fn mostAlignedField(u: Union, target: Target) u32 { | 1204 | pub fn mostAlignedField(u: Union, mod: *Module) u32 { |
| 1395 | assert(u.haveFieldTypes()); | 1205 | assert(u.haveFieldTypes()); |
| 1396 | var most_alignment: u32 = 0; | 1206 | var most_alignment: u32 = 0; |
| 1397 | var most_index: usize = undefined; | 1207 | var most_index: usize = undefined; |
| 1398 | for (u.fields.values(), 0..) |field, i| { | 1208 | for (u.fields.values(), 0..) |field, i| { |
| 1399 | if (!field.ty.hasRuntimeBits()) continue; | 1209 | if (!field.ty.hasRuntimeBits(mod)) continue; |
| 1400 | 1210 | ||
| 1401 | const field_align = field.normalAlignment(target); | 1211 | const field_align = field.normalAlignment(mod); |
| 1402 | if (field_align > most_alignment) { | 1212 | if (field_align > most_alignment) { |
| 1403 | most_alignment = field_align; | 1213 | most_alignment = field_align; |
| 1404 | most_index = i; | 1214 | most_index = i; |
| ... | @@ -1408,20 +1218,20 @@ pub const Union = struct { | ... | @@ -1408,20 +1218,20 @@ pub const Union = struct { |
| 1408 | } | 1218 | } |
| 1409 | 1219 | ||
| 1410 | /// Returns 0 if the union is represented with 0 bits at runtime. | 1220 | /// Returns 0 if the union is represented with 0 bits at runtime. |
| 1411 | pub fn abiAlignment(u: Union, target: Target, have_tag: bool) u32 { | 1221 | pub fn abiAlignment(u: Union, mod: *Module, have_tag: bool) u32 { |
| 1412 | var max_align: u32 = 0; | 1222 | var max_align: u32 = 0; |
| 1413 | if (have_tag) max_align = u.tag_ty.abiAlignment(target); | 1223 | if (have_tag) max_align = u.tag_ty.abiAlignment(mod); |
| 1414 | for (u.fields.values()) |field| { | 1224 | for (u.fields.values()) |field| { |
| 1415 | if (!field.ty.hasRuntimeBits()) continue; | 1225 | if (!field.ty.hasRuntimeBits(mod)) continue; |
| 1416 | 1226 | ||
| 1417 | const field_align = field.normalAlignment(target); | 1227 | const field_align = field.normalAlignment(mod); |
| 1418 | max_align = @max(max_align, field_align); | 1228 | max_align = @max(max_align, field_align); |
| 1419 | } | 1229 | } |
| 1420 | return max_align; | 1230 | return max_align; |
| 1421 | } | 1231 | } |
| 1422 | 1232 | ||
| 1423 | pub fn abiSize(u: Union, target: Target, have_tag: bool) u64 { | 1233 | pub fn abiSize(u: Union, mod: *Module, have_tag: bool) u64 { |
| 1424 | return u.getLayout(target, have_tag).abi_size; | 1234 | return u.getLayout(mod, have_tag).abi_size; |
| 1425 | } | 1235 | } |
| 1426 | 1236 | ||
| 1427 | pub const Layout = struct { | 1237 | pub const Layout = struct { |
| ... | @@ -1451,7 +1261,7 @@ pub const Union = struct { | ... | @@ -1451,7 +1261,7 @@ pub const Union = struct { |
| 1451 | }; | 1261 | }; |
| 1452 | } | 1262 | } |
| 1453 | 1263 | ||
| 1454 | pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout { | 1264 | pub fn getLayout(u: Union, mod: *Module, have_tag: bool) Layout { |
| 1455 | assert(u.haveLayout()); | 1265 | assert(u.haveLayout()); |
| 1456 | var most_aligned_field: u32 = undefined; | 1266 | var most_aligned_field: u32 = undefined; |
| 1457 | var most_aligned_field_size: u64 = undefined; | 1267 | var most_aligned_field_size: u64 = undefined; |
| ... | @@ -1460,16 +1270,16 @@ pub const Union = struct { | ... | @@ -1460,16 +1270,16 @@ pub const Union = struct { |
| 1460 | var payload_align: u32 = 0; | 1270 | var payload_align: u32 = 0; |
| 1461 | const fields = u.fields.values(); | 1271 | const fields = u.fields.values(); |
| 1462 | for (fields, 0..) |field, i| { | 1272 | for (fields, 0..) |field, i| { |
| 1463 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 1273 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 1464 | 1274 | ||
| 1465 | const field_align = a: { | 1275 | const field_align = a: { |
| 1466 | if (field.abi_align == 0) { | 1276 | if (field.abi_align == 0) { |
| 1467 | break :a field.ty.abiAlignment(target); | 1277 | break :a field.ty.abiAlignment(mod); |
| 1468 | } else { | 1278 | } else { |
| 1469 | break :a field.abi_align; | 1279 | break :a field.abi_align; |
| 1470 | } | 1280 | } |
| 1471 | }; | 1281 | }; |
| 1472 | const field_size = field.ty.abiSize(target); | 1282 | const field_size = field.ty.abiSize(mod); |
| 1473 | if (field_size > payload_size) { | 1283 | if (field_size > payload_size) { |
| 1474 | payload_size = field_size; | 1284 | payload_size = field_size; |
| 1475 | biggest_field = @intCast(u32, i); | 1285 | biggest_field = @intCast(u32, i); |
| ... | @@ -1481,7 +1291,7 @@ pub const Union = struct { | ... | @@ -1481,7 +1291,7 @@ pub const Union = struct { |
| 1481 | } | 1291 | } |
| 1482 | } | 1292 | } |
| 1483 | payload_align = @max(payload_align, 1); | 1293 | payload_align = @max(payload_align, 1); |
| 1484 | if (!have_tag or !u.tag_ty.hasRuntimeBits()) { | 1294 | if (!have_tag or !u.tag_ty.hasRuntimeBits(mod)) { |
| 1485 | return .{ | 1295 | return .{ |
| 1486 | .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align), | 1296 | .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align), |
| 1487 | .abi_align = payload_align, | 1297 | .abi_align = payload_align, |
| ... | @@ -1497,8 +1307,8 @@ pub const Union = struct { | ... | @@ -1497,8 +1307,8 @@ pub const Union = struct { |
| 1497 | } | 1307 | } |
| 1498 | // Put the tag before or after the payload depending on which one's | 1308 | // Put the tag before or after the payload depending on which one's |
| 1499 | // alignment is greater. | 1309 | // alignment is greater. |
| 1500 | const tag_size = u.tag_ty.abiSize(target); | 1310 | const tag_size = u.tag_ty.abiSize(mod); |
| 1501 | const tag_align = @max(1, u.tag_ty.abiAlignment(target)); | 1311 | const tag_align = @max(1, u.tag_ty.abiAlignment(mod)); |
| 1502 | var size: u64 = 0; | 1312 | var size: u64 = 0; |
| 1503 | var padding: u32 = undefined; | 1313 | var padding: u32 = undefined; |
| 1504 | if (tag_align >= payload_align) { | 1314 | if (tag_align >= payload_align) { |
| ... | @@ -1533,26 +1343,6 @@ pub const Union = struct { | ... | @@ -1533,26 +1343,6 @@ pub const Union = struct { |
| 1533 | } | 1343 | } |
| 1534 | }; | 1344 | }; |
| 1535 | 1345 | ||
| 1536 | pub const Opaque = struct { | ||
| 1537 | /// The Decl that corresponds to the opaque itself. | ||
| 1538 | owner_decl: Decl.Index, | ||
| 1539 | /// Represents the declarations inside this opaque. | ||
| 1540 | namespace: Namespace, | ||
| 1541 | |||
| 1542 | pub fn srcLoc(self: Opaque, mod: *Module) SrcLoc { | ||
| 1543 | const owner_decl = mod.declPtr(self.owner_decl); | ||
| 1544 | return .{ | ||
| 1545 | .file_scope = owner_decl.getFileScope(), | ||
| 1546 | .parent_decl_node = owner_decl.src_node, | ||
| 1547 | .lazy = LazySrcLoc.nodeOffset(0), | ||
| 1548 | }; | ||
| 1549 | } | ||
| 1550 | |||
| 1551 | pub fn getFullyQualifiedName(s: *Opaque, mod: *Module) ![:0]u8 { | ||
| 1552 | return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); | ||
| 1553 | } | ||
| 1554 | }; | ||
| 1555 | |||
| 1556 | /// Some extern function struct memory is owned by the Decl's TypedValue.Managed | 1346 | /// Some extern function struct memory is owned by the Decl's TypedValue.Managed |
| 1557 | /// arena allocator. | 1347 | /// arena allocator. |
| 1558 | pub const ExternFn = struct { | 1348 | pub const ExternFn = struct { |
| ... | @@ -1630,12 +1420,27 @@ pub const Fn = struct { | ... | @@ -1630,12 +1420,27 @@ pub const Fn = struct { |
| 1630 | is_noinline: bool, | 1420 | is_noinline: bool, |
| 1631 | calls_or_awaits_errorable_fn: bool = false, | 1421 | calls_or_awaits_errorable_fn: bool = false, |
| 1632 | 1422 | ||
| 1633 | /// Any inferred error sets that this function owns, both its own inferred error set and | 1423 | pub const Index = enum(u32) { |
| 1634 | /// inferred error sets of any inline/comptime functions called. Not to be confused | 1424 | _, |
| 1635 | /// with inferred error sets of generic instantiations of this function, which are | 1425 | |
| 1636 | /// *not* tracked here - they are tracked in the new `Fn` object created for the | 1426 | pub fn toOptional(i: Index) OptionalIndex { |
| 1637 | /// instantiations. | 1427 | return @intToEnum(OptionalIndex, @enumToInt(i)); |
| 1638 | inferred_error_sets: InferredErrorSetList = .{}, | 1428 | } |
| 1429 | }; | ||
| 1430 | |||
| 1431 | pub const OptionalIndex = enum(u32) { | ||
| 1432 | none = std.math.maxInt(u32), | ||
| 1433 | _, | ||
| 1434 | |||
| 1435 | pub fn init(oi: ?Index) OptionalIndex { | ||
| 1436 | return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none)); | ||
| 1437 | } | ||
| 1438 | |||
| 1439 | pub fn unwrap(oi: OptionalIndex) ?Index { | ||
| 1440 | if (oi == .none) return null; | ||
| 1441 | return @intToEnum(Index, @enumToInt(oi)); | ||
| 1442 | } | ||
| 1443 | }; | ||
| 1639 | 1444 | ||
| 1640 | pub const Analysis = enum { | 1445 | pub const Analysis = enum { |
| 1641 | /// This function has not yet undergone analysis, because we have not | 1446 | /// This function has not yet undergone analysis, because we have not |
| ... | @@ -1662,16 +1467,16 @@ pub const Fn = struct { | ... | @@ -1662,16 +1467,16 @@ pub const Fn = struct { |
| 1662 | /// or comptime functions. | 1467 | /// or comptime functions. |
| 1663 | pub const InferredErrorSet = struct { | 1468 | pub const InferredErrorSet = struct { |
| 1664 | /// The function from which this error set originates. | 1469 | /// The function from which this error set originates. |
| 1665 | func: *Fn, | 1470 | func: Fn.Index, |
| 1666 | 1471 | ||
| 1667 | /// All currently known errors that this error set contains. This includes | 1472 | /// All currently known errors that this error set contains. This includes |
| 1668 | /// direct additions via `return error.Foo;`, and possibly also errors that | 1473 | /// direct additions via `return error.Foo;`, and possibly also errors that |
| 1669 | /// are returned from any dependent functions. When the inferred error set is | 1474 | /// are returned from any dependent functions. When the inferred error set is |
| 1670 | /// fully resolved, this map contains all the errors that the function might return. | 1475 | /// fully resolved, this map contains all the errors that the function might return. |
| 1671 | errors: ErrorSet.NameMap = .{}, | 1476 | errors: NameMap = .{}, |
| 1672 | 1477 | ||
| 1673 | /// Other inferred error sets which this inferred error set should include. | 1478 | /// Other inferred error sets which this inferred error set should include. |
| 1674 | inferred_error_sets: std.AutoArrayHashMapUnmanaged(*InferredErrorSet, void) = .{}, | 1479 | inferred_error_sets: std.AutoArrayHashMapUnmanaged(InferredErrorSet.Index, void) = .{}, |
| 1675 | 1480 | ||
| 1676 | /// Whether the function returned anyerror. This is true if either of | 1481 | /// Whether the function returned anyerror. This is true if either of |
| 1677 | /// the dependent functions returns anyerror. | 1482 | /// the dependent functions returns anyerror. |
| ... | @@ -1681,52 +1486,57 @@ pub const Fn = struct { | ... | @@ -1681,52 +1486,57 @@ pub const Fn = struct { |
| 1681 | /// can skip resolving any dependents of this inferred error set. | 1486 | /// can skip resolving any dependents of this inferred error set. |
| 1682 | is_resolved: bool = false, | 1487 | is_resolved: bool = false, |
| 1683 | 1488 | ||
| 1684 | pub fn addErrorSet(self: *InferredErrorSet, gpa: Allocator, err_set_ty: Type) !void { | 1489 | pub const NameMap = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void); |
| 1685 | switch (err_set_ty.tag()) { | 1490 | |
| 1686 | .error_set => { | 1491 | pub const Index = enum(u32) { |
| 1687 | const names = err_set_ty.castTag(.error_set).?.data.names.keys(); | 1492 | _, |
| 1688 | for (names) |name| { | 1493 | |
| 1689 | try self.errors.put(gpa, name, {}); | 1494 | pub fn toOptional(i: InferredErrorSet.Index) InferredErrorSet.OptionalIndex { |
| 1690 | } | 1495 | return @intToEnum(InferredErrorSet.OptionalIndex, @enumToInt(i)); |
| 1691 | }, | 1496 | } |
| 1692 | .error_set_single => { | 1497 | }; |
| 1693 | const name = err_set_ty.castTag(.error_set_single).?.data; | 1498 | |
| 1694 | try self.errors.put(gpa, name, {}); | 1499 | pub const OptionalIndex = enum(u32) { |
| 1695 | }, | 1500 | none = std.math.maxInt(u32), |
| 1696 | .error_set_inferred => { | 1501 | _, |
| 1697 | const ies = err_set_ty.castTag(.error_set_inferred).?.data; | 1502 | |
| 1698 | try self.inferred_error_sets.put(gpa, ies, {}); | 1503 | pub fn init(oi: ?InferredErrorSet.Index) InferredErrorSet.OptionalIndex { |
| 1699 | }, | 1504 | return @intToEnum(InferredErrorSet.OptionalIndex, @enumToInt(oi orelse return .none)); |
| 1700 | .error_set_merged => { | 1505 | } |
| 1701 | const names = err_set_ty.castTag(.error_set_merged).?.data.keys(); | 1506 | |
| 1702 | for (names) |name| { | 1507 | pub fn unwrap(oi: InferredErrorSet.OptionalIndex) ?InferredErrorSet.Index { |
| 1703 | try self.errors.put(gpa, name, {}); | 1508 | if (oi == .none) return null; |
| 1704 | } | 1509 | return @intToEnum(InferredErrorSet.Index, @enumToInt(oi)); |
| 1705 | }, | 1510 | } |
| 1706 | .anyerror => { | 1511 | }; |
| 1512 | |||
| 1513 | pub fn addErrorSet( | ||
| 1514 | self: *InferredErrorSet, | ||
| 1515 | err_set_ty: Type, | ||
| 1516 | ip: *InternPool, | ||
| 1517 | gpa: Allocator, | ||
| 1518 | ) !void { | ||
| 1519 | switch (err_set_ty.toIntern()) { | ||
| 1520 | .anyerror_type => { | ||
| 1707 | self.is_anyerror = true; | 1521 | self.is_anyerror = true; |
| 1708 | }, | 1522 | }, |
| 1709 | else => unreachable, | 1523 | else => switch (ip.indexToKey(err_set_ty.toIntern())) { |
| 1524 | .error_set_type => |error_set_type| { | ||
| 1525 | for (error_set_type.names) |name| { | ||
| 1526 | try self.errors.put(gpa, name, {}); | ||
| 1527 | } | ||
| 1528 | }, | ||
| 1529 | .inferred_error_set_type => |ies_index| { | ||
| 1530 | try self.inferred_error_sets.put(gpa, ies_index, {}); | ||
| 1531 | }, | ||
| 1532 | else => unreachable, | ||
| 1533 | }, | ||
| 1710 | } | 1534 | } |
| 1711 | } | 1535 | } |
| 1712 | }; | 1536 | }; |
| 1713 | 1537 | ||
| 1714 | pub const InferredErrorSetList = std.SinglyLinkedList(InferredErrorSet); | ||
| 1715 | pub const InferredErrorSetListNode = InferredErrorSetList.Node; | ||
| 1716 | |||
| 1717 | pub fn deinit(func: *Fn, gpa: Allocator) void { | ||
| 1718 | var it = func.inferred_error_sets.first; | ||
| 1719 | while (it) |node| { | ||
| 1720 | const next = node.next; | ||
| 1721 | node.data.errors.deinit(gpa); | ||
| 1722 | node.data.inferred_error_sets.deinit(gpa); | ||
| 1723 | gpa.destroy(node); | ||
| 1724 | it = next; | ||
| 1725 | } | ||
| 1726 | } | ||
| 1727 | |||
| 1728 | pub fn isAnytypeParam(func: Fn, mod: *Module, index: u32) bool { | 1538 | pub fn isAnytypeParam(func: Fn, mod: *Module, index: u32) bool { |
| 1729 | const file = mod.declPtr(func.owner_decl).getFileScope(); | 1539 | const file = mod.declPtr(func.owner_decl).getFileScope(mod); |
| 1730 | 1540 | ||
| 1731 | const tags = file.zir.instructions.items(.tag); | 1541 | const tags = file.zir.instructions.items(.tag); |
| 1732 | 1542 | ||
| ... | @@ -1741,7 +1551,7 @@ pub const Fn = struct { | ... | @@ -1741,7 +1551,7 @@ pub const Fn = struct { |
| 1741 | } | 1551 | } |
| 1742 | 1552 | ||
| 1743 | pub fn getParamName(func: Fn, mod: *Module, index: u32) [:0]const u8 { | 1553 | pub fn getParamName(func: Fn, mod: *Module, index: u32) [:0]const u8 { |
| 1744 | const file = mod.declPtr(func.owner_decl).getFileScope(); | 1554 | const file = mod.declPtr(func.owner_decl).getFileScope(mod); |
| 1745 | 1555 | ||
| 1746 | const tags = file.zir.instructions.items(.tag); | 1556 | const tags = file.zir.instructions.items(.tag); |
| 1747 | const data = file.zir.instructions.items(.data); | 1557 | const data = file.zir.instructions.items(.data); |
| ... | @@ -1764,7 +1574,7 @@ pub const Fn = struct { | ... | @@ -1764,7 +1574,7 @@ pub const Fn = struct { |
| 1764 | 1574 | ||
| 1765 | pub fn hasInferredErrorSet(func: Fn, mod: *Module) bool { | 1575 | pub fn hasInferredErrorSet(func: Fn, mod: *Module) bool { |
| 1766 | const owner_decl = mod.declPtr(func.owner_decl); | 1576 | const owner_decl = mod.declPtr(func.owner_decl); |
| 1767 | const zir = owner_decl.getFileScope().zir; | 1577 | const zir = owner_decl.getFileScope(mod).zir; |
| 1768 | const zir_tags = zir.instructions.items(.tag); | 1578 | const zir_tags = zir.instructions.items(.tag); |
| 1769 | switch (zir_tags[func.zir_body_inst]) { | 1579 | switch (zir_tags[func.zir_body_inst]) { |
| 1770 | .func => return false, | 1580 | .func => return false, |
| ... | @@ -1779,46 +1589,24 @@ pub const Fn = struct { | ... | @@ -1779,46 +1589,24 @@ pub const Fn = struct { |
| 1779 | } | 1589 | } |
| 1780 | }; | 1590 | }; |
| 1781 | 1591 | ||
| 1782 | pub const Var = struct { | ||
| 1783 | /// if is_extern == true this is undefined | ||
| 1784 | init: Value, | ||
| 1785 | owner_decl: Decl.Index, | ||
| 1786 | |||
| 1787 | /// Library name if specified. | ||
| 1788 | /// For example `extern "c" var stderrp = ...` would have 'c' as library name. | ||
| 1789 | /// Allocated with Module's allocator; outlives the ZIR code. | ||
| 1790 | lib_name: ?[*:0]const u8, | ||
| 1791 | |||
| 1792 | is_extern: bool, | ||
| 1793 | is_mutable: bool, | ||
| 1794 | is_threadlocal: bool, | ||
| 1795 | is_weak_linkage: bool, | ||
| 1796 | |||
| 1797 | pub fn deinit(variable: *Var, gpa: Allocator) void { | ||
| 1798 | if (variable.lib_name) |lib_name| { | ||
| 1799 | gpa.free(mem.sliceTo(lib_name, 0)); | ||
| 1800 | } | ||
| 1801 | } | ||
| 1802 | }; | ||
| 1803 | |||
| 1804 | pub const DeclAdapter = struct { | 1592 | pub const DeclAdapter = struct { |
| 1805 | mod: *Module, | 1593 | mod: *Module, |
| 1806 | 1594 | ||
| 1807 | pub fn hash(self: @This(), s: []const u8) u32 { | 1595 | pub fn hash(self: @This(), s: InternPool.NullTerminatedString) u32 { |
| 1808 | _ = self; | 1596 | _ = self; |
| 1809 | return @truncate(u32, std.hash.Wyhash.hash(0, s)); | 1597 | return std.hash.uint32(@enumToInt(s)); |
| 1810 | } | 1598 | } |
| 1811 | 1599 | ||
| 1812 | pub fn eql(self: @This(), a: []const u8, b_decl_index: Decl.Index, b_index: usize) bool { | 1600 | pub fn eql(self: @This(), a: InternPool.NullTerminatedString, b_decl_index: Decl.Index, b_index: usize) bool { |
| 1813 | _ = b_index; | 1601 | _ = b_index; |
| 1814 | const b_decl = self.mod.declPtr(b_decl_index); | 1602 | const b_decl = self.mod.declPtr(b_decl_index); |
| 1815 | return mem.eql(u8, a, mem.sliceTo(b_decl.name, 0)); | 1603 | return a == b_decl.name; |
| 1816 | } | 1604 | } |
| 1817 | }; | 1605 | }; |
| 1818 | 1606 | ||
| 1819 | /// The container that structs, enums, unions, and opaques have. | 1607 | /// The container that structs, enums, unions, and opaques have. |
| 1820 | pub const Namespace = struct { | 1608 | pub const Namespace = struct { |
| 1821 | parent: ?*Namespace, | 1609 | parent: OptionalIndex, |
| 1822 | file_scope: *File, | 1610 | file_scope: *File, |
| 1823 | /// Will be a struct, enum, union, or opaque. | 1611 | /// Will be a struct, enum, union, or opaque. |
| 1824 | ty: Type, | 1612 | ty: Type, |
| ... | @@ -1836,21 +1624,41 @@ pub const Namespace = struct { | ... | @@ -1836,21 +1624,41 @@ pub const Namespace = struct { |
| 1836 | /// Value is whether the usingnamespace decl is marked `pub`. | 1624 | /// Value is whether the usingnamespace decl is marked `pub`. |
| 1837 | usingnamespace_set: std.AutoHashMapUnmanaged(Decl.Index, bool) = .{}, | 1625 | usingnamespace_set: std.AutoHashMapUnmanaged(Decl.Index, bool) = .{}, |
| 1838 | 1626 | ||
| 1627 | pub const Index = enum(u32) { | ||
| 1628 | _, | ||
| 1629 | |||
| 1630 | pub fn toOptional(i: Index) OptionalIndex { | ||
| 1631 | return @intToEnum(OptionalIndex, @enumToInt(i)); | ||
| 1632 | } | ||
| 1633 | }; | ||
| 1634 | |||
| 1635 | pub const OptionalIndex = enum(u32) { | ||
| 1636 | none = std.math.maxInt(u32), | ||
| 1637 | _, | ||
| 1638 | |||
| 1639 | pub fn init(oi: ?Index) OptionalIndex { | ||
| 1640 | return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none)); | ||
| 1641 | } | ||
| 1642 | |||
| 1643 | pub fn unwrap(oi: OptionalIndex) ?Index { | ||
| 1644 | if (oi == .none) return null; | ||
| 1645 | return @intToEnum(Index, @enumToInt(oi)); | ||
| 1646 | } | ||
| 1647 | }; | ||
| 1648 | |||
| 1839 | const DeclContext = struct { | 1649 | const DeclContext = struct { |
| 1840 | module: *Module, | 1650 | module: *Module, |
| 1841 | 1651 | ||
| 1842 | pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 { | 1652 | pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 { |
| 1843 | const decl = ctx.module.declPtr(decl_index); | 1653 | const decl = ctx.module.declPtr(decl_index); |
| 1844 | return @truncate(u32, std.hash.Wyhash.hash(0, mem.sliceTo(decl.name, 0))); | 1654 | return std.hash.uint32(@enumToInt(decl.name)); |
| 1845 | } | 1655 | } |
| 1846 | 1656 | ||
| 1847 | pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool { | 1657 | pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool { |
| 1848 | _ = b_index; | 1658 | _ = b_index; |
| 1849 | const a_decl = ctx.module.declPtr(a_decl_index); | 1659 | const a_decl = ctx.module.declPtr(a_decl_index); |
| 1850 | const b_decl = ctx.module.declPtr(b_decl_index); | 1660 | const b_decl = ctx.module.declPtr(b_decl_index); |
| 1851 | const a_name = mem.sliceTo(a_decl.name, 0); | 1661 | return a_decl.name == b_decl.name; |
| 1852 | const b_name = mem.sliceTo(b_decl.name, 0); | ||
| 1853 | return mem.eql(u8, a_name, b_name); | ||
| 1854 | } | 1662 | } |
| 1855 | }; | 1663 | }; |
| 1856 | 1664 | ||
| ... | @@ -1862,8 +1670,6 @@ pub const Namespace = struct { | ... | @@ -1862,8 +1670,6 @@ pub const Namespace = struct { |
| 1862 | pub fn destroyDecls(ns: *Namespace, mod: *Module) void { | 1670 | pub fn destroyDecls(ns: *Namespace, mod: *Module) void { |
| 1863 | const gpa = mod.gpa; | 1671 | const gpa = mod.gpa; |
| 1864 | 1672 | ||
| 1865 | log.debug("destroyDecls {*}", .{ns}); | ||
| 1866 | |||
| 1867 | var decls = ns.decls; | 1673 | var decls = ns.decls; |
| 1868 | ns.decls = .{}; | 1674 | ns.decls = .{}; |
| 1869 | 1675 | ||
| ... | @@ -1889,8 +1695,6 @@ pub const Namespace = struct { | ... | @@ -1889,8 +1695,6 @@ pub const Namespace = struct { |
| 1889 | ) !void { | 1695 | ) !void { |
| 1890 | const gpa = mod.gpa; | 1696 | const gpa = mod.gpa; |
| 1891 | 1697 | ||
| 1892 | log.debug("deleteAllDecls {*}", .{ns}); | ||
| 1893 | |||
| 1894 | var decls = ns.decls; | 1698 | var decls = ns.decls; |
| 1895 | ns.decls = .{}; | 1699 | ns.decls = .{}; |
| 1896 | 1700 | ||
| ... | @@ -1919,46 +1723,38 @@ pub const Namespace = struct { | ... | @@ -1919,46 +1723,38 @@ pub const Namespace = struct { |
| 1919 | pub fn renderFullyQualifiedName( | 1723 | pub fn renderFullyQualifiedName( |
| 1920 | ns: Namespace, | 1724 | ns: Namespace, |
| 1921 | mod: *Module, | 1725 | mod: *Module, |
| 1922 | name: []const u8, | 1726 | name: InternPool.NullTerminatedString, |
| 1923 | writer: anytype, | 1727 | writer: anytype, |
| 1924 | ) @TypeOf(writer).Error!void { | 1728 | ) @TypeOf(writer).Error!void { |
| 1925 | if (ns.parent) |parent| { | 1729 | if (ns.parent.unwrap()) |parent| { |
| 1926 | const decl_index = ns.getDeclIndex(); | 1730 | const decl = mod.declPtr(ns.getDeclIndex(mod)); |
| 1927 | const decl = mod.declPtr(decl_index); | 1731 | try mod.namespacePtr(parent).renderFullyQualifiedName(mod, decl.name, writer); |
| 1928 | try parent.renderFullyQualifiedName(mod, mem.sliceTo(decl.name, 0), writer); | ||
| 1929 | } else { | 1732 | } else { |
| 1930 | try ns.file_scope.renderFullyQualifiedName(writer); | 1733 | try ns.file_scope.renderFullyQualifiedName(writer); |
| 1931 | } | 1734 | } |
| 1932 | if (name.len != 0) { | 1735 | if (name != .empty) try writer.print(".{}", .{name.fmt(&mod.intern_pool)}); |
| 1933 | try writer.writeAll("."); | ||
| 1934 | try writer.writeAll(name); | ||
| 1935 | } | ||
| 1936 | } | 1736 | } |
| 1937 | 1737 | ||
| 1938 | /// This renders e.g. "std/fs.zig:Dir.OpenOptions" | 1738 | /// This renders e.g. "std/fs.zig:Dir.OpenOptions" |
| 1939 | pub fn renderFullyQualifiedDebugName( | 1739 | pub fn renderFullyQualifiedDebugName( |
| 1940 | ns: Namespace, | 1740 | ns: Namespace, |
| 1941 | mod: *Module, | 1741 | mod: *Module, |
| 1942 | name: []const u8, | 1742 | name: InternPool.NullTerminatedString, |
| 1943 | writer: anytype, | 1743 | writer: anytype, |
| 1944 | ) @TypeOf(writer).Error!void { | 1744 | ) @TypeOf(writer).Error!void { |
| 1945 | var separator_char: u8 = '.'; | 1745 | const separator_char: u8 = if (ns.parent.unwrap()) |parent| sep: { |
| 1946 | if (ns.parent) |parent| { | 1746 | const decl = mod.declPtr(ns.getDeclIndex(mod)); |
| 1947 | const decl_index = ns.getDeclIndex(); | 1747 | try mod.namespacePtr(parent).renderFullyQualifiedDebugName(mod, decl.name, writer); |
| 1948 | const decl = mod.declPtr(decl_index); | 1748 | break :sep '.'; |
| 1949 | try parent.renderFullyQualifiedDebugName(mod, mem.sliceTo(decl.name, 0), writer); | 1749 | } else sep: { |
| 1950 | } else { | ||
| 1951 | try ns.file_scope.renderFullyQualifiedDebugName(writer); | 1750 | try ns.file_scope.renderFullyQualifiedDebugName(writer); |
| 1952 | separator_char = ':'; | 1751 | break :sep ':'; |
| 1953 | } | 1752 | }; |
| 1954 | if (name.len != 0) { | 1753 | if (name != .empty) try writer.print("{c}{}", .{ separator_char, name.fmt(&mod.intern_pool) }); |
| 1955 | try writer.writeByte(separator_char); | ||
| 1956 | try writer.writeAll(name); | ||
| 1957 | } | ||
| 1958 | } | 1754 | } |
| 1959 | 1755 | ||
| 1960 | pub fn getDeclIndex(ns: Namespace) Decl.Index { | 1756 | pub fn getDeclIndex(ns: Namespace, mod: *Module) Decl.Index { |
| 1961 | return ns.ty.getOwnerDecl(); | 1757 | return ns.ty.getOwnerDecl(mod); |
| 1962 | } | 1758 | } |
| 1963 | }; | 1759 | }; |
| 1964 | 1760 | ||
| ... | @@ -2140,11 +1936,11 @@ pub const File = struct { | ... | @@ -2140,11 +1936,11 @@ pub const File = struct { |
| 2140 | }; | 1936 | }; |
| 2141 | } | 1937 | } |
| 2142 | 1938 | ||
| 2143 | pub fn fullyQualifiedNameZ(file: File, gpa: Allocator) ![:0]u8 { | 1939 | pub fn fullyQualifiedName(file: File, mod: *Module) !InternPool.NullTerminatedString { |
| 2144 | var buf = std.ArrayList(u8).init(gpa); | 1940 | const ip = &mod.intern_pool; |
| 2145 | defer buf.deinit(); | 1941 | const start = ip.string_bytes.items.len; |
| 2146 | try file.renderFullyQualifiedName(buf.writer()); | 1942 | try file.renderFullyQualifiedName(ip.string_bytes.writer(mod.gpa)); |
| 2147 | return buf.toOwnedSliceSentinel(0); | 1943 | return ip.getOrPutTrailingString(mod.gpa, ip.string_bytes.items.len - start); |
| 2148 | } | 1944 | } |
| 2149 | 1945 | ||
| 2150 | /// Returns the full path to this file relative to its package. | 1946 | /// Returns the full path to this file relative to its package. |
| ... | @@ -2268,7 +2064,7 @@ pub const ErrorMsg = struct { | ... | @@ -2268,7 +2064,7 @@ pub const ErrorMsg = struct { |
| 2268 | reference_trace: []Trace = &.{}, | 2064 | reference_trace: []Trace = &.{}, |
| 2269 | 2065 | ||
| 2270 | pub const Trace = struct { | 2066 | pub const Trace = struct { |
| 2271 | decl: ?[*:0]const u8, | 2067 | decl: InternPool.OptionalNullTerminatedString, |
| 2272 | src_loc: SrcLoc, | 2068 | src_loc: SrcLoc, |
| 2273 | hidden: u32 = 0, | 2069 | hidden: u32 = 0, |
| 2274 | }; | 2070 | }; |
| ... | @@ -2281,7 +2077,7 @@ pub const ErrorMsg = struct { | ... | @@ -2281,7 +2077,7 @@ pub const ErrorMsg = struct { |
| 2281 | ) !*ErrorMsg { | 2077 | ) !*ErrorMsg { |
| 2282 | const err_msg = try gpa.create(ErrorMsg); | 2078 | const err_msg = try gpa.create(ErrorMsg); |
| 2283 | errdefer gpa.destroy(err_msg); | 2079 | errdefer gpa.destroy(err_msg); |
| 2284 | err_msg.* = try init(gpa, src_loc, format, args); | 2080 | err_msg.* = try ErrorMsg.init(gpa, src_loc, format, args); |
| 2285 | return err_msg; | 2081 | return err_msg; |
| 2286 | } | 2082 | } |
| 2287 | 2083 | ||
| ... | @@ -3287,7 +3083,7 @@ pub const LazySrcLoc = union(enum) { | ... | @@ -3287,7 +3083,7 @@ pub const LazySrcLoc = union(enum) { |
| 3287 | } | 3083 | } |
| 3288 | 3084 | ||
| 3289 | /// Upgrade to a `SrcLoc` based on the `Decl` provided. | 3085 | /// Upgrade to a `SrcLoc` based on the `Decl` provided. |
| 3290 | pub fn toSrcLoc(lazy: LazySrcLoc, decl: *Decl) SrcLoc { | 3086 | pub fn toSrcLoc(lazy: LazySrcLoc, decl: *Decl, mod: *Module) SrcLoc { |
| 3291 | return switch (lazy) { | 3087 | return switch (lazy) { |
| 3292 | .unneeded, | 3088 | .unneeded, |
| 3293 | .entire_file, | 3089 | .entire_file, |
| ... | @@ -3295,7 +3091,7 @@ pub const LazySrcLoc = union(enum) { | ... | @@ -3295,7 +3091,7 @@ pub const LazySrcLoc = union(enum) { |
| 3295 | .token_abs, | 3091 | .token_abs, |
| 3296 | .node_abs, | 3092 | .node_abs, |
| 3297 | => .{ | 3093 | => .{ |
| 3298 | .file_scope = decl.getFileScope(), | 3094 | .file_scope = decl.getFileScope(mod), |
| 3299 | .parent_decl_node = 0, | 3095 | .parent_decl_node = 0, |
| 3300 | .lazy = lazy, | 3096 | .lazy = lazy, |
| 3301 | }, | 3097 | }, |
| ... | @@ -3361,7 +3157,7 @@ pub const LazySrcLoc = union(enum) { | ... | @@ -3361,7 +3157,7 @@ pub const LazySrcLoc = union(enum) { |
| 3361 | .for_input, | 3157 | .for_input, |
| 3362 | .for_capture_from_input, | 3158 | .for_capture_from_input, |
| 3363 | => .{ | 3159 | => .{ |
| 3364 | .file_scope = decl.getFileScope(), | 3160 | .file_scope = decl.getFileScope(mod), |
| 3365 | .parent_decl_node = decl.src_node, | 3161 | .parent_decl_node = decl.src_node, |
| 3366 | .lazy = lazy, | 3162 | .lazy = lazy, |
| 3367 | }, | 3163 | }, |
| ... | @@ -3391,6 +3187,12 @@ pub const CompileError = error{ | ... | @@ -3391,6 +3187,12 @@ pub const CompileError = error{ |
| 3391 | ComptimeBreak, | 3187 | ComptimeBreak, |
| 3392 | }; | 3188 | }; |
| 3393 | 3189 | ||
| 3190 | pub fn init(mod: *Module) !void { | ||
| 3191 | const gpa = mod.gpa; | ||
| 3192 | try mod.intern_pool.init(gpa); | ||
| 3193 | try mod.global_error_set.put(gpa, .empty, {}); | ||
| 3194 | } | ||
| 3195 | |||
| 3394 | pub fn deinit(mod: *Module) void { | 3196 | pub fn deinit(mod: *Module) void { |
| 3395 | const gpa = mod.gpa; | 3197 | const gpa = mod.gpa; |
| 3396 | 3198 | ||
| ... | @@ -3489,42 +3291,29 @@ pub fn deinit(mod: *Module) void { | ... | @@ -3489,42 +3291,29 @@ pub fn deinit(mod: *Module) void { |
| 3489 | } | 3291 | } |
| 3490 | mod.export_owners.deinit(gpa); | 3292 | mod.export_owners.deinit(gpa); |
| 3491 | 3293 | ||
| 3492 | { | 3294 | mod.global_error_set.deinit(gpa); |
| 3493 | var it = mod.global_error_set.keyIterator(); | ||
| 3494 | while (it.next()) |key| { | ||
| 3495 | gpa.free(key.*); | ||
| 3496 | } | ||
| 3497 | mod.global_error_set.deinit(gpa); | ||
| 3498 | } | ||
| 3499 | 3295 | ||
| 3500 | mod.error_name_list.deinit(gpa); | ||
| 3501 | mod.test_functions.deinit(gpa); | 3296 | mod.test_functions.deinit(gpa); |
| 3502 | mod.align_stack_fns.deinit(gpa); | 3297 | mod.align_stack_fns.deinit(gpa); |
| 3503 | mod.monomorphed_funcs.deinit(gpa); | 3298 | mod.monomorphed_funcs.deinit(gpa); |
| 3504 | 3299 | ||
| 3505 | { | ||
| 3506 | var it = mod.memoized_calls.iterator(); | ||
| 3507 | while (it.next()) |entry| { | ||
| 3508 | gpa.free(entry.key_ptr.args); | ||
| 3509 | entry.value_ptr.arena.promote(gpa).deinit(); | ||
| 3510 | } | ||
| 3511 | mod.memoized_calls.deinit(gpa); | ||
| 3512 | } | ||
| 3513 | |||
| 3514 | mod.decls_free_list.deinit(gpa); | 3300 | mod.decls_free_list.deinit(gpa); |
| 3515 | mod.allocated_decls.deinit(gpa); | 3301 | mod.allocated_decls.deinit(gpa); |
| 3516 | mod.global_assembly.deinit(gpa); | 3302 | mod.global_assembly.deinit(gpa); |
| 3517 | mod.reference_table.deinit(gpa); | 3303 | mod.reference_table.deinit(gpa); |
| 3518 | 3304 | ||
| 3519 | mod.string_literal_table.deinit(gpa); | 3305 | mod.namespaces_free_list.deinit(gpa); |
| 3520 | mod.string_literal_bytes.deinit(gpa); | 3306 | mod.allocated_namespaces.deinit(gpa); |
| 3307 | |||
| 3308 | mod.memoized_decls.deinit(gpa); | ||
| 3309 | mod.intern_pool.deinit(gpa); | ||
| 3310 | mod.tmp_hack_arena.deinit(); | ||
| 3521 | } | 3311 | } |
| 3522 | 3312 | ||
| 3523 | pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { | 3313 | pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { |
| 3524 | const gpa = mod.gpa; | 3314 | const gpa = mod.gpa; |
| 3525 | { | 3315 | { |
| 3526 | const decl = mod.declPtr(decl_index); | 3316 | const decl = mod.declPtr(decl_index); |
| 3527 | log.debug("destroy {*} ({s})", .{ decl, decl.name }); | ||
| 3528 | _ = mod.test_functions.swapRemove(decl_index); | 3317 | _ = mod.test_functions.swapRemove(decl_index); |
| 3529 | if (decl.deletion_flag) { | 3318 | if (decl.deletion_flag) { |
| 3530 | assert(mod.deletion_set.swapRemove(decl_index)); | 3319 | assert(mod.deletion_set.swapRemove(decl_index)); |
| ... | @@ -3533,14 +3322,15 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { | ... | @@ -3533,14 +3322,15 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { |
| 3533 | gpa.free(kv.value); | 3322 | gpa.free(kv.value); |
| 3534 | } | 3323 | } |
| 3535 | if (decl.has_tv) { | 3324 | if (decl.has_tv) { |
| 3536 | if (decl.getInnerNamespace()) |namespace| { | 3325 | if (decl.getOwnedInnerNamespaceIndex(mod).unwrap()) |i| { |
| 3537 | namespace.destroyDecls(mod); | 3326 | mod.namespacePtr(i).destroyDecls(mod); |
| 3327 | mod.destroyNamespace(i); | ||
| 3538 | } | 3328 | } |
| 3539 | } | 3329 | } |
| 3330 | if (decl.src_scope) |scope| scope.decRef(gpa); | ||
| 3540 | decl.clearValues(mod); | 3331 | decl.clearValues(mod); |
| 3541 | decl.dependants.deinit(gpa); | 3332 | decl.dependants.deinit(gpa); |
| 3542 | decl.dependencies.deinit(gpa); | 3333 | decl.dependencies.deinit(gpa); |
| 3543 | decl.clearName(gpa); | ||
| 3544 | decl.* = undefined; | 3334 | decl.* = undefined; |
| 3545 | } | 3335 | } |
| 3546 | mod.decls_free_list.append(gpa, decl_index) catch { | 3336 | mod.decls_free_list.append(gpa, decl_index) catch { |
| ... | @@ -3554,24 +3344,55 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { | ... | @@ -3554,24 +3344,55 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { |
| 3554 | } | 3344 | } |
| 3555 | } | 3345 | } |
| 3556 | 3346 | ||
| 3557 | pub fn declPtr(mod: *Module, decl_index: Decl.Index) *Decl { | 3347 | pub fn declPtr(mod: *Module, index: Decl.Index) *Decl { |
| 3558 | return mod.allocated_decls.at(@enumToInt(decl_index)); | 3348 | return mod.allocated_decls.at(@enumToInt(index)); |
| 3349 | } | ||
| 3350 | |||
| 3351 | pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace { | ||
| 3352 | return mod.allocated_namespaces.at(@enumToInt(index)); | ||
| 3353 | } | ||
| 3354 | |||
| 3355 | pub fn unionPtr(mod: *Module, index: Union.Index) *Union { | ||
| 3356 | return mod.intern_pool.unionPtr(index); | ||
| 3357 | } | ||
| 3358 | |||
| 3359 | pub fn structPtr(mod: *Module, index: Struct.Index) *Struct { | ||
| 3360 | return mod.intern_pool.structPtr(index); | ||
| 3361 | } | ||
| 3362 | |||
| 3363 | pub fn funcPtr(mod: *Module, index: Fn.Index) *Fn { | ||
| 3364 | return mod.intern_pool.funcPtr(index); | ||
| 3365 | } | ||
| 3366 | |||
| 3367 | pub fn inferredErrorSetPtr(mod: *Module, index: Fn.InferredErrorSet.Index) *Fn.InferredErrorSet { | ||
| 3368 | return mod.intern_pool.inferredErrorSetPtr(index); | ||
| 3369 | } | ||
| 3370 | |||
| 3371 | pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace { | ||
| 3372 | return mod.namespacePtr(index.unwrap() orelse return null); | ||
| 3373 | } | ||
| 3374 | |||
| 3375 | /// This one accepts an index from the InternPool and asserts that it is not | ||
| 3376 | /// the anonymous empty struct type. | ||
| 3377 | pub fn structPtrUnwrap(mod: *Module, index: Struct.OptionalIndex) ?*Struct { | ||
| 3378 | return mod.structPtr(index.unwrap() orelse return null); | ||
| 3379 | } | ||
| 3380 | |||
| 3381 | pub fn funcPtrUnwrap(mod: *Module, index: Fn.OptionalIndex) ?*Fn { | ||
| 3382 | return mod.funcPtr(index.unwrap() orelse return null); | ||
| 3559 | } | 3383 | } |
| 3560 | 3384 | ||
| 3561 | /// Returns true if and only if the Decl is the top level struct associated with a File. | 3385 | /// Returns true if and only if the Decl is the top level struct associated with a File. |
| 3562 | pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { | 3386 | pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { |
| 3563 | const decl = mod.declPtr(decl_index); | 3387 | const decl = mod.declPtr(decl_index); |
| 3564 | if (decl.src_namespace.parent != null) | 3388 | const namespace = mod.namespacePtr(decl.src_namespace); |
| 3389 | if (namespace.parent != .none) | ||
| 3565 | return false; | 3390 | return false; |
| 3566 | return decl_index == decl.src_namespace.getDeclIndex(); | 3391 | return decl_index == namespace.getDeclIndex(mod); |
| 3567 | } | 3392 | } |
| 3568 | 3393 | ||
| 3569 | fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void { | 3394 | fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void { |
| 3570 | for (export_list.items) |exp| { | 3395 | for (export_list.items) |exp| gpa.destroy(exp); |
| 3571 | gpa.free(exp.options.name); | ||
| 3572 | if (exp.options.section) |s| gpa.free(s); | ||
| 3573 | gpa.destroy(exp); | ||
| 3574 | } | ||
| 3575 | export_list.deinit(gpa); | 3396 | export_list.deinit(gpa); |
| 3576 | } | 3397 | } |
| 3577 | 3398 | ||
| ... | @@ -3990,9 +3811,6 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { | ... | @@ -3990,9 +3811,6 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { |
| 3990 | if (decl.zir_decl_index != 0) { | 3811 | if (decl.zir_decl_index != 0) { |
| 3991 | const old_zir_decl_index = decl.zir_decl_index; | 3812 | const old_zir_decl_index = decl.zir_decl_index; |
| 3992 | const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse { | 3813 | const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse { |
| 3993 | log.debug("updateZirRefs {s}: delete {*} ({s})", .{ | ||
| 3994 | file.sub_file_path, decl, decl.name, | ||
| 3995 | }); | ||
| 3996 | try file.deleted_decls.append(gpa, decl_index); | 3814 | try file.deleted_decls.append(gpa, decl_index); |
| 3997 | continue; | 3815 | continue; |
| 3998 | }; | 3816 | }; |
| ... | @@ -4000,41 +3818,34 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { | ... | @@ -4000,41 +3818,34 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { |
| 4000 | decl.zir_decl_index = new_zir_decl_index; | 3818 | decl.zir_decl_index = new_zir_decl_index; |
| 4001 | const new_hash = decl.contentsHashZir(new_zir); | 3819 | const new_hash = decl.contentsHashZir(new_zir); |
| 4002 | if (!std.zig.srcHashEql(old_hash, new_hash)) { | 3820 | if (!std.zig.srcHashEql(old_hash, new_hash)) { |
| 4003 | log.debug("updateZirRefs {s}: outdated {*} ({s}) {d} => {d}", .{ | ||
| 4004 | file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, | ||
| 4005 | }); | ||
| 4006 | try file.outdated_decls.append(gpa, decl_index); | 3821 | try file.outdated_decls.append(gpa, decl_index); |
| 4007 | } else { | ||
| 4008 | log.debug("updateZirRefs {s}: unchanged {*} ({s}) {d} => {d}", .{ | ||
| 4009 | file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, | ||
| 4010 | }); | ||
| 4011 | } | 3822 | } |
| 4012 | } | 3823 | } |
| 4013 | 3824 | ||
| 4014 | if (!decl.owns_tv) continue; | 3825 | if (!decl.owns_tv) continue; |
| 4015 | 3826 | ||
| 4016 | if (decl.getStruct()) |struct_obj| { | 3827 | if (decl.getOwnedStruct(mod)) |struct_obj| { |
| 4017 | struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { | 3828 | struct_obj.zir_index = inst_map.get(struct_obj.zir_index) orelse { |
| 4018 | try file.deleted_decls.append(gpa, decl_index); | 3829 | try file.deleted_decls.append(gpa, decl_index); |
| 4019 | continue; | 3830 | continue; |
| 4020 | }; | 3831 | }; |
| 4021 | } | 3832 | } |
| 4022 | 3833 | ||
| 4023 | if (decl.getUnion()) |union_obj| { | 3834 | if (decl.getOwnedUnion(mod)) |union_obj| { |
| 4024 | union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse { | 3835 | union_obj.zir_index = inst_map.get(union_obj.zir_index) orelse { |
| 4025 | try file.deleted_decls.append(gpa, decl_index); | 3836 | try file.deleted_decls.append(gpa, decl_index); |
| 4026 | continue; | 3837 | continue; |
| 4027 | }; | 3838 | }; |
| 4028 | } | 3839 | } |
| 4029 | 3840 | ||
| 4030 | if (decl.getFunction()) |func| { | 3841 | if (decl.getOwnedFunction(mod)) |func| { |
| 4031 | func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse { | 3842 | func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse { |
| 4032 | try file.deleted_decls.append(gpa, decl_index); | 3843 | try file.deleted_decls.append(gpa, decl_index); |
| 4033 | continue; | 3844 | continue; |
| 4034 | }; | 3845 | }; |
| 4035 | } | 3846 | } |
| 4036 | 3847 | ||
| 4037 | if (decl.getInnerNamespace()) |namespace| { | 3848 | if (decl.getOwnedInnerNamespace(mod)) |namespace| { |
| 4038 | for (namespace.decls.keys()) |sub_decl| { | 3849 | for (namespace.decls.keys()) |sub_decl| { |
| 4039 | try decl_stack.append(gpa, sub_decl); | 3850 | try decl_stack.append(gpa, sub_decl); |
| 4040 | } | 3851 | } |
| ... | @@ -4207,14 +4018,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -4207,14 +4018,12 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4207 | .complete => return, | 4018 | .complete => return, |
| 4208 | 4019 | ||
| 4209 | .outdated => blk: { | 4020 | .outdated => blk: { |
| 4210 | log.debug("re-analyzing {*} ({s})", .{ decl, decl.name }); | ||
| 4211 | |||
| 4212 | // The exports this Decl performs will be re-discovered, so we remove them here | 4021 | // The exports this Decl performs will be re-discovered, so we remove them here |
| 4213 | // prior to re-analysis. | 4022 | // prior to re-analysis. |
| 4214 | try mod.deleteDeclExports(decl_index); | 4023 | try mod.deleteDeclExports(decl_index); |
| 4215 | 4024 | ||
| 4216 | // Similarly, `@setAlignStack` invocations will be re-discovered. | 4025 | // Similarly, `@setAlignStack` invocations will be re-discovered. |
| 4217 | if (decl.getFunction()) |func| { | 4026 | if (decl.getOwnedFunctionIndex(mod).unwrap()) |func| { |
| 4218 | _ = mod.align_stack_fns.remove(func); | 4027 | _ = mod.align_stack_fns.remove(func); |
| 4219 | } | 4028 | } |
| 4220 | 4029 | ||
| ... | @@ -4223,9 +4032,6 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -4223,9 +4032,6 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4223 | const dep = mod.declPtr(dep_index); | 4032 | const dep = mod.declPtr(dep_index); |
| 4224 | dep.removeDependant(decl_index); | 4033 | dep.removeDependant(decl_index); |
| 4225 | if (dep.dependants.count() == 0 and !dep.deletion_flag) { | 4034 | if (dep.dependants.count() == 0 and !dep.deletion_flag) { |
| 4226 | log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{ | ||
| 4227 | decl, decl.name, dep, dep.name, | ||
| 4228 | }); | ||
| 4229 | try mod.markDeclForDeletion(dep_index); | 4035 | try mod.markDeclForDeletion(dep_index); |
| 4230 | } | 4036 | } |
| 4231 | } | 4037 | } |
| ... | @@ -4237,7 +4043,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -4237,7 +4043,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4237 | .unreferenced => false, | 4043 | .unreferenced => false, |
| 4238 | }; | 4044 | }; |
| 4239 | 4045 | ||
| 4240 | var decl_prog_node = mod.sema_prog_node.start(mem.sliceTo(decl.name, 0), 0); | 4046 | var decl_prog_node = mod.sema_prog_node.start("", 0); |
| 4241 | decl_prog_node.activate(); | 4047 | decl_prog_node.activate(); |
| 4242 | defer decl_prog_node.end(); | 4048 | defer decl_prog_node.end(); |
| 4243 | 4049 | ||
| ... | @@ -4264,7 +4070,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -4264,7 +4070,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4264 | try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); | 4070 | try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); |
| 4265 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( | 4071 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( |
| 4266 | mod.gpa, | 4072 | mod.gpa, |
| 4267 | decl.srcLoc(), | 4073 | decl.srcLoc(mod), |
| 4268 | "unable to analyze: {s}", | 4074 | "unable to analyze: {s}", |
| 4269 | .{@errorName(e)}, | 4075 | .{@errorName(e)}, |
| 4270 | )); | 4076 | )); |
| ... | @@ -4277,7 +4083,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -4277,7 +4083,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4277 | // Update all dependents which have at least this level of dependency. | 4083 | // Update all dependents which have at least this level of dependency. |
| 4278 | // If our type remained the same and we're a function, only update | 4084 | // If our type remained the same and we're a function, only update |
| 4279 | // decls which depend on our body; otherwise, update all dependents. | 4085 | // decls which depend on our body; otherwise, update all dependents. |
| 4280 | const update_level: Decl.DepType = if (!type_changed and decl.ty.zigTypeTag() == .Fn) .function_body else .normal; | 4086 | const update_level: Decl.DepType = if (!type_changed and decl.ty.zigTypeTag(mod) == .Fn) .function_body else .normal; |
| 4281 | 4087 | ||
| 4282 | for (decl.dependants.keys(), decl.dependants.values()) |dep_index, dep_type| { | 4088 | for (decl.dependants.keys(), decl.dependants.values()) |dep_index, dep_type| { |
| 4283 | if (@enumToInt(dep_type) < @enumToInt(update_level)) continue; | 4089 | if (@enumToInt(dep_type) < @enumToInt(update_level)) continue; |
| ... | @@ -4304,10 +4110,11 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -4304,10 +4110,11 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4304 | } | 4110 | } |
| 4305 | } | 4111 | } |
| 4306 | 4112 | ||
| 4307 | pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { | 4113 | pub fn ensureFuncBodyAnalyzed(mod: *Module, func_index: Fn.Index) SemaError!void { |
| 4308 | const tracy = trace(@src()); | 4114 | const tracy = trace(@src()); |
| 4309 | defer tracy.end(); | 4115 | defer tracy.end(); |
| 4310 | 4116 | ||
| 4117 | const func = mod.funcPtr(func_index); | ||
| 4311 | const decl_index = func.owner_decl; | 4118 | const decl_index = func.owner_decl; |
| 4312 | const decl = mod.declPtr(decl_index); | 4119 | const decl = mod.declPtr(decl_index); |
| 4313 | 4120 | ||
| ... | @@ -4339,7 +4146,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { | ... | @@ -4339,7 +4146,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4339 | defer tmp_arena.deinit(); | 4146 | defer tmp_arena.deinit(); |
| 4340 | const sema_arena = tmp_arena.allocator(); | 4147 | const sema_arena = tmp_arena.allocator(); |
| 4341 | 4148 | ||
| 4342 | var air = mod.analyzeFnBody(func, sema_arena) catch |err| switch (err) { | 4149 | var air = mod.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) { |
| 4343 | error.AnalysisFail => { | 4150 | error.AnalysisFail => { |
| 4344 | if (func.state == .in_progress) { | 4151 | if (func.state == .in_progress) { |
| 4345 | // If this decl caused the compile error, the analysis field would | 4152 | // If this decl caused the compile error, the analysis field would |
| ... | @@ -4365,17 +4172,14 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { | ... | @@ -4365,17 +4172,14 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4365 | 4172 | ||
| 4366 | if (no_bin_file and !dump_air and !dump_llvm_ir) return; | 4173 | if (no_bin_file and !dump_air and !dump_llvm_ir) return; |
| 4367 | 4174 | ||
| 4368 | log.debug("analyze liveness of {s}", .{decl.name}); | 4175 | var liveness = try Liveness.analyze(gpa, air, &mod.intern_pool); |
| 4369 | var liveness = try Liveness.analyze(gpa, air); | ||
| 4370 | defer liveness.deinit(gpa); | 4176 | defer liveness.deinit(gpa); |
| 4371 | 4177 | ||
| 4372 | if (dump_air) { | 4178 | if (dump_air) { |
| 4373 | const fqn = try decl.getFullyQualifiedName(mod); | 4179 | const fqn = try decl.getFullyQualifiedName(mod); |
| 4374 | defer mod.gpa.free(fqn); | 4180 | std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(&mod.intern_pool)}); |
| 4375 | |||
| 4376 | std.debug.print("# Begin Function AIR: {s}:\n", .{fqn}); | ||
| 4377 | @import("print_air.zig").dump(mod, air, liveness); | 4181 | @import("print_air.zig").dump(mod, air, liveness); |
| 4378 | std.debug.print("# End Function AIR: {s}\n\n", .{fqn}); | 4182 | std.debug.print("# End Function AIR: {}\n\n", .{fqn.fmt(&mod.intern_pool)}); |
| 4379 | } | 4183 | } |
| 4380 | 4184 | ||
| 4381 | if (std.debug.runtime_safety) { | 4185 | if (std.debug.runtime_safety) { |
| ... | @@ -4383,6 +4187,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { | ... | @@ -4383,6 +4187,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4383 | .gpa = gpa, | 4187 | .gpa = gpa, |
| 4384 | .air = air, | 4188 | .air = air, |
| 4385 | .liveness = liveness, | 4189 | .liveness = liveness, |
| 4190 | .intern_pool = &mod.intern_pool, | ||
| 4386 | }; | 4191 | }; |
| 4387 | defer verify.deinit(); | 4192 | defer verify.deinit(); |
| 4388 | 4193 | ||
| ... | @@ -4394,7 +4199,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { | ... | @@ -4394,7 +4199,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4394 | decl_index, | 4199 | decl_index, |
| 4395 | try Module.ErrorMsg.create( | 4200 | try Module.ErrorMsg.create( |
| 4396 | gpa, | 4201 | gpa, |
| 4397 | decl.srcLoc(), | 4202 | decl.srcLoc(mod), |
| 4398 | "invalid liveness: {s}", | 4203 | "invalid liveness: {s}", |
| 4399 | .{@errorName(err)}, | 4204 | .{@errorName(err)}, |
| 4400 | ), | 4205 | ), |
| ... | @@ -4407,7 +4212,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { | ... | @@ -4407,7 +4212,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4407 | 4212 | ||
| 4408 | if (no_bin_file and !dump_llvm_ir) return; | 4213 | if (no_bin_file and !dump_llvm_ir) return; |
| 4409 | 4214 | ||
| 4410 | comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) { | 4215 | comp.bin_file.updateFunc(mod, func_index, air, liveness) catch |err| switch (err) { |
| 4411 | error.OutOfMemory => return error.OutOfMemory, | 4216 | error.OutOfMemory => return error.OutOfMemory, |
| 4412 | error.AnalysisFail => { | 4217 | error.AnalysisFail => { |
| 4413 | decl.analysis = .codegen_failure; | 4218 | decl.analysis = .codegen_failure; |
| ... | @@ -4417,7 +4222,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { | ... | @@ -4417,7 +4222,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4417 | try mod.failed_decls.ensureUnusedCapacity(gpa, 1); | 4222 | try mod.failed_decls.ensureUnusedCapacity(gpa, 1); |
| 4418 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( | 4223 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( |
| 4419 | gpa, | 4224 | gpa, |
| 4420 | decl.srcLoc(), | 4225 | decl.srcLoc(mod), |
| 4421 | "unable to codegen: {s}", | 4226 | "unable to codegen: {s}", |
| 4422 | .{@errorName(err)}, | 4227 | .{@errorName(err)}, |
| 4423 | )); | 4228 | )); |
| ... | @@ -4437,7 +4242,8 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { | ... | @@ -4437,7 +4242,8 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4437 | /// analyzed, and for ensuring it can exist at runtime (see | 4242 | /// analyzed, and for ensuring it can exist at runtime (see |
| 4438 | /// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body | 4243 | /// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body |
| 4439 | /// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`. | 4244 | /// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`. |
| 4440 | pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func: *Fn) !void { | 4245 | pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: Fn.Index) !void { |
| 4246 | const func = mod.funcPtr(func_index); | ||
| 4441 | const decl_index = func.owner_decl; | 4247 | const decl_index = func.owner_decl; |
| 4442 | const decl = mod.declPtr(decl_index); | 4248 | const decl = mod.declPtr(decl_index); |
| 4443 | 4249 | ||
| ... | @@ -4475,7 +4281,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func: *Fn) !void { | ... | @@ -4475,7 +4281,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func: *Fn) !void { |
| 4475 | 4281 | ||
| 4476 | // Decl itself is safely analyzed, and body analysis is not yet queued | 4282 | // Decl itself is safely analyzed, and body analysis is not yet queued |
| 4477 | 4283 | ||
| 4478 | try mod.comp.work_queue.writeItem(.{ .codegen_func = func }); | 4284 | try mod.comp.work_queue.writeItem(.{ .codegen_func = func_index }); |
| 4479 | if (mod.emit_h != null) { | 4285 | if (mod.emit_h != null) { |
| 4480 | // TODO: we ideally only want to do this if the function's type changed | 4286 | // TODO: we ideally only want to do this if the function's type changed |
| 4481 | // since the last update | 4287 | // since the last update |
| ... | @@ -4527,42 +4333,54 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { | ... | @@ -4527,42 +4333,54 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 4527 | if (file.root_decl != .none) return; | 4333 | if (file.root_decl != .none) return; |
| 4528 | 4334 | ||
| 4529 | const gpa = mod.gpa; | 4335 | const gpa = mod.gpa; |
| 4530 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | 4336 | |
| 4531 | errdefer new_decl_arena.deinit(); | 4337 | // Because these three things each reference each other, `undefined` |
| 4532 | const new_decl_arena_allocator = new_decl_arena.allocator(); | 4338 | // placeholders are used before being set after the struct type gains an |
| 4533 | 4339 | // InternPool index. | |
| 4534 | const struct_obj = try new_decl_arena_allocator.create(Module.Struct); | 4340 | const new_namespace_index = try mod.createNamespace(.{ |
| 4535 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); | 4341 | .parent = .none, |
| 4536 | const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); | 4342 | .ty = undefined, |
| 4537 | const ty_ty = comptime Type.initTag(.type); | 4343 | .file_scope = file, |
| 4538 | struct_obj.* = .{ | 4344 | }); |
| 4539 | .owner_decl = undefined, // set below | 4345 | const new_namespace = mod.namespacePtr(new_namespace_index); |
| 4346 | errdefer mod.destroyNamespace(new_namespace_index); | ||
| 4347 | |||
| 4348 | const new_decl_index = try mod.allocateNewDecl(new_namespace_index, 0, null); | ||
| 4349 | const new_decl = mod.declPtr(new_decl_index); | ||
| 4350 | errdefer @panic("TODO error handling"); | ||
| 4351 | |||
| 4352 | const struct_index = try mod.createStruct(.{ | ||
| 4353 | .owner_decl = new_decl_index, | ||
| 4540 | .fields = .{}, | 4354 | .fields = .{}, |
| 4541 | .zir_index = undefined, // set below | 4355 | .zir_index = undefined, // set below |
| 4542 | .layout = .Auto, | 4356 | .layout = .Auto, |
| 4543 | .status = .none, | 4357 | .status = .none, |
| 4544 | .known_non_opv = undefined, | 4358 | .known_non_opv = undefined, |
| 4545 | .is_tuple = undefined, // set below | 4359 | .is_tuple = undefined, // set below |
| 4546 | .namespace = .{ | 4360 | .namespace = new_namespace_index, |
| 4547 | .parent = null, | 4361 | }); |
| 4548 | .ty = struct_ty, | 4362 | errdefer mod.destroyStruct(struct_index); |
| 4549 | .file_scope = file, | 4363 | |
| 4550 | }, | 4364 | const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ |
| 4551 | }; | 4365 | .index = struct_index.toOptional(), |
| 4552 | const new_decl_index = try mod.allocateNewDecl(&struct_obj.namespace, 0, null); | 4366 | .namespace = new_namespace_index.toOptional(), |
| 4553 | const new_decl = mod.declPtr(new_decl_index); | 4367 | } }); |
| 4368 | // TODO: figure out InternPool removals for incremental compilation | ||
| 4369 | //errdefer mod.intern_pool.remove(struct_ty); | ||
| 4370 | |||
| 4371 | new_namespace.ty = struct_ty.toType(); | ||
| 4554 | file.root_decl = new_decl_index.toOptional(); | 4372 | file.root_decl = new_decl_index.toOptional(); |
| 4555 | struct_obj.owner_decl = new_decl_index; | 4373 | |
| 4556 | new_decl.name = try file.fullyQualifiedNameZ(gpa); | 4374 | new_decl.name = try file.fullyQualifiedName(mod); |
| 4557 | new_decl.src_line = 0; | 4375 | new_decl.src_line = 0; |
| 4558 | new_decl.is_pub = true; | 4376 | new_decl.is_pub = true; |
| 4559 | new_decl.is_exported = false; | 4377 | new_decl.is_exported = false; |
| 4560 | new_decl.has_align = false; | 4378 | new_decl.has_align = false; |
| 4561 | new_decl.has_linksection_or_addrspace = false; | 4379 | new_decl.has_linksection_or_addrspace = false; |
| 4562 | new_decl.ty = ty_ty; | 4380 | new_decl.ty = Type.type; |
| 4563 | new_decl.val = struct_val; | 4381 | new_decl.val = struct_ty.toValue(); |
| 4564 | new_decl.@"align" = 0; | 4382 | new_decl.@"align" = 0; |
| 4565 | new_decl.@"linksection" = null; | 4383 | new_decl.@"linksection" = .none; |
| 4566 | new_decl.has_tv = true; | 4384 | new_decl.has_tv = true; |
| 4567 | new_decl.owns_tv = true; | 4385 | new_decl.owns_tv = true; |
| 4568 | new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. | 4386 | new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. |
| ... | @@ -4573,6 +4391,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { | ... | @@ -4573,6 +4391,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 4573 | if (file.status == .success_zir) { | 4391 | if (file.status == .success_zir) { |
| 4574 | assert(file.zir_loaded); | 4392 | assert(file.zir_loaded); |
| 4575 | const main_struct_inst = Zir.main_struct_inst; | 4393 | const main_struct_inst = Zir.main_struct_inst; |
| 4394 | const struct_obj = mod.structPtr(struct_index); | ||
| 4576 | struct_obj.zir_index = main_struct_inst; | 4395 | struct_obj.zir_index = main_struct_inst; |
| 4577 | const extended = file.zir.instructions.items(.data)[main_struct_inst].extended; | 4396 | const extended = file.zir.instructions.items(.data)[main_struct_inst].extended; |
| 4578 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); | 4397 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| ... | @@ -4582,25 +4401,34 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { | ... | @@ -4582,25 +4401,34 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 4582 | defer sema_arena.deinit(); | 4401 | defer sema_arena.deinit(); |
| 4583 | const sema_arena_allocator = sema_arena.allocator(); | 4402 | const sema_arena_allocator = sema_arena.allocator(); |
| 4584 | 4403 | ||
| 4404 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | ||
| 4405 | defer comptime_mutable_decls.deinit(); | ||
| 4406 | |||
| 4585 | var sema: Sema = .{ | 4407 | var sema: Sema = .{ |
| 4586 | .mod = mod, | 4408 | .mod = mod, |
| 4587 | .gpa = gpa, | 4409 | .gpa = gpa, |
| 4588 | .arena = sema_arena_allocator, | 4410 | .arena = sema_arena_allocator, |
| 4589 | .perm_arena = new_decl_arena_allocator, | ||
| 4590 | .code = file.zir, | 4411 | .code = file.zir, |
| 4591 | .owner_decl = new_decl, | 4412 | .owner_decl = new_decl, |
| 4592 | .owner_decl_index = new_decl_index, | 4413 | .owner_decl_index = new_decl_index, |
| 4593 | .func = null, | 4414 | .func = null, |
| 4415 | .func_index = .none, | ||
| 4594 | .fn_ret_ty = Type.void, | 4416 | .fn_ret_ty = Type.void, |
| 4595 | .owner_func = null, | 4417 | .owner_func = null, |
| 4418 | .owner_func_index = .none, | ||
| 4419 | .comptime_mutable_decls = &comptime_mutable_decls, | ||
| 4596 | }; | 4420 | }; |
| 4597 | defer sema.deinit(); | 4421 | defer sema.deinit(); |
| 4598 | 4422 | ||
| 4599 | var wip_captures = try WipCaptureScope.init(gpa, new_decl_arena_allocator, null); | 4423 | var wip_captures = try WipCaptureScope.init(gpa, null); |
| 4600 | defer wip_captures.deinit(); | 4424 | defer wip_captures.deinit(); |
| 4601 | 4425 | ||
| 4602 | if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_obj)) |_| { | 4426 | if (sema.analyzeStructDecl(new_decl, main_struct_inst, struct_index)) |_| { |
| 4603 | try wip_captures.finalize(); | 4427 | try wip_captures.finalize(); |
| 4428 | for (comptime_mutable_decls.items) |decl_index| { | ||
| 4429 | const decl = mod.declPtr(decl_index); | ||
| 4430 | try decl.intern(mod); | ||
| 4431 | } | ||
| 4604 | new_decl.analysis = .complete; | 4432 | new_decl.analysis = .complete; |
| 4605 | } else |err| switch (err) { | 4433 | } else |err| switch (err) { |
| 4606 | error.OutOfMemory => return error.OutOfMemory, | 4434 | error.OutOfMemory => return error.OutOfMemory, |
| ... | @@ -4632,8 +4460,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { | ... | @@ -4632,8 +4460,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 4632 | } else { | 4460 | } else { |
| 4633 | new_decl.analysis = .file_failure; | 4461 | new_decl.analysis = .file_failure; |
| 4634 | } | 4462 | } |
| 4635 | |||
| 4636 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 4637 | } | 4463 | } |
| 4638 | 4464 | ||
| 4639 | /// Returns `true` if the Decl type changed. | 4465 | /// Returns `true` if the Decl type changed. |
| ... | @@ -4645,68 +4471,52 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | ... | @@ -4645,68 +4471,52 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4645 | 4471 | ||
| 4646 | const decl = mod.declPtr(decl_index); | 4472 | const decl = mod.declPtr(decl_index); |
| 4647 | 4473 | ||
| 4648 | if (decl.getFileScope().status != .success_zir) { | 4474 | if (decl.getFileScope(mod).status != .success_zir) { |
| 4649 | return error.AnalysisFail; | 4475 | return error.AnalysisFail; |
| 4650 | } | 4476 | } |
| 4651 | 4477 | ||
| 4652 | const gpa = mod.gpa; | 4478 | const gpa = mod.gpa; |
| 4653 | const zir = decl.getFileScope().zir; | 4479 | const zir = decl.getFileScope(mod).zir; |
| 4654 | const zir_datas = zir.instructions.items(.data); | 4480 | const zir_datas = zir.instructions.items(.data); |
| 4655 | 4481 | ||
| 4656 | decl.analysis = .in_progress; | 4482 | decl.analysis = .in_progress; |
| 4657 | 4483 | ||
| 4658 | // We need the memory for the Type to go into the arena for the Decl | ||
| 4659 | var decl_arena = std.heap.ArenaAllocator.init(gpa); | ||
| 4660 | const decl_arena_allocator = decl_arena.allocator(); | ||
| 4661 | const decl_value_arena = blk: { | ||
| 4662 | errdefer decl_arena.deinit(); | ||
| 4663 | const s = try decl_arena_allocator.create(ValueArena); | ||
| 4664 | s.* = .{ .state = undefined }; | ||
| 4665 | break :blk s; | ||
| 4666 | }; | ||
| 4667 | defer { | ||
| 4668 | if (decl.value_arena) |value_arena| { | ||
| 4669 | assert(value_arena.state_acquired == null); | ||
| 4670 | decl_value_arena.prev = value_arena; | ||
| 4671 | } | ||
| 4672 | |||
| 4673 | decl_value_arena.state = decl_arena.state; | ||
| 4674 | decl.value_arena = decl_value_arena; | ||
| 4675 | } | ||
| 4676 | |||
| 4677 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | 4484 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 4678 | defer analysis_arena.deinit(); | 4485 | defer analysis_arena.deinit(); |
| 4679 | const analysis_arena_allocator = analysis_arena.allocator(); | 4486 | |
| 4487 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | ||
| 4488 | defer comptime_mutable_decls.deinit(); | ||
| 4680 | 4489 | ||
| 4681 | var sema: Sema = .{ | 4490 | var sema: Sema = .{ |
| 4682 | .mod = mod, | 4491 | .mod = mod, |
| 4683 | .gpa = gpa, | 4492 | .gpa = gpa, |
| 4684 | .arena = analysis_arena_allocator, | 4493 | .arena = analysis_arena.allocator(), |
| 4685 | .perm_arena = decl_arena_allocator, | ||
| 4686 | .code = zir, | 4494 | .code = zir, |
| 4687 | .owner_decl = decl, | 4495 | .owner_decl = decl, |
| 4688 | .owner_decl_index = decl_index, | 4496 | .owner_decl_index = decl_index, |
| 4689 | .func = null, | 4497 | .func = null, |
| 4498 | .func_index = .none, | ||
| 4690 | .fn_ret_ty = Type.void, | 4499 | .fn_ret_ty = Type.void, |
| 4691 | .owner_func = null, | 4500 | .owner_func = null, |
| 4501 | .owner_func_index = .none, | ||
| 4502 | .comptime_mutable_decls = &comptime_mutable_decls, | ||
| 4692 | }; | 4503 | }; |
| 4693 | defer sema.deinit(); | 4504 | defer sema.deinit(); |
| 4694 | 4505 | ||
| 4695 | if (mod.declIsRoot(decl_index)) { | 4506 | if (mod.declIsRoot(decl_index)) { |
| 4696 | log.debug("semaDecl root {*} ({s})", .{ decl, decl.name }); | ||
| 4697 | const main_struct_inst = Zir.main_struct_inst; | 4507 | const main_struct_inst = Zir.main_struct_inst; |
| 4698 | const struct_obj = decl.getStruct().?; | 4508 | const struct_index = decl.getOwnedStructIndex(mod).unwrap().?; |
| 4509 | const struct_obj = mod.structPtr(struct_index); | ||
| 4699 | // This might not have gotten set in `semaFile` if the first time had | 4510 | // This might not have gotten set in `semaFile` if the first time had |
| 4700 | // a ZIR failure, so we set it here in case. | 4511 | // a ZIR failure, so we set it here in case. |
| 4701 | struct_obj.zir_index = main_struct_inst; | 4512 | struct_obj.zir_index = main_struct_inst; |
| 4702 | try sema.analyzeStructDecl(decl, main_struct_inst, struct_obj); | 4513 | try sema.analyzeStructDecl(decl, main_struct_inst, struct_index); |
| 4703 | decl.analysis = .complete; | 4514 | decl.analysis = .complete; |
| 4704 | decl.generation = mod.generation; | 4515 | decl.generation = mod.generation; |
| 4705 | return false; | 4516 | return false; |
| 4706 | } | 4517 | } |
| 4707 | log.debug("semaDecl {*} ({s})", .{ decl, decl.name }); | ||
| 4708 | 4518 | ||
| 4709 | var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); | 4519 | var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope); |
| 4710 | defer wip_captures.deinit(); | 4520 | defer wip_captures.deinit(); |
| 4711 | 4521 | ||
| 4712 | var block_scope: Sema.Block = .{ | 4522 | var block_scope: Sema.Block = .{ |
| ... | @@ -4724,12 +4534,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | ... | @@ -4724,12 +4534,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4724 | block_scope.params.deinit(gpa); | 4534 | block_scope.params.deinit(gpa); |
| 4725 | } | 4535 | } |
| 4726 | 4536 | ||
| 4727 | const zir_block_index = decl.zirBlockIndex(); | 4537 | const zir_block_index = decl.zirBlockIndex(mod); |
| 4728 | const inst_data = zir_datas[zir_block_index].pl_node; | 4538 | const inst_data = zir_datas[zir_block_index].pl_node; |
| 4729 | const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index); | 4539 | const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index); |
| 4730 | const body = zir.extra[extra.end..][0..extra.data.body_len]; | 4540 | const body = zir.extra[extra.end..][0..extra.data.body_len]; |
| 4731 | const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand; | 4541 | const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand; |
| 4732 | try wip_captures.finalize(); | 4542 | try wip_captures.finalize(); |
| 4543 | for (comptime_mutable_decls.items) |ct_decl_index| { | ||
| 4544 | const ct_decl = mod.declPtr(ct_decl_index); | ||
| 4545 | try ct_decl.intern(mod); | ||
| 4546 | } | ||
| 4733 | const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 }; | 4547 | const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 }; |
| 4734 | const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 }; | 4548 | const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 }; |
| 4735 | const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 }; | 4549 | const address_space_src: LazySrcLoc = .{ .node_offset_var_decl_addrspace = 0 }; |
| ... | @@ -4748,16 +4562,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | ... | @@ -4748,16 +4562,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4748 | decl_tv.ty.fmt(mod), | 4562 | decl_tv.ty.fmt(mod), |
| 4749 | }); | 4563 | }); |
| 4750 | } | 4564 | } |
| 4751 | var buffer: Value.ToTypeBuffer = undefined; | 4565 | const ty = decl_tv.val.toType(); |
| 4752 | const ty = try decl_tv.val.toType(&buffer).copy(decl_arena_allocator); | 4566 | if (ty.getNamespace(mod) == null) { |
| 4753 | if (ty.getNamespace() == null) { | ||
| 4754 | return sema.fail(&block_scope, ty_src, "type {} has no namespace", .{ty.fmt(mod)}); | 4567 | return sema.fail(&block_scope, ty_src, "type {} has no namespace", .{ty.fmt(mod)}); |
| 4755 | } | 4568 | } |
| 4756 | 4569 | ||
| 4757 | decl.ty = Type.type; | 4570 | decl.ty = InternPool.Index.type_type.toType(); |
| 4758 | decl.val = try Value.Tag.ty.create(decl_arena_allocator, ty); | 4571 | decl.val = ty.toValue(); |
| 4759 | decl.@"align" = 0; | 4572 | decl.@"align" = 0; |
| 4760 | decl.@"linksection" = null; | 4573 | decl.@"linksection" = .none; |
| 4761 | decl.has_tv = true; | 4574 | decl.has_tv = true; |
| 4762 | decl.owns_tv = false; | 4575 | decl.owns_tv = false; |
| 4763 | decl.analysis = .complete; | 4576 | decl.analysis = .complete; |
| ... | @@ -4766,8 +4579,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | ... | @@ -4766,8 +4579,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4766 | return true; | 4579 | return true; |
| 4767 | } | 4580 | } |
| 4768 | 4581 | ||
| 4769 | if (decl_tv.val.castTag(.function)) |fn_payload| { | 4582 | if (mod.intern_pool.indexToFunc(decl_tv.val.toIntern()).unwrap()) |func_index| { |
| 4770 | const func = fn_payload.data; | 4583 | const func = mod.funcPtr(func_index); |
| 4771 | const owns_tv = func.owner_decl == decl_index; | 4584 | const owns_tv = func.owner_decl == decl_index; |
| 4772 | if (owns_tv) { | 4585 | if (owns_tv) { |
| 4773 | var prev_type_has_bits = false; | 4586 | var prev_type_has_bits = false; |
| ... | @@ -4775,31 +4588,30 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | ... | @@ -4775,31 +4588,30 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4775 | var type_changed = true; | 4588 | var type_changed = true; |
| 4776 | 4589 | ||
| 4777 | if (decl.has_tv) { | 4590 | if (decl.has_tv) { |
| 4778 | prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(); | 4591 | prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(mod); |
| 4779 | type_changed = !decl.ty.eql(decl_tv.ty, mod); | 4592 | type_changed = !decl.ty.eql(decl_tv.ty, mod); |
| 4780 | if (decl.getFunction()) |prev_func| { | 4593 | if (decl.getOwnedFunction(mod)) |prev_func| { |
| 4781 | prev_is_inline = prev_func.state == .inline_only; | 4594 | prev_is_inline = prev_func.state == .inline_only; |
| 4782 | } | 4595 | } |
| 4783 | } | 4596 | } |
| 4784 | decl.clearValues(mod); | 4597 | decl.clearValues(mod); |
| 4785 | 4598 | ||
| 4786 | decl.ty = try decl_tv.ty.copy(decl_arena_allocator); | 4599 | decl.ty = decl_tv.ty; |
| 4787 | decl.val = try decl_tv.val.copy(decl_arena_allocator); | 4600 | decl.val = (try decl_tv.val.intern(decl_tv.ty, mod)).toValue(); |
| 4788 | // linksection, align, and addrspace were already set by Sema | 4601 | // linksection, align, and addrspace were already set by Sema |
| 4789 | decl.has_tv = true; | 4602 | decl.has_tv = true; |
| 4790 | decl.owns_tv = owns_tv; | 4603 | decl.owns_tv = owns_tv; |
| 4791 | decl.analysis = .complete; | 4604 | decl.analysis = .complete; |
| 4792 | decl.generation = mod.generation; | 4605 | decl.generation = mod.generation; |
| 4793 | 4606 | ||
| 4794 | const is_inline = decl.ty.fnCallingConvention() == .Inline; | 4607 | const is_inline = decl.ty.fnCallingConvention(mod) == .Inline; |
| 4795 | if (decl.is_exported) { | 4608 | if (decl.is_exported) { |
| 4796 | const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) }; | 4609 | const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) }; |
| 4797 | if (is_inline) { | 4610 | if (is_inline) { |
| 4798 | return sema.fail(&block_scope, export_src, "export of inline function", .{}); | 4611 | return sema.fail(&block_scope, export_src, "export of inline function", .{}); |
| 4799 | } | 4612 | } |
| 4800 | // The scope needs to have the decl in it. | 4613 | // The scope needs to have the decl in it. |
| 4801 | const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) }; | 4614 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); |
| 4802 | try sema.analyzeExport(&block_scope, export_src, options, decl_index); | ||
| 4803 | } | 4615 | } |
| 4804 | return type_changed or is_inline != prev_is_inline; | 4616 | return type_changed or is_inline != prev_is_inline; |
| 4805 | } | 4617 | } |
| ... | @@ -4813,64 +4625,57 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | ... | @@ -4813,64 +4625,57 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4813 | decl.owns_tv = false; | 4625 | decl.owns_tv = false; |
| 4814 | var queue_linker_work = false; | 4626 | var queue_linker_work = false; |
| 4815 | var is_extern = false; | 4627 | var is_extern = false; |
| 4816 | switch (decl_tv.val.tag()) { | 4628 | switch (decl_tv.val.toIntern()) { |
| 4817 | .variable => { | ||
| 4818 | const variable = decl_tv.val.castTag(.variable).?.data; | ||
| 4819 | if (variable.owner_decl == decl_index) { | ||
| 4820 | decl.owns_tv = true; | ||
| 4821 | queue_linker_work = true; | ||
| 4822 | |||
| 4823 | const copied_init = try variable.init.copy(decl_arena_allocator); | ||
| 4824 | variable.init = copied_init; | ||
| 4825 | } | ||
| 4826 | }, | ||
| 4827 | .extern_fn => { | ||
| 4828 | const extern_fn = decl_tv.val.castTag(.extern_fn).?.data; | ||
| 4829 | if (extern_fn.owner_decl == decl_index) { | ||
| 4830 | decl.owns_tv = true; | ||
| 4831 | queue_linker_work = true; | ||
| 4832 | is_extern = true; | ||
| 4833 | } | ||
| 4834 | }, | ||
| 4835 | |||
| 4836 | .generic_poison => unreachable, | 4629 | .generic_poison => unreachable, |
| 4837 | .unreachable_value => unreachable, | 4630 | .unreachable_value => unreachable, |
| 4631 | else => switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) { | ||
| 4632 | .variable => |variable| if (variable.decl == decl_index) { | ||
| 4633 | decl.owns_tv = true; | ||
| 4634 | queue_linker_work = true; | ||
| 4635 | }, | ||
| 4838 | 4636 | ||
| 4839 | .function => {}, | 4637 | .extern_func => |extern_fn| if (extern_fn.decl == decl_index) { |
| 4638 | decl.owns_tv = true; | ||
| 4639 | queue_linker_work = true; | ||
| 4640 | is_extern = true; | ||
| 4641 | }, | ||
| 4840 | 4642 | ||
| 4841 | else => { | 4643 | .func => {}, |
| 4842 | log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name }); | 4644 | |
| 4843 | queue_linker_work = true; | 4645 | else => { |
| 4646 | queue_linker_work = true; | ||
| 4647 | }, | ||
| 4844 | }, | 4648 | }, |
| 4845 | } | 4649 | } |
| 4846 | 4650 | ||
| 4847 | decl.ty = try decl_tv.ty.copy(decl_arena_allocator); | 4651 | decl.ty = decl_tv.ty; |
| 4848 | decl.val = try decl_tv.val.copy(decl_arena_allocator); | 4652 | decl.val = (try decl_tv.val.intern(decl_tv.ty, mod)).toValue(); |
| 4849 | decl.@"align" = blk: { | 4653 | decl.@"align" = blk: { |
| 4850 | const align_ref = decl.zirAlignRef(); | 4654 | const align_ref = decl.zirAlignRef(mod); |
| 4851 | if (align_ref == .none) break :blk 0; | 4655 | if (align_ref == .none) break :blk 0; |
| 4852 | break :blk try sema.resolveAlign(&block_scope, align_src, align_ref); | 4656 | break :blk try sema.resolveAlign(&block_scope, align_src, align_ref); |
| 4853 | }; | 4657 | }; |
| 4854 | decl.@"linksection" = blk: { | 4658 | decl.@"linksection" = blk: { |
| 4855 | const linksection_ref = decl.zirLinksectionRef(); | 4659 | const linksection_ref = decl.zirLinksectionRef(mod); |
| 4856 | if (linksection_ref == .none) break :blk null; | 4660 | if (linksection_ref == .none) break :blk .none; |
| 4857 | const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, "linksection must be comptime-known"); | 4661 | const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, "linksection must be comptime-known"); |
| 4858 | if (mem.indexOfScalar(u8, bytes, 0) != null) { | 4662 | if (mem.indexOfScalar(u8, bytes, 0) != null) { |
| 4859 | return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); | 4663 | return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); |
| 4860 | } else if (bytes.len == 0) { | 4664 | } else if (bytes.len == 0) { |
| 4861 | return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); | 4665 | return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); |
| 4862 | } | 4666 | } |
| 4863 | break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr; | 4667 | const section = try mod.intern_pool.getOrPutString(gpa, bytes); |
| 4668 | break :blk section.toOptional(); | ||
| 4864 | }; | 4669 | }; |
| 4865 | decl.@"addrspace" = blk: { | 4670 | decl.@"addrspace" = blk: { |
| 4866 | const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.tag()) { | 4671 | const addrspace_ctx: Sema.AddressSpaceContext = switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) { |
| 4867 | .function, .extern_fn => .function, | ||
| 4868 | .variable => .variable, | 4672 | .variable => .variable, |
| 4673 | .extern_func, .func => .function, | ||
| 4869 | else => .constant, | 4674 | else => .constant, |
| 4870 | }; | 4675 | }; |
| 4871 | 4676 | ||
| 4872 | const target = sema.mod.getTarget(); | 4677 | const target = sema.mod.getTarget(); |
| 4873 | break :blk switch (decl.zirAddrspaceRef()) { | 4678 | break :blk switch (decl.zirAddrspaceRef(mod)) { |
| 4874 | .none => switch (addrspace_ctx) { | 4679 | .none => switch (addrspace_ctx) { |
| 4875 | .function => target_util.defaultAddressSpace(target, .function), | 4680 | .function => target_util.defaultAddressSpace(target, .function), |
| 4876 | .variable => target_util.defaultAddressSpace(target, .global_mutable), | 4681 | .variable => target_util.defaultAddressSpace(target, .global_mutable), |
| ... | @@ -4888,7 +4693,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | ... | @@ -4888,7 +4693,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4888 | (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty)); | 4693 | (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty)); |
| 4889 | 4694 | ||
| 4890 | if (has_runtime_bits) { | 4695 | if (has_runtime_bits) { |
| 4891 | log.debug("queue linker work for {*} ({s})", .{ decl, decl.name }); | ||
| 4892 | 4696 | ||
| 4893 | // Needed for codegen_decl which will call updateDecl and then the | 4697 | // Needed for codegen_decl which will call updateDecl and then the |
| 4894 | // codegen backend wants full access to the Decl Type. | 4698 | // codegen backend wants full access to the Decl Type. |
| ... | @@ -4904,8 +4708,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | ... | @@ -4904,8 +4708,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4904 | if (decl.is_exported) { | 4708 | if (decl.is_exported) { |
| 4905 | const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) }; | 4709 | const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) }; |
| 4906 | // The scope needs to have the decl in it. | 4710 | // The scope needs to have the decl in it. |
| 4907 | const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) }; | 4711 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); |
| 4908 | try sema.analyzeExport(&block_scope, export_src, options, decl_index); | ||
| 4909 | } | 4712 | } |
| 4910 | 4713 | ||
| 4911 | return type_changed; | 4714 | return type_changed; |
| ... | @@ -4930,10 +4733,6 @@ pub fn declareDeclDependencyType(mod: *Module, depender_index: Decl.Index, depen | ... | @@ -4930,10 +4733,6 @@ pub fn declareDeclDependencyType(mod: *Module, depender_index: Decl.Index, depen |
| 4930 | } | 4733 | } |
| 4931 | } | 4734 | } |
| 4932 | 4735 | ||
| 4933 | log.debug("{*} ({s}) depends on {*} ({s})", .{ | ||
| 4934 | depender, depender.name, dependee, dependee.name, | ||
| 4935 | }); | ||
| 4936 | |||
| 4937 | if (dependee.deletion_flag) { | 4736 | if (dependee.deletion_flag) { |
| 4938 | dependee.deletion_flag = false; | 4737 | dependee.deletion_flag = false; |
| 4939 | assert(mod.deletion_set.swapRemove(dependee_index)); | 4738 | assert(mod.deletion_set.swapRemove(dependee_index)); |
| ... | @@ -5222,7 +5021,7 @@ pub fn detectEmbedFileUpdate(mod: *Module, embed_file: *EmbedFile) !void { | ... | @@ -5222,7 +5021,7 @@ pub fn detectEmbedFileUpdate(mod: *Module, embed_file: *EmbedFile) !void { |
| 5222 | 5021 | ||
| 5223 | pub fn scanNamespace( | 5022 | pub fn scanNamespace( |
| 5224 | mod: *Module, | 5023 | mod: *Module, |
| 5225 | namespace: *Namespace, | 5024 | namespace_index: Namespace.Index, |
| 5226 | extra_start: usize, | 5025 | extra_start: usize, |
| 5227 | decls_len: u32, | 5026 | decls_len: u32, |
| 5228 | parent_decl: *Decl, | 5027 | parent_decl: *Decl, |
| ... | @@ -5231,6 +5030,7 @@ pub fn scanNamespace( | ... | @@ -5231,6 +5030,7 @@ pub fn scanNamespace( |
| 5231 | defer tracy.end(); | 5030 | defer tracy.end(); |
| 5232 | 5031 | ||
| 5233 | const gpa = mod.gpa; | 5032 | const gpa = mod.gpa; |
| 5033 | const namespace = mod.namespacePtr(namespace_index); | ||
| 5234 | const zir = namespace.file_scope.zir; | 5034 | const zir = namespace.file_scope.zir; |
| 5235 | 5035 | ||
| 5236 | try mod.comp.work_queue.ensureUnusedCapacity(decls_len); | 5036 | try mod.comp.work_queue.ensureUnusedCapacity(decls_len); |
| ... | @@ -5243,7 +5043,7 @@ pub fn scanNamespace( | ... | @@ -5243,7 +5043,7 @@ pub fn scanNamespace( |
| 5243 | var decl_i: u32 = 0; | 5043 | var decl_i: u32 = 0; |
| 5244 | var scan_decl_iter: ScanDeclIter = .{ | 5044 | var scan_decl_iter: ScanDeclIter = .{ |
| 5245 | .module = mod, | 5045 | .module = mod, |
| 5246 | .namespace = namespace, | 5046 | .namespace_index = namespace_index, |
| 5247 | .parent_decl = parent_decl, | 5047 | .parent_decl = parent_decl, |
| 5248 | }; | 5048 | }; |
| 5249 | while (decl_i < decls_len) : (decl_i += 1) { | 5049 | while (decl_i < decls_len) : (decl_i += 1) { |
| ... | @@ -5266,7 +5066,7 @@ pub fn scanNamespace( | ... | @@ -5266,7 +5066,7 @@ pub fn scanNamespace( |
| 5266 | 5066 | ||
| 5267 | const ScanDeclIter = struct { | 5067 | const ScanDeclIter = struct { |
| 5268 | module: *Module, | 5068 | module: *Module, |
| 5269 | namespace: *Namespace, | 5069 | namespace_index: Namespace.Index, |
| 5270 | parent_decl: *Decl, | 5070 | parent_decl: *Decl, |
| 5271 | usingnamespace_index: usize = 0, | 5071 | usingnamespace_index: usize = 0, |
| 5272 | comptime_index: usize = 0, | 5072 | comptime_index: usize = 0, |
| ... | @@ -5278,9 +5078,11 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -5278,9 +5078,11 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5278 | defer tracy.end(); | 5078 | defer tracy.end(); |
| 5279 | 5079 | ||
| 5280 | const mod = iter.module; | 5080 | const mod = iter.module; |
| 5281 | const namespace = iter.namespace; | 5081 | const namespace_index = iter.namespace_index; |
| 5082 | const namespace = mod.namespacePtr(namespace_index); | ||
| 5282 | const gpa = mod.gpa; | 5083 | const gpa = mod.gpa; |
| 5283 | const zir = namespace.file_scope.zir; | 5084 | const zir = namespace.file_scope.zir; |
| 5085 | const ip = &mod.intern_pool; | ||
| 5284 | 5086 | ||
| 5285 | // zig fmt: off | 5087 | // zig fmt: off |
| 5286 | const is_pub = (flags & 0b0001) != 0; | 5088 | const is_pub = (flags & 0b0001) != 0; |
| ... | @@ -5300,31 +5102,31 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -5300,31 +5102,31 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5300 | // Every Decl needs a name. | 5102 | // Every Decl needs a name. |
| 5301 | var is_named_test = false; | 5103 | var is_named_test = false; |
| 5302 | var kind: Decl.Kind = .named; | 5104 | var kind: Decl.Kind = .named; |
| 5303 | const decl_name: [:0]const u8 = switch (decl_name_index) { | 5105 | const decl_name: InternPool.NullTerminatedString = switch (decl_name_index) { |
| 5304 | 0 => name: { | 5106 | 0 => name: { |
| 5305 | if (export_bit) { | 5107 | if (export_bit) { |
| 5306 | const i = iter.usingnamespace_index; | 5108 | const i = iter.usingnamespace_index; |
| 5307 | iter.usingnamespace_index += 1; | 5109 | iter.usingnamespace_index += 1; |
| 5308 | kind = .@"usingnamespace"; | 5110 | kind = .@"usingnamespace"; |
| 5309 | break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i}); | 5111 | break :name try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}); |
| 5310 | } else { | 5112 | } else { |
| 5311 | const i = iter.comptime_index; | 5113 | const i = iter.comptime_index; |
| 5312 | iter.comptime_index += 1; | 5114 | iter.comptime_index += 1; |
| 5313 | kind = .@"comptime"; | 5115 | kind = .@"comptime"; |
| 5314 | break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i}); | 5116 | break :name try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}); |
| 5315 | } | 5117 | } |
| 5316 | }, | 5118 | }, |
| 5317 | 1 => name: { | 5119 | 1 => name: { |
| 5318 | const i = iter.unnamed_test_index; | 5120 | const i = iter.unnamed_test_index; |
| 5319 | iter.unnamed_test_index += 1; | 5121 | iter.unnamed_test_index += 1; |
| 5320 | kind = .@"test"; | 5122 | kind = .@"test"; |
| 5321 | break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i}); | 5123 | break :name try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}); |
| 5322 | }, | 5124 | }, |
| 5323 | 2 => name: { | 5125 | 2 => name: { |
| 5324 | is_named_test = true; | 5126 | is_named_test = true; |
| 5325 | const test_name = zir.nullTerminatedString(decl_doccomment_index); | 5127 | const test_name = zir.nullTerminatedString(decl_doccomment_index); |
| 5326 | kind = .@"test"; | 5128 | kind = .@"test"; |
| 5327 | break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name}); | 5129 | break :name try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{test_name}); |
| 5328 | }, | 5130 | }, |
| 5329 | else => name: { | 5131 | else => name: { |
| 5330 | const raw_name = zir.nullTerminatedString(decl_name_index); | 5132 | const raw_name = zir.nullTerminatedString(decl_name_index); |
| ... | @@ -5332,14 +5134,12 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -5332,14 +5134,12 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5332 | is_named_test = true; | 5134 | is_named_test = true; |
| 5333 | const test_name = zir.nullTerminatedString(decl_name_index + 1); | 5135 | const test_name = zir.nullTerminatedString(decl_name_index + 1); |
| 5334 | kind = .@"test"; | 5136 | kind = .@"test"; |
| 5335 | break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name}); | 5137 | break :name try ip.getOrPutStringFmt(gpa, "test.{s}", .{test_name}); |
| 5336 | } else { | 5138 | } else { |
| 5337 | break :name try gpa.dupeZ(u8, raw_name); | 5139 | break :name try ip.getOrPutString(gpa, raw_name); |
| 5338 | } | 5140 | } |
| 5339 | }, | 5141 | }, |
| 5340 | }; | 5142 | }; |
| 5341 | var must_free_decl_name = true; | ||
| 5342 | defer if (must_free_decl_name) gpa.free(decl_name); | ||
| 5343 | 5143 | ||
| 5344 | const is_exported = export_bit and decl_name_index != 0; | 5144 | const is_exported = export_bit and decl_name_index != 0; |
| 5345 | if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); | 5145 | if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); |
| ... | @@ -5347,21 +5147,19 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -5347,21 +5147,19 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5347 | // We create a Decl for it regardless of analysis status. | 5147 | // We create a Decl for it regardless of analysis status. |
| 5348 | const gop = try namespace.decls.getOrPutContextAdapted( | 5148 | const gop = try namespace.decls.getOrPutContextAdapted( |
| 5349 | gpa, | 5149 | gpa, |
| 5350 | @as([]const u8, mem.sliceTo(decl_name, 0)), | 5150 | decl_name, |
| 5351 | DeclAdapter{ .mod = mod }, | 5151 | DeclAdapter{ .mod = mod }, |
| 5352 | Namespace.DeclContext{ .module = mod }, | 5152 | Namespace.DeclContext{ .module = mod }, |
| 5353 | ); | 5153 | ); |
| 5354 | const comp = mod.comp; | 5154 | const comp = mod.comp; |
| 5355 | if (!gop.found_existing) { | 5155 | if (!gop.found_existing) { |
| 5356 | const new_decl_index = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope); | 5156 | const new_decl_index = try mod.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope); |
| 5357 | const new_decl = mod.declPtr(new_decl_index); | 5157 | const new_decl = mod.declPtr(new_decl_index); |
| 5358 | new_decl.kind = kind; | 5158 | new_decl.kind = kind; |
| 5359 | new_decl.name = decl_name; | 5159 | new_decl.name = decl_name; |
| 5360 | must_free_decl_name = false; | ||
| 5361 | if (kind == .@"usingnamespace") { | 5160 | if (kind == .@"usingnamespace") { |
| 5362 | namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub); | 5161 | namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub); |
| 5363 | } | 5162 | } |
| 5364 | log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace }); | ||
| 5365 | new_decl.src_line = line; | 5163 | new_decl.src_line = line; |
| 5366 | gop.key_ptr.* = new_decl_index; | 5164 | gop.key_ptr.* = new_decl_index; |
| 5367 | // Exported decls, comptime decls, usingnamespace decls, and | 5165 | // Exported decls, comptime decls, usingnamespace decls, and |
| ... | @@ -5382,7 +5180,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -5382,7 +5180,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5382 | if (!comp.bin_file.options.is_test) break :blk false; | 5180 | if (!comp.bin_file.options.is_test) break :blk false; |
| 5383 | if (decl_pkg != mod.main_pkg) break :blk false; | 5181 | if (decl_pkg != mod.main_pkg) break :blk false; |
| 5384 | if (comp.test_filter) |test_filter| { | 5182 | if (comp.test_filter) |test_filter| { |
| 5385 | if (mem.indexOf(u8, decl_name, test_filter) == null) { | 5183 | if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) { |
| 5386 | break :blk false; | 5184 | break :blk false; |
| 5387 | } | 5185 | } |
| 5388 | } | 5186 | } |
| ... | @@ -5405,16 +5203,13 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -5405,16 +5203,13 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5405 | const decl = mod.declPtr(decl_index); | 5203 | const decl = mod.declPtr(decl_index); |
| 5406 | if (kind == .@"test") { | 5204 | if (kind == .@"test") { |
| 5407 | const src_loc = SrcLoc{ | 5205 | const src_loc = SrcLoc{ |
| 5408 | .file_scope = decl.getFileScope(), | 5206 | .file_scope = decl.getFileScope(mod), |
| 5409 | .parent_decl_node = decl.src_node, | 5207 | .parent_decl_node = decl.src_node, |
| 5410 | .lazy = .{ .token_offset = 1 }, | 5208 | .lazy = .{ .token_offset = 1 }, |
| 5411 | }; | 5209 | }; |
| 5412 | const msg = try ErrorMsg.create( | 5210 | const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{ |
| 5413 | gpa, | 5211 | decl_name.fmt(&mod.intern_pool), |
| 5414 | src_loc, | 5212 | }); |
| 5415 | "duplicate test name: {s}", | ||
| 5416 | .{decl_name}, | ||
| 5417 | ); | ||
| 5418 | errdefer msg.destroy(gpa); | 5213 | errdefer msg.destroy(gpa); |
| 5419 | try mod.failed_decls.putNoClobber(gpa, decl_index, msg); | 5214 | try mod.failed_decls.putNoClobber(gpa, decl_index, msg); |
| 5420 | const other_src_loc = SrcLoc{ | 5215 | const other_src_loc = SrcLoc{ |
| ... | @@ -5424,7 +5219,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -5424,7 +5219,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5424 | }; | 5219 | }; |
| 5425 | try mod.errNoteNonLazy(other_src_loc, msg, "other test here", .{}); | 5220 | try mod.errNoteNonLazy(other_src_loc, msg, "other test here", .{}); |
| 5426 | } | 5221 | } |
| 5427 | log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl.name, namespace }); | ||
| 5428 | // Update the AST node of the decl; even if its contents are unchanged, it may | 5222 | // Update the AST node of the decl; even if its contents are unchanged, it may |
| 5429 | // have been re-ordered. | 5223 | // have been re-ordered. |
| 5430 | decl.src_node = decl_node; | 5224 | decl.src_node = decl_node; |
| ... | @@ -5436,7 +5230,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -5436,7 +5230,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5436 | decl.has_align = has_align; | 5230 | decl.has_align = has_align; |
| 5437 | decl.has_linksection_or_addrspace = has_linksection_or_addrspace; | 5231 | decl.has_linksection_or_addrspace = has_linksection_or_addrspace; |
| 5438 | decl.zir_decl_index = @intCast(u32, decl_sub_index); | 5232 | decl.zir_decl_index = @intCast(u32, decl_sub_index); |
| 5439 | if (decl.getFunction()) |_| { | 5233 | if (decl.getOwnedFunctionIndex(mod) != .none) { |
| 5440 | switch (comp.bin_file.tag) { | 5234 | switch (comp.bin_file.tag) { |
| 5441 | .coff, .elf, .macho, .plan9 => { | 5235 | .coff, .elf, .macho, .plan9 => { |
| 5442 | // TODO Look into detecting when this would be unnecessary by storing enough state | 5236 | // TODO Look into detecting when this would be unnecessary by storing enough state |
| ... | @@ -5458,7 +5252,6 @@ pub fn clearDecl( | ... | @@ -5458,7 +5252,6 @@ pub fn clearDecl( |
| 5458 | defer tracy.end(); | 5252 | defer tracy.end(); |
| 5459 | 5253 | ||
| 5460 | const decl = mod.declPtr(decl_index); | 5254 | const decl = mod.declPtr(decl_index); |
| 5461 | log.debug("clearing {*} ({s})", .{ decl, decl.name }); | ||
| 5462 | 5255 | ||
| 5463 | const gpa = mod.gpa; | 5256 | const gpa = mod.gpa; |
| 5464 | try mod.deletion_set.ensureUnusedCapacity(gpa, decl.dependencies.count()); | 5257 | try mod.deletion_set.ensureUnusedCapacity(gpa, decl.dependencies.count()); |
| ... | @@ -5473,9 +5266,6 @@ pub fn clearDecl( | ... | @@ -5473,9 +5266,6 @@ pub fn clearDecl( |
| 5473 | const dep = mod.declPtr(dep_index); | 5266 | const dep = mod.declPtr(dep_index); |
| 5474 | dep.removeDependant(decl_index); | 5267 | dep.removeDependant(decl_index); |
| 5475 | if (dep.dependants.count() == 0 and !dep.deletion_flag) { | 5268 | if (dep.dependants.count() == 0 and !dep.deletion_flag) { |
| 5476 | log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{ | ||
| 5477 | decl, decl.name, dep, dep.name, | ||
| 5478 | }); | ||
| 5479 | // We don't recursively perform a deletion here, because during the update, | 5269 | // We don't recursively perform a deletion here, because during the update, |
| 5480 | // another reference to it may turn up. | 5270 | // another reference to it may turn up. |
| 5481 | dep.deletion_flag = true; | 5271 | dep.deletion_flag = true; |
| ... | @@ -5510,10 +5300,10 @@ pub fn clearDecl( | ... | @@ -5510,10 +5300,10 @@ pub fn clearDecl( |
| 5510 | try mod.deleteDeclExports(decl_index); | 5300 | try mod.deleteDeclExports(decl_index); |
| 5511 | 5301 | ||
| 5512 | if (decl.has_tv) { | 5302 | if (decl.has_tv) { |
| 5513 | if (decl.ty.isFnOrHasRuntimeBits()) { | 5303 | if (decl.ty.isFnOrHasRuntimeBits(mod)) { |
| 5514 | mod.comp.bin_file.freeDecl(decl_index); | 5304 | mod.comp.bin_file.freeDecl(decl_index); |
| 5515 | } | 5305 | } |
| 5516 | if (decl.getInnerNamespace()) |namespace| { | 5306 | if (decl.getOwnedInnerNamespace(mod)) |namespace| { |
| 5517 | try namespace.deleteAllDecls(mod, outdated_decls); | 5307 | try namespace.deleteAllDecls(mod, outdated_decls); |
| 5518 | } | 5308 | } |
| 5519 | } | 5309 | } |
| ... | @@ -5530,10 +5320,9 @@ pub fn clearDecl( | ... | @@ -5530,10 +5320,9 @@ pub fn clearDecl( |
| 5530 | /// This function is exclusively called for anonymous decls. | 5320 | /// This function is exclusively called for anonymous decls. |
| 5531 | pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { | 5321 | pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { |
| 5532 | const decl = mod.declPtr(decl_index); | 5322 | const decl = mod.declPtr(decl_index); |
| 5533 | log.debug("deleteUnusedDecl {d} ({s})", .{ decl_index, decl.name }); | ||
| 5534 | 5323 | ||
| 5535 | assert(!mod.declIsRoot(decl_index)); | 5324 | assert(!mod.declIsRoot(decl_index)); |
| 5536 | assert(decl.src_namespace.anon_decls.swapRemove(decl_index)); | 5325 | assert(mod.namespacePtr(decl.src_namespace).anon_decls.swapRemove(decl_index)); |
| 5537 | 5326 | ||
| 5538 | const dependants = decl.dependants.keys(); | 5327 | const dependants = decl.dependants.keys(); |
| 5539 | for (dependants) |dep| { | 5328 | for (dependants) |dep| { |
| ... | @@ -5558,10 +5347,9 @@ fn markDeclForDeletion(mod: *Module, decl_index: Decl.Index) !void { | ... | @@ -5558,10 +5347,9 @@ fn markDeclForDeletion(mod: *Module, decl_index: Decl.Index) !void { |
| 5558 | /// If other decls depend on this decl, they must be aborted first. | 5347 | /// If other decls depend on this decl, they must be aborted first. |
| 5559 | pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { | 5348 | pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { |
| 5560 | const decl = mod.declPtr(decl_index); | 5349 | const decl = mod.declPtr(decl_index); |
| 5561 | log.debug("abortAnonDecl {*} ({s})", .{ decl, decl.name }); | ||
| 5562 | 5350 | ||
| 5563 | assert(!mod.declIsRoot(decl_index)); | 5351 | assert(!mod.declIsRoot(decl_index)); |
| 5564 | assert(decl.src_namespace.anon_decls.swapRemove(decl_index)); | 5352 | assert(mod.namespacePtr(decl.src_namespace).anon_decls.swapRemove(decl_index)); |
| 5565 | 5353 | ||
| 5566 | // An aborted decl must not have dependants -- they must have | 5354 | // An aborted decl must not have dependants -- they must have |
| 5567 | // been aborted first and removed from this list. | 5355 | // been aborted first and removed from this list. |
| ... | @@ -5575,6 +5363,17 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { | ... | @@ -5575,6 +5363,17 @@ pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { |
| 5575 | mod.destroyDecl(decl_index); | 5363 | mod.destroyDecl(decl_index); |
| 5576 | } | 5364 | } |
| 5577 | 5365 | ||
| 5366 | /// Finalize the creation of an anon decl. | ||
| 5367 | pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { | ||
| 5368 | // The Decl starts off with alive=false and the codegen backend will set alive=true | ||
| 5369 | // if the Decl is referenced by an instruction or another constant. Otherwise, | ||
| 5370 | // the Decl will be garbage collected by the `codegen_decl` task instead of sent | ||
| 5371 | // to the linker. | ||
| 5372 | if (mod.declPtr(decl_index).ty.isFnOrHasRuntimeBits(mod)) { | ||
| 5373 | try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = decl_index }); | ||
| 5374 | } | ||
| 5375 | } | ||
| 5376 | |||
| 5578 | /// Delete all the Export objects that are caused by this Decl. Re-analysis of | 5377 | /// Delete all the Export objects that are caused by this Decl. Re-analysis of |
| 5579 | /// this Decl will cause them to be re-created (or not). | 5378 | /// this Decl will cause them to be re-created (or not). |
| 5580 | fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { | 5379 | fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { |
| ... | @@ -5600,51 +5399,53 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void | ... | @@ -5600,51 +5399,53 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void |
| 5600 | } | 5399 | } |
| 5601 | } | 5400 | } |
| 5602 | if (mod.comp.bin_file.cast(link.File.Elf)) |elf| { | 5401 | if (mod.comp.bin_file.cast(link.File.Elf)) |elf| { |
| 5603 | elf.deleteDeclExport(decl_index, exp.options.name); | 5402 | elf.deleteDeclExport(decl_index, exp.opts.name); |
| 5604 | } | 5403 | } |
| 5605 | if (mod.comp.bin_file.cast(link.File.MachO)) |macho| { | 5404 | if (mod.comp.bin_file.cast(link.File.MachO)) |macho| { |
| 5606 | try macho.deleteDeclExport(decl_index, exp.options.name); | 5405 | try macho.deleteDeclExport(decl_index, exp.opts.name); |
| 5607 | } | 5406 | } |
| 5608 | if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| { | 5407 | if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| { |
| 5609 | wasm.deleteDeclExport(decl_index); | 5408 | wasm.deleteDeclExport(decl_index); |
| 5610 | } | 5409 | } |
| 5611 | if (mod.comp.bin_file.cast(link.File.Coff)) |coff| { | 5410 | if (mod.comp.bin_file.cast(link.File.Coff)) |coff| { |
| 5612 | coff.deleteDeclExport(decl_index, exp.options.name); | 5411 | coff.deleteDeclExport(decl_index, exp.opts.name); |
| 5613 | } | 5412 | } |
| 5614 | if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| { | 5413 | if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| { |
| 5615 | failed_kv.value.destroy(mod.gpa); | 5414 | failed_kv.value.destroy(mod.gpa); |
| 5616 | } | 5415 | } |
| 5617 | mod.gpa.free(exp.options.name); | ||
| 5618 | mod.gpa.destroy(exp); | 5416 | mod.gpa.destroy(exp); |
| 5619 | } | 5417 | } |
| 5620 | export_owners.deinit(mod.gpa); | 5418 | export_owners.deinit(mod.gpa); |
| 5621 | } | 5419 | } |
| 5622 | 5420 | ||
| 5623 | pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | 5421 | pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaError!Air { |
| 5624 | const tracy = trace(@src()); | 5422 | const tracy = trace(@src()); |
| 5625 | defer tracy.end(); | 5423 | defer tracy.end(); |
| 5626 | 5424 | ||
| 5627 | const gpa = mod.gpa; | 5425 | const gpa = mod.gpa; |
| 5426 | const func = mod.funcPtr(func_index); | ||
| 5628 | const decl_index = func.owner_decl; | 5427 | const decl_index = func.owner_decl; |
| 5629 | const decl = mod.declPtr(decl_index); | 5428 | const decl = mod.declPtr(decl_index); |
| 5630 | 5429 | ||
| 5631 | // Use the Decl's arena for captured values. | 5430 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); |
| 5632 | var decl_arena: std.heap.ArenaAllocator = undefined; | 5431 | defer comptime_mutable_decls.deinit(); |
| 5633 | const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); | 5432 | |
| 5634 | defer decl.value_arena.?.release(&decl_arena); | 5433 | const fn_ty = decl.ty; |
| 5635 | 5434 | ||
| 5636 | var sema: Sema = .{ | 5435 | var sema: Sema = .{ |
| 5637 | .mod = mod, | 5436 | .mod = mod, |
| 5638 | .gpa = gpa, | 5437 | .gpa = gpa, |
| 5639 | .arena = arena, | 5438 | .arena = arena, |
| 5640 | .perm_arena = decl_arena_allocator, | 5439 | .code = decl.getFileScope(mod).zir, |
| 5641 | .code = decl.getFileScope().zir, | ||
| 5642 | .owner_decl = decl, | 5440 | .owner_decl = decl, |
| 5643 | .owner_decl_index = decl_index, | 5441 | .owner_decl_index = decl_index, |
| 5644 | .func = func, | 5442 | .func = func, |
| 5645 | .fn_ret_ty = decl.ty.fnReturnType(), | 5443 | .func_index = func_index.toOptional(), |
| 5444 | .fn_ret_ty = mod.typeToFunc(fn_ty).?.return_type.toType(), | ||
| 5646 | .owner_func = func, | 5445 | .owner_func = func, |
| 5446 | .owner_func_index = func_index.toOptional(), | ||
| 5647 | .branch_quota = @max(func.branch_quota, Sema.default_branch_quota), | 5447 | .branch_quota = @max(func.branch_quota, Sema.default_branch_quota), |
| 5448 | .comptime_mutable_decls = &comptime_mutable_decls, | ||
| 5648 | }; | 5449 | }; |
| 5649 | defer sema.deinit(); | 5450 | defer sema.deinit(); |
| 5650 | 5451 | ||
| ... | @@ -5656,7 +5457,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5656,7 +5457,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5656 | try sema.air_extra.ensureTotalCapacity(gpa, reserved_count); | 5457 | try sema.air_extra.ensureTotalCapacity(gpa, reserved_count); |
| 5657 | sema.air_extra.items.len += reserved_count; | 5458 | sema.air_extra.items.len += reserved_count; |
| 5658 | 5459 | ||
| 5659 | var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); | 5460 | var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope); |
| 5660 | defer wip_captures.deinit(); | 5461 | defer wip_captures.deinit(); |
| 5661 | 5462 | ||
| 5662 | var inner_block: Sema.Block = .{ | 5463 | var inner_block: Sema.Block = .{ |
| ... | @@ -5680,9 +5481,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5680,9 +5481,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5680 | // This could be a generic function instantiation, however, in which case we need to | 5481 | // This could be a generic function instantiation, however, in which case we need to |
| 5681 | // map the comptime parameters to constant values and only emit arg AIR instructions | 5482 | // map the comptime parameters to constant values and only emit arg AIR instructions |
| 5682 | // for the runtime ones. | 5483 | // for the runtime ones. |
| 5683 | const fn_ty = decl.ty; | 5484 | const runtime_params_len = @intCast(u32, mod.typeToFunc(fn_ty).?.param_types.len); |
| 5684 | const fn_ty_info = fn_ty.fnInfo(); | ||
| 5685 | const runtime_params_len = @intCast(u32, fn_ty_info.param_types.len); | ||
| 5686 | try inner_block.instructions.ensureTotalCapacityPrecise(gpa, runtime_params_len); | 5485 | try inner_block.instructions.ensureTotalCapacityPrecise(gpa, runtime_params_len); |
| 5687 | try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType` | 5486 | try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType` |
| 5688 | try sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body); | 5487 | try sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body); |
| ... | @@ -5697,9 +5496,9 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5697,9 +5496,9 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5697 | const param_ty = if (func.comptime_args) |comptime_args| t: { | 5496 | const param_ty = if (func.comptime_args) |comptime_args| t: { |
| 5698 | const arg_tv = comptime_args[total_param_index]; | 5497 | const arg_tv = comptime_args[total_param_index]; |
| 5699 | 5498 | ||
| 5700 | const arg_val = if (arg_tv.val.tag() != .generic_poison) | 5499 | const arg_val = if (!arg_tv.val.isGenericPoison()) |
| 5701 | arg_tv.val | 5500 | arg_tv.val |
| 5702 | else if (arg_tv.ty.onePossibleValue()) |opv| | 5501 | else if (try arg_tv.ty.onePossibleValue(mod)) |opv| |
| 5703 | opv | 5502 | opv |
| 5704 | else | 5503 | else |
| 5705 | break :t arg_tv.ty; | 5504 | break :t arg_tv.ty; |
| ... | @@ -5708,7 +5507,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5708,7 +5507,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5708 | sema.inst_map.putAssumeCapacityNoClobber(inst, arg); | 5507 | sema.inst_map.putAssumeCapacityNoClobber(inst, arg); |
| 5709 | total_param_index += 1; | 5508 | total_param_index += 1; |
| 5710 | continue; | 5509 | continue; |
| 5711 | } else fn_ty_info.param_types[runtime_param_index]; | 5510 | } else mod.typeToFunc(fn_ty).?.param_types[runtime_param_index].toType(); |
| 5712 | 5511 | ||
| 5713 | const opt_opv = sema.typeHasOnePossibleValue(param_ty) catch |err| switch (err) { | 5512 | const opt_opv = sema.typeHasOnePossibleValue(param_ty) catch |err| switch (err) { |
| 5714 | error.NeededSourceLocation => unreachable, | 5513 | error.NeededSourceLocation => unreachable, |
| ... | @@ -5740,7 +5539,6 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5740,7 +5539,6 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5740 | } | 5539 | } |
| 5741 | 5540 | ||
| 5742 | func.state = .in_progress; | 5541 | func.state = .in_progress; |
| 5743 | log.debug("set {s} to in_progress", .{decl.name}); | ||
| 5744 | 5542 | ||
| 5745 | const last_arg_index = inner_block.instructions.items.len; | 5543 | const last_arg_index = inner_block.instructions.items.len; |
| 5746 | 5544 | ||
| ... | @@ -5765,7 +5563,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5765,7 +5563,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5765 | // is unused so it just has to be a no-op. | 5563 | // is unused so it just has to be a no-op. |
| 5766 | sema.air_instructions.set(ptr_inst.*, .{ | 5564 | sema.air_instructions.set(ptr_inst.*, .{ |
| 5767 | .tag = .alloc, | 5565 | .tag = .alloc, |
| 5768 | .data = .{ .ty = Type.initTag(.single_const_pointer_to_comptime_int) }, | 5566 | .data = .{ .ty = Type.single_const_pointer_to_comptime_int }, |
| 5769 | }); | 5567 | }); |
| 5770 | } | 5568 | } |
| 5771 | } | 5569 | } |
| ... | @@ -5773,7 +5571,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5773,7 +5571,7 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5773 | // If we don't get an error return trace from a caller, create our own. | 5571 | // If we don't get an error return trace from a caller, create our own. |
| 5774 | if (func.calls_or_awaits_errorable_fn and | 5572 | if (func.calls_or_awaits_errorable_fn and |
| 5775 | mod.comp.bin_file.options.error_return_tracing and | 5573 | mod.comp.bin_file.options.error_return_tracing and |
| 5776 | !sema.fn_ret_ty.isError()) | 5574 | !sema.fn_ret_ty.isError(mod)) |
| 5777 | { | 5575 | { |
| 5778 | sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) { | 5576 | sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) { |
| 5779 | // TODO make these unreachable instead of @panic | 5577 | // TODO make these unreachable instead of @panic |
| ... | @@ -5786,6 +5584,10 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5786,6 +5584,10 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5786 | } | 5584 | } |
| 5787 | 5585 | ||
| 5788 | try wip_captures.finalize(); | 5586 | try wip_captures.finalize(); |
| 5587 | for (comptime_mutable_decls.items) |ct_decl_index| { | ||
| 5588 | const ct_decl = mod.declPtr(ct_decl_index); | ||
| 5589 | try ct_decl.intern(mod); | ||
| 5590 | } | ||
| 5789 | 5591 | ||
| 5790 | // Copy the block into place and mark that as the main block. | 5592 | // Copy the block into place and mark that as the main block. |
| 5791 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + | 5593 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + |
| ... | @@ -5797,14 +5599,13 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5797,14 +5599,13 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5797 | sema.air_extra.items[@enumToInt(Air.ExtraIndex.main_block)] = main_block_index; | 5599 | sema.air_extra.items[@enumToInt(Air.ExtraIndex.main_block)] = main_block_index; |
| 5798 | 5600 | ||
| 5799 | func.state = .success; | 5601 | func.state = .success; |
| 5800 | log.debug("set {s} to success", .{decl.name}); | ||
| 5801 | 5602 | ||
| 5802 | // Finally we must resolve the return type and parameter types so that backends | 5603 | // Finally we must resolve the return type and parameter types so that backends |
| 5803 | // have full access to type information. | 5604 | // have full access to type information. |
| 5804 | // Crucially, this happens *after* we set the function state to success above, | 5605 | // Crucially, this happens *after* we set the function state to success above, |
| 5805 | // so that dependencies on the function body will now be satisfied rather than | 5606 | // so that dependencies on the function body will now be satisfied rather than |
| 5806 | // result in circular dependency errors. | 5607 | // result in circular dependency errors. |
| 5807 | sema.resolveFnTypes(fn_ty_info) catch |err| switch (err) { | 5608 | sema.resolveFnTypes(fn_ty) catch |err| switch (err) { |
| 5808 | error.NeededSourceLocation => unreachable, | 5609 | error.NeededSourceLocation => unreachable, |
| 5809 | error.GenericPoison => unreachable, | 5610 | error.GenericPoison => unreachable, |
| 5810 | error.ComptimeReturn => unreachable, | 5611 | error.ComptimeReturn => unreachable, |
| ... | @@ -5820,9 +5621,8 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5820,9 +5621,8 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5820 | 5621 | ||
| 5821 | // Similarly, resolve any queued up types that were requested to be resolved for | 5622 | // Similarly, resolve any queued up types that were requested to be resolved for |
| 5822 | // the backends. | 5623 | // the backends. |
| 5823 | for (sema.types_to_resolve.items) |inst_ref| { | 5624 | for (sema.types_to_resolve.keys()) |ty| { |
| 5824 | const ty = sema.getTmpAir().getRefType(inst_ref); | 5625 | sema.resolveTypeFully(ty.toType()) catch |err| switch (err) { |
| 5825 | sema.resolveTypeFully(ty) catch |err| switch (err) { | ||
| 5826 | error.NeededSourceLocation => unreachable, | 5626 | error.NeededSourceLocation => unreachable, |
| 5827 | error.GenericPoison => unreachable, | 5627 | error.GenericPoison => unreachable, |
| 5828 | error.ComptimeReturn => unreachable, | 5628 | error.ComptimeReturn => unreachable, |
| ... | @@ -5840,13 +5640,11 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | ... | @@ -5840,13 +5640,11 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5840 | return Air{ | 5640 | return Air{ |
| 5841 | .instructions = sema.air_instructions.toOwnedSlice(), | 5641 | .instructions = sema.air_instructions.toOwnedSlice(), |
| 5842 | .extra = try sema.air_extra.toOwnedSlice(gpa), | 5642 | .extra = try sema.air_extra.toOwnedSlice(gpa), |
| 5843 | .values = try sema.air_values.toOwnedSlice(gpa), | ||
| 5844 | }; | 5643 | }; |
| 5845 | } | 5644 | } |
| 5846 | 5645 | ||
| 5847 | fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { | 5646 | fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { |
| 5848 | const decl = mod.declPtr(decl_index); | 5647 | const decl = mod.declPtr(decl_index); |
| 5849 | log.debug("mark outdated {*} ({s})", .{ decl, decl.name }); | ||
| 5850 | try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl_index }); | 5648 | try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl_index }); |
| 5851 | if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { | 5649 | if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { |
| 5852 | kv.value.destroy(mod.gpa); | 5650 | kv.value.destroy(mod.gpa); |
| ... | @@ -5854,11 +5652,8 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { | ... | @@ -5854,11 +5652,8 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { |
| 5854 | if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| { | 5652 | if (mod.cimport_errors.fetchSwapRemove(decl_index)) |kv| { |
| 5855 | for (kv.value) |err| err.deinit(mod.gpa); | 5653 | for (kv.value) |err| err.deinit(mod.gpa); |
| 5856 | } | 5654 | } |
| 5857 | if (decl.has_tv and decl.owns_tv) { | 5655 | if (decl.getOwnedFunctionIndex(mod).unwrap()) |func| { |
| 5858 | if (decl.val.castTag(.function)) |payload| { | 5656 | _ = mod.align_stack_fns.remove(func); |
| 5859 | const func = payload.data; | ||
| 5860 | _ = mod.align_stack_fns.remove(func); | ||
| 5861 | } | ||
| 5862 | } | 5657 | } |
| 5863 | if (mod.emit_h) |emit_h| { | 5658 | if (mod.emit_h) |emit_h| { |
| 5864 | if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| { | 5659 | if (emit_h.failed_decls.fetchSwapRemove(decl_index)) |kv| { |
| ... | @@ -5869,9 +5664,51 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { | ... | @@ -5869,9 +5664,51 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { |
| 5869 | decl.analysis = .outdated; | 5664 | decl.analysis = .outdated; |
| 5870 | } | 5665 | } |
| 5871 | 5666 | ||
| 5667 | pub fn createNamespace(mod: *Module, initialization: Namespace) !Namespace.Index { | ||
| 5668 | if (mod.namespaces_free_list.popOrNull()) |index| { | ||
| 5669 | mod.allocated_namespaces.at(@enumToInt(index)).* = initialization; | ||
| 5670 | return index; | ||
| 5671 | } | ||
| 5672 | const ptr = try mod.allocated_namespaces.addOne(mod.gpa); | ||
| 5673 | ptr.* = initialization; | ||
| 5674 | return @intToEnum(Namespace.Index, mod.allocated_namespaces.len - 1); | ||
| 5675 | } | ||
| 5676 | |||
| 5677 | pub fn destroyNamespace(mod: *Module, index: Namespace.Index) void { | ||
| 5678 | mod.namespacePtr(index).* = undefined; | ||
| 5679 | mod.namespaces_free_list.append(mod.gpa, index) catch { | ||
| 5680 | // In order to keep `destroyNamespace` a non-fallible function, we ignore memory | ||
| 5681 | // allocation failures here, instead leaking the Namespace until garbage collection. | ||
| 5682 | }; | ||
| 5683 | } | ||
| 5684 | |||
| 5685 | pub fn createStruct(mod: *Module, initialization: Struct) Allocator.Error!Struct.Index { | ||
| 5686 | return mod.intern_pool.createStruct(mod.gpa, initialization); | ||
| 5687 | } | ||
| 5688 | |||
| 5689 | pub fn destroyStruct(mod: *Module, index: Struct.Index) void { | ||
| 5690 | return mod.intern_pool.destroyStruct(mod.gpa, index); | ||
| 5691 | } | ||
| 5692 | |||
| 5693 | pub fn createUnion(mod: *Module, initialization: Union) Allocator.Error!Union.Index { | ||
| 5694 | return mod.intern_pool.createUnion(mod.gpa, initialization); | ||
| 5695 | } | ||
| 5696 | |||
| 5697 | pub fn destroyUnion(mod: *Module, index: Union.Index) void { | ||
| 5698 | return mod.intern_pool.destroyUnion(mod.gpa, index); | ||
| 5699 | } | ||
| 5700 | |||
| 5701 | pub fn createFunc(mod: *Module, initialization: Fn) Allocator.Error!Fn.Index { | ||
| 5702 | return mod.intern_pool.createFunc(mod.gpa, initialization); | ||
| 5703 | } | ||
| 5704 | |||
| 5705 | pub fn destroyFunc(mod: *Module, index: Fn.Index) void { | ||
| 5706 | return mod.intern_pool.destroyFunc(mod.gpa, index); | ||
| 5707 | } | ||
| 5708 | |||
| 5872 | pub fn allocateNewDecl( | 5709 | pub fn allocateNewDecl( |
| 5873 | mod: *Module, | 5710 | mod: *Module, |
| 5874 | namespace: *Namespace, | 5711 | namespace: Namespace.Index, |
| 5875 | src_node: Ast.Node.Index, | 5712 | src_node: Ast.Node.Index, |
| 5876 | src_scope: ?*CaptureScope, | 5713 | src_scope: ?*CaptureScope, |
| 5877 | ) !Decl.Index { | 5714 | ) !Decl.Index { |
| ... | @@ -5896,6 +5733,7 @@ pub fn allocateNewDecl( | ... | @@ -5896,6 +5733,7 @@ pub fn allocateNewDecl( |
| 5896 | }; | 5733 | }; |
| 5897 | }; | 5734 | }; |
| 5898 | 5735 | ||
| 5736 | if (src_scope) |scope| scope.incRef(); | ||
| 5899 | decl_and_index.new_decl.* = .{ | 5737 | decl_and_index.new_decl.* = .{ |
| 5900 | .name = undefined, | 5738 | .name = undefined, |
| 5901 | .src_namespace = namespace, | 5739 | .src_namespace = namespace, |
| ... | @@ -5906,7 +5744,7 @@ pub fn allocateNewDecl( | ... | @@ -5906,7 +5744,7 @@ pub fn allocateNewDecl( |
| 5906 | .ty = undefined, | 5744 | .ty = undefined, |
| 5907 | .val = undefined, | 5745 | .val = undefined, |
| 5908 | .@"align" = undefined, | 5746 | .@"align" = undefined, |
| 5909 | .@"linksection" = undefined, | 5747 | .@"linksection" = .none, |
| 5910 | .@"addrspace" = .generic, | 5748 | .@"addrspace" = .generic, |
| 5911 | .analysis = .unreferenced, | 5749 | .analysis = .unreferenced, |
| 5912 | .deletion_flag = false, | 5750 | .deletion_flag = false, |
| ... | @@ -5924,25 +5762,20 @@ pub fn allocateNewDecl( | ... | @@ -5924,25 +5762,20 @@ pub fn allocateNewDecl( |
| 5924 | return decl_and_index.decl_index; | 5762 | return decl_and_index.decl_index; |
| 5925 | } | 5763 | } |
| 5926 | 5764 | ||
| 5927 | /// Get error value for error tag `name`. | 5765 | pub fn getErrorValue( |
| 5928 | pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged(ErrorInt).KV { | 5766 | mod: *Module, |
| 5767 | name: InternPool.NullTerminatedString, | ||
| 5768 | ) Allocator.Error!ErrorInt { | ||
| 5929 | const gop = try mod.global_error_set.getOrPut(mod.gpa, name); | 5769 | const gop = try mod.global_error_set.getOrPut(mod.gpa, name); |
| 5930 | if (gop.found_existing) { | 5770 | return @intCast(ErrorInt, gop.index); |
| 5931 | return std.StringHashMapUnmanaged(ErrorInt).KV{ | 5771 | } |
| 5932 | .key = gop.key_ptr.*, | ||
| 5933 | .value = gop.value_ptr.*, | ||
| 5934 | }; | ||
| 5935 | } | ||
| 5936 | 5772 | ||
| 5937 | errdefer assert(mod.global_error_set.remove(name)); | 5773 | pub fn getErrorValueFromSlice( |
| 5938 | try mod.error_name_list.ensureUnusedCapacity(mod.gpa, 1); | 5774 | mod: *Module, |
| 5939 | gop.key_ptr.* = try mod.gpa.dupe(u8, name); | 5775 | name: []const u8, |
| 5940 | gop.value_ptr.* = @intCast(ErrorInt, mod.error_name_list.items.len); | 5776 | ) Allocator.Error!ErrorInt { |
| 5941 | mod.error_name_list.appendAssumeCapacity(gop.key_ptr.*); | 5777 | const interned_name = try mod.intern_pool.getOrPutString(mod.gpa, name); |
| 5942 | return std.StringHashMapUnmanaged(ErrorInt).KV{ | 5778 | return getErrorValue(mod, interned_name); |
| 5943 | .key = gop.key_ptr.*, | ||
| 5944 | .value = gop.value_ptr.*, | ||
| 5945 | }; | ||
| 5946 | } | 5779 | } |
| 5947 | 5780 | ||
| 5948 | pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index { | 5781 | pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index { |
| ... | @@ -5953,29 +5786,28 @@ pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedV | ... | @@ -5953,29 +5786,28 @@ pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedV |
| 5953 | pub fn createAnonymousDeclFromDecl( | 5786 | pub fn createAnonymousDeclFromDecl( |
| 5954 | mod: *Module, | 5787 | mod: *Module, |
| 5955 | src_decl: *Decl, | 5788 | src_decl: *Decl, |
| 5956 | namespace: *Namespace, | 5789 | namespace: Namespace.Index, |
| 5957 | src_scope: ?*CaptureScope, | 5790 | src_scope: ?*CaptureScope, |
| 5958 | tv: TypedValue, | 5791 | tv: TypedValue, |
| 5959 | ) !Decl.Index { | 5792 | ) !Decl.Index { |
| 5960 | const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope); | 5793 | const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope); |
| 5961 | errdefer mod.destroyDecl(new_decl_index); | 5794 | errdefer mod.destroyDecl(new_decl_index); |
| 5962 | const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ | 5795 | const name = try mod.intern_pool.getOrPutStringFmt(mod.gpa, "{}__anon_{d}", .{ |
| 5963 | src_decl.name, @enumToInt(new_decl_index), | 5796 | src_decl.name.fmt(&mod.intern_pool), @enumToInt(new_decl_index), |
| 5964 | }); | 5797 | }); |
| 5965 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, tv, name); | 5798 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, tv, name); |
| 5966 | return new_decl_index; | 5799 | return new_decl_index; |
| 5967 | } | 5800 | } |
| 5968 | 5801 | ||
| 5969 | /// Takes ownership of `name` even if it returns an error. | ||
| 5970 | pub fn initNewAnonDecl( | 5802 | pub fn initNewAnonDecl( |
| 5971 | mod: *Module, | 5803 | mod: *Module, |
| 5972 | new_decl_index: Decl.Index, | 5804 | new_decl_index: Decl.Index, |
| 5973 | src_line: u32, | 5805 | src_line: u32, |
| 5974 | namespace: *Namespace, | 5806 | namespace: Namespace.Index, |
| 5975 | typed_value: TypedValue, | 5807 | typed_value: TypedValue, |
| 5976 | name: [:0]u8, | 5808 | name: InternPool.NullTerminatedString, |
| 5977 | ) !void { | 5809 | ) Allocator.Error!void { |
| 5978 | errdefer mod.gpa.free(name); | 5810 | assert(typed_value.ty.toIntern() == mod.intern_pool.typeOf(typed_value.val.toIntern())); |
| 5979 | 5811 | ||
| 5980 | const new_decl = mod.declPtr(new_decl_index); | 5812 | const new_decl = mod.declPtr(new_decl_index); |
| 5981 | 5813 | ||
| ... | @@ -5984,34 +5816,12 @@ pub fn initNewAnonDecl( | ... | @@ -5984,34 +5816,12 @@ pub fn initNewAnonDecl( |
| 5984 | new_decl.ty = typed_value.ty; | 5816 | new_decl.ty = typed_value.ty; |
| 5985 | new_decl.val = typed_value.val; | 5817 | new_decl.val = typed_value.val; |
| 5986 | new_decl.@"align" = 0; | 5818 | new_decl.@"align" = 0; |
| 5987 | new_decl.@"linksection" = null; | 5819 | new_decl.@"linksection" = .none; |
| 5988 | new_decl.has_tv = true; | 5820 | new_decl.has_tv = true; |
| 5989 | new_decl.analysis = .complete; | 5821 | new_decl.analysis = .complete; |
| 5990 | new_decl.generation = mod.generation; | 5822 | new_decl.generation = mod.generation; |
| 5991 | 5823 | ||
| 5992 | try namespace.anon_decls.putNoClobber(mod.gpa, new_decl_index, {}); | 5824 | try mod.namespacePtr(namespace).anon_decls.putNoClobber(mod.gpa, new_decl_index, {}); |
| 5993 | |||
| 5994 | // The Decl starts off with alive=false and the codegen backend will set alive=true | ||
| 5995 | // if the Decl is referenced by an instruction or another constant. Otherwise, | ||
| 5996 | // the Decl will be garbage collected by the `codegen_decl` task instead of sent | ||
| 5997 | // to the linker. | ||
| 5998 | if (typed_value.ty.isFnOrHasRuntimeBits()) { | ||
| 5999 | try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl_index }); | ||
| 6000 | } | ||
| 6001 | } | ||
| 6002 | |||
| 6003 | pub fn makeIntType(arena: Allocator, signedness: std.builtin.Signedness, bits: u16) !Type { | ||
| 6004 | const int_payload = try arena.create(Type.Payload.Bits); | ||
| 6005 | int_payload.* = .{ | ||
| 6006 | .base = .{ | ||
| 6007 | .tag = switch (signedness) { | ||
| 6008 | .signed => .int_signed, | ||
| 6009 | .unsigned => .int_unsigned, | ||
| 6010 | }, | ||
| 6011 | }, | ||
| 6012 | .data = bits, | ||
| 6013 | }; | ||
| 6014 | return Type.initPayload(&int_payload.base); | ||
| 6015 | } | 5825 | } |
| 6016 | 5826 | ||
| 6017 | pub fn errNoteNonLazy( | 5827 | pub fn errNoteNonLazy( |
| ... | @@ -6073,16 +5883,17 @@ pub const SwitchProngSrc = union(enum) { | ... | @@ -6073,16 +5883,17 @@ pub const SwitchProngSrc = union(enum) { |
| 6073 | /// the LazySrcLoc in order to emit a compile error. | 5883 | /// the LazySrcLoc in order to emit a compile error. |
| 6074 | pub fn resolve( | 5884 | pub fn resolve( |
| 6075 | prong_src: SwitchProngSrc, | 5885 | prong_src: SwitchProngSrc, |
| 6076 | gpa: Allocator, | 5886 | mod: *Module, |
| 6077 | decl: *Decl, | 5887 | decl: *Decl, |
| 6078 | switch_node_offset: i32, | 5888 | switch_node_offset: i32, |
| 6079 | range_expand: RangeExpand, | 5889 | range_expand: RangeExpand, |
| 6080 | ) LazySrcLoc { | 5890 | ) LazySrcLoc { |
| 6081 | @setCold(true); | 5891 | @setCold(true); |
| 6082 | const tree = decl.getFileScope().getTree(gpa) catch |err| { | 5892 | const gpa = mod.gpa; |
| 5893 | const tree = decl.getFileScope(mod).getTree(gpa) catch |err| { | ||
| 6083 | // In this case we emit a warning + a less precise source location. | 5894 | // In this case we emit a warning + a less precise source location. |
| 6084 | log.warn("unable to load {s}: {s}", .{ | 5895 | log.warn("unable to load {s}: {s}", .{ |
| 6085 | decl.getFileScope().sub_file_path, @errorName(err), | 5896 | decl.getFileScope(mod).sub_file_path, @errorName(err), |
| 6086 | }); | 5897 | }); |
| 6087 | return LazySrcLoc.nodeOffset(0); | 5898 | return LazySrcLoc.nodeOffset(0); |
| 6088 | }; | 5899 | }; |
| ... | @@ -6166,11 +5977,12 @@ pub const PeerTypeCandidateSrc = union(enum) { | ... | @@ -6166,11 +5977,12 @@ pub const PeerTypeCandidateSrc = union(enum) { |
| 6166 | 5977 | ||
| 6167 | pub fn resolve( | 5978 | pub fn resolve( |
| 6168 | self: PeerTypeCandidateSrc, | 5979 | self: PeerTypeCandidateSrc, |
| 6169 | gpa: Allocator, | 5980 | mod: *Module, |
| 6170 | decl: *Decl, | 5981 | decl: *Decl, |
| 6171 | candidate_i: usize, | 5982 | candidate_i: usize, |
| 6172 | ) ?LazySrcLoc { | 5983 | ) ?LazySrcLoc { |
| 6173 | @setCold(true); | 5984 | @setCold(true); |
| 5985 | const gpa = mod.gpa; | ||
| 6174 | 5986 | ||
| 6175 | switch (self) { | 5987 | switch (self) { |
| 6176 | .none => { | 5988 | .none => { |
| ... | @@ -6192,10 +6004,10 @@ pub const PeerTypeCandidateSrc = union(enum) { | ... | @@ -6192,10 +6004,10 @@ pub const PeerTypeCandidateSrc = union(enum) { |
| 6192 | else => {}, | 6004 | else => {}, |
| 6193 | } | 6005 | } |
| 6194 | 6006 | ||
| 6195 | const tree = decl.getFileScope().getTree(gpa) catch |err| { | 6007 | const tree = decl.getFileScope(mod).getTree(gpa) catch |err| { |
| 6196 | // In this case we emit a warning + a less precise source location. | 6008 | // In this case we emit a warning + a less precise source location. |
| 6197 | log.warn("unable to load {s}: {s}", .{ | 6009 | log.warn("unable to load {s}: {s}", .{ |
| 6198 | decl.getFileScope().sub_file_path, @errorName(err), | 6010 | decl.getFileScope(mod).sub_file_path, @errorName(err), |
| 6199 | }); | 6011 | }); |
| 6200 | return LazySrcLoc.nodeOffset(0); | 6012 | return LazySrcLoc.nodeOffset(0); |
| 6201 | }; | 6013 | }; |
| ... | @@ -6254,15 +6066,16 @@ fn queryFieldSrc( | ... | @@ -6254,15 +6066,16 @@ fn queryFieldSrc( |
| 6254 | 6066 | ||
| 6255 | pub fn paramSrc( | 6067 | pub fn paramSrc( |
| 6256 | func_node_offset: i32, | 6068 | func_node_offset: i32, |
| 6257 | gpa: Allocator, | 6069 | mod: *Module, |
| 6258 | decl: *Decl, | 6070 | decl: *Decl, |
| 6259 | param_i: usize, | 6071 | param_i: usize, |
| 6260 | ) LazySrcLoc { | 6072 | ) LazySrcLoc { |
| 6261 | @setCold(true); | 6073 | @setCold(true); |
| 6262 | const tree = decl.getFileScope().getTree(gpa) catch |err| { | 6074 | const gpa = mod.gpa; |
| 6075 | const tree = decl.getFileScope(mod).getTree(gpa) catch |err| { | ||
| 6263 | // In this case we emit a warning + a less precise source location. | 6076 | // In this case we emit a warning + a less precise source location. |
| 6264 | log.warn("unable to load {s}: {s}", .{ | 6077 | log.warn("unable to load {s}: {s}", .{ |
| 6265 | decl.getFileScope().sub_file_path, @errorName(err), | 6078 | decl.getFileScope(mod).sub_file_path, @errorName(err), |
| 6266 | }); | 6079 | }); |
| 6267 | return LazySrcLoc.nodeOffset(0); | 6080 | return LazySrcLoc.nodeOffset(0); |
| 6268 | }; | 6081 | }; |
| ... | @@ -6284,19 +6097,20 @@ pub fn paramSrc( | ... | @@ -6284,19 +6097,20 @@ pub fn paramSrc( |
| 6284 | } | 6097 | } |
| 6285 | 6098 | ||
| 6286 | pub fn argSrc( | 6099 | pub fn argSrc( |
| 6100 | mod: *Module, | ||
| 6287 | call_node_offset: i32, | 6101 | call_node_offset: i32, |
| 6288 | gpa: Allocator, | ||
| 6289 | decl: *Decl, | 6102 | decl: *Decl, |
| 6290 | start_arg_i: usize, | 6103 | start_arg_i: usize, |
| 6291 | bound_arg_src: ?LazySrcLoc, | 6104 | bound_arg_src: ?LazySrcLoc, |
| 6292 | ) LazySrcLoc { | 6105 | ) LazySrcLoc { |
| 6106 | @setCold(true); | ||
| 6107 | const gpa = mod.gpa; | ||
| 6293 | if (start_arg_i == 0 and bound_arg_src != null) return bound_arg_src.?; | 6108 | if (start_arg_i == 0 and bound_arg_src != null) return bound_arg_src.?; |
| 6294 | const arg_i = start_arg_i - @boolToInt(bound_arg_src != null); | 6109 | const arg_i = start_arg_i - @boolToInt(bound_arg_src != null); |
| 6295 | @setCold(true); | 6110 | const tree = decl.getFileScope(mod).getTree(gpa) catch |err| { |
| 6296 | const tree = decl.getFileScope().getTree(gpa) catch |err| { | ||
| 6297 | // In this case we emit a warning + a less precise source location. | 6111 | // In this case we emit a warning + a less precise source location. |
| 6298 | log.warn("unable to load {s}: {s}", .{ | 6112 | log.warn("unable to load {s}: {s}", .{ |
| 6299 | decl.getFileScope().sub_file_path, @errorName(err), | 6113 | decl.getFileScope(mod).sub_file_path, @errorName(err), |
| 6300 | }); | 6114 | }); |
| 6301 | return LazySrcLoc.nodeOffset(0); | 6115 | return LazySrcLoc.nodeOffset(0); |
| 6302 | }; | 6116 | }; |
| ... | @@ -6310,7 +6124,7 @@ pub fn argSrc( | ... | @@ -6310,7 +6124,7 @@ pub fn argSrc( |
| 6310 | const node_datas = tree.nodes.items(.data); | 6124 | const node_datas = tree.nodes.items(.data); |
| 6311 | const call_args_node = tree.extra_data[node_datas[node].rhs - 1]; | 6125 | const call_args_node = tree.extra_data[node_datas[node].rhs - 1]; |
| 6312 | const call_args_offset = decl.nodeIndexToRelative(call_args_node); | 6126 | const call_args_offset = decl.nodeIndexToRelative(call_args_node); |
| 6313 | return initSrc(call_args_offset, gpa, decl, arg_i); | 6127 | return mod.initSrc(call_args_offset, decl, arg_i); |
| 6314 | }, | 6128 | }, |
| 6315 | else => unreachable, | 6129 | else => unreachable, |
| 6316 | }; | 6130 | }; |
| ... | @@ -6318,16 +6132,17 @@ pub fn argSrc( | ... | @@ -6318,16 +6132,17 @@ pub fn argSrc( |
| 6318 | } | 6132 | } |
| 6319 | 6133 | ||
| 6320 | pub fn initSrc( | 6134 | pub fn initSrc( |
| 6135 | mod: *Module, | ||
| 6321 | init_node_offset: i32, | 6136 | init_node_offset: i32, |
| 6322 | gpa: Allocator, | ||
| 6323 | decl: *Decl, | 6137 | decl: *Decl, |
| 6324 | init_index: usize, | 6138 | init_index: usize, |
| 6325 | ) LazySrcLoc { | 6139 | ) LazySrcLoc { |
| 6326 | @setCold(true); | 6140 | @setCold(true); |
| 6327 | const tree = decl.getFileScope().getTree(gpa) catch |err| { | 6141 | const gpa = mod.gpa; |
| 6142 | const tree = decl.getFileScope(mod).getTree(gpa) catch |err| { | ||
| 6328 | // In this case we emit a warning + a less precise source location. | 6143 | // In this case we emit a warning + a less precise source location. |
| 6329 | log.warn("unable to load {s}: {s}", .{ | 6144 | log.warn("unable to load {s}: {s}", .{ |
| 6330 | decl.getFileScope().sub_file_path, @errorName(err), | 6145 | decl.getFileScope(mod).sub_file_path, @errorName(err), |
| 6331 | }); | 6146 | }); |
| 6332 | return LazySrcLoc.nodeOffset(0); | 6147 | return LazySrcLoc.nodeOffset(0); |
| 6333 | }; | 6148 | }; |
| ... | @@ -6363,12 +6178,13 @@ pub fn initSrc( | ... | @@ -6363,12 +6178,13 @@ pub fn initSrc( |
| 6363 | } | 6178 | } |
| 6364 | } | 6179 | } |
| 6365 | 6180 | ||
| 6366 | pub fn optionsSrc(gpa: Allocator, decl: *Decl, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc { | 6181 | pub fn optionsSrc(mod: *Module, decl: *Decl, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc { |
| 6367 | @setCold(true); | 6182 | @setCold(true); |
| 6368 | const tree = decl.getFileScope().getTree(gpa) catch |err| { | 6183 | const gpa = mod.gpa; |
| 6184 | const tree = decl.getFileScope(mod).getTree(gpa) catch |err| { | ||
| 6369 | // In this case we emit a warning + a less precise source location. | 6185 | // In this case we emit a warning + a less precise source location. |
| 6370 | log.warn("unable to load {s}: {s}", .{ | 6186 | log.warn("unable to load {s}: {s}", .{ |
| 6371 | decl.getFileScope().sub_file_path, @errorName(err), | 6187 | decl.getFileScope(mod).sub_file_path, @errorName(err), |
| 6372 | }); | 6188 | }); |
| 6373 | return LazySrcLoc.nodeOffset(0); | 6189 | return LazySrcLoc.nodeOffset(0); |
| 6374 | }; | 6190 | }; |
| ... | @@ -6430,11 +6246,13 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { | ... | @@ -6430,11 +6246,13 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { |
| 6430 | // deletion set at this time. | 6246 | // deletion set at this time. |
| 6431 | for (file.deleted_decls.items) |decl_index| { | 6247 | for (file.deleted_decls.items) |decl_index| { |
| 6432 | const decl = mod.declPtr(decl_index); | 6248 | const decl = mod.declPtr(decl_index); |
| 6433 | log.debug("deleted from source: {*} ({s})", .{ decl, decl.name }); | ||
| 6434 | 6249 | ||
| 6435 | // Remove from the namespace it resides in, preserving declaration order. | 6250 | // Remove from the namespace it resides in, preserving declaration order. |
| 6436 | assert(decl.zir_decl_index != 0); | 6251 | assert(decl.zir_decl_index != 0); |
| 6437 | _ = decl.src_namespace.decls.orderedRemoveAdapted(@as([]const u8, mem.sliceTo(decl.name, 0)), DeclAdapter{ .mod = mod }); | 6252 | _ = mod.namespacePtr(decl.src_namespace).decls.orderedRemoveAdapted( |
| 6253 | decl.name, | ||
| 6254 | DeclAdapter{ .mod = mod }, | ||
| 6255 | ); | ||
| 6438 | 6256 | ||
| 6439 | try mod.clearDecl(decl_index, &outdated_decls); | 6257 | try mod.clearDecl(decl_index, &outdated_decls); |
| 6440 | mod.destroyDecl(decl_index); | 6258 | mod.destroyDecl(decl_index); |
| ... | @@ -6454,7 +6272,7 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { | ... | @@ -6454,7 +6272,7 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { |
| 6454 | pub fn processExports(mod: *Module) !void { | 6272 | pub fn processExports(mod: *Module) !void { |
| 6455 | const gpa = mod.gpa; | 6273 | const gpa = mod.gpa; |
| 6456 | // Map symbol names to `Export` for name collision detection. | 6274 | // Map symbol names to `Export` for name collision detection. |
| 6457 | var symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{}; | 6275 | var symbol_exports: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export) = .{}; |
| 6458 | defer symbol_exports.deinit(gpa); | 6276 | defer symbol_exports.deinit(gpa); |
| 6459 | 6277 | ||
| 6460 | var it = mod.decl_exports.iterator(); | 6278 | var it = mod.decl_exports.iterator(); |
| ... | @@ -6462,13 +6280,13 @@ pub fn processExports(mod: *Module) !void { | ... | @@ -6462,13 +6280,13 @@ pub fn processExports(mod: *Module) !void { |
| 6462 | const exported_decl = entry.key_ptr.*; | 6280 | const exported_decl = entry.key_ptr.*; |
| 6463 | const exports = entry.value_ptr.items; | 6281 | const exports = entry.value_ptr.items; |
| 6464 | for (exports) |new_export| { | 6282 | for (exports) |new_export| { |
| 6465 | const gop = try symbol_exports.getOrPut(gpa, new_export.options.name); | 6283 | const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name); |
| 6466 | if (gop.found_existing) { | 6284 | if (gop.found_existing) { |
| 6467 | new_export.status = .failed_retryable; | 6285 | new_export.status = .failed_retryable; |
| 6468 | try mod.failed_exports.ensureUnusedCapacity(gpa, 1); | 6286 | try mod.failed_exports.ensureUnusedCapacity(gpa, 1); |
| 6469 | const src_loc = new_export.getSrcLoc(mod); | 6287 | const src_loc = new_export.getSrcLoc(mod); |
| 6470 | const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {s}", .{ | 6288 | const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {}", .{ |
| 6471 | new_export.options.name, | 6289 | new_export.opts.name.fmt(&mod.intern_pool), |
| 6472 | }); | 6290 | }); |
| 6473 | errdefer msg.destroy(gpa); | 6291 | errdefer msg.destroy(gpa); |
| 6474 | const other_export = gop.value_ptr.*; | 6292 | const other_export = gop.value_ptr.*; |
| ... | @@ -6501,11 +6319,16 @@ pub fn populateTestFunctions( | ... | @@ -6501,11 +6319,16 @@ pub fn populateTestFunctions( |
| 6501 | main_progress_node: *std.Progress.Node, | 6319 | main_progress_node: *std.Progress.Node, |
| 6502 | ) !void { | 6320 | ) !void { |
| 6503 | const gpa = mod.gpa; | 6321 | const gpa = mod.gpa; |
| 6322 | const ip = &mod.intern_pool; | ||
| 6504 | const builtin_pkg = mod.main_pkg.table.get("builtin").?; | 6323 | const builtin_pkg = mod.main_pkg.table.get("builtin").?; |
| 6505 | const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file; | 6324 | const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file; |
| 6506 | const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?); | 6325 | const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?); |
| 6507 | const builtin_namespace = root_decl.src_namespace; | 6326 | const builtin_namespace = mod.namespacePtr(root_decl.src_namespace); |
| 6508 | const decl_index = builtin_namespace.decls.getKeyAdapted(@as([]const u8, "test_functions"), DeclAdapter{ .mod = mod }).?; | 6327 | const test_functions_str = try ip.getOrPutString(gpa, "test_functions"); |
| 6328 | const decl_index = builtin_namespace.decls.getKeyAdapted( | ||
| 6329 | test_functions_str, | ||
| 6330 | DeclAdapter{ .mod = mod }, | ||
| 6331 | ).?; | ||
| 6509 | { | 6332 | { |
| 6510 | // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` | 6333 | // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` |
| 6511 | // was not referenced by start code. | 6334 | // was not referenced by start code. |
| ... | @@ -6518,90 +6341,117 @@ pub fn populateTestFunctions( | ... | @@ -6518,90 +6341,117 @@ pub fn populateTestFunctions( |
| 6518 | try mod.ensureDeclAnalyzed(decl_index); | 6341 | try mod.ensureDeclAnalyzed(decl_index); |
| 6519 | } | 6342 | } |
| 6520 | const decl = mod.declPtr(decl_index); | 6343 | const decl = mod.declPtr(decl_index); |
| 6521 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 6344 | const test_fn_ty = decl.ty.slicePtrFieldType(mod).childType(mod); |
| 6522 | const tmp_test_fn_ty = decl.ty.slicePtrFieldType(&buf).elemType(); | 6345 | const null_usize = try mod.intern(.{ .opt = .{ |
| 6346 | .ty = try mod.intern(.{ .opt_type = .usize_type }), | ||
| 6347 | .val = .none, | ||
| 6348 | } }); | ||
| 6523 | 6349 | ||
| 6524 | const array_decl_index = d: { | 6350 | const array_decl_index = d: { |
| 6525 | // Add mod.test_functions to an array decl then make the test_functions | 6351 | // Add mod.test_functions to an array decl then make the test_functions |
| 6526 | // decl reference it as a slice. | 6352 | // decl reference it as a slice. |
| 6527 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | 6353 | const test_fn_vals = try gpa.alloc(InternPool.Index, mod.test_functions.count()); |
| 6528 | errdefer new_decl_arena.deinit(); | 6354 | defer gpa.free(test_fn_vals); |
| 6529 | const arena = new_decl_arena.allocator(); | ||
| 6530 | |||
| 6531 | const test_fn_vals = try arena.alloc(Value, mod.test_functions.count()); | ||
| 6532 | const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{ | ||
| 6533 | .ty = try Type.Tag.array.create(arena, .{ | ||
| 6534 | .len = test_fn_vals.len, | ||
| 6535 | .elem_type = try tmp_test_fn_ty.copy(arena), | ||
| 6536 | }), | ||
| 6537 | .val = try Value.Tag.aggregate.create(arena, test_fn_vals), | ||
| 6538 | }); | ||
| 6539 | const array_decl = mod.declPtr(array_decl_index); | ||
| 6540 | 6355 | ||
| 6541 | // Add a dependency on each test name and function pointer. | 6356 | // Add a dependency on each test name and function pointer. |
| 6542 | try array_decl.dependencies.ensureUnusedCapacity(gpa, test_fn_vals.len * 2); | 6357 | var array_decl_dependencies = std.ArrayListUnmanaged(Decl.Index){}; |
| 6358 | defer array_decl_dependencies.deinit(gpa); | ||
| 6359 | try array_decl_dependencies.ensureUnusedCapacity(gpa, test_fn_vals.len * 2); | ||
| 6543 | 6360 | ||
| 6544 | for (mod.test_functions.keys(), 0..) |test_decl_index, i| { | 6361 | for (test_fn_vals, mod.test_functions.keys()) |*test_fn_val, test_decl_index| { |
| 6545 | const test_decl = mod.declPtr(test_decl_index); | 6362 | const test_decl = mod.declPtr(test_decl_index); |
| 6546 | const test_name_slice = mem.sliceTo(test_decl.name, 0); | 6363 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 6364 | const test_decl_name = try gpa.dupe(u8, ip.stringToSlice(test_decl.name)); | ||
| 6365 | defer gpa.free(test_decl_name); | ||
| 6547 | const test_name_decl_index = n: { | 6366 | const test_name_decl_index = n: { |
| 6548 | var name_decl_arena = std.heap.ArenaAllocator.init(gpa); | 6367 | const test_name_decl_ty = try mod.arrayType(.{ |
| 6549 | errdefer name_decl_arena.deinit(); | 6368 | .len = test_decl_name.len, |
| 6550 | const bytes = try name_decl_arena.allocator().dupe(u8, test_name_slice); | 6369 | .child = .u8_type, |
| 6551 | const test_name_decl_index = try mod.createAnonymousDeclFromDecl(array_decl, array_decl.src_namespace, null, .{ | 6370 | }); |
| 6552 | .ty = try Type.Tag.array_u8.create(name_decl_arena.allocator(), bytes.len), | 6371 | const test_name_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{ |
| 6553 | .val = try Value.Tag.bytes.create(name_decl_arena.allocator(), bytes), | 6372 | .ty = test_name_decl_ty, |
| 6373 | .val = (try mod.intern(.{ .aggregate = .{ | ||
| 6374 | .ty = test_name_decl_ty.toIntern(), | ||
| 6375 | .storage = .{ .bytes = test_decl_name }, | ||
| 6376 | } })).toValue(), | ||
| 6554 | }); | 6377 | }); |
| 6555 | try mod.declPtr(test_name_decl_index).finalizeNewArena(&name_decl_arena); | ||
| 6556 | break :n test_name_decl_index; | 6378 | break :n test_name_decl_index; |
| 6557 | }; | 6379 | }; |
| 6558 | array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, .normal); | 6380 | array_decl_dependencies.appendAssumeCapacity(test_decl_index); |
| 6559 | array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, .normal); | 6381 | array_decl_dependencies.appendAssumeCapacity(test_name_decl_index); |
| 6560 | try mod.linkerUpdateDecl(test_name_decl_index); | 6382 | try mod.linkerUpdateDecl(test_name_decl_index); |
| 6561 | 6383 | ||
| 6562 | const field_vals = try arena.create([3]Value); | 6384 | const test_fn_fields = .{ |
| 6563 | field_vals.* = .{ | 6385 | // name |
| 6564 | try Value.Tag.slice.create(arena, .{ | 6386 | try mod.intern(.{ .ptr = .{ |
| 6565 | .ptr = try Value.Tag.decl_ref.create(arena, test_name_decl_index), | 6387 | .ty = .slice_const_u8_type, |
| 6566 | .len = try Value.Tag.int_u64.create(arena, test_name_slice.len), | 6388 | .addr = .{ .decl = test_name_decl_index }, |
| 6567 | }), // name | 6389 | .len = try mod.intern(.{ .int = .{ |
| 6568 | try Value.Tag.decl_ref.create(arena, test_decl_index), // func | 6390 | .ty = .usize_type, |
| 6569 | Value.initTag(.null_value), // async_frame_size | 6391 | .storage = .{ .u64 = test_decl_name.len }, |
| 6392 | } }), | ||
| 6393 | } }), | ||
| 6394 | // func | ||
| 6395 | try mod.intern(.{ .ptr = .{ | ||
| 6396 | .ty = try mod.intern(.{ .ptr_type = .{ | ||
| 6397 | .child = test_decl.ty.toIntern(), | ||
| 6398 | .flags = .{ | ||
| 6399 | .is_const = true, | ||
| 6400 | }, | ||
| 6401 | } }), | ||
| 6402 | .addr = .{ .decl = test_decl_index }, | ||
| 6403 | } }), | ||
| 6404 | // async_frame_size | ||
| 6405 | null_usize, | ||
| 6570 | }; | 6406 | }; |
| 6571 | test_fn_vals[i] = try Value.Tag.aggregate.create(arena, field_vals); | 6407 | test_fn_val.* = try mod.intern(.{ .aggregate = .{ |
| 6408 | .ty = test_fn_ty.toIntern(), | ||
| 6409 | .storage = .{ .elems = &test_fn_fields }, | ||
| 6410 | } }); | ||
| 6411 | } | ||
| 6412 | |||
| 6413 | const array_decl_ty = try mod.arrayType(.{ | ||
| 6414 | .len = test_fn_vals.len, | ||
| 6415 | .child = test_fn_ty.toIntern(), | ||
| 6416 | .sentinel = .none, | ||
| 6417 | }); | ||
| 6418 | const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{ | ||
| 6419 | .ty = array_decl_ty, | ||
| 6420 | .val = (try mod.intern(.{ .aggregate = .{ | ||
| 6421 | .ty = array_decl_ty.toIntern(), | ||
| 6422 | .storage = .{ .elems = test_fn_vals }, | ||
| 6423 | } })).toValue(), | ||
| 6424 | }); | ||
| 6425 | for (array_decl_dependencies.items) |array_decl_dependency| { | ||
| 6426 | try mod.declareDeclDependency(array_decl_index, array_decl_dependency); | ||
| 6572 | } | 6427 | } |
| 6573 | 6428 | ||
| 6574 | try array_decl.finalizeNewArena(&new_decl_arena); | ||
| 6575 | break :d array_decl_index; | 6429 | break :d array_decl_index; |
| 6576 | }; | 6430 | }; |
| 6577 | try mod.linkerUpdateDecl(array_decl_index); | 6431 | try mod.linkerUpdateDecl(array_decl_index); |
| 6578 | 6432 | ||
| 6579 | { | 6433 | { |
| 6580 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | 6434 | const new_ty = try mod.ptrType(.{ |
| 6581 | errdefer new_decl_arena.deinit(); | 6435 | .child = test_fn_ty.toIntern(), |
| 6582 | const arena = new_decl_arena.allocator(); | 6436 | .flags = .{ |
| 6583 | 6437 | .is_const = true, | |
| 6584 | { | 6438 | .size = .Slice, |
| 6585 | // This copy accesses the old Decl Type/Value so it must be done before `clearValues`. | 6439 | }, |
| 6586 | const new_ty = try Type.Tag.const_slice.create(arena, try tmp_test_fn_ty.copy(arena)); | 6440 | }); |
| 6587 | const new_var = try gpa.create(Var); | 6441 | const new_val = decl.val; |
| 6588 | errdefer gpa.destroy(new_var); | 6442 | const new_init = try mod.intern(.{ .ptr = .{ |
| 6589 | new_var.* = decl.val.castTag(.variable).?.data.*; | 6443 | .ty = new_ty.toIntern(), |
| 6590 | new_var.init = try Value.Tag.slice.create(arena, .{ | 6444 | .addr = .{ .decl = array_decl_index }, |
| 6591 | .ptr = try Value.Tag.decl_ref.create(arena, array_decl_index), | 6445 | .len = (try mod.intValue(Type.usize, mod.test_functions.count())).toIntern(), |
| 6592 | .len = try Value.Tag.int_u64.create(arena, mod.test_functions.count()), | 6446 | } }); |
| 6593 | }); | 6447 | ip.mutateVarInit(decl.val.toIntern(), new_init); |
| 6594 | const new_val = try Value.Tag.variable.create(arena, new_var); | 6448 | |
| 6595 | 6449 | // Since we are replacing the Decl's value we must perform cleanup on the | |
| 6596 | // Since we are replacing the Decl's value we must perform cleanup on the | 6450 | // previous value. |
| 6597 | // previous value. | 6451 | decl.clearValues(mod); |
| 6598 | decl.clearValues(mod); | 6452 | decl.ty = new_ty; |
| 6599 | decl.ty = new_ty; | 6453 | decl.val = new_val; |
| 6600 | decl.val = new_val; | 6454 | decl.has_tv = true; |
| 6601 | decl.has_tv = true; | ||
| 6602 | } | ||
| 6603 | |||
| 6604 | try decl.finalizeNewArena(&new_decl_arena); | ||
| 6605 | } | 6455 | } |
| 6606 | try mod.linkerUpdateDecl(decl_index); | 6456 | try mod.linkerUpdateDecl(decl_index); |
| 6607 | } | 6457 | } |
| ... | @@ -6631,7 +6481,7 @@ pub fn linkerUpdateDecl(mod: *Module, decl_index: Decl.Index) !void { | ... | @@ -6631,7 +6481,7 @@ pub fn linkerUpdateDecl(mod: *Module, decl_index: Decl.Index) !void { |
| 6631 | try mod.failed_decls.ensureUnusedCapacity(gpa, 1); | 6481 | try mod.failed_decls.ensureUnusedCapacity(gpa, 1); |
| 6632 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( | 6482 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( |
| 6633 | gpa, | 6483 | gpa, |
| 6634 | decl.srcLoc(), | 6484 | decl.srcLoc(mod), |
| 6635 | "unable to codegen: {s}", | 6485 | "unable to codegen: {s}", |
| 6636 | .{@errorName(err)}, | 6486 | .{@errorName(err)}, |
| 6637 | )); | 6487 | )); |
| ... | @@ -6673,64 +6523,49 @@ fn reportRetryableFileError( | ... | @@ -6673,64 +6523,49 @@ fn reportRetryableFileError( |
| 6673 | gop.value_ptr.* = err_msg; | 6523 | gop.value_ptr.* = err_msg; |
| 6674 | } | 6524 | } |
| 6675 | 6525 | ||
| 6676 | pub fn markReferencedDeclsAlive(mod: *Module, val: Value) void { | 6526 | pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void { |
| 6677 | switch (val.tag()) { | 6527 | switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 6678 | .decl_ref_mut => return mod.markDeclIndexAlive(val.castTag(.decl_ref_mut).?.data.decl_index), | 6528 | .variable => |variable| try mod.markDeclIndexAlive(variable.decl), |
| 6679 | .extern_fn => return mod.markDeclIndexAlive(val.castTag(.extern_fn).?.data.owner_decl), | 6529 | .extern_func => |extern_func| try mod.markDeclIndexAlive(extern_func.decl), |
| 6680 | .function => return mod.markDeclIndexAlive(val.castTag(.function).?.data.owner_decl), | 6530 | .func => |func| try mod.markDeclIndexAlive(mod.funcPtr(func.index).owner_decl), |
| 6681 | .variable => return mod.markDeclIndexAlive(val.castTag(.variable).?.data.owner_decl), | 6531 | .error_union => |error_union| switch (error_union.val) { |
| 6682 | .decl_ref => return mod.markDeclIndexAlive(val.cast(Value.Payload.Decl).?.data), | 6532 | .err_name => {}, |
| 6683 | 6533 | .payload => |payload| try mod.markReferencedDeclsAlive(payload.toValue()), | |
| 6684 | .repeated, | ||
| 6685 | .eu_payload, | ||
| 6686 | .opt_payload, | ||
| 6687 | .empty_array_sentinel, | ||
| 6688 | => return mod.markReferencedDeclsAlive(val.cast(Value.Payload.SubValue).?.data), | ||
| 6689 | |||
| 6690 | .eu_payload_ptr, | ||
| 6691 | .opt_payload_ptr, | ||
| 6692 | => return mod.markReferencedDeclsAlive(val.cast(Value.Payload.PayloadPtr).?.data.container_ptr), | ||
| 6693 | |||
| 6694 | .slice => { | ||
| 6695 | const slice = val.cast(Value.Payload.Slice).?.data; | ||
| 6696 | mod.markReferencedDeclsAlive(slice.ptr); | ||
| 6697 | mod.markReferencedDeclsAlive(slice.len); | ||
| 6698 | }, | ||
| 6699 | |||
| 6700 | .elem_ptr => { | ||
| 6701 | const elem_ptr = val.cast(Value.Payload.ElemPtr).?.data; | ||
| 6702 | return mod.markReferencedDeclsAlive(elem_ptr.array_ptr); | ||
| 6703 | }, | ||
| 6704 | .field_ptr => { | ||
| 6705 | const field_ptr = val.cast(Value.Payload.FieldPtr).?.data; | ||
| 6706 | return mod.markReferencedDeclsAlive(field_ptr.container_ptr); | ||
| 6707 | }, | 6534 | }, |
| 6708 | .aggregate => { | 6535 | .ptr => |ptr| { |
| 6709 | for (val.castTag(.aggregate).?.data) |field_val| { | 6536 | switch (ptr.addr) { |
| 6710 | mod.markReferencedDeclsAlive(field_val); | 6537 | .decl => |decl| try mod.markDeclIndexAlive(decl), |
| 6538 | .mut_decl => |mut_decl| try mod.markDeclIndexAlive(mut_decl.decl), | ||
| 6539 | .int, .comptime_field => {}, | ||
| 6540 | .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(parent.toValue()), | ||
| 6541 | .elem, .field => |base_index| try mod.markReferencedDeclsAlive(base_index.base.toValue()), | ||
| 6711 | } | 6542 | } |
| 6543 | if (ptr.len != .none) try mod.markReferencedDeclsAlive(ptr.len.toValue()); | ||
| 6712 | }, | 6544 | }, |
| 6713 | .@"union" => { | 6545 | .opt => |opt| if (opt.val != .none) try mod.markReferencedDeclsAlive(opt.val.toValue()), |
| 6714 | const data = val.cast(Value.Payload.Union).?.data; | 6546 | .aggregate => |aggregate| for (aggregate.storage.values()) |elem| |
| 6715 | mod.markReferencedDeclsAlive(data.tag); | 6547 | try mod.markReferencedDeclsAlive(elem.toValue()), |
| 6716 | mod.markReferencedDeclsAlive(data.val); | 6548 | .un => |un| { |
| 6549 | try mod.markReferencedDeclsAlive(un.tag.toValue()); | ||
| 6550 | try mod.markReferencedDeclsAlive(un.val.toValue()); | ||
| 6717 | }, | 6551 | }, |
| 6718 | |||
| 6719 | else => {}, | 6552 | else => {}, |
| 6720 | } | 6553 | } |
| 6721 | } | 6554 | } |
| 6722 | 6555 | ||
| 6723 | pub fn markDeclAlive(mod: *Module, decl: *Decl) void { | 6556 | pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void { |
| 6724 | if (decl.alive) return; | 6557 | if (decl.alive) return; |
| 6725 | decl.alive = true; | 6558 | decl.alive = true; |
| 6726 | 6559 | ||
| 6560 | try decl.intern(mod); | ||
| 6561 | |||
| 6727 | // This is the first time we are marking this Decl alive. We must | 6562 | // This is the first time we are marking this Decl alive. We must |
| 6728 | // therefore recurse into its value and mark any Decl it references | 6563 | // therefore recurse into its value and mark any Decl it references |
| 6729 | // as also alive, so that any Decl referenced does not get garbage collected. | 6564 | // as also alive, so that any Decl referenced does not get garbage collected. |
| 6730 | mod.markReferencedDeclsAlive(decl.val); | 6565 | try mod.markReferencedDeclsAlive(decl.val); |
| 6731 | } | 6566 | } |
| 6732 | 6567 | ||
| 6733 | fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) void { | 6568 | fn markDeclIndexAlive(mod: *Module, decl_index: Decl.Index) Allocator.Error!void { |
| 6734 | return mod.markDeclAlive(mod.declPtr(decl_index)); | 6569 | return mod.markDeclAlive(mod.declPtr(decl_index)); |
| 6735 | } | 6570 | } |
| 6736 | 6571 | ||
| ... | @@ -6779,3 +6614,522 @@ pub fn backendSupportsFeature(mod: Module, feature: Feature) bool { | ... | @@ -6779,3 +6614,522 @@ pub fn backendSupportsFeature(mod: Module, feature: Feature) bool { |
| 6779 | .field_reordering => mod.comp.bin_file.options.use_llvm, | 6614 | .field_reordering => mod.comp.bin_file.options.use_llvm, |
| 6780 | }; | 6615 | }; |
| 6781 | } | 6616 | } |
| 6617 | |||
| 6618 | /// Shortcut for calling `intern_pool.get`. | ||
| 6619 | pub fn intern(mod: *Module, key: InternPool.Key) Allocator.Error!InternPool.Index { | ||
| 6620 | return mod.intern_pool.get(mod.gpa, key); | ||
| 6621 | } | ||
| 6622 | |||
| 6623 | /// Shortcut for calling `intern_pool.getCoerced`. | ||
| 6624 | pub fn getCoerced(mod: *Module, val: Value, new_ty: Type) Allocator.Error!Value { | ||
| 6625 | return (try mod.intern_pool.getCoerced(mod.gpa, val.toIntern(), new_ty.toIntern())).toValue(); | ||
| 6626 | } | ||
| 6627 | |||
| 6628 | pub fn intType(mod: *Module, signedness: std.builtin.Signedness, bits: u16) Allocator.Error!Type { | ||
| 6629 | return (try intern(mod, .{ .int_type = .{ | ||
| 6630 | .signedness = signedness, | ||
| 6631 | .bits = bits, | ||
| 6632 | } })).toType(); | ||
| 6633 | } | ||
| 6634 | |||
| 6635 | pub fn arrayType(mod: *Module, info: InternPool.Key.ArrayType) Allocator.Error!Type { | ||
| 6636 | const i = try intern(mod, .{ .array_type = info }); | ||
| 6637 | return i.toType(); | ||
| 6638 | } | ||
| 6639 | |||
| 6640 | pub fn vectorType(mod: *Module, info: InternPool.Key.VectorType) Allocator.Error!Type { | ||
| 6641 | const i = try intern(mod, .{ .vector_type = info }); | ||
| 6642 | return i.toType(); | ||
| 6643 | } | ||
| 6644 | |||
| 6645 | pub fn optionalType(mod: *Module, child_type: InternPool.Index) Allocator.Error!Type { | ||
| 6646 | const i = try intern(mod, .{ .opt_type = child_type }); | ||
| 6647 | return i.toType(); | ||
| 6648 | } | ||
| 6649 | |||
| 6650 | pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type { | ||
| 6651 | var canon_info = info; | ||
| 6652 | const have_elem_layout = info.child.toType().layoutIsResolved(mod); | ||
| 6653 | |||
| 6654 | if (info.flags.size == .C) canon_info.flags.is_allowzero = true; | ||
| 6655 | |||
| 6656 | // Canonicalize non-zero alignment. If it matches the ABI alignment of the pointee | ||
| 6657 | // type, we change it to 0 here. If this causes an assertion trip because the | ||
| 6658 | // pointee type needs to be resolved more, that needs to be done before calling | ||
| 6659 | // this ptr() function. | ||
| 6660 | if (info.flags.alignment.toByteUnitsOptional()) |info_align| { | ||
| 6661 | if (have_elem_layout and info_align == info.child.toType().abiAlignment(mod)) { | ||
| 6662 | canon_info.flags.alignment = .none; | ||
| 6663 | } | ||
| 6664 | } | ||
| 6665 | |||
| 6666 | switch (info.flags.vector_index) { | ||
| 6667 | // Canonicalize host_size. If it matches the bit size of the pointee type, | ||
| 6668 | // we change it to 0 here. If this causes an assertion trip, the pointee type | ||
| 6669 | // needs to be resolved before calling this ptr() function. | ||
| 6670 | .none => if (have_elem_layout and info.packed_offset.host_size != 0) { | ||
| 6671 | const elem_bit_size = info.child.toType().bitSize(mod); | ||
| 6672 | assert(info.packed_offset.bit_offset + elem_bit_size <= info.packed_offset.host_size * 8); | ||
| 6673 | if (info.packed_offset.host_size * 8 == elem_bit_size) { | ||
| 6674 | canon_info.packed_offset.host_size = 0; | ||
| 6675 | } | ||
| 6676 | }, | ||
| 6677 | .runtime => {}, | ||
| 6678 | _ => assert(@enumToInt(info.flags.vector_index) < info.packed_offset.host_size), | ||
| 6679 | } | ||
| 6680 | |||
| 6681 | return (try intern(mod, .{ .ptr_type = canon_info })).toType(); | ||
| 6682 | } | ||
| 6683 | |||
| 6684 | pub fn singleMutPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { | ||
| 6685 | return ptrType(mod, .{ .child = child_type.toIntern() }); | ||
| 6686 | } | ||
| 6687 | |||
| 6688 | pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { | ||
| 6689 | return ptrType(mod, .{ | ||
| 6690 | .child = child_type.toIntern(), | ||
| 6691 | .flags = .{ | ||
| 6692 | .is_const = true, | ||
| 6693 | }, | ||
| 6694 | }); | ||
| 6695 | } | ||
| 6696 | |||
| 6697 | pub fn manyConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { | ||
| 6698 | return ptrType(mod, .{ | ||
| 6699 | .child = child_type.toIntern(), | ||
| 6700 | .flags = .{ | ||
| 6701 | .size = .Many, | ||
| 6702 | .is_const = true, | ||
| 6703 | }, | ||
| 6704 | }); | ||
| 6705 | } | ||
| 6706 | |||
| 6707 | pub fn adjustPtrTypeChild(mod: *Module, ptr_ty: Type, new_child: Type) Allocator.Error!Type { | ||
| 6708 | const info = Type.ptrInfoIp(&mod.intern_pool, ptr_ty.toIntern()); | ||
| 6709 | return mod.ptrType(.{ | ||
| 6710 | .child = new_child.toIntern(), | ||
| 6711 | .sentinel = info.sentinel, | ||
| 6712 | .flags = info.flags, | ||
| 6713 | .packed_offset = info.packed_offset, | ||
| 6714 | }); | ||
| 6715 | } | ||
| 6716 | |||
| 6717 | pub fn funcType(mod: *Module, info: InternPool.Key.FuncType) Allocator.Error!Type { | ||
| 6718 | return (try intern(mod, .{ .func_type = info })).toType(); | ||
| 6719 | } | ||
| 6720 | |||
| 6721 | /// Use this for `anyframe->T` only. | ||
| 6722 | /// For `anyframe`, use the `InternPool.Index.anyframe` tag directly. | ||
| 6723 | pub fn anyframeType(mod: *Module, payload_ty: Type) Allocator.Error!Type { | ||
| 6724 | return (try intern(mod, .{ .anyframe_type = payload_ty.toIntern() })).toType(); | ||
| 6725 | } | ||
| 6726 | |||
| 6727 | pub fn errorUnionType(mod: *Module, error_set_ty: Type, payload_ty: Type) Allocator.Error!Type { | ||
| 6728 | return (try intern(mod, .{ .error_union_type = .{ | ||
| 6729 | .error_set_type = error_set_ty.toIntern(), | ||
| 6730 | .payload_type = payload_ty.toIntern(), | ||
| 6731 | } })).toType(); | ||
| 6732 | } | ||
| 6733 | |||
| 6734 | pub fn singleErrorSetType(mod: *Module, name: InternPool.NullTerminatedString) Allocator.Error!Type { | ||
| 6735 | const names: *const [1]InternPool.NullTerminatedString = &name; | ||
| 6736 | return (try mod.intern_pool.get(mod.gpa, .{ .error_set_type = .{ .names = names } })).toType(); | ||
| 6737 | } | ||
| 6738 | |||
| 6739 | /// Sorts `names` in place. | ||
| 6740 | pub fn errorSetFromUnsortedNames( | ||
| 6741 | mod: *Module, | ||
| 6742 | names: []InternPool.NullTerminatedString, | ||
| 6743 | ) Allocator.Error!Type { | ||
| 6744 | std.mem.sort( | ||
| 6745 | InternPool.NullTerminatedString, | ||
| 6746 | names, | ||
| 6747 | {}, | ||
| 6748 | InternPool.NullTerminatedString.indexLessThan, | ||
| 6749 | ); | ||
| 6750 | const new_ty = try mod.intern(.{ .error_set_type = .{ .names = names } }); | ||
| 6751 | return new_ty.toType(); | ||
| 6752 | } | ||
| 6753 | |||
| 6754 | /// Supports optionals in addition to pointers. | ||
| 6755 | pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value { | ||
| 6756 | return mod.getCoerced(try mod.intValue_u64(Type.usize, x), ty); | ||
| 6757 | } | ||
| 6758 | |||
| 6759 | /// Supports only pointers. See `ptrIntValue` for pointer-like optional support. | ||
| 6760 | pub fn ptrIntValue_ptronly(mod: *Module, ty: Type, x: u64) Allocator.Error!Value { | ||
| 6761 | assert(ty.zigTypeTag(mod) == .Pointer); | ||
| 6762 | const i = try intern(mod, .{ .ptr = .{ | ||
| 6763 | .ty = ty.toIntern(), | ||
| 6764 | .addr = .{ .int = try mod.intValue_u64(Type.usize, x) }, | ||
| 6765 | } }); | ||
| 6766 | return i.toValue(); | ||
| 6767 | } | ||
| 6768 | |||
| 6769 | /// Creates an enum tag value based on the integer tag value. | ||
| 6770 | pub fn enumValue(mod: *Module, ty: Type, tag_int: InternPool.Index) Allocator.Error!Value { | ||
| 6771 | if (std.debug.runtime_safety) { | ||
| 6772 | const tag = ty.zigTypeTag(mod); | ||
| 6773 | assert(tag == .Enum); | ||
| 6774 | } | ||
| 6775 | const i = try intern(mod, .{ .enum_tag = .{ | ||
| 6776 | .ty = ty.toIntern(), | ||
| 6777 | .int = tag_int, | ||
| 6778 | } }); | ||
| 6779 | return i.toValue(); | ||
| 6780 | } | ||
| 6781 | |||
| 6782 | /// Creates an enum tag value based on the field index according to source code | ||
| 6783 | /// declaration order. | ||
| 6784 | pub fn enumValueFieldIndex(mod: *Module, ty: Type, field_index: u32) Allocator.Error!Value { | ||
| 6785 | const ip = &mod.intern_pool; | ||
| 6786 | const gpa = mod.gpa; | ||
| 6787 | const enum_type = ip.indexToKey(ty.toIntern()).enum_type; | ||
| 6788 | |||
| 6789 | if (enum_type.values.len == 0) { | ||
| 6790 | // Auto-numbered fields. | ||
| 6791 | return (try ip.get(gpa, .{ .enum_tag = .{ | ||
| 6792 | .ty = ty.toIntern(), | ||
| 6793 | .int = try ip.get(gpa, .{ .int = .{ | ||
| 6794 | .ty = enum_type.tag_ty, | ||
| 6795 | .storage = .{ .u64 = field_index }, | ||
| 6796 | } }), | ||
| 6797 | } })).toValue(); | ||
| 6798 | } | ||
| 6799 | |||
| 6800 | return (try ip.get(gpa, .{ .enum_tag = .{ | ||
| 6801 | .ty = ty.toIntern(), | ||
| 6802 | .int = enum_type.values[field_index], | ||
| 6803 | } })).toValue(); | ||
| 6804 | } | ||
| 6805 | |||
| 6806 | pub fn intValue(mod: *Module, ty: Type, x: anytype) Allocator.Error!Value { | ||
| 6807 | if (std.math.cast(u64, x)) |casted| return intValue_u64(mod, ty, casted); | ||
| 6808 | if (std.math.cast(i64, x)) |casted| return intValue_i64(mod, ty, casted); | ||
| 6809 | var limbs_buffer: [4]usize = undefined; | ||
| 6810 | var big_int = BigIntMutable.init(&limbs_buffer, x); | ||
| 6811 | return intValue_big(mod, ty, big_int.toConst()); | ||
| 6812 | } | ||
| 6813 | |||
| 6814 | pub fn intValue_big(mod: *Module, ty: Type, x: BigIntConst) Allocator.Error!Value { | ||
| 6815 | const i = try intern(mod, .{ .int = .{ | ||
| 6816 | .ty = ty.toIntern(), | ||
| 6817 | .storage = .{ .big_int = x }, | ||
| 6818 | } }); | ||
| 6819 | return i.toValue(); | ||
| 6820 | } | ||
| 6821 | |||
| 6822 | pub fn intValue_u64(mod: *Module, ty: Type, x: u64) Allocator.Error!Value { | ||
| 6823 | const i = try intern(mod, .{ .int = .{ | ||
| 6824 | .ty = ty.toIntern(), | ||
| 6825 | .storage = .{ .u64 = x }, | ||
| 6826 | } }); | ||
| 6827 | return i.toValue(); | ||
| 6828 | } | ||
| 6829 | |||
| 6830 | pub fn intValue_i64(mod: *Module, ty: Type, x: i64) Allocator.Error!Value { | ||
| 6831 | const i = try intern(mod, .{ .int = .{ | ||
| 6832 | .ty = ty.toIntern(), | ||
| 6833 | .storage = .{ .i64 = x }, | ||
| 6834 | } }); | ||
| 6835 | return i.toValue(); | ||
| 6836 | } | ||
| 6837 | |||
| 6838 | pub fn unionValue(mod: *Module, union_ty: Type, tag: Value, val: Value) Allocator.Error!Value { | ||
| 6839 | const i = try intern(mod, .{ .un = .{ | ||
| 6840 | .ty = union_ty.toIntern(), | ||
| 6841 | .tag = tag.toIntern(), | ||
| 6842 | .val = val.toIntern(), | ||
| 6843 | } }); | ||
| 6844 | return i.toValue(); | ||
| 6845 | } | ||
| 6846 | |||
| 6847 | /// This function casts the float representation down to the representation of the type, potentially | ||
| 6848 | /// losing data if the representation wasn't correct. | ||
| 6849 | pub fn floatValue(mod: *Module, ty: Type, x: anytype) Allocator.Error!Value { | ||
| 6850 | const storage: InternPool.Key.Float.Storage = switch (ty.floatBits(mod.getTarget())) { | ||
| 6851 | 16 => .{ .f16 = @floatCast(f16, x) }, | ||
| 6852 | 32 => .{ .f32 = @floatCast(f32, x) }, | ||
| 6853 | 64 => .{ .f64 = @floatCast(f64, x) }, | ||
| 6854 | 80 => .{ .f80 = @floatCast(f80, x) }, | ||
| 6855 | 128 => .{ .f128 = @floatCast(f128, x) }, | ||
| 6856 | else => unreachable, | ||
| 6857 | }; | ||
| 6858 | const i = try intern(mod, .{ .float = .{ | ||
| 6859 | .ty = ty.toIntern(), | ||
| 6860 | .storage = storage, | ||
| 6861 | } }); | ||
| 6862 | return i.toValue(); | ||
| 6863 | } | ||
| 6864 | |||
| 6865 | pub fn nullValue(mod: *Module, opt_ty: Type) Allocator.Error!Value { | ||
| 6866 | const ip = &mod.intern_pool; | ||
| 6867 | assert(ip.isOptionalType(opt_ty.toIntern())); | ||
| 6868 | const result = try ip.get(mod.gpa, .{ .opt = .{ | ||
| 6869 | .ty = opt_ty.toIntern(), | ||
| 6870 | .val = .none, | ||
| 6871 | } }); | ||
| 6872 | return result.toValue(); | ||
| 6873 | } | ||
| 6874 | |||
| 6875 | pub fn smallestUnsignedInt(mod: *Module, max: u64) Allocator.Error!Type { | ||
| 6876 | return intType(mod, .unsigned, Type.smallestUnsignedBits(max)); | ||
| 6877 | } | ||
| 6878 | |||
| 6879 | /// Returns the smallest possible integer type containing both `min` and | ||
| 6880 | /// `max`. Asserts that neither value is undef. | ||
| 6881 | /// TODO: if #3806 is implemented, this becomes trivial | ||
| 6882 | pub fn intFittingRange(mod: *Module, min: Value, max: Value) !Type { | ||
| 6883 | assert(!min.isUndef(mod)); | ||
| 6884 | assert(!max.isUndef(mod)); | ||
| 6885 | |||
| 6886 | if (std.debug.runtime_safety) { | ||
| 6887 | assert(Value.order(min, max, mod).compare(.lte)); | ||
| 6888 | } | ||
| 6889 | |||
| 6890 | const sign = min.orderAgainstZero(mod) == .lt; | ||
| 6891 | |||
| 6892 | const min_val_bits = intBitsForValue(mod, min, sign); | ||
| 6893 | const max_val_bits = intBitsForValue(mod, max, sign); | ||
| 6894 | |||
| 6895 | return mod.intType( | ||
| 6896 | if (sign) .signed else .unsigned, | ||
| 6897 | @max(min_val_bits, max_val_bits), | ||
| 6898 | ); | ||
| 6899 | } | ||
| 6900 | |||
| 6901 | /// Given a value representing an integer, returns the number of bits necessary to represent | ||
| 6902 | /// this value in an integer. If `sign` is true, returns the number of bits necessary in a | ||
| 6903 | /// twos-complement integer; otherwise in an unsigned integer. | ||
| 6904 | /// Asserts that `val` is not undef. If `val` is negative, asserts that `sign` is true. | ||
| 6905 | pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 { | ||
| 6906 | assert(!val.isUndef(mod)); | ||
| 6907 | |||
| 6908 | const key = mod.intern_pool.indexToKey(val.toIntern()); | ||
| 6909 | switch (key.int.storage) { | ||
| 6910 | .i64 => |x| { | ||
| 6911 | if (std.math.cast(u64, x)) |casted| return Type.smallestUnsignedBits(casted) + @boolToInt(sign); | ||
| 6912 | assert(sign); | ||
| 6913 | // Protect against overflow in the following negation. | ||
| 6914 | if (x == std.math.minInt(i64)) return 64; | ||
| 6915 | return Type.smallestUnsignedBits(@intCast(u64, -x - 1)) + 1; | ||
| 6916 | }, | ||
| 6917 | .u64 => |x| { | ||
| 6918 | return Type.smallestUnsignedBits(x) + @boolToInt(sign); | ||
| 6919 | }, | ||
| 6920 | .big_int => |big| { | ||
| 6921 | if (big.positive) return @intCast(u16, big.bitCountAbs() + @boolToInt(sign)); | ||
| 6922 | |||
| 6923 | // Zero is still a possibility, in which case unsigned is fine | ||
| 6924 | if (big.eqZero()) return 0; | ||
| 6925 | |||
| 6926 | return @intCast(u16, big.bitCountTwosComp()); | ||
| 6927 | }, | ||
| 6928 | .lazy_align => |lazy_ty| { | ||
| 6929 | return Type.smallestUnsignedBits(lazy_ty.toType().abiAlignment(mod)) + @boolToInt(sign); | ||
| 6930 | }, | ||
| 6931 | .lazy_size => |lazy_ty| { | ||
| 6932 | return Type.smallestUnsignedBits(lazy_ty.toType().abiSize(mod)) + @boolToInt(sign); | ||
| 6933 | }, | ||
| 6934 | } | ||
| 6935 | } | ||
| 6936 | |||
| 6937 | pub const AtomicPtrAlignmentError = error{ | ||
| 6938 | FloatTooBig, | ||
| 6939 | IntTooBig, | ||
| 6940 | BadType, | ||
| 6941 | OutOfMemory, | ||
| 6942 | }; | ||
| 6943 | |||
| 6944 | pub const AtomicPtrAlignmentDiagnostics = struct { | ||
| 6945 | bits: u16 = undefined, | ||
| 6946 | max_bits: u16 = undefined, | ||
| 6947 | }; | ||
| 6948 | |||
| 6949 | /// If ABI alignment of `ty` is OK for atomic operations, returns 0. | ||
| 6950 | /// Otherwise returns the alignment required on a pointer for the target | ||
| 6951 | /// to perform atomic operations. | ||
| 6952 | // TODO this function does not take into account CPU features, which can affect | ||
| 6953 | // this value. Audit this! | ||
| 6954 | pub fn atomicPtrAlignment( | ||
| 6955 | mod: *Module, | ||
| 6956 | ty: Type, | ||
| 6957 | diags: *AtomicPtrAlignmentDiagnostics, | ||
| 6958 | ) AtomicPtrAlignmentError!u32 { | ||
| 6959 | const target = mod.getTarget(); | ||
| 6960 | const max_atomic_bits: u16 = switch (target.cpu.arch) { | ||
| 6961 | .avr, | ||
| 6962 | .msp430, | ||
| 6963 | .spu_2, | ||
| 6964 | => 16, | ||
| 6965 | |||
| 6966 | .arc, | ||
| 6967 | .arm, | ||
| 6968 | .armeb, | ||
| 6969 | .hexagon, | ||
| 6970 | .m68k, | ||
| 6971 | .le32, | ||
| 6972 | .mips, | ||
| 6973 | .mipsel, | ||
| 6974 | .nvptx, | ||
| 6975 | .powerpc, | ||
| 6976 | .powerpcle, | ||
| 6977 | .r600, | ||
| 6978 | .riscv32, | ||
| 6979 | .sparc, | ||
| 6980 | .sparcel, | ||
| 6981 | .tce, | ||
| 6982 | .tcele, | ||
| 6983 | .thumb, | ||
| 6984 | .thumbeb, | ||
| 6985 | .x86, | ||
| 6986 | .xcore, | ||
| 6987 | .amdil, | ||
| 6988 | .hsail, | ||
| 6989 | .spir, | ||
| 6990 | .kalimba, | ||
| 6991 | .lanai, | ||
| 6992 | .shave, | ||
| 6993 | .wasm32, | ||
| 6994 | .renderscript32, | ||
| 6995 | .csky, | ||
| 6996 | .spirv32, | ||
| 6997 | .dxil, | ||
| 6998 | .loongarch32, | ||
| 6999 | .xtensa, | ||
| 7000 | => 32, | ||
| 7001 | |||
| 7002 | .amdgcn, | ||
| 7003 | .bpfel, | ||
| 7004 | .bpfeb, | ||
| 7005 | .le64, | ||
| 7006 | .mips64, | ||
| 7007 | .mips64el, | ||
| 7008 | .nvptx64, | ||
| 7009 | .powerpc64, | ||
| 7010 | .powerpc64le, | ||
| 7011 | .riscv64, | ||
| 7012 | .sparc64, | ||
| 7013 | .s390x, | ||
| 7014 | .amdil64, | ||
| 7015 | .hsail64, | ||
| 7016 | .spir64, | ||
| 7017 | .wasm64, | ||
| 7018 | .renderscript64, | ||
| 7019 | .ve, | ||
| 7020 | .spirv64, | ||
| 7021 | .loongarch64, | ||
| 7022 | => 64, | ||
| 7023 | |||
| 7024 | .aarch64, | ||
| 7025 | .aarch64_be, | ||
| 7026 | .aarch64_32, | ||
| 7027 | => 128, | ||
| 7028 | |||
| 7029 | .x86_64 => if (std.Target.x86.featureSetHas(target.cpu.features, .cx16)) 128 else 64, | ||
| 7030 | }; | ||
| 7031 | |||
| 7032 | const int_ty = switch (ty.zigTypeTag(mod)) { | ||
| 7033 | .Int => ty, | ||
| 7034 | .Enum => ty.intTagType(mod), | ||
| 7035 | .Float => { | ||
| 7036 | const bit_count = ty.floatBits(target); | ||
| 7037 | if (bit_count > max_atomic_bits) { | ||
| 7038 | diags.* = .{ | ||
| 7039 | .bits = bit_count, | ||
| 7040 | .max_bits = max_atomic_bits, | ||
| 7041 | }; | ||
| 7042 | return error.FloatTooBig; | ||
| 7043 | } | ||
| 7044 | return 0; | ||
| 7045 | }, | ||
| 7046 | .Bool => return 0, | ||
| 7047 | else => { | ||
| 7048 | if (ty.isPtrAtRuntime(mod)) return 0; | ||
| 7049 | return error.BadType; | ||
| 7050 | }, | ||
| 7051 | }; | ||
| 7052 | |||
| 7053 | const bit_count = int_ty.intInfo(mod).bits; | ||
| 7054 | if (bit_count > max_atomic_bits) { | ||
| 7055 | diags.* = .{ | ||
| 7056 | .bits = bit_count, | ||
| 7057 | .max_bits = max_atomic_bits, | ||
| 7058 | }; | ||
| 7059 | return error.IntTooBig; | ||
| 7060 | } | ||
| 7061 | |||
| 7062 | return 0; | ||
| 7063 | } | ||
| 7064 | |||
| 7065 | pub fn opaqueSrcLoc(mod: *Module, opaque_type: InternPool.Key.OpaqueType) SrcLoc { | ||
| 7066 | return mod.declPtr(opaque_type.decl).srcLoc(mod); | ||
| 7067 | } | ||
| 7068 | |||
| 7069 | pub fn opaqueFullyQualifiedName(mod: *Module, opaque_type: InternPool.Key.OpaqueType) !InternPool.NullTerminatedString { | ||
| 7070 | return mod.declPtr(opaque_type.decl).getFullyQualifiedName(mod); | ||
| 7071 | } | ||
| 7072 | |||
| 7073 | pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File { | ||
| 7074 | return mod.declPtr(decl_index).getFileScope(mod); | ||
| 7075 | } | ||
| 7076 | |||
| 7077 | pub fn namespaceDeclIndex(mod: *Module, namespace_index: Namespace.Index) Decl.Index { | ||
| 7078 | return mod.namespacePtr(namespace_index).getDeclIndex(mod); | ||
| 7079 | } | ||
| 7080 | |||
| 7081 | /// Returns null in the following cases: | ||
| 7082 | /// * `@TypeOf(.{})` | ||
| 7083 | /// * A struct which has no fields (`struct {}`). | ||
| 7084 | /// * Not a struct. | ||
| 7085 | pub fn typeToStruct(mod: *Module, ty: Type) ?*Struct { | ||
| 7086 | if (ty.ip_index == .none) return null; | ||
| 7087 | const struct_index = mod.intern_pool.indexToStructType(ty.toIntern()).unwrap() orelse return null; | ||
| 7088 | return mod.structPtr(struct_index); | ||
| 7089 | } | ||
| 7090 | |||
| 7091 | pub fn typeToUnion(mod: *Module, ty: Type) ?*Union { | ||
| 7092 | if (ty.ip_index == .none) return null; | ||
| 7093 | const union_index = mod.intern_pool.indexToUnionType(ty.toIntern()).unwrap() orelse return null; | ||
| 7094 | return mod.unionPtr(union_index); | ||
| 7095 | } | ||
| 7096 | |||
| 7097 | pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType { | ||
| 7098 | if (ty.ip_index == .none) return null; | ||
| 7099 | return mod.intern_pool.indexToFuncType(ty.toIntern()); | ||
| 7100 | } | ||
| 7101 | |||
| 7102 | pub fn typeToInferredErrorSet(mod: *Module, ty: Type) ?*Fn.InferredErrorSet { | ||
| 7103 | const index = typeToInferredErrorSetIndex(mod, ty).unwrap() orelse return null; | ||
| 7104 | return mod.inferredErrorSetPtr(index); | ||
| 7105 | } | ||
| 7106 | |||
| 7107 | pub fn typeToInferredErrorSetIndex(mod: *Module, ty: Type) Fn.InferredErrorSet.OptionalIndex { | ||
| 7108 | if (ty.ip_index == .none) return .none; | ||
| 7109 | return mod.intern_pool.indexToInferredErrorSetType(ty.toIntern()); | ||
| 7110 | } | ||
| 7111 | |||
| 7112 | pub fn fieldSrcLoc(mod: *Module, owner_decl_index: Decl.Index, query: FieldSrcQuery) SrcLoc { | ||
| 7113 | @setCold(true); | ||
| 7114 | const owner_decl = mod.declPtr(owner_decl_index); | ||
| 7115 | const file = owner_decl.getFileScope(mod); | ||
| 7116 | const tree = file.getTree(mod.gpa) catch |err| { | ||
| 7117 | // In this case we emit a warning + a less precise source location. | ||
| 7118 | log.warn("unable to load {s}: {s}", .{ | ||
| 7119 | file.sub_file_path, @errorName(err), | ||
| 7120 | }); | ||
| 7121 | return owner_decl.srcLoc(mod); | ||
| 7122 | }; | ||
| 7123 | const node = owner_decl.relativeToNodeIndex(0); | ||
| 7124 | var buf: [2]Ast.Node.Index = undefined; | ||
| 7125 | if (tree.fullContainerDecl(&buf, node)) |container_decl| { | ||
| 7126 | return queryFieldSrc(tree.*, query, file, container_decl); | ||
| 7127 | } else { | ||
| 7128 | // This type was generated using @Type | ||
| 7129 | return owner_decl.srcLoc(mod); | ||
| 7130 | } | ||
| 7131 | } | ||
| 7132 | |||
| 7133 | pub fn toEnum(mod: *Module, comptime E: type, val: Value) E { | ||
| 7134 | return mod.intern_pool.toEnum(E, val.toIntern()); | ||
| 7135 | } |
src/RangeSet.zig+33-26| ... | @@ -1,18 +1,18 @@ | ... | @@ -1,18 +1,18 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const assert = std.debug.assert; | ||
| 2 | const Order = std.math.Order; | 3 | const Order = std.math.Order; |
| 3 | 4 | ||
| 4 | const RangeSet = @This(); | 5 | const InternPool = @import("InternPool.zig"); |
| 5 | const Module = @import("Module.zig"); | 6 | const Module = @import("Module.zig"); |
| 7 | const RangeSet = @This(); | ||
| 6 | const SwitchProngSrc = @import("Module.zig").SwitchProngSrc; | 8 | const SwitchProngSrc = @import("Module.zig").SwitchProngSrc; |
| 7 | const Type = @import("type.zig").Type; | ||
| 8 | const Value = @import("value.zig").Value; | ||
| 9 | 9 | ||
| 10 | ranges: std.ArrayList(Range), | 10 | ranges: std.ArrayList(Range), |
| 11 | module: *Module, | 11 | module: *Module, |
| 12 | 12 | ||
| 13 | pub const Range = struct { | 13 | pub const Range = struct { |
| 14 | first: Value, | 14 | first: InternPool.Index, |
| 15 | last: Value, | 15 | last: InternPool.Index, |
| 16 | src: SwitchProngSrc, | 16 | src: SwitchProngSrc, |
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| ... | @@ -29,18 +29,27 @@ pub fn deinit(self: *RangeSet) void { | ... | @@ -29,18 +29,27 @@ pub fn deinit(self: *RangeSet) void { |
| 29 | 29 | ||
| 30 | pub fn add( | 30 | pub fn add( |
| 31 | self: *RangeSet, | 31 | self: *RangeSet, |
| 32 | first: Value, | 32 | first: InternPool.Index, |
| 33 | last: Value, | 33 | last: InternPool.Index, |
| 34 | ty: Type, | ||
| 35 | src: SwitchProngSrc, | 34 | src: SwitchProngSrc, |
| 36 | ) !?SwitchProngSrc { | 35 | ) !?SwitchProngSrc { |
| 36 | const mod = self.module; | ||
| 37 | const ip = &mod.intern_pool; | ||
| 38 | |||
| 39 | const ty = ip.typeOf(first); | ||
| 40 | assert(ty == ip.typeOf(last)); | ||
| 41 | |||
| 37 | for (self.ranges.items) |range| { | 42 | for (self.ranges.items) |range| { |
| 38 | if (last.compareAll(.gte, range.first, ty, self.module) and | 43 | assert(ty == ip.typeOf(range.first)); |
| 39 | first.compareAll(.lte, range.last, ty, self.module)) | 44 | assert(ty == ip.typeOf(range.last)); |
| 45 | |||
| 46 | if (last.toValue().compareScalar(.gte, range.first.toValue(), ty.toType(), mod) and | ||
| 47 | first.toValue().compareScalar(.lte, range.last.toValue(), ty.toType(), mod)) | ||
| 40 | { | 48 | { |
| 41 | return range.src; // They overlap. | 49 | return range.src; // They overlap. |
| 42 | } | 50 | } |
| 43 | } | 51 | } |
| 52 | |||
| 44 | try self.ranges.append(.{ | 53 | try self.ranges.append(.{ |
| 45 | .first = first, | 54 | .first = first, |
| 46 | .last = last, | 55 | .last = last, |
| ... | @@ -49,45 +58,43 @@ pub fn add( | ... | @@ -49,45 +58,43 @@ pub fn add( |
| 49 | return null; | 58 | return null; |
| 50 | } | 59 | } |
| 51 | 60 | ||
| 52 | const LessThanContext = struct { ty: Type, module: *Module }; | ||
| 53 | |||
| 54 | /// Assumes a and b do not overlap | 61 | /// Assumes a and b do not overlap |
| 55 | fn lessThan(ctx: LessThanContext, a: Range, b: Range) bool { | 62 | fn lessThan(mod: *Module, a: Range, b: Range) bool { |
| 56 | return a.first.compareAll(.lt, b.first, ctx.ty, ctx.module); | 63 | const ty = mod.intern_pool.typeOf(a.first).toType(); |
| 64 | return a.first.toValue().compareScalar(.lt, b.first.toValue(), ty, mod); | ||
| 57 | } | 65 | } |
| 58 | 66 | ||
| 59 | pub fn spans(self: *RangeSet, first: Value, last: Value, ty: Type) !bool { | 67 | pub fn spans(self: *RangeSet, first: InternPool.Index, last: InternPool.Index) !bool { |
| 68 | const mod = self.module; | ||
| 69 | const ip = &mod.intern_pool; | ||
| 70 | assert(ip.typeOf(first) == ip.typeOf(last)); | ||
| 71 | |||
| 60 | if (self.ranges.items.len == 0) | 72 | if (self.ranges.items.len == 0) |
| 61 | return false; | 73 | return false; |
| 62 | 74 | ||
| 63 | std.mem.sort(Range, self.ranges.items, LessThanContext{ | 75 | std.mem.sort(Range, self.ranges.items, mod, lessThan); |
| 64 | .ty = ty, | ||
| 65 | .module = self.module, | ||
| 66 | }, lessThan); | ||
| 67 | 76 | ||
| 68 | if (!self.ranges.items[0].first.eql(first, ty, self.module) or | 77 | if (self.ranges.items[0].first != first or |
| 69 | !self.ranges.items[self.ranges.items.len - 1].last.eql(last, ty, self.module)) | 78 | self.ranges.items[self.ranges.items.len - 1].last != last) |
| 70 | { | 79 | { |
| 71 | return false; | 80 | return false; |
| 72 | } | 81 | } |
| 73 | 82 | ||
| 74 | var space: Value.BigIntSpace = undefined; | 83 | var space: InternPool.Key.Int.Storage.BigIntSpace = undefined; |
| 75 | 84 | ||
| 76 | var counter = try std.math.big.int.Managed.init(self.ranges.allocator); | 85 | var counter = try std.math.big.int.Managed.init(self.ranges.allocator); |
| 77 | defer counter.deinit(); | 86 | defer counter.deinit(); |
| 78 | 87 | ||
| 79 | const target = self.module.getTarget(); | ||
| 80 | |||
| 81 | // look for gaps | 88 | // look for gaps |
| 82 | for (self.ranges.items[1..], 0..) |cur, i| { | 89 | for (self.ranges.items[1..], 0..) |cur, i| { |
| 83 | // i starts counting from the second item. | 90 | // i starts counting from the second item. |
| 84 | const prev = self.ranges.items[i]; | 91 | const prev = self.ranges.items[i]; |
| 85 | 92 | ||
| 86 | // prev.last + 1 == cur.first | 93 | // prev.last + 1 == cur.first |
| 87 | try counter.copy(prev.last.toBigInt(&space, target)); | 94 | try counter.copy(prev.last.toValue().toBigInt(&space, mod)); |
| 88 | try counter.addScalar(&counter, 1); | 95 | try counter.addScalar(&counter, 1); |
| 89 | 96 | ||
| 90 | const cur_start_int = cur.first.toBigInt(&space, target); | 97 | const cur_start_int = cur.first.toValue().toBigInt(&space, mod); |
| 91 | if (!cur_start_int.eq(counter.toConst())) { | 98 | if (!cur_start_int.eq(counter.toConst())) { |
| 92 | return false; | 99 | return false; |
| 93 | } | 100 | } |
src/Sema.zig+8816-8097| ... | @@ -11,13 +11,9 @@ gpa: Allocator, | ... | @@ -11,13 +11,9 @@ gpa: Allocator, |
| 11 | /// Points to the temporary arena allocator of the Sema. | 11 | /// Points to the temporary arena allocator of the Sema. |
| 12 | /// This arena will be cleared when the sema is destroyed. | 12 | /// This arena will be cleared when the sema is destroyed. |
| 13 | arena: Allocator, | 13 | arena: Allocator, |
| 14 | /// Points to the arena allocator for the owner_decl. | ||
| 15 | /// This arena will persist until the decl is invalidated. | ||
| 16 | perm_arena: Allocator, | ||
| 17 | code: Zir, | 14 | code: Zir, |
| 18 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, | 15 | air_instructions: std.MultiArrayList(Air.Inst) = .{}, |
| 19 | air_extra: std.ArrayListUnmanaged(u32) = .{}, | 16 | air_extra: std.ArrayListUnmanaged(u32) = .{}, |
| 20 | air_values: std.ArrayListUnmanaged(Value) = .{}, | ||
| 21 | /// Maps ZIR to AIR. | 17 | /// Maps ZIR to AIR. |
| 22 | inst_map: InstMap = .{}, | 18 | inst_map: InstMap = .{}, |
| 23 | /// When analyzing an inline function call, owner_decl is the Decl of the caller | 19 | /// When analyzing an inline function call, owner_decl is the Decl of the caller |
| ... | @@ -28,10 +24,12 @@ owner_decl_index: Decl.Index, | ... | @@ -28,10 +24,12 @@ owner_decl_index: Decl.Index, |
| 28 | /// For an inline or comptime function call, this will be the root parent function | 24 | /// For an inline or comptime function call, this will be the root parent function |
| 29 | /// which contains the callsite. Corresponds to `owner_decl`. | 25 | /// which contains the callsite. Corresponds to `owner_decl`. |
| 30 | owner_func: ?*Module.Fn, | 26 | owner_func: ?*Module.Fn, |
| 27 | owner_func_index: Module.Fn.OptionalIndex, | ||
| 31 | /// The function this ZIR code is the body of, according to the source code. | 28 | /// The function this ZIR code is the body of, according to the source code. |
| 32 | /// This starts out the same as `owner_func` and then diverges in the case of | 29 | /// This starts out the same as `owner_func` and then diverges in the case of |
| 33 | /// an inline or comptime function call. | 30 | /// an inline or comptime function call. |
| 34 | func: ?*Module.Fn, | 31 | func: ?*Module.Fn, |
| 32 | func_index: Module.Fn.OptionalIndex, | ||
| 35 | /// Used to restore the error return trace when returning a non-error from a function. | 33 | /// Used to restore the error return trace when returning a non-error from a function. |
| 36 | error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none, | 34 | error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none, |
| 37 | /// When semantic analysis needs to know the return type of the function whose body | 35 | /// When semantic analysis needs to know the return type of the function whose body |
| ... | @@ -65,12 +63,15 @@ comptime_args_fn_inst: Zir.Inst.Index = 0, | ... | @@ -65,12 +63,15 @@ comptime_args_fn_inst: Zir.Inst.Index = 0, |
| 65 | /// to use this instead of allocating a fresh one. This avoids an unnecessary | 63 | /// to use this instead of allocating a fresh one. This avoids an unnecessary |
| 66 | /// extra hash table lookup in the `monomorphed_funcs` set. | 64 | /// extra hash table lookup in the `monomorphed_funcs` set. |
| 67 | /// Sema will set this to null when it takes ownership. | 65 | /// Sema will set this to null when it takes ownership. |
| 68 | preallocated_new_func: ?*Module.Fn = null, | 66 | preallocated_new_func: Module.Fn.OptionalIndex = .none, |
| 69 | /// The key is `constant` AIR instructions to types that must be fully resolved | 67 | /// The key is types that must be fully resolved prior to machine code |
| 70 | /// after the current function body analysis is done. | 68 | /// generation pass. Types are added to this set when resolving them |
| 71 | /// TODO: after upgrading to use InternPool change the key here to be an | 69 | /// immediately could cause a dependency loop, but they do need to be resolved |
| 72 | /// InternPool value index. | 70 | /// before machine code generation passes process the AIR. |
| 73 | types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{}, | 71 | /// It would work fine if this were an array list instead of an array hash map. |
| 72 | /// I chose array hash map with the intention to save time by omitting | ||
| 73 | /// duplicates. | ||
| 74 | types_to_resolve: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}, | ||
| 74 | /// These are lazily created runtime blocks from block_inline instructions. | 75 | /// These are lazily created runtime blocks from block_inline instructions. |
| 75 | /// They are created when an break_inline passes through a runtime condition, because | 76 | /// They are created when an break_inline passes through a runtime condition, because |
| 76 | /// Sema must convert comptime control flow to runtime control flow, which means | 77 | /// Sema must convert comptime control flow to runtime control flow, which means |
| ... | @@ -84,12 +85,22 @@ is_generic_instantiation: bool = false, | ... | @@ -84,12 +85,22 @@ is_generic_instantiation: bool = false, |
| 84 | /// function types will emit generic poison instead of a partial type. | 85 | /// function types will emit generic poison instead of a partial type. |
| 85 | no_partial_func_ty: bool = false, | 86 | no_partial_func_ty: bool = false, |
| 86 | 87 | ||
| 87 | unresolved_inferred_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, void) = .{}, | 88 | /// The temporary arena is used for the memory of the `InferredAlloc` values |
| 89 | /// here so the values can be dropped without any cleanup. | ||
| 90 | unresolved_inferred_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .{}, | ||
| 91 | |||
| 92 | /// Indices of comptime-mutable decls created by this Sema. These decls' values | ||
| 93 | /// should be interned after analysis completes, as they may refer to memory in | ||
| 94 | /// the Sema arena. | ||
| 95 | /// TODO: this is a workaround for memory bugs triggered by the removal of | ||
| 96 | /// Decl.value_arena. A better solution needs to be found. Probably this will | ||
| 97 | /// involve transitioning comptime-mutable memory away from using Decls at all. | ||
| 98 | comptime_mutable_decls: *std.ArrayList(Decl.Index), | ||
| 88 | 99 | ||
| 89 | const std = @import("std"); | 100 | const std = @import("std"); |
| 90 | const math = std.math; | 101 | const math = std.math; |
| 91 | const mem = std.mem; | 102 | const mem = std.mem; |
| 92 | const Allocator = std.mem.Allocator; | 103 | const Allocator = mem.Allocator; |
| 93 | const assert = std.debug.assert; | 104 | const assert = std.debug.assert; |
| 94 | const log = std.log.scoped(.sema); | 105 | const log = std.log.scoped(.sema); |
| 95 | 106 | ||
| ... | @@ -114,6 +125,7 @@ const Package = @import("Package.zig"); | ... | @@ -114,6 +125,7 @@ const Package = @import("Package.zig"); |
| 114 | const crash_report = @import("crash_report.zig"); | 125 | const crash_report = @import("crash_report.zig"); |
| 115 | const build_options = @import("build_options"); | 126 | const build_options = @import("build_options"); |
| 116 | const Compilation = @import("Compilation.zig"); | 127 | const Compilation = @import("Compilation.zig"); |
| 128 | const InternPool = @import("InternPool.zig"); | ||
| 117 | 129 | ||
| 118 | pub const default_branch_quota = 1000; | 130 | pub const default_branch_quota = 1000; |
| 119 | pub const default_reference_trace_len = 2; | 131 | pub const default_reference_trace_len = 2; |
| ... | @@ -226,7 +238,7 @@ pub const Block = struct { | ... | @@ -226,7 +238,7 @@ pub const Block = struct { |
| 226 | sema: *Sema, | 238 | sema: *Sema, |
| 227 | /// The namespace to use for lookups from this source block | 239 | /// The namespace to use for lookups from this source block |
| 228 | /// When analyzing fields, this is different from src_decl.src_namespace. | 240 | /// When analyzing fields, this is different from src_decl.src_namespace. |
| 229 | namespace: *Namespace, | 241 | namespace: Namespace.Index, |
| 230 | /// The AIR instructions generated for this block. | 242 | /// The AIR instructions generated for this block. |
| 231 | instructions: std.ArrayListUnmanaged(Air.Inst.Index), | 243 | instructions: std.ArrayListUnmanaged(Air.Inst.Index), |
| 232 | // `param` instructions are collected here to be used by the `func` instruction. | 244 | // `param` instructions are collected here to be used by the `func` instruction. |
| ... | @@ -285,6 +297,7 @@ pub const Block = struct { | ... | @@ -285,6 +297,7 @@ pub const Block = struct { |
| 285 | 297 | ||
| 286 | fn explain(cr: ComptimeReason, sema: *Sema, msg: ?*Module.ErrorMsg) !void { | 298 | fn explain(cr: ComptimeReason, sema: *Sema, msg: ?*Module.ErrorMsg) !void { |
| 287 | const parent = msg orelse return; | 299 | const parent = msg orelse return; |
| 300 | const mod = sema.mod; | ||
| 288 | const prefix = "expression is evaluated at comptime because "; | 301 | const prefix = "expression is evaluated at comptime because "; |
| 289 | switch (cr) { | 302 | switch (cr) { |
| 290 | .c_import => |ci| { | 303 | .c_import => |ci| { |
| ... | @@ -292,21 +305,21 @@ pub const Block = struct { | ... | @@ -292,21 +305,21 @@ pub const Block = struct { |
| 292 | }, | 305 | }, |
| 293 | .comptime_ret_ty => |rt| { | 306 | .comptime_ret_ty => |rt| { |
| 294 | const src_loc = if (try sema.funcDeclSrc(rt.func)) |fn_decl| blk: { | 307 | const src_loc = if (try sema.funcDeclSrc(rt.func)) |fn_decl| blk: { |
| 295 | var src_loc = fn_decl.srcLoc(); | 308 | var src_loc = fn_decl.srcLoc(mod); |
| 296 | src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 }; | 309 | src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 297 | break :blk src_loc; | 310 | break :blk src_loc; |
| 298 | } else blk: { | 311 | } else blk: { |
| 299 | const src_decl = sema.mod.declPtr(rt.block.src_decl); | 312 | const src_decl = mod.declPtr(rt.block.src_decl); |
| 300 | break :blk rt.func_src.toSrcLoc(src_decl); | 313 | break :blk rt.func_src.toSrcLoc(src_decl, mod); |
| 301 | }; | 314 | }; |
| 302 | if (rt.return_ty.tag() == .generic_poison) { | 315 | if (rt.return_ty.isGenericPoison()) { |
| 303 | return sema.mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{}); | 316 | return mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{}); |
| 304 | } | 317 | } |
| 305 | try sema.mod.errNoteNonLazy( | 318 | try mod.errNoteNonLazy( |
| 306 | src_loc, | 319 | src_loc, |
| 307 | parent, | 320 | parent, |
| 308 | prefix ++ "the function returns a comptime-only type '{}'", | 321 | prefix ++ "the function returns a comptime-only type '{}'", |
| 309 | .{rt.return_ty.fmt(sema.mod)}, | 322 | .{rt.return_ty.fmt(mod)}, |
| 310 | ); | 323 | ); |
| 311 | try sema.explainWhyTypeIsComptime(parent, src_loc, rt.return_ty); | 324 | try sema.explainWhyTypeIsComptime(parent, src_loc, rt.return_ty); |
| 312 | }, | 325 | }, |
| ... | @@ -398,8 +411,8 @@ pub const Block = struct { | ... | @@ -398,8 +411,8 @@ pub const Block = struct { |
| 398 | }; | 411 | }; |
| 399 | } | 412 | } |
| 400 | 413 | ||
| 401 | pub fn getFileScope(block: *Block) *Module.File { | 414 | pub fn getFileScope(block: *Block, mod: *Module) *Module.File { |
| 402 | return block.namespace.file_scope; | 415 | return mod.namespacePtr(block.namespace).file_scope; |
| 403 | } | 416 | } |
| 404 | 417 | ||
| 405 | fn addTy( | 418 | fn addTy( |
| ... | @@ -584,13 +597,18 @@ pub const Block = struct { | ... | @@ -584,13 +597,18 @@ pub const Block = struct { |
| 584 | } | 597 | } |
| 585 | 598 | ||
| 586 | fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator) !Air.Inst.Ref { | 599 | fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator) !Air.Inst.Ref { |
| 600 | const sema = block.sema; | ||
| 601 | const mod = sema.mod; | ||
| 587 | return block.addInst(.{ | 602 | return block.addInst(.{ |
| 588 | .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector, | 603 | .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector, |
| 589 | .data = .{ .ty_pl = .{ | 604 | .data = .{ .ty_pl = .{ |
| 590 | .ty = try block.sema.addType( | 605 | .ty = try sema.addType( |
| 591 | try Type.vector(block.sema.arena, block.sema.typeOf(lhs).vectorLen(), Type.bool), | 606 | try mod.vectorType(.{ |
| 607 | .len = sema.typeOf(lhs).vectorLen(mod), | ||
| 608 | .child = .bool_type, | ||
| 609 | }), | ||
| 592 | ), | 610 | ), |
| 593 | .payload = try block.sema.addExtra(Air.VectorCmp{ | 611 | .payload = try sema.addExtra(Air.VectorCmp{ |
| 594 | .lhs = lhs, | 612 | .lhs = lhs, |
| 595 | .rhs = rhs, | 613 | .rhs = rhs, |
| 596 | .op = Air.VectorCmp.encodeOp(cmp_op), | 614 | .op = Air.VectorCmp.encodeOp(cmp_op), |
| ... | @@ -684,29 +702,20 @@ pub const Block = struct { | ... | @@ -684,29 +702,20 @@ pub const Block = struct { |
| 684 | pub fn startAnonDecl(block: *Block) !WipAnonDecl { | 702 | pub fn startAnonDecl(block: *Block) !WipAnonDecl { |
| 685 | return WipAnonDecl{ | 703 | return WipAnonDecl{ |
| 686 | .block = block, | 704 | .block = block, |
| 687 | .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa), | ||
| 688 | .finished = false, | 705 | .finished = false, |
| 689 | }; | 706 | }; |
| 690 | } | 707 | } |
| 691 | 708 | ||
| 692 | pub const WipAnonDecl = struct { | 709 | pub const WipAnonDecl = struct { |
| 693 | block: *Block, | 710 | block: *Block, |
| 694 | new_decl_arena: std.heap.ArenaAllocator, | ||
| 695 | finished: bool, | 711 | finished: bool, |
| 696 | 712 | ||
| 697 | pub fn arena(wad: *WipAnonDecl) Allocator { | ||
| 698 | return wad.new_decl_arena.allocator(); | ||
| 699 | } | ||
| 700 | |||
| 701 | pub fn deinit(wad: *WipAnonDecl) void { | 713 | pub fn deinit(wad: *WipAnonDecl) void { |
| 702 | if (!wad.finished) { | ||
| 703 | wad.new_decl_arena.deinit(); | ||
| 704 | } | ||
| 705 | wad.* = undefined; | 714 | wad.* = undefined; |
| 706 | } | 715 | } |
| 707 | 716 | ||
| 708 | /// `alignment` value of 0 means to use ABI alignment. | 717 | /// `alignment` value of 0 means to use ABI alignment. |
| 709 | pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value, alignment: u32) !Decl.Index { | 718 | pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value, alignment: u64) !Decl.Index { |
| 710 | const sema = wad.block.sema; | 719 | const sema = wad.block.sema; |
| 711 | // Do this ahead of time because `createAnonymousDecl` depends on calling | 720 | // Do this ahead of time because `createAnonymousDecl` depends on calling |
| 712 | // `type.hasRuntimeBits()`. | 721 | // `type.hasRuntimeBits()`. |
| ... | @@ -716,10 +725,11 @@ pub const Block = struct { | ... | @@ -716,10 +725,11 @@ pub const Block = struct { |
| 716 | .val = val, | 725 | .val = val, |
| 717 | }); | 726 | }); |
| 718 | const new_decl = sema.mod.declPtr(new_decl_index); | 727 | const new_decl = sema.mod.declPtr(new_decl_index); |
| 719 | new_decl.@"align" = alignment; | 728 | // TODO: migrate Decl alignment to use `InternPool.Alignment` |
| 729 | new_decl.@"align" = @intCast(u32, alignment); | ||
| 720 | errdefer sema.mod.abortAnonDecl(new_decl_index); | 730 | errdefer sema.mod.abortAnonDecl(new_decl_index); |
| 721 | try new_decl.finalizeNewArena(&wad.new_decl_arena); | ||
| 722 | wad.finished = true; | 731 | wad.finished = true; |
| 732 | try sema.mod.finalizeAnonDecl(new_decl_index); | ||
| 723 | return new_decl_index; | 733 | return new_decl_index; |
| 724 | } | 734 | } |
| 725 | }; | 735 | }; |
| ... | @@ -736,11 +746,27 @@ const LabeledBlock = struct { | ... | @@ -736,11 +746,27 @@ const LabeledBlock = struct { |
| 736 | } | 746 | } |
| 737 | }; | 747 | }; |
| 738 | 748 | ||
| 749 | /// The value stored in the inferred allocation. This will go into | ||
| 750 | /// peer type resolution. This is stored in a separate list so that | ||
| 751 | /// the items are contiguous in memory and thus can be passed to | ||
| 752 | /// `Module.resolvePeerTypes`. | ||
| 753 | const InferredAlloc = struct { | ||
| 754 | prongs: std.MultiArrayList(struct { | ||
| 755 | /// The dummy instruction used as a peer to resolve the type. | ||
| 756 | /// Although this has a redundant type with placeholder, this is | ||
| 757 | /// needed in addition because it may be a constant value, which | ||
| 758 | /// affects peer type resolution. | ||
| 759 | stored_inst: Air.Inst.Ref, | ||
| 760 | /// The bitcast instruction used as a placeholder when the | ||
| 761 | /// new result pointer type is not yet known. | ||
| 762 | placeholder: Air.Inst.Index, | ||
| 763 | }) = .{}, | ||
| 764 | }; | ||
| 765 | |||
| 739 | pub fn deinit(sema: *Sema) void { | 766 | pub fn deinit(sema: *Sema) void { |
| 740 | const gpa = sema.gpa; | 767 | const gpa = sema.gpa; |
| 741 | sema.air_instructions.deinit(gpa); | 768 | sema.air_instructions.deinit(gpa); |
| 742 | sema.air_extra.deinit(gpa); | 769 | sema.air_extra.deinit(gpa); |
| 743 | sema.air_values.deinit(gpa); | ||
| 744 | sema.inst_map.deinit(gpa); | 770 | sema.inst_map.deinit(gpa); |
| 745 | sema.decl_val_table.deinit(gpa); | 771 | sema.decl_val_table.deinit(gpa); |
| 746 | sema.types_to_resolve.deinit(gpa); | 772 | sema.types_to_resolve.deinit(gpa); |
| ... | @@ -823,7 +849,7 @@ pub fn analyzeBodyBreak( | ... | @@ -823,7 +849,7 @@ pub fn analyzeBodyBreak( |
| 823 | else => |e| return e, | 849 | else => |e| return e, |
| 824 | }; | 850 | }; |
| 825 | if (block.instructions.items.len != 0 and | 851 | if (block.instructions.items.len != 0 and |
| 826 | sema.typeOf(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])).isNoReturn()) | 852 | sema.isNoReturn(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1]))) |
| 827 | return null; | 853 | return null; |
| 828 | const break_data = sema.code.instructions.items(.data)[break_inst].@"break"; | 854 | const break_data = sema.code.instructions.items(.data)[break_inst].@"break"; |
| 829 | const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data; | 855 | const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data; |
| ... | @@ -858,18 +884,20 @@ fn analyzeBodyInner( | ... | @@ -858,18 +884,20 @@ fn analyzeBodyInner( |
| 858 | 884 | ||
| 859 | try sema.inst_map.ensureSpaceForInstructions(sema.gpa, body); | 885 | try sema.inst_map.ensureSpaceForInstructions(sema.gpa, body); |
| 860 | 886 | ||
| 887 | // Most of the time, we don't need to construct a new capture scope for a | ||
| 888 | // block. However, successive iterations of comptime loops can capture | ||
| 889 | // different values for the same Zir.Inst.Index, so in those cases, we will | ||
| 890 | // have to create nested capture scopes; see the `.repeat` case below. | ||
| 861 | const parent_capture_scope = block.wip_capture_scope; | 891 | const parent_capture_scope = block.wip_capture_scope; |
| 862 | 892 | parent_capture_scope.incRef(); | |
| 863 | var wip_captures = WipCaptureScope{ | 893 | var wip_captures: WipCaptureScope = .{ |
| 864 | .finalized = true, | ||
| 865 | .scope = parent_capture_scope, | 894 | .scope = parent_capture_scope, |
| 866 | .perm_arena = sema.perm_arena, | ||
| 867 | .gpa = sema.gpa, | 895 | .gpa = sema.gpa, |
| 896 | .finalized = true, // don't finalize the parent scope | ||
| 868 | }; | 897 | }; |
| 869 | defer if (wip_captures.scope != parent_capture_scope) { | 898 | defer wip_captures.deinit(); |
| 870 | wip_captures.deinit(); | ||
| 871 | }; | ||
| 872 | 899 | ||
| 900 | const mod = sema.mod; | ||
| 873 | const map = &sema.inst_map; | 901 | const map = &sema.inst_map; |
| 874 | const tags = sema.code.instructions.items(.tag); | 902 | const tags = sema.code.instructions.items(.tag); |
| 875 | const datas = sema.code.instructions.items(.data); | 903 | const datas = sema.code.instructions.items(.data); |
| ... | @@ -890,15 +918,15 @@ fn analyzeBodyInner( | ... | @@ -890,15 +918,15 @@ fn analyzeBodyInner( |
| 890 | crash_info.setBodyIndex(i); | 918 | crash_info.setBodyIndex(i); |
| 891 | const inst = body[i]; | 919 | const inst = body[i]; |
| 892 | std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{ | 920 | std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{ |
| 893 | sema.mod.declPtr(block.src_decl).src_namespace.file_scope.sub_file_path, inst, | 921 | mod.namespacePtr(mod.declPtr(block.src_decl).src_namespace).file_scope.sub_file_path, inst, |
| 894 | }); | 922 | }); |
| 895 | const air_inst: Air.Inst.Ref = switch (tags[inst]) { | 923 | const air_inst: Air.Inst.Ref = switch (tags[inst]) { |
| 896 | // zig fmt: off | 924 | // zig fmt: off |
| 897 | .alloc => try sema.zirAlloc(block, inst), | 925 | .alloc => try sema.zirAlloc(block, inst), |
| 898 | .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)), | 926 | .alloc_inferred => try sema.zirAllocInferred(block, inst, true), |
| 899 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)), | 927 | .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, false), |
| 900 | .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_const)), | 928 | .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst, true), |
| 901 | .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_mut)), | 929 | .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(inst, false), |
| 902 | .alloc_mut => try sema.zirAllocMut(block, inst), | 930 | .alloc_mut => try sema.zirAllocMut(block, inst), |
| 903 | .alloc_comptime_mut => try sema.zirAllocComptime(block, inst), | 931 | .alloc_comptime_mut => try sema.zirAllocComptime(block, inst), |
| 904 | .make_ptr_const => try sema.zirMakePtrConst(block, inst), | 932 | .make_ptr_const => try sema.zirMakePtrConst(block, inst), |
| ... | @@ -962,7 +990,7 @@ fn analyzeBodyInner( | ... | @@ -962,7 +990,7 @@ fn analyzeBodyInner( |
| 962 | .int_big => try sema.zirIntBig(block, inst), | 990 | .int_big => try sema.zirIntBig(block, inst), |
| 963 | .float => try sema.zirFloat(block, inst), | 991 | .float => try sema.zirFloat(block, inst), |
| 964 | .float128 => try sema.zirFloat128(block, inst), | 992 | .float128 => try sema.zirFloat128(block, inst), |
| 965 | .int_type => try sema.zirIntType(block, inst), | 993 | .int_type => try sema.zirIntType(inst), |
| 966 | .is_non_err => try sema.zirIsNonErr(block, inst), | 994 | .is_non_err => try sema.zirIsNonErr(block, inst), |
| 967 | .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), | 995 | .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), |
| 968 | .ret_is_non_err => try sema.zirRetIsNonErr(block, inst), | 996 | .ret_is_non_err => try sema.zirRetIsNonErr(block, inst), |
| ... | @@ -1420,6 +1448,11 @@ fn analyzeBodyInner( | ... | @@ -1420,6 +1448,11 @@ fn analyzeBodyInner( |
| 1420 | const src = LazySrcLoc.nodeOffset(datas[inst].node); | 1448 | const src = LazySrcLoc.nodeOffset(datas[inst].node); |
| 1421 | try sema.emitBackwardBranch(block, src); | 1449 | try sema.emitBackwardBranch(block, src); |
| 1422 | if (wip_captures.scope.captures.count() != orig_captures) { | 1450 | if (wip_captures.scope.captures.count() != orig_captures) { |
| 1451 | // We need to construct new capture scopes for the next loop iteration so it | ||
| 1452 | // can capture values without clobbering the earlier iteration's captures. | ||
| 1453 | // At first, we reused the parent capture scope as an optimization, but for | ||
| 1454 | // successive scopes we have to create new ones as children of the parent | ||
| 1455 | // scope. | ||
| 1423 | try wip_captures.reset(parent_capture_scope); | 1456 | try wip_captures.reset(parent_capture_scope); |
| 1424 | block.wip_capture_scope = wip_captures.scope; | 1457 | block.wip_capture_scope = wip_captures.scope; |
| 1425 | orig_captures = 0; | 1458 | orig_captures = 0; |
| ... | @@ -1435,6 +1468,11 @@ fn analyzeBodyInner( | ... | @@ -1435,6 +1468,11 @@ fn analyzeBodyInner( |
| 1435 | const src = LazySrcLoc.nodeOffset(datas[inst].node); | 1468 | const src = LazySrcLoc.nodeOffset(datas[inst].node); |
| 1436 | try sema.emitBackwardBranch(block, src); | 1469 | try sema.emitBackwardBranch(block, src); |
| 1437 | if (wip_captures.scope.captures.count() != orig_captures) { | 1470 | if (wip_captures.scope.captures.count() != orig_captures) { |
| 1471 | // We need to construct new capture scopes for the next loop iteration so it | ||
| 1472 | // can capture values without clobbering the earlier iteration's captures. | ||
| 1473 | // At first, we reused the parent capture scope as an optimization, but for | ||
| 1474 | // successive scopes we have to create new ones as children of the parent | ||
| 1475 | // scope. | ||
| 1438 | try wip_captures.reset(parent_capture_scope); | 1476 | try wip_captures.reset(parent_capture_scope); |
| 1439 | block.wip_capture_scope = wip_captures.scope; | 1477 | block.wip_capture_scope = wip_captures.scope; |
| 1440 | orig_captures = 0; | 1478 | orig_captures = 0; |
| ... | @@ -1621,18 +1659,18 @@ fn analyzeBodyInner( | ... | @@ -1621,18 +1659,18 @@ fn analyzeBodyInner( |
| 1621 | const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; | 1659 | const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 1622 | const err_union = try sema.resolveInst(extra.data.operand); | 1660 | const err_union = try sema.resolveInst(extra.data.operand); |
| 1623 | const err_union_ty = sema.typeOf(err_union); | 1661 | const err_union_ty = sema.typeOf(err_union); |
| 1624 | if (err_union_ty.zigTypeTag() != .ErrorUnion) { | 1662 | if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) { |
| 1625 | return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ | 1663 | return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ |
| 1626 | err_union_ty.fmt(sema.mod), | 1664 | err_union_ty.fmt(mod), |
| 1627 | }); | 1665 | }); |
| 1628 | } | 1666 | } |
| 1629 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); | 1667 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); |
| 1630 | assert(is_non_err != .none); | 1668 | assert(is_non_err != .none); |
| 1631 | const is_non_err_tv = sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| { | 1669 | const is_non_err_val = sema.resolveConstValue(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| { |
| 1632 | if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err); | 1670 | if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err); |
| 1633 | return err; | 1671 | return err; |
| 1634 | }; | 1672 | }; |
| 1635 | if (is_non_err_tv.val.toBool()) { | 1673 | if (is_non_err_val.toBool()) { |
| 1636 | break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false); | 1674 | break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false); |
| 1637 | } | 1675 | } |
| 1638 | const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse | 1676 | const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse |
| ... | @@ -1654,11 +1692,11 @@ fn analyzeBodyInner( | ... | @@ -1654,11 +1692,11 @@ fn analyzeBodyInner( |
| 1654 | const err_union = try sema.analyzeLoad(block, src, operand, operand_src); | 1692 | const err_union = try sema.analyzeLoad(block, src, operand, operand_src); |
| 1655 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); | 1693 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union); |
| 1656 | assert(is_non_err != .none); | 1694 | assert(is_non_err != .none); |
| 1657 | const is_non_err_tv = sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| { | 1695 | const is_non_err_val = sema.resolveConstValue(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| { |
| 1658 | if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err); | 1696 | if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err); |
| 1659 | return err; | 1697 | return err; |
| 1660 | }; | 1698 | }; |
| 1661 | if (is_non_err_tv.val.toBool()) { | 1699 | if (is_non_err_val.toBool()) { |
| 1662 | break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); | 1700 | break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); |
| 1663 | } | 1701 | } |
| 1664 | const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse | 1702 | const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse |
| ... | @@ -1684,7 +1722,7 @@ fn analyzeBodyInner( | ... | @@ -1684,7 +1722,7 @@ fn analyzeBodyInner( |
| 1684 | const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data; | 1722 | const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data; |
| 1685 | const defer_body = sema.code.extra[extra.index..][0..extra.len]; | 1723 | const defer_body = sema.code.extra[extra.index..][0..extra.len]; |
| 1686 | const err_code = try sema.resolveInst(inst_data.err_code); | 1724 | const err_code = try sema.resolveInst(inst_data.err_code); |
| 1687 | sema.inst_map.putAssumeCapacity(extra.remapped_err_code, err_code); | 1725 | map.putAssumeCapacity(extra.remapped_err_code, err_code); |
| 1688 | const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) { | 1726 | const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) { |
| 1689 | error.ComptimeBreak => sema.comptime_break_inst, | 1727 | error.ComptimeBreak => sema.comptime_break_inst, |
| 1690 | else => |e| return e, | 1728 | else => |e| return e, |
| ... | @@ -1693,8 +1731,12 @@ fn analyzeBodyInner( | ... | @@ -1693,8 +1731,12 @@ fn analyzeBodyInner( |
| 1693 | break :blk Air.Inst.Ref.void_value; | 1731 | break :blk Air.Inst.Ref.void_value; |
| 1694 | }, | 1732 | }, |
| 1695 | }; | 1733 | }; |
| 1696 | if (sema.typeOf(air_inst).isNoReturn()) | 1734 | if (sema.isNoReturn(air_inst)) { |
| 1735 | // We're going to assume that the body itself is noreturn, so let's ensure that now | ||
| 1736 | assert(block.instructions.items.len > 0); | ||
| 1737 | assert(sema.isNoReturn(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1]))); | ||
| 1697 | break always_noreturn; | 1738 | break always_noreturn; |
| 1739 | } | ||
| 1698 | map.putAssumeCapacity(inst, air_inst); | 1740 | map.putAssumeCapacity(inst, air_inst); |
| 1699 | i += 1; | 1741 | i += 1; |
| 1700 | }; | 1742 | }; |
| ... | @@ -1703,7 +1745,7 @@ fn analyzeBodyInner( | ... | @@ -1703,7 +1745,7 @@ fn analyzeBodyInner( |
| 1703 | const noreturn_inst = block.instructions.popOrNull(); | 1745 | const noreturn_inst = block.instructions.popOrNull(); |
| 1704 | while (dbg_block_begins > 0) { | 1746 | while (dbg_block_begins > 0) { |
| 1705 | dbg_block_begins -= 1; | 1747 | dbg_block_begins -= 1; |
| 1706 | if (block.is_comptime or sema.mod.comp.bin_file.options.strip) continue; | 1748 | if (block.is_comptime or mod.comp.bin_file.options.strip) continue; |
| 1707 | 1749 | ||
| 1708 | _ = try block.addInst(.{ | 1750 | _ = try block.addInst(.{ |
| 1709 | .tag = .dbg_block_end, | 1751 | .tag = .dbg_block_end, |
| ... | @@ -1713,6 +1755,8 @@ fn analyzeBodyInner( | ... | @@ -1713,6 +1755,8 @@ fn analyzeBodyInner( |
| 1713 | if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); | 1755 | if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); |
| 1714 | 1756 | ||
| 1715 | if (!wip_captures.finalized) { | 1757 | if (!wip_captures.finalized) { |
| 1758 | // We've updated the capture scope due to a `repeat` instruction where | ||
| 1759 | // the body had a capture; finalize our child scope and reset | ||
| 1716 | try wip_captures.finalize(); | 1760 | try wip_captures.finalize(); |
| 1717 | block.wip_capture_scope = parent_capture_scope; | 1761 | block.wip_capture_scope = parent_capture_scope; |
| 1718 | } | 1762 | } |
| ... | @@ -1720,20 +1764,23 @@ fn analyzeBodyInner( | ... | @@ -1720,20 +1764,23 @@ fn analyzeBodyInner( |
| 1720 | return result; | 1764 | return result; |
| 1721 | } | 1765 | } |
| 1722 | 1766 | ||
| 1723 | pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { | 1767 | pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { |
| 1724 | var i: usize = @enumToInt(zir_ref); | 1768 | if (zir_ref == .none) { |
| 1725 | 1769 | return .none; | |
| 1726 | // First section of indexes correspond to a set number of constant values. | 1770 | } else { |
| 1727 | if (i < Zir.Inst.Ref.typed_value_map.len) { | 1771 | return resolveInst(sema, zir_ref); |
| 1728 | // We intentionally map the same indexes to the same values between ZIR and AIR. | ||
| 1729 | return zir_ref; | ||
| 1730 | } | 1772 | } |
| 1731 | i -= Zir.Inst.Ref.typed_value_map.len; | 1773 | } |
| 1732 | 1774 | ||
| 1733 | // Finally, the last section of indexes refers to the map of ZIR=>AIR. | 1775 | pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref { |
| 1734 | const inst = sema.inst_map.get(@intCast(u32, i)).?; | 1776 | assert(zir_ref != .none); |
| 1735 | const ty = sema.typeOf(inst); | 1777 | const i = @enumToInt(zir_ref); |
| 1736 | if (ty.tag() == .generic_poison) return error.GenericPoison; | 1778 | // First section of indexes correspond to a set number of constant values. |
| 1779 | // We intentionally map the same indexes to the same values between ZIR and AIR. | ||
| 1780 | if (i < InternPool.static_len) return @intToEnum(Air.Inst.Ref, i); | ||
| 1781 | // The last section of indexes refers to the map of ZIR => AIR. | ||
| 1782 | const inst = sema.inst_map.get(i - InternPool.static_len).?; | ||
| 1783 | if (inst == .generic_poison) return error.GenericPoison; | ||
| 1737 | return inst; | 1784 | return inst; |
| 1738 | } | 1785 | } |
| 1739 | 1786 | ||
| ... | @@ -1759,18 +1806,31 @@ pub fn resolveConstString( | ... | @@ -1759,18 +1806,31 @@ pub fn resolveConstString( |
| 1759 | reason: []const u8, | 1806 | reason: []const u8, |
| 1760 | ) ![]u8 { | 1807 | ) ![]u8 { |
| 1761 | const air_inst = try sema.resolveInst(zir_ref); | 1808 | const air_inst = try sema.resolveInst(zir_ref); |
| 1762 | const wanted_type = Type.initTag(.const_slice_u8); | 1809 | const wanted_type = Type.slice_const_u8; |
| 1763 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); | 1810 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); |
| 1764 | const val = try sema.resolveConstValue(block, src, coerced_inst, reason); | 1811 | const val = try sema.resolveConstValue(block, src, coerced_inst, reason); |
| 1765 | return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod); | 1812 | return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod); |
| 1766 | } | 1813 | } |
| 1767 | 1814 | ||
| 1815 | pub fn resolveConstStringIntern( | ||
| 1816 | sema: *Sema, | ||
| 1817 | block: *Block, | ||
| 1818 | src: LazySrcLoc, | ||
| 1819 | zir_ref: Zir.Inst.Ref, | ||
| 1820 | reason: []const u8, | ||
| 1821 | ) !InternPool.NullTerminatedString { | ||
| 1822 | const air_inst = try sema.resolveInst(zir_ref); | ||
| 1823 | const wanted_type = Type.slice_const_u8; | ||
| 1824 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); | ||
| 1825 | const val = try sema.resolveConstValue(block, src, coerced_inst, reason); | ||
| 1826 | return val.toIpString(wanted_type, sema.mod); | ||
| 1827 | } | ||
| 1828 | |||
| 1768 | pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { | 1829 | pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { |
| 1769 | assert(zir_ref != .var_args_param); | ||
| 1770 | const air_inst = try sema.resolveInst(zir_ref); | 1830 | const air_inst = try sema.resolveInst(zir_ref); |
| 1771 | assert(air_inst != .var_args_param); | 1831 | assert(air_inst != .var_args_param_type); |
| 1772 | const ty = try sema.analyzeAsType(block, src, air_inst); | 1832 | const ty = try sema.analyzeAsType(block, src, air_inst); |
| 1773 | if (ty.tag() == .generic_poison) return error.GenericPoison; | 1833 | if (ty.isGenericPoison()) return error.GenericPoison; |
| 1774 | return ty; | 1834 | return ty; |
| 1775 | } | 1835 | } |
| 1776 | 1836 | ||
| ... | @@ -1780,45 +1840,48 @@ fn analyzeAsType( | ... | @@ -1780,45 +1840,48 @@ fn analyzeAsType( |
| 1780 | src: LazySrcLoc, | 1840 | src: LazySrcLoc, |
| 1781 | air_inst: Air.Inst.Ref, | 1841 | air_inst: Air.Inst.Ref, |
| 1782 | ) !Type { | 1842 | ) !Type { |
| 1783 | const wanted_type = Type.initTag(.type); | 1843 | const wanted_type = Type.type; |
| 1784 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); | 1844 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); |
| 1785 | const val = try sema.resolveConstValue(block, src, coerced_inst, "types must be comptime-known"); | 1845 | const val = try sema.resolveConstValue(block, src, coerced_inst, "types must be comptime-known"); |
| 1786 | var buffer: Value.ToTypeBuffer = undefined; | 1846 | return val.toType(); |
| 1787 | const ty = val.toType(&buffer); | ||
| 1788 | return ty.copy(sema.arena); | ||
| 1789 | } | 1847 | } |
| 1790 | 1848 | ||
| 1791 | pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void { | 1849 | pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void { |
| 1792 | if (!sema.mod.backendSupportsFeature(.error_return_trace)) return; | 1850 | const mod = sema.mod; |
| 1851 | const gpa = sema.gpa; | ||
| 1852 | const ip = &mod.intern_pool; | ||
| 1853 | if (!mod.backendSupportsFeature(.error_return_trace)) return; | ||
| 1793 | 1854 | ||
| 1794 | assert(!block.is_comptime); | 1855 | assert(!block.is_comptime); |
| 1795 | var err_trace_block = block.makeSubBlock(); | 1856 | var err_trace_block = block.makeSubBlock(); |
| 1796 | defer err_trace_block.instructions.deinit(sema.gpa); | 1857 | defer err_trace_block.instructions.deinit(gpa); |
| 1797 | 1858 | ||
| 1798 | const src: LazySrcLoc = .unneeded; | 1859 | const src: LazySrcLoc = .unneeded; |
| 1799 | 1860 | ||
| 1800 | // var addrs: [err_return_trace_addr_count]usize = undefined; | 1861 | // var addrs: [err_return_trace_addr_count]usize = undefined; |
| 1801 | const err_return_trace_addr_count = 32; | 1862 | const err_return_trace_addr_count = 32; |
| 1802 | const addr_arr_ty = try Type.array(sema.arena, err_return_trace_addr_count, null, Type.usize, sema.mod); | 1863 | const addr_arr_ty = try Type.array(sema.arena, err_return_trace_addr_count, null, Type.usize, mod); |
| 1803 | const addrs_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, addr_arr_ty)); | 1864 | const addrs_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(addr_arr_ty)); |
| 1804 | 1865 | ||
| 1805 | // var st: StackTrace = undefined; | 1866 | // var st: StackTrace = undefined; |
| 1806 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); | 1867 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 1807 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); | 1868 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); |
| 1808 | const st_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty)); | 1869 | const st_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(stack_trace_ty)); |
| 1809 | 1870 | ||
| 1810 | // st.instruction_addresses = &addrs; | 1871 | // st.instruction_addresses = &addrs; |
| 1811 | const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src, true); | 1872 | const instruction_addresses_field_name = try ip.getOrPutString(gpa, "instruction_addresses"); |
| 1873 | const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, instruction_addresses_field_name, src, true); | ||
| 1812 | try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store); | 1874 | try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store); |
| 1813 | 1875 | ||
| 1814 | // st.index = 0; | 1876 | // st.index = 0; |
| 1815 | const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true); | 1877 | const index_field_name = try ip.getOrPutString(gpa, "index"); |
| 1878 | const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, index_field_name, src, true); | ||
| 1816 | try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store); | 1879 | try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store); |
| 1817 | 1880 | ||
| 1818 | // @errorReturnTrace() = &st; | 1881 | // @errorReturnTrace() = &st; |
| 1819 | _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr); | 1882 | _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr); |
| 1820 | 1883 | ||
| 1821 | try block.instructions.insertSlice(sema.gpa, last_arg_index, err_trace_block.instructions.items); | 1884 | try block.instructions.insertSlice(gpa, last_arg_index, err_trace_block.instructions.items); |
| 1822 | } | 1885 | } |
| 1823 | 1886 | ||
| 1824 | /// May return Value Tags: `variable`, `undef`. | 1887 | /// May return Value Tags: `variable`, `undef`. |
| ... | @@ -1832,7 +1895,7 @@ fn resolveValue( | ... | @@ -1832,7 +1895,7 @@ fn resolveValue( |
| 1832 | reason: []const u8, | 1895 | reason: []const u8, |
| 1833 | ) CompileError!Value { | 1896 | ) CompileError!Value { |
| 1834 | if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| { | 1897 | if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| { |
| 1835 | if (val.tag() == .generic_poison) return error.GenericPoison; | 1898 | if (val.isGenericPoison()) return error.GenericPoison; |
| 1836 | return val; | 1899 | return val; |
| 1837 | } | 1900 | } |
| 1838 | return sema.failWithNeededComptime(block, src, reason); | 1901 | return sema.failWithNeededComptime(block, src, reason); |
| ... | @@ -1848,10 +1911,12 @@ fn resolveConstMaybeUndefVal( | ... | @@ -1848,10 +1911,12 @@ fn resolveConstMaybeUndefVal( |
| 1848 | reason: []const u8, | 1911 | reason: []const u8, |
| 1849 | ) CompileError!Value { | 1912 | ) CompileError!Value { |
| 1850 | if (try sema.resolveMaybeUndefValAllowVariables(inst)) |val| { | 1913 | if (try sema.resolveMaybeUndefValAllowVariables(inst)) |val| { |
| 1851 | switch (val.tag()) { | 1914 | switch (val.toIntern()) { |
| 1852 | .variable => return sema.failWithNeededComptime(block, src, reason), | ||
| 1853 | .generic_poison => return error.GenericPoison, | 1915 | .generic_poison => return error.GenericPoison, |
| 1854 | else => return val, | 1916 | else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) { |
| 1917 | .variable => return sema.failWithNeededComptime(block, src, reason), | ||
| 1918 | else => return val, | ||
| 1919 | }, | ||
| 1855 | } | 1920 | } |
| 1856 | } | 1921 | } |
| 1857 | return sema.failWithNeededComptime(block, src, reason); | 1922 | return sema.failWithNeededComptime(block, src, reason); |
| ... | @@ -1867,16 +1932,31 @@ fn resolveConstValue( | ... | @@ -1867,16 +1932,31 @@ fn resolveConstValue( |
| 1867 | reason: []const u8, | 1932 | reason: []const u8, |
| 1868 | ) CompileError!Value { | 1933 | ) CompileError!Value { |
| 1869 | if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| { | 1934 | if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| { |
| 1870 | switch (val.tag()) { | 1935 | switch (val.toIntern()) { |
| 1871 | .undef => return sema.failWithUseOfUndef(block, src), | ||
| 1872 | .variable => return sema.failWithNeededComptime(block, src, reason), | ||
| 1873 | .generic_poison => return error.GenericPoison, | 1936 | .generic_poison => return error.GenericPoison, |
| 1874 | else => return val, | 1937 | .undef => return sema.failWithUseOfUndef(block, src), |
| 1938 | else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) { | ||
| 1939 | .undef => return sema.failWithUseOfUndef(block, src), | ||
| 1940 | .variable => return sema.failWithNeededComptime(block, src, reason), | ||
| 1941 | else => return val, | ||
| 1942 | }, | ||
| 1875 | } | 1943 | } |
| 1876 | } | 1944 | } |
| 1877 | return sema.failWithNeededComptime(block, src, reason); | 1945 | return sema.failWithNeededComptime(block, src, reason); |
| 1878 | } | 1946 | } |
| 1879 | 1947 | ||
| 1948 | /// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors. | ||
| 1949 | /// Lazy values are recursively resolved. | ||
| 1950 | fn resolveConstLazyValue( | ||
| 1951 | sema: *Sema, | ||
| 1952 | block: *Block, | ||
| 1953 | src: LazySrcLoc, | ||
| 1954 | air_ref: Air.Inst.Ref, | ||
| 1955 | reason: []const u8, | ||
| 1956 | ) CompileError!Value { | ||
| 1957 | return sema.resolveLazyValue(try sema.resolveConstValue(block, src, air_ref, reason)); | ||
| 1958 | } | ||
| 1959 | |||
| 1880 | /// Value Tag `variable` causes this function to return `null`. | 1960 | /// Value Tag `variable` causes this function to return `null`. |
| 1881 | /// Value Tag `undef` causes this function to return a compile error. | 1961 | /// Value Tag `undef` causes this function to return a compile error. |
| 1882 | fn resolveDefinedValue( | 1962 | fn resolveDefinedValue( |
| ... | @@ -1885,8 +1965,9 @@ fn resolveDefinedValue( | ... | @@ -1885,8 +1965,9 @@ fn resolveDefinedValue( |
| 1885 | src: LazySrcLoc, | 1965 | src: LazySrcLoc, |
| 1886 | air_ref: Air.Inst.Ref, | 1966 | air_ref: Air.Inst.Ref, |
| 1887 | ) CompileError!?Value { | 1967 | ) CompileError!?Value { |
| 1968 | const mod = sema.mod; | ||
| 1888 | if (try sema.resolveMaybeUndefVal(air_ref)) |val| { | 1969 | if (try sema.resolveMaybeUndefVal(air_ref)) |val| { |
| 1889 | if (val.isUndef()) { | 1970 | if (val.isUndef(mod)) { |
| 1890 | if (block.is_typeof) return null; | 1971 | if (block.is_typeof) return null; |
| 1891 | return sema.failWithUseOfUndef(block, src); | 1972 | return sema.failWithUseOfUndef(block, src); |
| 1892 | } | 1973 | } |
| ... | @@ -1903,34 +1984,53 @@ fn resolveMaybeUndefVal( | ... | @@ -1903,34 +1984,53 @@ fn resolveMaybeUndefVal( |
| 1903 | inst: Air.Inst.Ref, | 1984 | inst: Air.Inst.Ref, |
| 1904 | ) CompileError!?Value { | 1985 | ) CompileError!?Value { |
| 1905 | const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null; | 1986 | const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null; |
| 1906 | switch (val.tag()) { | 1987 | switch (val.ip_index) { |
| 1907 | .variable => return null, | ||
| 1908 | .generic_poison => return error.GenericPoison, | 1988 | .generic_poison => return error.GenericPoison, |
| 1909 | else => return val, | 1989 | .none => return val, |
| 1990 | else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) { | ||
| 1991 | .variable => return null, | ||
| 1992 | else => return val, | ||
| 1993 | }, | ||
| 1910 | } | 1994 | } |
| 1911 | } | 1995 | } |
| 1912 | 1996 | ||
| 1997 | /// Value Tag `variable` causes this function to return `null`. | ||
| 1998 | /// Value Tag `undef` causes this function to return the Value. | ||
| 1999 | /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. | ||
| 2000 | /// Lazy values are recursively resolved. | ||
| 2001 | fn resolveMaybeUndefLazyVal( | ||
| 2002 | sema: *Sema, | ||
| 2003 | inst: Air.Inst.Ref, | ||
| 2004 | ) CompileError!?Value { | ||
| 2005 | return try sema.resolveLazyValue((try sema.resolveMaybeUndefVal(inst)) orelse return null); | ||
| 2006 | } | ||
| 2007 | |||
| 1913 | /// Value Tag `variable` results in `null`. | 2008 | /// Value Tag `variable` results in `null`. |
| 1914 | /// Value Tag `undef` results in the Value. | 2009 | /// Value Tag `undef` results in the Value. |
| 1915 | /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. | 2010 | /// Value Tag `generic_poison` causes `error.GenericPoison` to be returned. |
| 1916 | /// Value Tag `decl_ref` and `decl_ref_mut` or any nested such value results in `null`. | 2011 | /// Value Tag `decl_ref` and `decl_ref_mut` or any nested such value results in `null`. |
| 2012 | /// Lazy values are recursively resolved. | ||
| 1917 | fn resolveMaybeUndefValIntable( | 2013 | fn resolveMaybeUndefValIntable( |
| 1918 | sema: *Sema, | 2014 | sema: *Sema, |
| 1919 | inst: Air.Inst.Ref, | 2015 | inst: Air.Inst.Ref, |
| 1920 | ) CompileError!?Value { | 2016 | ) CompileError!?Value { |
| 1921 | const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null; | 2017 | const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null; |
| 1922 | var check = val; | 2018 | var check = val; |
| 1923 | while (true) switch (check.tag()) { | 2019 | while (true) switch (check.ip_index) { |
| 1924 | .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return null, | ||
| 1925 | .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr, | ||
| 1926 | .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr, | ||
| 1927 | .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr, | ||
| 1928 | .generic_poison => return error.GenericPoison, | 2020 | .generic_poison => return error.GenericPoison, |
| 1929 | else => { | 2021 | .none => break, |
| 1930 | try sema.resolveLazyValue(val); | 2022 | else => switch (sema.mod.intern_pool.indexToKey(check.toIntern())) { |
| 1931 | return val; | 2023 | .variable => return null, |
| 2024 | .ptr => |ptr| switch (ptr.addr) { | ||
| 2025 | .decl, .mut_decl, .comptime_field => return null, | ||
| 2026 | .int => break, | ||
| 2027 | .eu_payload, .opt_payload => |base| check = base.toValue(), | ||
| 2028 | .elem, .field => |base_index| check = base_index.base.toValue(), | ||
| 2029 | }, | ||
| 2030 | else => break, | ||
| 1932 | }, | 2031 | }, |
| 1933 | }; | 2032 | }; |
| 2033 | return try sema.resolveLazyValue(val); | ||
| 1934 | } | 2034 | } |
| 1935 | 2035 | ||
| 1936 | /// Returns all Value tags including `variable` and `undef`. | 2036 | /// Returns all Value tags including `variable` and `undef`. |
| ... | @@ -1949,35 +2049,33 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( | ... | @@ -1949,35 +2049,33 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( |
| 1949 | inst: Air.Inst.Ref, | 2049 | inst: Air.Inst.Ref, |
| 1950 | make_runtime: *bool, | 2050 | make_runtime: *bool, |
| 1951 | ) CompileError!?Value { | 2051 | ) CompileError!?Value { |
| 2052 | assert(inst != .none); | ||
| 1952 | // First section of indexes correspond to a set number of constant values. | 2053 | // First section of indexes correspond to a set number of constant values. |
| 1953 | var i: usize = @enumToInt(inst); | 2054 | const int = @enumToInt(inst); |
| 1954 | if (i < Air.Inst.Ref.typed_value_map.len) { | 2055 | if (int < InternPool.static_len) { |
| 1955 | return Air.Inst.Ref.typed_value_map[i].val; | 2056 | return @intToEnum(InternPool.Index, int).toValue(); |
| 1956 | } | 2057 | } |
| 1957 | i -= Air.Inst.Ref.typed_value_map.len; | ||
| 1958 | 2058 | ||
| 2059 | const i = int - InternPool.static_len; | ||
| 1959 | const air_tags = sema.air_instructions.items(.tag); | 2060 | const air_tags = sema.air_instructions.items(.tag); |
| 1960 | if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| { | 2061 | if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| { |
| 1961 | if (air_tags[i] == .constant) { | 2062 | if (air_tags[i] == .interned) { |
| 1962 | const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; | 2063 | const interned = sema.air_instructions.items(.data)[i].interned; |
| 1963 | const val = sema.air_values.items[ty_pl.payload]; | 2064 | const val = interned.toValue(); |
| 1964 | if (val.tag() == .variable) return val; | 2065 | if (val.getVariable(sema.mod) != null) return val; |
| 1965 | } | 2066 | } |
| 1966 | return opv; | 2067 | return opv; |
| 1967 | } | 2068 | } |
| 1968 | switch (air_tags[i]) { | 2069 | const air_datas = sema.air_instructions.items(.data); |
| 1969 | .constant => { | 2070 | const val = switch (air_tags[i]) { |
| 1970 | const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; | 2071 | .inferred_alloc => unreachable, |
| 1971 | const val = sema.air_values.items[ty_pl.payload]; | 2072 | .inferred_alloc_comptime => unreachable, |
| 1972 | if (val.tag() == .runtime_value) make_runtime.* = true; | 2073 | .interned => air_datas[i].interned.toValue(), |
| 1973 | if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true; | ||
| 1974 | return val; | ||
| 1975 | }, | ||
| 1976 | .const_ty => { | ||
| 1977 | return try sema.air_instructions.items(.data)[i].ty.toValue(sema.arena); | ||
| 1978 | }, | ||
| 1979 | else => return null, | 2074 | else => return null, |
| 1980 | } | 2075 | }; |
| 2076 | if (val.isRuntimeValue(sema.mod)) make_runtime.* = true; | ||
| 2077 | if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true; | ||
| 2078 | return val; | ||
| 1981 | } | 2079 | } |
| 1982 | 2080 | ||
| 1983 | fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: []const u8) CompileError { | 2081 | fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: []const u8) CompileError { |
| ... | @@ -2010,13 +2108,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, opt | ... | @@ -2010,13 +2108,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, opt |
| 2010 | } | 2108 | } |
| 2011 | 2109 | ||
| 2012 | fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { | 2110 | fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { |
| 2111 | const mod = sema.mod; | ||
| 2013 | const msg = msg: { | 2112 | const msg = msg: { |
| 2014 | const msg = try sema.errMsg(block, src, "type '{}' does not support array initialization syntax", .{ | 2113 | const msg = try sema.errMsg(block, src, "type '{}' does not support array initialization syntax", .{ |
| 2015 | ty.fmt(sema.mod), | 2114 | ty.fmt(mod), |
| 2016 | }); | 2115 | }); |
| 2017 | errdefer msg.destroy(sema.gpa); | 2116 | errdefer msg.destroy(sema.gpa); |
| 2018 | if (ty.isSlice()) { | 2117 | if (ty.isSlice(mod)) { |
| 2019 | try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2().fmt(sema.mod)}); | 2118 | try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2(mod).fmt(mod)}); |
| 2020 | } | 2119 | } |
| 2021 | break :msg msg; | 2120 | break :msg msg; |
| 2022 | }; | 2121 | }; |
| ... | @@ -2042,7 +2141,8 @@ fn failWithErrorSetCodeMissing( | ... | @@ -2042,7 +2141,8 @@ fn failWithErrorSetCodeMissing( |
| 2042 | } | 2141 | } |
| 2043 | 2142 | ||
| 2044 | fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError { | 2143 | fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError { |
| 2045 | if (int_ty.zigTypeTag() == .Vector) { | 2144 | const mod = sema.mod; |
| 2145 | if (int_ty.zigTypeTag(mod) == .Vector) { | ||
| 2046 | const msg = msg: { | 2146 | const msg = msg: { |
| 2047 | const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{ | 2147 | const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{ |
| 2048 | int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod), | 2148 | int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod), |
| ... | @@ -2059,16 +2159,17 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: | ... | @@ -2059,16 +2159,17 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: |
| 2059 | } | 2159 | } |
| 2060 | 2160 | ||
| 2061 | fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazySrcLoc, container_ty: Type, field_index: usize) CompileError { | 2161 | fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazySrcLoc, container_ty: Type, field_index: usize) CompileError { |
| 2162 | const mod = sema.mod; | ||
| 2062 | const msg = msg: { | 2163 | const msg = msg: { |
| 2063 | const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{}); | 2164 | const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{}); |
| 2064 | errdefer msg.destroy(sema.gpa); | 2165 | errdefer msg.destroy(sema.gpa); |
| 2065 | 2166 | ||
| 2066 | const struct_ty = container_ty.castTag(.@"struct") orelse break :msg msg; | 2167 | const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg; |
| 2067 | const default_value_src = struct_ty.data.fieldSrcLoc(sema.mod, .{ | 2168 | const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{ |
| 2068 | .index = field_index, | 2169 | .index = field_index, |
| 2069 | .range = .value, | 2170 | .range = .value, |
| 2070 | }); | 2171 | }); |
| 2071 | try sema.mod.errNoteNonLazy(default_value_src, msg, "default value set here", .{}); | 2172 | try mod.errNoteNonLazy(default_value_src, msg, "default value set here", .{}); |
| 2072 | break :msg msg; | 2173 | break :msg msg; |
| 2073 | }; | 2174 | }; |
| 2074 | return sema.failWithOwnedErrorMsg(msg); | 2175 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -2083,13 +2184,19 @@ fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError | ... | @@ -2083,13 +2184,19 @@ fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError |
| 2083 | return sema.failWithOwnedErrorMsg(msg); | 2184 | return sema.failWithOwnedErrorMsg(msg); |
| 2084 | } | 2185 | } |
| 2085 | 2186 | ||
| 2086 | fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, object_ty: Type, field_name: []const u8) CompileError { | 2187 | fn failWithInvalidFieldAccess( |
| 2087 | const inner_ty = if (object_ty.isSinglePointer()) object_ty.childType() else object_ty; | 2188 | sema: *Sema, |
| 2189 | block: *Block, | ||
| 2190 | src: LazySrcLoc, | ||
| 2191 | object_ty: Type, | ||
| 2192 | field_name: InternPool.NullTerminatedString, | ||
| 2193 | ) CompileError { | ||
| 2194 | const mod = sema.mod; | ||
| 2195 | const inner_ty = if (object_ty.isSinglePointer(mod)) object_ty.childType(mod) else object_ty; | ||
| 2088 | 2196 | ||
| 2089 | if (inner_ty.zigTypeTag() == .Optional) opt: { | 2197 | if (inner_ty.zigTypeTag(mod) == .Optional) opt: { |
| 2090 | var buf: Type.Payload.ElemType = undefined; | 2198 | const child_ty = inner_ty.optionalChild(mod); |
| 2091 | const child_ty = inner_ty.optionalChild(&buf); | 2199 | if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :opt; |
| 2092 | if (!typeSupportsFieldAccess(child_ty, field_name)) break :opt; | ||
| 2093 | const msg = msg: { | 2200 | const msg = msg: { |
| 2094 | const msg = try sema.errMsg(block, src, "optional type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); | 2201 | const msg = try sema.errMsg(block, src, "optional type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); |
| 2095 | errdefer msg.destroy(sema.gpa); | 2202 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -2097,9 +2204,9 @@ fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, objec | ... | @@ -2097,9 +2204,9 @@ fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, objec |
| 2097 | break :msg msg; | 2204 | break :msg msg; |
| 2098 | }; | 2205 | }; |
| 2099 | return sema.failWithOwnedErrorMsg(msg); | 2206 | return sema.failWithOwnedErrorMsg(msg); |
| 2100 | } else if (inner_ty.zigTypeTag() == .ErrorUnion) err: { | 2207 | } else if (inner_ty.zigTypeTag(mod) == .ErrorUnion) err: { |
| 2101 | const child_ty = inner_ty.errorUnionPayload(); | 2208 | const child_ty = inner_ty.errorUnionPayload(mod); |
| 2102 | if (!typeSupportsFieldAccess(child_ty, field_name)) break :err; | 2209 | if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :err; |
| 2103 | const msg = msg: { | 2210 | const msg = msg: { |
| 2104 | const msg = try sema.errMsg(block, src, "error union type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); | 2211 | const msg = try sema.errMsg(block, src, "error union type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); |
| 2105 | errdefer msg.destroy(sema.gpa); | 2212 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -2111,15 +2218,16 @@ fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, objec | ... | @@ -2111,15 +2218,16 @@ fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, objec |
| 2111 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); | 2218 | return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); |
| 2112 | } | 2219 | } |
| 2113 | 2220 | ||
| 2114 | fn typeSupportsFieldAccess(ty: Type, field_name: []const u8) bool { | 2221 | fn typeSupportsFieldAccess(mod: *const Module, ty: Type, field_name: InternPool.NullTerminatedString) bool { |
| 2115 | switch (ty.zigTypeTag()) { | 2222 | const ip = &mod.intern_pool; |
| 2116 | .Array => return mem.eql(u8, field_name, "len"), | 2223 | switch (ty.zigTypeTag(mod)) { |
| 2224 | .Array => return ip.stringEqlSlice(field_name, "len"), | ||
| 2117 | .Pointer => { | 2225 | .Pointer => { |
| 2118 | const ptr_info = ty.ptrInfo().data; | 2226 | const ptr_info = ty.ptrInfo(mod); |
| 2119 | if (ptr_info.size == .Slice) { | 2227 | if (ptr_info.size == .Slice) { |
| 2120 | return mem.eql(u8, field_name, "ptr") or mem.eql(u8, field_name, "len"); | 2228 | return ip.stringEqlSlice(field_name, "ptr") or ip.stringEqlSlice(field_name, "len"); |
| 2121 | } else if (ptr_info.pointee_type.zigTypeTag() == .Array) { | 2229 | } else if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) { |
| 2122 | return mem.eql(u8, field_name, "len"); | 2230 | return ip.stringEqlSlice(field_name, "len"); |
| 2123 | } else return false; | 2231 | } else return false; |
| 2124 | }, | 2232 | }, |
| 2125 | .Type, .Struct, .Union => return true, | 2233 | .Type, .Struct, .Union => return true, |
| ... | @@ -2139,7 +2247,7 @@ fn errNote( | ... | @@ -2139,7 +2247,7 @@ fn errNote( |
| 2139 | ) error{OutOfMemory}!void { | 2247 | ) error{OutOfMemory}!void { |
| 2140 | const mod = sema.mod; | 2248 | const mod = sema.mod; |
| 2141 | const src_decl = mod.declPtr(block.src_decl); | 2249 | const src_decl = mod.declPtr(block.src_decl); |
| 2142 | return mod.errNoteNonLazy(src.toSrcLoc(src_decl), parent, format, args); | 2250 | return mod.errNoteNonLazy(src.toSrcLoc(src_decl, mod), parent, format, args); |
| 2143 | } | 2251 | } |
| 2144 | 2252 | ||
| 2145 | fn addFieldErrNote( | 2253 | fn addFieldErrNote( |
| ... | @@ -2152,19 +2260,19 @@ fn addFieldErrNote( | ... | @@ -2152,19 +2260,19 @@ fn addFieldErrNote( |
| 2152 | ) !void { | 2260 | ) !void { |
| 2153 | @setCold(true); | 2261 | @setCold(true); |
| 2154 | const mod = sema.mod; | 2262 | const mod = sema.mod; |
| 2155 | const decl_index = container_ty.getOwnerDecl(); | 2263 | const decl_index = container_ty.getOwnerDecl(mod); |
| 2156 | const decl = mod.declPtr(decl_index); | 2264 | const decl = mod.declPtr(decl_index); |
| 2157 | 2265 | ||
| 2158 | const field_src = blk: { | 2266 | const field_src = blk: { |
| 2159 | const tree = decl.getFileScope().getTree(sema.gpa) catch |err| { | 2267 | const tree = decl.getFileScope(mod).getTree(sema.gpa) catch |err| { |
| 2160 | log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); | 2268 | log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); |
| 2161 | break :blk decl.srcLoc(); | 2269 | break :blk decl.srcLoc(mod); |
| 2162 | }; | 2270 | }; |
| 2163 | 2271 | ||
| 2164 | const container_node = decl.relativeToNodeIndex(0); | 2272 | const container_node = decl.relativeToNodeIndex(0); |
| 2165 | const node_tags = tree.nodes.items(.tag); | 2273 | const node_tags = tree.nodes.items(.tag); |
| 2166 | var buf: [2]std.zig.Ast.Node.Index = undefined; | 2274 | var buf: [2]std.zig.Ast.Node.Index = undefined; |
| 2167 | const container_decl = tree.fullContainerDecl(&buf, container_node) orelse break :blk decl.srcLoc(); | 2275 | const container_decl = tree.fullContainerDecl(&buf, container_node) orelse break :blk decl.srcLoc(mod); |
| 2168 | 2276 | ||
| 2169 | var it_index: usize = 0; | 2277 | var it_index: usize = 0; |
| 2170 | for (container_decl.ast.members) |member_node| { | 2278 | for (container_decl.ast.members) |member_node| { |
| ... | @@ -2174,7 +2282,7 @@ fn addFieldErrNote( | ... | @@ -2174,7 +2282,7 @@ fn addFieldErrNote( |
| 2174 | .container_field, | 2282 | .container_field, |
| 2175 | => { | 2283 | => { |
| 2176 | if (it_index == field_index) { | 2284 | if (it_index == field_index) { |
| 2177 | break :blk decl.nodeOffsetSrcLoc(decl.nodeIndexToRelative(member_node)); | 2285 | break :blk decl.nodeOffsetSrcLoc(decl.nodeIndexToRelative(member_node), mod); |
| 2178 | } | 2286 | } |
| 2179 | it_index += 1; | 2287 | it_index += 1; |
| 2180 | }, | 2288 | }, |
| ... | @@ -2195,7 +2303,7 @@ fn errMsg( | ... | @@ -2195,7 +2303,7 @@ fn errMsg( |
| 2195 | ) error{OutOfMemory}!*Module.ErrorMsg { | 2303 | ) error{OutOfMemory}!*Module.ErrorMsg { |
| 2196 | const mod = sema.mod; | 2304 | const mod = sema.mod; |
| 2197 | const src_decl = mod.declPtr(block.src_decl); | 2305 | const src_decl = mod.declPtr(block.src_decl); |
| 2198 | return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl), format, args); | 2306 | return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl, mod), format, args); |
| 2199 | } | 2307 | } |
| 2200 | 2308 | ||
| 2201 | pub fn fail( | 2309 | pub fn fail( |
| ... | @@ -2212,19 +2320,19 @@ pub fn fail( | ... | @@ -2212,19 +2320,19 @@ pub fn fail( |
| 2212 | fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { | 2320 | fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 2213 | @setCold(true); | 2321 | @setCold(true); |
| 2214 | const gpa = sema.gpa; | 2322 | const gpa = sema.gpa; |
| 2323 | const mod = sema.mod; | ||
| 2215 | 2324 | ||
| 2216 | if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) { | 2325 | if (crash_report.is_enabled and mod.comp.debug_compile_errors) { |
| 2217 | if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation; | 2326 | if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation; |
| 2218 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; | 2327 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; |
| 2219 | wip_errors.init(gpa) catch unreachable; | 2328 | wip_errors.init(gpa) catch unreachable; |
| 2220 | Compilation.addModuleErrorMsg(&wip_errors, err_msg.*) catch unreachable; | 2329 | Compilation.addModuleErrorMsg(mod, &wip_errors, err_msg.*) catch unreachable; |
| 2221 | std.debug.print("compile error during Sema:\n", .{}); | 2330 | std.debug.print("compile error during Sema:\n", .{}); |
| 2222 | var error_bundle = wip_errors.toOwnedBundle("") catch unreachable; | 2331 | var error_bundle = wip_errors.toOwnedBundle("") catch unreachable; |
| 2223 | error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); | 2332 | error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); |
| 2224 | crash_report.compilerPanic("unexpected compile error occurred", null, null); | 2333 | crash_report.compilerPanic("unexpected compile error occurred", null, null); |
| 2225 | } | 2334 | } |
| 2226 | 2335 | ||
| 2227 | const mod = sema.mod; | ||
| 2228 | ref: { | 2336 | ref: { |
| 2229 | errdefer err_msg.destroy(gpa); | 2337 | errdefer err_msg.destroy(gpa); |
| 2230 | if (err_msg.src_loc.lazy == .unneeded) { | 2338 | if (err_msg.src_loc.lazy == .unneeded) { |
| ... | @@ -2234,9 +2342,9 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { | ... | @@ -2234,9 +2342,9 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 2234 | try mod.failed_files.ensureUnusedCapacity(gpa, 1); | 2342 | try mod.failed_files.ensureUnusedCapacity(gpa, 1); |
| 2235 | 2343 | ||
| 2236 | const max_references = blk: { | 2344 | const max_references = blk: { |
| 2237 | if (sema.mod.comp.reference_trace) |num| break :blk num; | 2345 | if (mod.comp.reference_trace) |num| break :blk num; |
| 2238 | // Do not add multiple traces without explicit request. | 2346 | // Do not add multiple traces without explicit request. |
| 2239 | if (sema.mod.failed_decls.count() != 0) break :ref; | 2347 | if (mod.failed_decls.count() != 0) break :ref; |
| 2240 | break :blk default_reference_trace_len; | 2348 | break :blk default_reference_trace_len; |
| 2241 | }; | 2349 | }; |
| 2242 | 2350 | ||
| ... | @@ -2245,7 +2353,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { | ... | @@ -2245,7 +2353,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 2245 | defer reference_stack.deinit(); | 2353 | defer reference_stack.deinit(); |
| 2246 | 2354 | ||
| 2247 | // Avoid infinite loops. | 2355 | // Avoid infinite loops. |
| 2248 | var seen = std.AutoHashMap(Module.Decl.Index, void).init(gpa); | 2356 | var seen = std.AutoHashMap(Decl.Index, void).init(gpa); |
| 2249 | defer seen.deinit(); | 2357 | defer seen.deinit(); |
| 2250 | 2358 | ||
| 2251 | var cur_reference_trace: u32 = 0; | 2359 | var cur_reference_trace: u32 = 0; |
| ... | @@ -2254,13 +2362,16 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { | ... | @@ -2254,13 +2362,16 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { |
| 2254 | if (gop.found_existing) break; | 2362 | if (gop.found_existing) break; |
| 2255 | if (cur_reference_trace < max_references) { | 2363 | if (cur_reference_trace < max_references) { |
| 2256 | const decl = sema.mod.declPtr(ref.referencer); | 2364 | const decl = sema.mod.declPtr(ref.referencer); |
| 2257 | try reference_stack.append(.{ .decl = decl.name, .src_loc = ref.src.toSrcLoc(decl) }); | 2365 | try reference_stack.append(.{ |
| 2366 | .decl = decl.name.toOptional(), | ||
| 2367 | .src_loc = ref.src.toSrcLoc(decl, mod), | ||
| 2368 | }); | ||
| 2258 | } | 2369 | } |
| 2259 | referenced_by = ref.referencer; | 2370 | referenced_by = ref.referencer; |
| 2260 | } | 2371 | } |
| 2261 | if (sema.mod.comp.reference_trace == null and cur_reference_trace > 0) { | 2372 | if (sema.mod.comp.reference_trace == null and cur_reference_trace > 0) { |
| 2262 | try reference_stack.append(.{ | 2373 | try reference_stack.append(.{ |
| 2263 | .decl = null, | 2374 | .decl = .none, |
| 2264 | .src_loc = undefined, | 2375 | .src_loc = undefined, |
| 2265 | .hidden = 0, | 2376 | .hidden = 0, |
| 2266 | }); | 2377 | }); |
| ... | @@ -2352,10 +2463,10 @@ fn analyzeAsInt( | ... | @@ -2352,10 +2463,10 @@ fn analyzeAsInt( |
| 2352 | dest_ty: Type, | 2463 | dest_ty: Type, |
| 2353 | reason: []const u8, | 2464 | reason: []const u8, |
| 2354 | ) !u64 { | 2465 | ) !u64 { |
| 2466 | const mod = sema.mod; | ||
| 2355 | const coerced = try sema.coerce(block, dest_ty, air_ref, src); | 2467 | const coerced = try sema.coerce(block, dest_ty, air_ref, src); |
| 2356 | const val = try sema.resolveConstValue(block, src, coerced, reason); | 2468 | const val = try sema.resolveConstValue(block, src, coerced, reason); |
| 2357 | const target = sema.mod.getTarget(); | 2469 | return (try val.getUnsignedIntAdvanced(mod, sema)).?; |
| 2358 | return (try val.getUnsignedIntAdvanced(target, sema)).?; | ||
| 2359 | } | 2470 | } |
| 2360 | 2471 | ||
| 2361 | // Returns a compile error if the value has tag `variable`. See `resolveInstValue` for | 2472 | // Returns a compile error if the value has tag `variable`. See `resolveInstValue` for |
| ... | @@ -2396,73 +2507,77 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -2396,73 +2507,77 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 2396 | const tracy = trace(@src()); | 2507 | const tracy = trace(@src()); |
| 2397 | defer tracy.end(); | 2508 | defer tracy.end(); |
| 2398 | 2509 | ||
| 2510 | const mod = sema.mod; | ||
| 2399 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 2511 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2400 | const src = inst_data.src(); | 2512 | const src = inst_data.src(); |
| 2401 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 2513 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 2402 | const pointee_ty = try sema.resolveType(block, src, extra.lhs); | 2514 | const pointee_ty = try sema.resolveType(block, src, extra.lhs); |
| 2403 | const ptr = try sema.resolveInst(extra.rhs); | 2515 | const ptr = try sema.resolveInst(extra.rhs); |
| 2404 | const target = sema.mod.getTarget(); | 2516 | const target = mod.getTarget(); |
| 2405 | const addr_space = target_util.defaultAddressSpace(target, .local); | 2517 | const addr_space = target_util.defaultAddressSpace(target, .local); |
| 2406 | 2518 | ||
| 2407 | if (Air.refToIndex(ptr)) |ptr_inst| { | 2519 | if (Air.refToIndex(ptr)) |ptr_inst| { |
| 2408 | if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) { | 2520 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { |
| 2409 | const air_datas = sema.air_instructions.items(.data); | 2521 | .inferred_alloc => { |
| 2410 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; | 2522 | const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc; |
| 2411 | switch (ptr_val.tag()) { | 2523 | const ia2 = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; |
| 2412 | .inferred_alloc => { | 2524 | // Add the stored instruction to the set we will use to resolve peer types |
| 2413 | const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data; | 2525 | // for the inferred allocation. |
| 2414 | // Add the stored instruction to the set we will use to resolve peer types | 2526 | // This instruction will not make it to codegen; it is only to participate |
| 2415 | // for the inferred allocation. | 2527 | // in the `stored_inst_list` of the `inferred_alloc`. |
| 2416 | // This instruction will not make it to codegen; it is only to participate | 2528 | var trash_block = block.makeSubBlock(); |
| 2417 | // in the `stored_inst_list` of the `inferred_alloc`. | 2529 | defer trash_block.instructions.deinit(sema.gpa); |
| 2418 | var trash_block = block.makeSubBlock(); | 2530 | const operand = try trash_block.addBitCast(pointee_ty, .void_value); |
| 2419 | defer trash_block.instructions.deinit(sema.gpa); | 2531 | |
| 2420 | const operand = try trash_block.addBitCast(pointee_ty, .void_value); | 2532 | const ptr_ty = try mod.ptrType(.{ |
| 2421 | 2533 | .child = pointee_ty.toIntern(), | |
| 2422 | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 2534 | .flags = .{ |
| 2423 | .pointee_type = pointee_ty, | 2535 | .alignment = ia1.alignment, |
| 2424 | .@"align" = inferred_alloc.alignment, | 2536 | .address_space = addr_space, |
| 2425 | .@"addrspace" = addr_space, | 2537 | }, |
| 2426 | }); | 2538 | }); |
| 2427 | const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); | 2539 | const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr); |
| 2428 | 2540 | ||
| 2429 | try inferred_alloc.prongs.append(sema.arena, .{ | 2541 | try ia2.prongs.append(sema.arena, .{ |
| 2430 | .stored_inst = operand, | 2542 | .stored_inst = operand, |
| 2431 | .placeholder = Air.refToIndex(bitcasted_ptr).?, | 2543 | .placeholder = Air.refToIndex(bitcasted_ptr).?, |
| 2432 | }); | 2544 | }); |
| 2433 | 2545 | ||
| 2434 | return bitcasted_ptr; | 2546 | return bitcasted_ptr; |
| 2435 | }, | 2547 | }, |
| 2436 | .inferred_alloc_comptime => { | 2548 | .inferred_alloc_comptime => { |
| 2437 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; | 2549 | const alignment = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.alignment; |
| 2438 | // There will be only one coerce_result_ptr because we are running at comptime. | 2550 | // There will be only one coerce_result_ptr because we are running at comptime. |
| 2439 | // The alloc will turn into a Decl. | 2551 | // The alloc will turn into a Decl. |
| 2440 | var anon_decl = try block.startAnonDecl(); | 2552 | var anon_decl = try block.startAnonDecl(); |
| 2441 | defer anon_decl.deinit(); | 2553 | defer anon_decl.deinit(); |
| 2442 | iac.data.decl_index = try anon_decl.finish( | 2554 | const decl_index = try anon_decl.finish( |
| 2443 | try pointee_ty.copy(anon_decl.arena()), | 2555 | pointee_ty, |
| 2444 | Value.undef, | 2556 | (try mod.intern(.{ .undef = pointee_ty.toIntern() })).toValue(), |
| 2445 | iac.data.alignment, | 2557 | alignment.toByteUnits(0), |
| 2446 | ); | 2558 | ); |
| 2447 | if (iac.data.alignment != 0) { | 2559 | sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.decl_index = decl_index; |
| 2448 | try sema.resolveTypeLayout(pointee_ty); | 2560 | if (alignment != .none) { |
| 2449 | } | 2561 | try sema.resolveTypeLayout(pointee_ty); |
| 2450 | const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 2562 | } |
| 2451 | .pointee_type = pointee_ty, | 2563 | const ptr_ty = try mod.ptrType(.{ |
| 2452 | .@"align" = iac.data.alignment, | 2564 | .child = pointee_ty.toIntern(), |
| 2453 | .@"addrspace" = addr_space, | 2565 | .flags = .{ |
| 2454 | }); | 2566 | .alignment = alignment, |
| 2455 | try sema.maybeQueueFuncBodyAnalysis(iac.data.decl_index); | 2567 | .address_space = addr_space, |
| 2456 | return sema.addConstant( | 2568 | }, |
| 2457 | ptr_ty, | 2569 | }); |
| 2458 | try Value.Tag.decl_ref_mut.create(sema.arena, .{ | 2570 | try sema.maybeQueueFuncBodyAnalysis(decl_index); |
| 2459 | .decl_index = iac.data.decl_index, | 2571 | try sema.comptime_mutable_decls.append(decl_index); |
| 2460 | .runtime_index = block.runtime_index, | 2572 | return sema.addConstant(ptr_ty, (try mod.intern(.{ .ptr = .{ |
| 2461 | }), | 2573 | .ty = ptr_ty.toIntern(), |
| 2462 | ); | 2574 | .addr = .{ .mut_decl = .{ |
| 2463 | }, | 2575 | .decl = decl_index, |
| 2464 | else => {}, | 2576 | .runtime_index = block.runtime_index, |
| 2465 | } | 2577 | } }, |
| 2578 | } })).toValue()); | ||
| 2579 | }, | ||
| 2580 | else => {}, | ||
| 2466 | } | 2581 | } |
| 2467 | } | 2582 | } |
| 2468 | 2583 | ||
| ... | @@ -2487,6 +2602,7 @@ fn coerceResultPtr( | ... | @@ -2487,6 +2602,7 @@ fn coerceResultPtr( |
| 2487 | dummy_operand: Air.Inst.Ref, | 2602 | dummy_operand: Air.Inst.Ref, |
| 2488 | trash_block: *Block, | 2603 | trash_block: *Block, |
| 2489 | ) CompileError!Air.Inst.Ref { | 2604 | ) CompileError!Air.Inst.Ref { |
| 2605 | const mod = sema.mod; | ||
| 2490 | const target = sema.mod.getTarget(); | 2606 | const target = sema.mod.getTarget(); |
| 2491 | const addr_space = target_util.defaultAddressSpace(target, .local); | 2607 | const addr_space = target_util.defaultAddressSpace(target, .local); |
| 2492 | const pointee_ty = sema.typeOf(dummy_operand); | 2608 | const pointee_ty = sema.typeOf(dummy_operand); |
| ... | @@ -2530,7 +2646,7 @@ fn coerceResultPtr( | ... | @@ -2530,7 +2646,7 @@ fn coerceResultPtr( |
| 2530 | return sema.addConstant(ptr_ty, ptr_val); | 2646 | return sema.addConstant(ptr_ty, ptr_val); |
| 2531 | } | 2647 | } |
| 2532 | if (pointee_ty.eql(Type.null, sema.mod)) { | 2648 | if (pointee_ty.eql(Type.null, sema.mod)) { |
| 2533 | const opt_ty = sema.typeOf(new_ptr).childType(); | 2649 | const opt_ty = sema.typeOf(new_ptr).childType(mod); |
| 2534 | const null_inst = try sema.addConstant(opt_ty, Value.null); | 2650 | const null_inst = try sema.addConstant(opt_ty, Value.null); |
| 2535 | _ = try block.addBinOp(.store, new_ptr, null_inst); | 2651 | _ = try block.addBinOp(.store, new_ptr, null_inst); |
| 2536 | return Air.Inst.Ref.void_value; | 2652 | return Air.Inst.Ref.void_value; |
| ... | @@ -2563,7 +2679,7 @@ fn coerceResultPtr( | ... | @@ -2563,7 +2679,7 @@ fn coerceResultPtr( |
| 2563 | .@"addrspace" = addr_space, | 2679 | .@"addrspace" = addr_space, |
| 2564 | }); | 2680 | }); |
| 2565 | if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { | 2681 | if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| { |
| 2566 | new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val); | 2682 | new_ptr = try sema.addConstant(ptr_operand_ty, try mod.getCoerced(ptr_val, ptr_operand_ty)); |
| 2567 | } else { | 2683 | } else { |
| 2568 | new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src, null); | 2684 | new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src, null); |
| 2569 | } | 2685 | } |
| ... | @@ -2600,8 +2716,10 @@ pub fn analyzeStructDecl( | ... | @@ -2600,8 +2716,10 @@ pub fn analyzeStructDecl( |
| 2600 | sema: *Sema, | 2716 | sema: *Sema, |
| 2601 | new_decl: *Decl, | 2717 | new_decl: *Decl, |
| 2602 | inst: Zir.Inst.Index, | 2718 | inst: Zir.Inst.Index, |
| 2603 | struct_obj: *Module.Struct, | 2719 | struct_index: Module.Struct.Index, |
| 2604 | ) SemaError!void { | 2720 | ) SemaError!void { |
| 2721 | const mod = sema.mod; | ||
| 2722 | const struct_obj = mod.structPtr(struct_index); | ||
| 2605 | const extended = sema.code.instructions.items(.data)[inst].extended; | 2723 | const extended = sema.code.instructions.items(.data)[inst].extended; |
| 2606 | assert(extended.opcode == .struct_decl); | 2724 | assert(extended.opcode == .struct_decl); |
| 2607 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); | 2725 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| ... | @@ -2630,7 +2748,7 @@ pub fn analyzeStructDecl( | ... | @@ -2630,7 +2748,7 @@ pub fn analyzeStructDecl( |
| 2630 | } | 2748 | } |
| 2631 | } | 2749 | } |
| 2632 | 2750 | ||
| 2633 | _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl); | 2751 | _ = try mod.scanNamespace(struct_obj.namespace, extra_index, decls_len, new_decl); |
| 2634 | } | 2752 | } |
| 2635 | 2753 | ||
| 2636 | fn zirStructDecl( | 2754 | fn zirStructDecl( |
| ... | @@ -2639,28 +2757,35 @@ fn zirStructDecl( | ... | @@ -2639,28 +2757,35 @@ fn zirStructDecl( |
| 2639 | extended: Zir.Inst.Extended.InstData, | 2757 | extended: Zir.Inst.Extended.InstData, |
| 2640 | inst: Zir.Inst.Index, | 2758 | inst: Zir.Inst.Index, |
| 2641 | ) CompileError!Air.Inst.Ref { | 2759 | ) CompileError!Air.Inst.Ref { |
| 2760 | const mod = sema.mod; | ||
| 2761 | const gpa = sema.gpa; | ||
| 2642 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); | 2762 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| 2643 | const src: LazySrcLoc = if (small.has_src_node) blk: { | 2763 | const src: LazySrcLoc = if (small.has_src_node) blk: { |
| 2644 | const node_offset = @bitCast(i32, sema.code.extra[extended.operand]); | 2764 | const node_offset = @bitCast(i32, sema.code.extra[extended.operand]); |
| 2645 | break :blk LazySrcLoc.nodeOffset(node_offset); | 2765 | break :blk LazySrcLoc.nodeOffset(node_offset); |
| 2646 | } else sema.src; | 2766 | } else sema.src; |
| 2647 | 2767 | ||
| 2648 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | 2768 | // Because these three things each reference each other, `undefined` |
| 2649 | errdefer new_decl_arena.deinit(); | 2769 | // placeholders are used before being set after the struct type gains an |
| 2650 | const new_decl_arena_allocator = new_decl_arena.allocator(); | 2770 | // InternPool index. |
| 2651 | 2771 | ||
| 2652 | const mod = sema.mod; | ||
| 2653 | const struct_obj = try new_decl_arena_allocator.create(Module.Struct); | ||
| 2654 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); | ||
| 2655 | const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); | ||
| 2656 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ | 2772 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 2657 | .ty = Type.type, | 2773 | .ty = Type.noreturn, |
| 2658 | .val = struct_val, | 2774 | .val = Value.@"unreachable", |
| 2659 | }, small.name_strategy, "struct", inst); | 2775 | }, small.name_strategy, "struct", inst); |
| 2660 | const new_decl = mod.declPtr(new_decl_index); | 2776 | const new_decl = mod.declPtr(new_decl_index); |
| 2661 | new_decl.owns_tv = true; | 2777 | new_decl.owns_tv = true; |
| 2662 | errdefer mod.abortAnonDecl(new_decl_index); | 2778 | errdefer mod.abortAnonDecl(new_decl_index); |
| 2663 | struct_obj.* = .{ | 2779 | |
| 2780 | const new_namespace_index = try mod.createNamespace(.{ | ||
| 2781 | .parent = block.namespace.toOptional(), | ||
| 2782 | .ty = undefined, | ||
| 2783 | .file_scope = block.getFileScope(mod), | ||
| 2784 | }); | ||
| 2785 | const new_namespace = mod.namespacePtr(new_namespace_index); | ||
| 2786 | errdefer mod.destroyNamespace(new_namespace_index); | ||
| 2787 | |||
| 2788 | const struct_index = try mod.createStruct(.{ | ||
| 2664 | .owner_decl = new_decl_index, | 2789 | .owner_decl = new_decl_index, |
| 2665 | .fields = .{}, | 2790 | .fields = .{}, |
| 2666 | .zir_index = inst, | 2791 | .zir_index = inst, |
| ... | @@ -2668,18 +2793,25 @@ fn zirStructDecl( | ... | @@ -2668,18 +2793,25 @@ fn zirStructDecl( |
| 2668 | .status = .none, | 2793 | .status = .none, |
| 2669 | .known_non_opv = undefined, | 2794 | .known_non_opv = undefined, |
| 2670 | .is_tuple = small.is_tuple, | 2795 | .is_tuple = small.is_tuple, |
| 2671 | .namespace = .{ | 2796 | .namespace = new_namespace_index, |
| 2672 | .parent = block.namespace, | ||
| 2673 | .ty = struct_ty, | ||
| 2674 | .file_scope = block.getFileScope(), | ||
| 2675 | }, | ||
| 2676 | }; | ||
| 2677 | std.log.scoped(.module).debug("create struct {*} owned by {*} ({s})", .{ | ||
| 2678 | &struct_obj.namespace, new_decl, new_decl.name, | ||
| 2679 | }); | 2797 | }); |
| 2680 | try sema.analyzeStructDecl(new_decl, inst, struct_obj); | 2798 | errdefer mod.destroyStruct(struct_index); |
| 2681 | try new_decl.finalizeNewArena(&new_decl_arena); | 2799 | |
| 2682 | return sema.analyzeDeclVal(block, src, new_decl_index); | 2800 | const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ |
| 2801 | .index = struct_index.toOptional(), | ||
| 2802 | .namespace = new_namespace_index.toOptional(), | ||
| 2803 | } }); | ||
| 2804 | // TODO: figure out InternPool removals for incremental compilation | ||
| 2805 | //errdefer mod.intern_pool.remove(struct_ty); | ||
| 2806 | |||
| 2807 | new_decl.ty = Type.type; | ||
| 2808 | new_decl.val = struct_ty.toValue(); | ||
| 2809 | new_namespace.ty = struct_ty.toType(); | ||
| 2810 | |||
| 2811 | try sema.analyzeStructDecl(new_decl, inst, struct_index); | ||
| 2812 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); | ||
| 2813 | try mod.finalizeAnonDecl(new_decl_index); | ||
| 2814 | return decl_val; | ||
| 2683 | } | 2815 | } |
| 2684 | 2816 | ||
| 2685 | fn createAnonymousDeclTypeNamed( | 2817 | fn createAnonymousDeclTypeNamed( |
| ... | @@ -2692,6 +2824,7 @@ fn createAnonymousDeclTypeNamed( | ... | @@ -2692,6 +2824,7 @@ fn createAnonymousDeclTypeNamed( |
| 2692 | inst: ?Zir.Inst.Index, | 2824 | inst: ?Zir.Inst.Index, |
| 2693 | ) !Decl.Index { | 2825 | ) !Decl.Index { |
| 2694 | const mod = sema.mod; | 2826 | const mod = sema.mod; |
| 2827 | const gpa = sema.gpa; | ||
| 2695 | const namespace = block.namespace; | 2828 | const namespace = block.namespace; |
| 2696 | const src_scope = block.wip_capture_scope; | 2829 | const src_scope = block.wip_capture_scope; |
| 2697 | const src_decl = mod.declPtr(block.src_decl); | 2830 | const src_decl = mod.declPtr(block.src_decl); |
| ... | @@ -2707,16 +2840,15 @@ fn createAnonymousDeclTypeNamed( | ... | @@ -2707,16 +2840,15 @@ fn createAnonymousDeclTypeNamed( |
| 2707 | // semantically analyzed. | 2840 | // semantically analyzed. |
| 2708 | // This name is also used as the key in the parent namespace so it cannot be | 2841 | // This name is also used as the key in the parent namespace so it cannot be |
| 2709 | // renamed. | 2842 | // renamed. |
| 2710 | const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__{s}_{d}", .{ | 2843 | |
| 2711 | src_decl.name, anon_prefix, @enumToInt(new_decl_index), | 2844 | const name = mod.intern_pool.getOrPutStringFmt(gpa, "{}__{s}_{d}", .{ |
| 2712 | }); | 2845 | src_decl.name.fmt(&mod.intern_pool), anon_prefix, @enumToInt(new_decl_index), |
| 2713 | errdefer sema.gpa.free(name); | 2846 | }) catch unreachable; |
| 2714 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); | 2847 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); |
| 2715 | return new_decl_index; | 2848 | return new_decl_index; |
| 2716 | }, | 2849 | }, |
| 2717 | .parent => { | 2850 | .parent => { |
| 2718 | const name = try sema.gpa.dupeZ(u8, mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0)); | 2851 | const name = mod.declPtr(block.src_decl).name; |
| 2719 | errdefer sema.gpa.free(name); | ||
| 2720 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); | 2852 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); |
| 2721 | return new_decl_index; | 2853 | return new_decl_index; |
| 2722 | }, | 2854 | }, |
| ... | @@ -2724,10 +2856,11 @@ fn createAnonymousDeclTypeNamed( | ... | @@ -2724,10 +2856,11 @@ fn createAnonymousDeclTypeNamed( |
| 2724 | const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst); | 2856 | const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst); |
| 2725 | const zir_tags = sema.code.instructions.items(.tag); | 2857 | const zir_tags = sema.code.instructions.items(.tag); |
| 2726 | 2858 | ||
| 2727 | var buf = std.ArrayList(u8).init(sema.gpa); | 2859 | var buf = std.ArrayList(u8).init(gpa); |
| 2728 | defer buf.deinit(); | 2860 | defer buf.deinit(); |
| 2729 | try buf.appendSlice(mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0)); | 2861 | |
| 2730 | try buf.appendSlice("("); | 2862 | const writer = buf.writer(); |
| 2863 | try writer.print("{}(", .{mod.declPtr(block.src_decl).name.fmt(&mod.intern_pool)}); | ||
| 2731 | 2864 | ||
| 2732 | var arg_i: usize = 0; | 2865 | var arg_i: usize = 0; |
| 2733 | for (fn_info.param_body) |zir_inst| switch (zir_tags[zir_inst]) { | 2866 | for (fn_info.param_body) |zir_inst| switch (zir_tags[zir_inst]) { |
| ... | @@ -2741,8 +2874,8 @@ fn createAnonymousDeclTypeNamed( | ... | @@ -2741,8 +2874,8 @@ fn createAnonymousDeclTypeNamed( |
| 2741 | const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg, "") catch | 2874 | const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg, "") catch |
| 2742 | return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null); | 2875 | return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null); |
| 2743 | 2876 | ||
| 2744 | if (arg_i != 0) try buf.appendSlice(","); | 2877 | if (arg_i != 0) try writer.writeByte(','); |
| 2745 | try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)}); | 2878 | try writer.print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)}); |
| 2746 | 2879 | ||
| 2747 | arg_i += 1; | 2880 | arg_i += 1; |
| 2748 | continue; | 2881 | continue; |
| ... | @@ -2750,9 +2883,8 @@ fn createAnonymousDeclTypeNamed( | ... | @@ -2750,9 +2883,8 @@ fn createAnonymousDeclTypeNamed( |
| 2750 | else => continue, | 2883 | else => continue, |
| 2751 | }; | 2884 | }; |
| 2752 | 2885 | ||
| 2753 | try buf.appendSlice(")"); | 2886 | try writer.writeByte(')'); |
| 2754 | const name = try buf.toOwnedSliceSentinel(0); | 2887 | const name = try mod.intern_pool.getOrPutString(gpa, buf.items); |
| 2755 | errdefer sema.gpa.free(name); | ||
| 2756 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); | 2888 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); |
| 2757 | return new_decl_index; | 2889 | return new_decl_index; |
| 2758 | }, | 2890 | }, |
| ... | @@ -2765,10 +2897,9 @@ fn createAnonymousDeclTypeNamed( | ... | @@ -2765,10 +2897,9 @@ fn createAnonymousDeclTypeNamed( |
| 2765 | .dbg_var_ptr, .dbg_var_val => { | 2897 | .dbg_var_ptr, .dbg_var_val => { |
| 2766 | if (zir_data[i].str_op.operand != ref) continue; | 2898 | if (zir_data[i].str_op.operand != ref) continue; |
| 2767 | 2899 | ||
| 2768 | const name = try std.fmt.allocPrintZ(sema.gpa, "{s}.{s}", .{ | 2900 | const name = try mod.intern_pool.getOrPutStringFmt(gpa, "{}.{s}", .{ |
| 2769 | src_decl.name, zir_data[i].str_op.getStr(sema.code), | 2901 | src_decl.name.fmt(&mod.intern_pool), zir_data[i].str_op.getStr(sema.code), |
| 2770 | }); | 2902 | }); |
| 2771 | errdefer sema.gpa.free(name); | ||
| 2772 | 2903 | ||
| 2773 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); | 2904 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); |
| 2774 | return new_decl_index; | 2905 | return new_decl_index; |
| ... | @@ -2825,53 +2956,28 @@ fn zirEnumDecl( | ... | @@ -2825,53 +2956,28 @@ fn zirEnumDecl( |
| 2825 | break :blk decls_len; | 2956 | break :blk decls_len; |
| 2826 | } else 0; | 2957 | } else 0; |
| 2827 | 2958 | ||
| 2828 | var done = false; | 2959 | // Because these three things each reference each other, `undefined` |
| 2829 | 2960 | // placeholders are used before being set after the enum type gains an | |
| 2830 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | 2961 | // InternPool index. |
| 2831 | errdefer if (!done) new_decl_arena.deinit(); | ||
| 2832 | const new_decl_arena_allocator = new_decl_arena.allocator(); | ||
| 2833 | 2962 | ||
| 2834 | const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull); | 2963 | var done = false; |
| 2835 | const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull); | ||
| 2836 | enum_ty_payload.* = .{ | ||
| 2837 | .base = .{ .tag = if (small.nonexhaustive) .enum_nonexhaustive else .enum_full }, | ||
| 2838 | .data = enum_obj, | ||
| 2839 | }; | ||
| 2840 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | ||
| 2841 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); | ||
| 2842 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ | 2964 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 2843 | .ty = Type.type, | 2965 | .ty = Type.noreturn, |
| 2844 | .val = enum_val, | 2966 | .val = Value.@"unreachable", |
| 2845 | }, small.name_strategy, "enum", inst); | 2967 | }, small.name_strategy, "enum", inst); |
| 2846 | const new_decl = mod.declPtr(new_decl_index); | 2968 | const new_decl = mod.declPtr(new_decl_index); |
| 2847 | new_decl.owns_tv = true; | 2969 | new_decl.owns_tv = true; |
| 2848 | errdefer if (!done) mod.abortAnonDecl(new_decl_index); | 2970 | errdefer if (!done) mod.abortAnonDecl(new_decl_index); |
| 2849 | 2971 | ||
| 2850 | enum_obj.* = .{ | 2972 | const new_namespace_index = try mod.createNamespace(.{ |
| 2851 | .owner_decl = new_decl_index, | 2973 | .parent = block.namespace.toOptional(), |
| 2852 | .tag_ty = Type.null, | 2974 | .ty = undefined, |
| 2853 | .tag_ty_inferred = true, | 2975 | .file_scope = block.getFileScope(mod), |
| 2854 | .fields = .{}, | ||
| 2855 | .values = .{}, | ||
| 2856 | .namespace = .{ | ||
| 2857 | .parent = block.namespace, | ||
| 2858 | .ty = enum_ty, | ||
| 2859 | .file_scope = block.getFileScope(), | ||
| 2860 | }, | ||
| 2861 | }; | ||
| 2862 | std.log.scoped(.module).debug("create enum {*} owned by {*} ({s})", .{ | ||
| 2863 | &enum_obj.namespace, new_decl, new_decl.name, | ||
| 2864 | }); | 2976 | }); |
| 2977 | const new_namespace = mod.namespacePtr(new_namespace_index); | ||
| 2978 | errdefer if (!done) mod.destroyNamespace(new_namespace_index); | ||
| 2865 | 2979 | ||
| 2866 | try new_decl.finalizeNewArena(&new_decl_arena); | 2980 | extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl); |
| 2867 | const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index); | ||
| 2868 | done = true; | ||
| 2869 | |||
| 2870 | var decl_arena: std.heap.ArenaAllocator = undefined; | ||
| 2871 | const decl_arena_allocator = new_decl.value_arena.?.acquire(gpa, &decl_arena); | ||
| 2872 | defer new_decl.value_arena.?.release(&decl_arena); | ||
| 2873 | |||
| 2874 | extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl); | ||
| 2875 | 2981 | ||
| 2876 | const body = sema.code.extra[extra_index..][0..body_len]; | 2982 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 2877 | extra_index += body.len; | 2983 | extra_index += body.len; |
| ... | @@ -2880,7 +2986,34 @@ fn zirEnumDecl( | ... | @@ -2880,7 +2986,34 @@ fn zirEnumDecl( |
| 2880 | const body_end = extra_index; | 2986 | const body_end = extra_index; |
| 2881 | extra_index += bit_bags_count; | 2987 | extra_index += bit_bags_count; |
| 2882 | 2988 | ||
| 2883 | { | 2989 | const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| { |
| 2990 | if (bag != 0) break true; | ||
| 2991 | } else false; | ||
| 2992 | |||
| 2993 | const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{ | ||
| 2994 | .decl = new_decl_index, | ||
| 2995 | .namespace = new_namespace_index.toOptional(), | ||
| 2996 | .fields_len = fields_len, | ||
| 2997 | .has_values = any_values, | ||
| 2998 | .tag_mode = if (small.nonexhaustive) | ||
| 2999 | .nonexhaustive | ||
| 3000 | else if (tag_type_ref == .none) | ||
| 3001 | .auto | ||
| 3002 | else | ||
| 3003 | .explicit, | ||
| 3004 | }); | ||
| 3005 | // TODO: figure out InternPool removals for incremental compilation | ||
| 3006 | //errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index); | ||
| 3007 | |||
| 3008 | new_decl.ty = Type.type; | ||
| 3009 | new_decl.val = incomplete_enum.index.toValue(); | ||
| 3010 | new_namespace.ty = incomplete_enum.index.toType(); | ||
| 3011 | |||
| 3012 | const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index); | ||
| 3013 | try mod.finalizeAnonDecl(new_decl_index); | ||
| 3014 | done = true; | ||
| 3015 | |||
| 3016 | const int_tag_ty = ty: { | ||
| 2884 | // We create a block for the field type instructions because they | 3017 | // We create a block for the field type instructions because they |
| 2885 | // may need to reference Decls from inside the enum namespace. | 3018 | // may need to reference Decls from inside the enum namespace. |
| 2886 | // Within the field type, default value, and alignment expressions, the "owner decl" | 3019 | // Within the field type, default value, and alignment expressions, the "owner decl" |
| ... | @@ -2896,21 +3029,27 @@ fn zirEnumDecl( | ... | @@ -2896,21 +3029,27 @@ fn zirEnumDecl( |
| 2896 | } | 3029 | } |
| 2897 | 3030 | ||
| 2898 | const prev_owner_func = sema.owner_func; | 3031 | const prev_owner_func = sema.owner_func; |
| 3032 | const prev_owner_func_index = sema.owner_func_index; | ||
| 2899 | sema.owner_func = null; | 3033 | sema.owner_func = null; |
| 3034 | sema.owner_func_index = .none; | ||
| 2900 | defer sema.owner_func = prev_owner_func; | 3035 | defer sema.owner_func = prev_owner_func; |
| 3036 | defer sema.owner_func_index = prev_owner_func_index; | ||
| 2901 | 3037 | ||
| 2902 | const prev_func = sema.func; | 3038 | const prev_func = sema.func; |
| 3039 | const prev_func_index = sema.func_index; | ||
| 2903 | sema.func = null; | 3040 | sema.func = null; |
| 3041 | sema.func_index = .none; | ||
| 2904 | defer sema.func = prev_func; | 3042 | defer sema.func = prev_func; |
| 3043 | defer sema.func_index = prev_func_index; | ||
| 2905 | 3044 | ||
| 2906 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope); | 3045 | var wip_captures = try WipCaptureScope.init(gpa, new_decl.src_scope); |
| 2907 | defer wip_captures.deinit(); | 3046 | defer wip_captures.deinit(); |
| 2908 | 3047 | ||
| 2909 | var enum_block: Block = .{ | 3048 | var enum_block: Block = .{ |
| 2910 | .parent = null, | 3049 | .parent = null, |
| 2911 | .sema = sema, | 3050 | .sema = sema, |
| 2912 | .src_decl = new_decl_index, | 3051 | .src_decl = new_decl_index, |
| 2913 | .namespace = &enum_obj.namespace, | 3052 | .namespace = new_namespace_index, |
| 2914 | .wip_capture_scope = wip_captures.scope, | 3053 | .wip_capture_scope = wip_captures.scope, |
| 2915 | .instructions = .{}, | 3054 | .instructions = .{}, |
| 2916 | .inlining = null, | 3055 | .inlining = null, |
| ... | @@ -2926,43 +3065,29 @@ fn zirEnumDecl( | ... | @@ -2926,43 +3065,29 @@ fn zirEnumDecl( |
| 2926 | 3065 | ||
| 2927 | if (tag_type_ref != .none) { | 3066 | if (tag_type_ref != .none) { |
| 2928 | const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref); | 3067 | const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref); |
| 2929 | if (ty.zigTypeTag() != .Int and ty.zigTypeTag() != .ComptimeInt) { | 3068 | if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) { |
| 2930 | return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)}); | 3069 | return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)}); |
| 2931 | } | 3070 | } |
| 2932 | enum_obj.tag_ty = try ty.copy(decl_arena_allocator); | 3071 | incomplete_enum.setTagType(&mod.intern_pool, ty.toIntern()); |
| 2933 | enum_obj.tag_ty_inferred = false; | 3072 | break :ty ty; |
| 2934 | } else if (fields_len == 0) { | 3073 | } else if (fields_len == 0) { |
| 2935 | enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, 0); | 3074 | break :ty try mod.intType(.unsigned, 0); |
| 2936 | enum_obj.tag_ty_inferred = true; | ||
| 2937 | } else { | 3075 | } else { |
| 2938 | const bits = std.math.log2_int_ceil(usize, fields_len); | 3076 | const bits = std.math.log2_int_ceil(usize, fields_len); |
| 2939 | enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits); | 3077 | break :ty try mod.intType(.unsigned, bits); |
| 2940 | enum_obj.tag_ty_inferred = true; | ||
| 2941 | } | 3078 | } |
| 2942 | } | 3079 | }; |
| 2943 | 3080 | ||
| 2944 | if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag() != .ComptimeInt) { | 3081 | if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { |
| 2945 | if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(sema.mod.getTarget())) { | 3082 | if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) { |
| 2946 | return sema.fail(block, src, "non-exhaustive enum specifies every value", .{}); | 3083 | return sema.fail(block, src, "non-exhaustive enum specifies every value", .{}); |
| 2947 | } | 3084 | } |
| 2948 | } | 3085 | } |
| 2949 | 3086 | ||
| 2950 | try enum_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); | ||
| 2951 | const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| { | ||
| 2952 | if (bag != 0) break true; | ||
| 2953 | } else false; | ||
| 2954 | if (any_values) { | ||
| 2955 | try enum_obj.values.ensureTotalCapacityContext(decl_arena_allocator, fields_len, .{ | ||
| 2956 | .ty = enum_obj.tag_ty, | ||
| 2957 | .mod = mod, | ||
| 2958 | }); | ||
| 2959 | } | ||
| 2960 | |||
| 2961 | var bit_bag_index: usize = body_end; | 3087 | var bit_bag_index: usize = body_end; |
| 2962 | var cur_bit_bag: u32 = undefined; | 3088 | var cur_bit_bag: u32 = undefined; |
| 2963 | var field_i: u32 = 0; | 3089 | var field_i: u32 = 0; |
| 2964 | var last_tag_val: ?Value = null; | 3090 | var last_tag_val: ?Value = null; |
| 2965 | var tag_val_buf: Value.Payload.U64 = undefined; | ||
| 2966 | while (field_i < fields_len) : (field_i += 1) { | 3091 | while (field_i < fields_len) : (field_i += 1) { |
| 2967 | if (field_i % 32 == 0) { | 3092 | if (field_i % 32 == 0) { |
| 2968 | cur_bit_bag = sema.code.extra[bit_bag_index]; | 3093 | cur_bit_bag = sema.code.extra[bit_bag_index]; |
| ... | @@ -2977,15 +3102,12 @@ fn zirEnumDecl( | ... | @@ -2977,15 +3102,12 @@ fn zirEnumDecl( |
| 2977 | // doc comment | 3102 | // doc comment |
| 2978 | extra_index += 1; | 3103 | extra_index += 1; |
| 2979 | 3104 | ||
| 2980 | // This string needs to outlive the ZIR code. | 3105 | const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir); |
| 2981 | const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); | 3106 | if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name)) |other_index| { |
| 2982 | 3107 | const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; | |
| 2983 | const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name); | 3108 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; |
| 2984 | if (gop_field.found_existing) { | ||
| 2985 | const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; | ||
| 2986 | const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_field.index }).lazy; | ||
| 2987 | const msg = msg: { | 3109 | const msg = msg: { |
| 2988 | const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name}); | 3110 | const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name_zir}); |
| 2989 | errdefer msg.destroy(gpa); | 3111 | errdefer msg.destroy(gpa); |
| 2990 | try sema.errNote(block, other_field_src, msg, "other field here", .{}); | 3112 | try sema.errNote(block, other_field_src, msg, "other field here", .{}); |
| 2991 | break :msg msg; | 3113 | break :msg msg; |
| ... | @@ -2993,13 +3115,13 @@ fn zirEnumDecl( | ... | @@ -2993,13 +3115,13 @@ fn zirEnumDecl( |
| 2993 | return sema.failWithOwnedErrorMsg(msg); | 3115 | return sema.failWithOwnedErrorMsg(msg); |
| 2994 | } | 3116 | } |
| 2995 | 3117 | ||
| 2996 | if (has_tag_value) { | 3118 | const tag_overflow = if (has_tag_value) overflow: { |
| 2997 | const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 3119 | const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 2998 | extra_index += 1; | 3120 | extra_index += 1; |
| 2999 | const tag_inst = try sema.resolveInst(tag_val_ref); | 3121 | const tag_inst = try sema.resolveInst(tag_val_ref); |
| 3000 | const tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) { | 3122 | last_tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) { |
| 3001 | error.NeededSourceLocation => { | 3123 | error.NeededSourceLocation => { |
| 3002 | const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ | 3124 | const value_src = mod.fieldSrcLoc(new_decl_index, .{ |
| 3003 | .index = field_i, | 3125 | .index = field_i, |
| 3004 | .range = .value, | 3126 | .range = .value, |
| 3005 | }).lazy; | 3127 | }).lazy; |
| ... | @@ -3008,63 +3130,56 @@ fn zirEnumDecl( | ... | @@ -3008,63 +3130,56 @@ fn zirEnumDecl( |
| 3008 | }, | 3130 | }, |
| 3009 | else => |e| return e, | 3131 | else => |e| return e, |
| 3010 | }; | 3132 | }; |
| 3011 | last_tag_val = tag_val; | 3133 | if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; |
| 3012 | const copied_tag_val = try tag_val.copy(decl_arena_allocator); | 3134 | last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty); |
| 3013 | const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{ | 3135 | if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, last_tag_val.?.toIntern())) |other_index| { |
| 3014 | .ty = enum_obj.tag_ty, | 3136 | const value_src = mod.fieldSrcLoc(new_decl_index, .{ |
| 3015 | .mod = mod, | ||
| 3016 | }); | ||
| 3017 | if (gop_val.found_existing) { | ||
| 3018 | const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ | ||
| 3019 | .index = field_i, | 3137 | .index = field_i, |
| 3020 | .range = .value, | 3138 | .range = .value, |
| 3021 | }).lazy; | 3139 | }).lazy; |
| 3022 | const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy; | 3140 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; |
| 3023 | const msg = msg: { | 3141 | const msg = msg: { |
| 3024 | const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)}); | 3142 | const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)}); |
| 3025 | errdefer msg.destroy(gpa); | 3143 | errdefer msg.destroy(gpa); |
| 3026 | try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); | 3144 | try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); |
| 3027 | break :msg msg; | 3145 | break :msg msg; |
| 3028 | }; | 3146 | }; |
| 3029 | return sema.failWithOwnedErrorMsg(msg); | 3147 | return sema.failWithOwnedErrorMsg(msg); |
| 3030 | } | 3148 | } |
| 3031 | } else if (any_values) { | 3149 | break :overflow false; |
| 3032 | const tag_val = if (last_tag_val) |val| | 3150 | } else if (any_values) overflow: { |
| 3033 | try sema.intAdd(val, Value.one, enum_obj.tag_ty) | 3151 | var overflow: ?usize = null; |
| 3152 | last_tag_val = if (last_tag_val) |val| | ||
| 3153 | try sema.intAdd(val, try mod.intValue(int_tag_ty, 1), int_tag_ty, &overflow) | ||
| 3034 | else | 3154 | else |
| 3035 | Value.zero; | 3155 | try mod.intValue(int_tag_ty, 0); |
| 3036 | last_tag_val = tag_val; | 3156 | if (overflow != null) break :overflow true; |
| 3037 | const copied_tag_val = try tag_val.copy(decl_arena_allocator); | 3157 | if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, last_tag_val.?.toIntern())) |other_index| { |
| 3038 | const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{ | 3158 | const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy; |
| 3039 | .ty = enum_obj.tag_ty, | 3159 | const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy; |
| 3040 | .mod = mod, | ||
| 3041 | }); | ||
| 3042 | if (gop_val.found_existing) { | ||
| 3043 | const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; | ||
| 3044 | const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy; | ||
| 3045 | const msg = msg: { | 3160 | const msg = msg: { |
| 3046 | const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)}); | 3161 | const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)}); |
| 3047 | errdefer msg.destroy(gpa); | 3162 | errdefer msg.destroy(gpa); |
| 3048 | try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); | 3163 | try sema.errNote(block, other_field_src, msg, "other occurrence here", .{}); |
| 3049 | break :msg msg; | 3164 | break :msg msg; |
| 3050 | }; | 3165 | }; |
| 3051 | return sema.failWithOwnedErrorMsg(msg); | 3166 | return sema.failWithOwnedErrorMsg(msg); |
| 3052 | } | 3167 | } |
| 3053 | } else { | 3168 | break :overflow false; |
| 3054 | tag_val_buf = .{ | 3169 | } else overflow: { |
| 3055 | .base = .{ .tag = .int_u64 }, | 3170 | last_tag_val = try mod.intValue(Type.comptime_int, field_i); |
| 3056 | .data = field_i, | 3171 | if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true; |
| 3057 | }; | 3172 | last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty); |
| 3058 | last_tag_val = Value.initPayload(&tag_val_buf.base); | 3173 | break :overflow false; |
| 3059 | } | 3174 | }; |
| 3060 | 3175 | ||
| 3061 | if (!(try sema.intFitsInType(last_tag_val.?, enum_obj.tag_ty, null))) { | 3176 | if (tag_overflow) { |
| 3062 | const value_src = enum_obj.fieldSrcLoc(sema.mod, .{ | 3177 | const value_src = mod.fieldSrcLoc(new_decl_index, .{ |
| 3063 | .index = field_i, | 3178 | .index = field_i, |
| 3064 | .range = if (has_tag_value) .value else .name, | 3179 | .range = if (has_tag_value) .value else .name, |
| 3065 | }).lazy; | 3180 | }).lazy; |
| 3066 | const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{ | 3181 | const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{ |
| 3067 | last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod), | 3182 | last_tag_val.?.fmtValue(int_tag_ty, mod), int_tag_ty.fmt(mod), |
| 3068 | }); | 3183 | }); |
| 3069 | return sema.failWithOwnedErrorMsg(msg); | 3184 | return sema.failWithOwnedErrorMsg(msg); |
| 3070 | } | 3185 | } |
| ... | @@ -3081,6 +3196,8 @@ fn zirUnionDecl( | ... | @@ -3081,6 +3196,8 @@ fn zirUnionDecl( |
| 3081 | const tracy = trace(@src()); | 3196 | const tracy = trace(@src()); |
| 3082 | defer tracy.end(); | 3197 | defer tracy.end(); |
| 3083 | 3198 | ||
| 3199 | const mod = sema.mod; | ||
| 3200 | const gpa = sema.gpa; | ||
| 3084 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); | 3201 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); |
| 3085 | var extra_index: usize = extended.operand; | 3202 | var extra_index: usize = extended.operand; |
| 3086 | 3203 | ||
| ... | @@ -3100,55 +3217,60 @@ fn zirUnionDecl( | ... | @@ -3100,55 +3217,60 @@ fn zirUnionDecl( |
| 3100 | break :blk decls_len; | 3217 | break :blk decls_len; |
| 3101 | } else 0; | 3218 | } else 0; |
| 3102 | 3219 | ||
| 3103 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | 3220 | // Because these three things each reference each other, `undefined` |
| 3104 | errdefer new_decl_arena.deinit(); | 3221 | // placeholders are used before being set after the union type gains an |
| 3105 | const new_decl_arena_allocator = new_decl_arena.allocator(); | 3222 | // InternPool index. |
| 3106 | 3223 | ||
| 3107 | const union_obj = try new_decl_arena_allocator.create(Module.Union); | ||
| 3108 | const type_tag = if (small.has_tag_type or small.auto_enum_tag) | ||
| 3109 | Type.Tag.union_tagged | ||
| 3110 | else if (small.layout != .Auto) | ||
| 3111 | Type.Tag.@"union" | ||
| 3112 | else switch (block.sema.mod.optimizeMode()) { | ||
| 3113 | .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged, | ||
| 3114 | .ReleaseFast, .ReleaseSmall => Type.Tag.@"union", | ||
| 3115 | }; | ||
| 3116 | const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union); | ||
| 3117 | union_payload.* = .{ | ||
| 3118 | .base = .{ .tag = type_tag }, | ||
| 3119 | .data = union_obj, | ||
| 3120 | }; | ||
| 3121 | const union_ty = Type.initPayload(&union_payload.base); | ||
| 3122 | const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); | ||
| 3123 | const mod = sema.mod; | ||
| 3124 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ | 3224 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 3125 | .ty = Type.type, | 3225 | .ty = Type.noreturn, |
| 3126 | .val = union_val, | 3226 | .val = Value.@"unreachable", |
| 3127 | }, small.name_strategy, "union", inst); | 3227 | }, small.name_strategy, "union", inst); |
| 3128 | const new_decl = mod.declPtr(new_decl_index); | 3228 | const new_decl = mod.declPtr(new_decl_index); |
| 3129 | new_decl.owns_tv = true; | 3229 | new_decl.owns_tv = true; |
| 3130 | errdefer mod.abortAnonDecl(new_decl_index); | 3230 | errdefer mod.abortAnonDecl(new_decl_index); |
| 3131 | union_obj.* = .{ | 3231 | |
| 3232 | const new_namespace_index = try mod.createNamespace(.{ | ||
| 3233 | .parent = block.namespace.toOptional(), | ||
| 3234 | .ty = undefined, | ||
| 3235 | .file_scope = block.getFileScope(mod), | ||
| 3236 | }); | ||
| 3237 | const new_namespace = mod.namespacePtr(new_namespace_index); | ||
| 3238 | errdefer mod.destroyNamespace(new_namespace_index); | ||
| 3239 | |||
| 3240 | const union_index = try mod.createUnion(.{ | ||
| 3132 | .owner_decl = new_decl_index, | 3241 | .owner_decl = new_decl_index, |
| 3133 | .tag_ty = Type.initTag(.null), | 3242 | .tag_ty = Type.null, |
| 3134 | .fields = .{}, | 3243 | .fields = .{}, |
| 3135 | .zir_index = inst, | 3244 | .zir_index = inst, |
| 3136 | .layout = small.layout, | 3245 | .layout = small.layout, |
| 3137 | .status = .none, | 3246 | .status = .none, |
| 3138 | .namespace = .{ | 3247 | .namespace = new_namespace_index, |
| 3139 | .parent = block.namespace, | ||
| 3140 | .ty = union_ty, | ||
| 3141 | .file_scope = block.getFileScope(), | ||
| 3142 | }, | ||
| 3143 | }; | ||
| 3144 | std.log.scoped(.module).debug("create union {*} owned by {*} ({s})", .{ | ||
| 3145 | &union_obj.namespace, new_decl, new_decl.name, | ||
| 3146 | }); | 3248 | }); |
| 3147 | 3249 | errdefer mod.destroyUnion(union_index); | |
| 3148 | _ = try mod.scanNamespace(&union_obj.namespace, extra_index, decls_len, new_decl); | 3250 | |
| 3149 | 3251 | const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{ | |
| 3150 | try new_decl.finalizeNewArena(&new_decl_arena); | 3252 | .index = union_index, |
| 3151 | return sema.analyzeDeclVal(block, src, new_decl_index); | 3253 | .runtime_tag = if (small.has_tag_type or small.auto_enum_tag) |
| 3254 | .tagged | ||
| 3255 | else if (small.layout != .Auto) | ||
| 3256 | .none | ||
| 3257 | else switch (block.sema.mod.optimizeMode()) { | ||
| 3258 | .Debug, .ReleaseSafe => .safety, | ||
| 3259 | .ReleaseFast, .ReleaseSmall => .none, | ||
| 3260 | }, | ||
| 3261 | } }); | ||
| 3262 | // TODO: figure out InternPool removals for incremental compilation | ||
| 3263 | //errdefer mod.intern_pool.remove(union_ty); | ||
| 3264 | |||
| 3265 | new_decl.ty = Type.type; | ||
| 3266 | new_decl.val = union_ty.toValue(); | ||
| 3267 | new_namespace.ty = union_ty.toType(); | ||
| 3268 | |||
| 3269 | _ = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl); | ||
| 3270 | |||
| 3271 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); | ||
| 3272 | try mod.finalizeAnonDecl(new_decl_index); | ||
| 3273 | return decl_val; | ||
| 3152 | } | 3274 | } |
| 3153 | 3275 | ||
| 3154 | fn zirOpaqueDecl( | 3276 | fn zirOpaqueDecl( |
| ... | @@ -3161,7 +3283,6 @@ fn zirOpaqueDecl( | ... | @@ -3161,7 +3283,6 @@ fn zirOpaqueDecl( |
| 3161 | defer tracy.end(); | 3283 | defer tracy.end(); |
| 3162 | 3284 | ||
| 3163 | const mod = sema.mod; | 3285 | const mod = sema.mod; |
| 3164 | const gpa = sema.gpa; | ||
| 3165 | const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small); | 3286 | const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small); |
| 3166 | var extra_index: usize = extended.operand; | 3287 | var extra_index: usize = extended.operand; |
| 3167 | 3288 | ||
| ... | @@ -3177,42 +3298,42 @@ fn zirOpaqueDecl( | ... | @@ -3177,42 +3298,42 @@ fn zirOpaqueDecl( |
| 3177 | break :blk decls_len; | 3298 | break :blk decls_len; |
| 3178 | } else 0; | 3299 | } else 0; |
| 3179 | 3300 | ||
| 3180 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | 3301 | // Because these three things each reference each other, `undefined` |
| 3181 | errdefer new_decl_arena.deinit(); | 3302 | // placeholders are used in two places before being set after the opaque |
| 3182 | const new_decl_arena_allocator = new_decl_arena.allocator(); | 3303 | // type gains an InternPool index. |
| 3183 | 3304 | ||
| 3184 | const opaque_obj = try new_decl_arena_allocator.create(Module.Opaque); | ||
| 3185 | const opaque_ty_payload = try new_decl_arena_allocator.create(Type.Payload.Opaque); | ||
| 3186 | opaque_ty_payload.* = .{ | ||
| 3187 | .base = .{ .tag = .@"opaque" }, | ||
| 3188 | .data = opaque_obj, | ||
| 3189 | }; | ||
| 3190 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); | ||
| 3191 | const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); | ||
| 3192 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ | 3305 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 3193 | .ty = Type.type, | 3306 | .ty = Type.noreturn, |
| 3194 | .val = opaque_val, | 3307 | .val = Value.@"unreachable", |
| 3195 | }, small.name_strategy, "opaque", inst); | 3308 | }, small.name_strategy, "opaque", inst); |
| 3196 | const new_decl = mod.declPtr(new_decl_index); | 3309 | const new_decl = mod.declPtr(new_decl_index); |
| 3197 | new_decl.owns_tv = true; | 3310 | new_decl.owns_tv = true; |
| 3198 | errdefer mod.abortAnonDecl(new_decl_index); | 3311 | errdefer mod.abortAnonDecl(new_decl_index); |
| 3199 | 3312 | ||
| 3200 | opaque_obj.* = .{ | 3313 | const new_namespace_index = try mod.createNamespace(.{ |
| 3201 | .owner_decl = new_decl_index, | 3314 | .parent = block.namespace.toOptional(), |
| 3202 | .namespace = .{ | 3315 | .ty = undefined, |
| 3203 | .parent = block.namespace, | 3316 | .file_scope = block.getFileScope(mod), |
| 3204 | .ty = opaque_ty, | ||
| 3205 | .file_scope = block.getFileScope(), | ||
| 3206 | }, | ||
| 3207 | }; | ||
| 3208 | std.log.scoped(.module).debug("create opaque {*} owned by {*} ({s})", .{ | ||
| 3209 | &opaque_obj.namespace, new_decl, new_decl.name, | ||
| 3210 | }); | 3317 | }); |
| 3318 | const new_namespace = mod.namespacePtr(new_namespace_index); | ||
| 3319 | errdefer mod.destroyNamespace(new_namespace_index); | ||
| 3320 | |||
| 3321 | const opaque_ty = try mod.intern(.{ .opaque_type = .{ | ||
| 3322 | .decl = new_decl_index, | ||
| 3323 | .namespace = new_namespace_index, | ||
| 3324 | } }); | ||
| 3325 | // TODO: figure out InternPool removals for incremental compilation | ||
| 3326 | //errdefer mod.intern_pool.remove(opaque_ty); | ||
| 3211 | 3327 | ||
| 3212 | extra_index = try mod.scanNamespace(&opaque_obj.namespace, extra_index, decls_len, new_decl); | 3328 | new_decl.ty = Type.type; |
| 3329 | new_decl.val = opaque_ty.toValue(); | ||
| 3330 | new_namespace.ty = opaque_ty.toType(); | ||
| 3213 | 3331 | ||
| 3214 | try new_decl.finalizeNewArena(&new_decl_arena); | 3332 | extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl); |
| 3215 | return sema.analyzeDeclVal(block, src, new_decl_index); | 3333 | |
| 3334 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); | ||
| 3335 | try mod.finalizeAnonDecl(new_decl_index); | ||
| 3336 | return decl_val; | ||
| 3216 | } | 3337 | } |
| 3217 | 3338 | ||
| 3218 | fn zirErrorSetDecl( | 3339 | fn zirErrorSetDecl( |
| ... | @@ -3224,48 +3345,39 @@ fn zirErrorSetDecl( | ... | @@ -3224,48 +3345,39 @@ fn zirErrorSetDecl( |
| 3224 | const tracy = trace(@src()); | 3345 | const tracy = trace(@src()); |
| 3225 | defer tracy.end(); | 3346 | defer tracy.end(); |
| 3226 | 3347 | ||
| 3348 | const mod = sema.mod; | ||
| 3227 | const gpa = sema.gpa; | 3349 | const gpa = sema.gpa; |
| 3228 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 3350 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 3229 | const src = inst_data.src(); | 3351 | const src = inst_data.src(); |
| 3230 | const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); | 3352 | const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); |
| 3231 | 3353 | ||
| 3232 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | 3354 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; |
| 3233 | errdefer new_decl_arena.deinit(); | 3355 | try names.ensureUnusedCapacity(sema.arena, extra.data.fields_len); |
| 3234 | const new_decl_arena_allocator = new_decl_arena.allocator(); | ||
| 3235 | |||
| 3236 | const error_set = try new_decl_arena_allocator.create(Module.ErrorSet); | ||
| 3237 | const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set); | ||
| 3238 | const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty); | ||
| 3239 | const mod = sema.mod; | ||
| 3240 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ | ||
| 3241 | .ty = Type.type, | ||
| 3242 | .val = error_set_val, | ||
| 3243 | }, name_strategy, "error", inst); | ||
| 3244 | const new_decl = mod.declPtr(new_decl_index); | ||
| 3245 | new_decl.owns_tv = true; | ||
| 3246 | errdefer mod.abortAnonDecl(new_decl_index); | ||
| 3247 | |||
| 3248 | var names = Module.ErrorSet.NameMap{}; | ||
| 3249 | try names.ensureUnusedCapacity(new_decl_arena_allocator, extra.data.fields_len); | ||
| 3250 | 3356 | ||
| 3251 | var extra_index = @intCast(u32, extra.end); | 3357 | var extra_index = @intCast(u32, extra.end); |
| 3252 | const extra_index_end = extra_index + (extra.data.fields_len * 2); | 3358 | const extra_index_end = extra_index + (extra.data.fields_len * 2); |
| 3253 | while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string | 3359 | while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string |
| 3254 | const str_index = sema.code.extra[extra_index]; | 3360 | const str_index = sema.code.extra[extra_index]; |
| 3255 | const kv = try mod.getErrorValue(sema.code.nullTerminatedString(str_index)); | 3361 | const name = sema.code.nullTerminatedString(str_index); |
| 3256 | const result = names.getOrPutAssumeCapacity(kv.key); | 3362 | const name_ip = try mod.intern_pool.getOrPutString(gpa, name); |
| 3363 | _ = try mod.getErrorValue(name_ip); | ||
| 3364 | const result = names.getOrPutAssumeCapacity(name_ip); | ||
| 3257 | assert(!result.found_existing); // verified in AstGen | 3365 | assert(!result.found_existing); // verified in AstGen |
| 3258 | } | 3366 | } |
| 3259 | 3367 | ||
| 3260 | // names must be sorted. | 3368 | const error_set_ty = try mod.errorSetFromUnsortedNames(names.keys()); |
| 3261 | Module.ErrorSet.sortNames(&names); | ||
| 3262 | 3369 | ||
| 3263 | error_set.* = .{ | 3370 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 3264 | .owner_decl = new_decl_index, | 3371 | .ty = Type.type, |
| 3265 | .names = names, | 3372 | .val = error_set_ty.toValue(), |
| 3266 | }; | 3373 | }, name_strategy, "error", inst); |
| 3267 | try new_decl.finalizeNewArena(&new_decl_arena); | 3374 | const new_decl = mod.declPtr(new_decl_index); |
| 3268 | return sema.analyzeDeclVal(block, src, new_decl_index); | 3375 | new_decl.owns_tv = true; |
| 3376 | errdefer mod.abortAnonDecl(new_decl_index); | ||
| 3377 | |||
| 3378 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); | ||
| 3379 | try mod.finalizeAnonDecl(new_decl_index); | ||
| 3380 | return decl_val; | ||
| 3269 | } | 3381 | } |
| 3270 | 3382 | ||
| 3271 | fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { | 3383 | fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| ... | @@ -3319,7 +3431,8 @@ fn ensureResultUsed( | ... | @@ -3319,7 +3431,8 @@ fn ensureResultUsed( |
| 3319 | ty: Type, | 3431 | ty: Type, |
| 3320 | src: LazySrcLoc, | 3432 | src: LazySrcLoc, |
| 3321 | ) CompileError!void { | 3433 | ) CompileError!void { |
| 3322 | switch (ty.zigTypeTag()) { | 3434 | const mod = sema.mod; |
| 3435 | switch (ty.zigTypeTag(mod)) { | ||
| 3323 | .Void, .NoReturn => return, | 3436 | .Void, .NoReturn => return, |
| 3324 | .ErrorSet, .ErrorUnion => { | 3437 | .ErrorSet, .ErrorUnion => { |
| 3325 | const msg = msg: { | 3438 | const msg = msg: { |
| ... | @@ -3347,11 +3460,12 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -3347,11 +3460,12 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3347 | const tracy = trace(@src()); | 3460 | const tracy = trace(@src()); |
| 3348 | defer tracy.end(); | 3461 | defer tracy.end(); |
| 3349 | 3462 | ||
| 3463 | const mod = sema.mod; | ||
| 3350 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 3464 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3351 | const operand = try sema.resolveInst(inst_data.operand); | 3465 | const operand = try sema.resolveInst(inst_data.operand); |
| 3352 | const src = inst_data.src(); | 3466 | const src = inst_data.src(); |
| 3353 | const operand_ty = sema.typeOf(operand); | 3467 | const operand_ty = sema.typeOf(operand); |
| 3354 | switch (operand_ty.zigTypeTag()) { | 3468 | switch (operand_ty.zigTypeTag(mod)) { |
| 3355 | .ErrorSet, .ErrorUnion => { | 3469 | .ErrorSet, .ErrorUnion => { |
| 3356 | const msg = msg: { | 3470 | const msg = msg: { |
| 3357 | const msg = try sema.errMsg(block, src, "error is discarded", .{}); | 3471 | const msg = try sema.errMsg(block, src, "error is discarded", .{}); |
| ... | @@ -3369,16 +3483,17 @@ fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index | ... | @@ -3369,16 +3483,17 @@ fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index |
| 3369 | const tracy = trace(@src()); | 3483 | const tracy = trace(@src()); |
| 3370 | defer tracy.end(); | 3484 | defer tracy.end(); |
| 3371 | 3485 | ||
| 3486 | const mod = sema.mod; | ||
| 3372 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 3487 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3373 | const src = inst_data.src(); | 3488 | const src = inst_data.src(); |
| 3374 | const operand = try sema.resolveInst(inst_data.operand); | 3489 | const operand = try sema.resolveInst(inst_data.operand); |
| 3375 | const operand_ty = sema.typeOf(operand); | 3490 | const operand_ty = sema.typeOf(operand); |
| 3376 | const err_union_ty = if (operand_ty.zigTypeTag() == .Pointer) | 3491 | const err_union_ty = if (operand_ty.zigTypeTag(mod) == .Pointer) |
| 3377 | operand_ty.childType() | 3492 | operand_ty.childType(mod) |
| 3378 | else | 3493 | else |
| 3379 | operand_ty; | 3494 | operand_ty; |
| 3380 | if (err_union_ty.zigTypeTag() != .ErrorUnion) return; | 3495 | if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) return; |
| 3381 | const payload_ty = err_union_ty.errorUnionPayload().zigTypeTag(); | 3496 | const payload_ty = err_union_ty.errorUnionPayload(mod).zigTypeTag(mod); |
| 3382 | if (payload_ty != .Void and payload_ty != .NoReturn) { | 3497 | if (payload_ty != .Void and payload_ty != .NoReturn) { |
| 3383 | const msg = msg: { | 3498 | const msg = msg: { |
| 3384 | const msg = try sema.errMsg(block, src, "error union payload is ignored", .{}); | 3499 | const msg = try sema.errMsg(block, src, "error union payload is ignored", .{}); |
| ... | @@ -3407,11 +3522,13 @@ fn indexablePtrLen( | ... | @@ -3407,11 +3522,13 @@ fn indexablePtrLen( |
| 3407 | src: LazySrcLoc, | 3522 | src: LazySrcLoc, |
| 3408 | object: Air.Inst.Ref, | 3523 | object: Air.Inst.Ref, |
| 3409 | ) CompileError!Air.Inst.Ref { | 3524 | ) CompileError!Air.Inst.Ref { |
| 3525 | const mod = sema.mod; | ||
| 3410 | const object_ty = sema.typeOf(object); | 3526 | const object_ty = sema.typeOf(object); |
| 3411 | const is_pointer_to = object_ty.isSinglePointer(); | 3527 | const is_pointer_to = object_ty.isSinglePointer(mod); |
| 3412 | const indexable_ty = if (is_pointer_to) object_ty.childType() else object_ty; | 3528 | const indexable_ty = if (is_pointer_to) object_ty.childType(mod) else object_ty; |
| 3413 | try checkIndexable(sema, block, src, indexable_ty); | 3529 | try checkIndexable(sema, block, src, indexable_ty); |
| 3414 | return sema.fieldVal(block, src, object, "len", src); | 3530 | const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "len"); |
| 3531 | return sema.fieldVal(block, src, object, field_name, src); | ||
| 3415 | } | 3532 | } |
| 3416 | 3533 | ||
| 3417 | fn indexablePtrLenOrNone( | 3534 | fn indexablePtrLenOrNone( |
| ... | @@ -3420,10 +3537,12 @@ fn indexablePtrLenOrNone( | ... | @@ -3420,10 +3537,12 @@ fn indexablePtrLenOrNone( |
| 3420 | src: LazySrcLoc, | 3537 | src: LazySrcLoc, |
| 3421 | operand: Air.Inst.Ref, | 3538 | operand: Air.Inst.Ref, |
| 3422 | ) CompileError!Air.Inst.Ref { | 3539 | ) CompileError!Air.Inst.Ref { |
| 3540 | const mod = sema.mod; | ||
| 3423 | const operand_ty = sema.typeOf(operand); | 3541 | const operand_ty = sema.typeOf(operand); |
| 3424 | try checkMemOperand(sema, block, src, operand_ty); | 3542 | try checkMemOperand(sema, block, src, operand_ty); |
| 3425 | if (operand_ty.ptrSize() == .Many) return .none; | 3543 | if (operand_ty.ptrSize(mod) == .Many) return .none; |
| 3426 | return sema.fieldVal(block, src, operand, "len", src); | 3544 | const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "len"); |
| 3545 | return sema.fieldVal(block, src, operand, field_name, src); | ||
| 3427 | } | 3546 | } |
| 3428 | 3547 | ||
| 3429 | fn zirAllocExtended( | 3548 | fn zirAllocExtended( |
| ... | @@ -3431,6 +3550,7 @@ fn zirAllocExtended( | ... | @@ -3431,6 +3550,7 @@ fn zirAllocExtended( |
| 3431 | block: *Block, | 3550 | block: *Block, |
| 3432 | extended: Zir.Inst.Extended.InstData, | 3551 | extended: Zir.Inst.Extended.InstData, |
| 3433 | ) CompileError!Air.Inst.Ref { | 3552 | ) CompileError!Air.Inst.Ref { |
| 3553 | const gpa = sema.gpa; | ||
| 3434 | const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); | 3554 | const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); |
| 3435 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node }; | 3555 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node }; |
| 3436 | const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node }; | 3556 | const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node }; |
| ... | @@ -3451,22 +3571,19 @@ fn zirAllocExtended( | ... | @@ -3451,22 +3571,19 @@ fn zirAllocExtended( |
| 3451 | break :blk alignment; | 3571 | break :blk alignment; |
| 3452 | } else 0; | 3572 | } else 0; |
| 3453 | 3573 | ||
| 3454 | const inferred_alloc_ty = if (small.is_const) | ||
| 3455 | Type.initTag(.inferred_alloc_const) | ||
| 3456 | else | ||
| 3457 | Type.initTag(.inferred_alloc_mut); | ||
| 3458 | |||
| 3459 | if (block.is_comptime or small.is_comptime) { | 3574 | if (block.is_comptime or small.is_comptime) { |
| 3460 | if (small.has_type) { | 3575 | if (small.has_type) { |
| 3461 | return sema.analyzeComptimeAlloc(block, var_ty, alignment); | 3576 | return sema.analyzeComptimeAlloc(block, var_ty, alignment); |
| 3462 | } else { | 3577 | } else { |
| 3463 | return sema.addConstant( | 3578 | try sema.air_instructions.append(gpa, .{ |
| 3464 | inferred_alloc_ty, | 3579 | .tag = .inferred_alloc_comptime, |
| 3465 | try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ | 3580 | .data = .{ .inferred_alloc_comptime = .{ |
| 3466 | .decl_index = undefined, | 3581 | .decl_index = undefined, |
| 3467 | .alignment = alignment, | 3582 | .alignment = InternPool.Alignment.fromByteUnits(alignment), |
| 3468 | }), | 3583 | .is_const = small.is_const, |
| 3469 | ); | 3584 | } }, |
| 3585 | }); | ||
| 3586 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); | ||
| 3470 | } | 3587 | } |
| 3471 | } | 3588 | } |
| 3472 | 3589 | ||
| ... | @@ -3484,17 +3601,15 @@ fn zirAllocExtended( | ... | @@ -3484,17 +3601,15 @@ fn zirAllocExtended( |
| 3484 | return block.addTy(.alloc, ptr_type); | 3601 | return block.addTy(.alloc, ptr_type); |
| 3485 | } | 3602 | } |
| 3486 | 3603 | ||
| 3487 | // `Sema.addConstant` does not add the instruction to the block because it is | 3604 | const result_index = try block.addInstAsIndex(.{ |
| 3488 | // not needed in the case of constant values. However here, we plan to "downgrade" | 3605 | .tag = .inferred_alloc, |
| 3489 | // to a normal instruction when we hit `resolve_inferred_alloc`. So we append | 3606 | .data = .{ .inferred_alloc = .{ |
| 3490 | // to the block even though it is currently a `.constant`. | 3607 | .alignment = InternPool.Alignment.fromByteUnits(alignment), |
| 3491 | const result = try sema.addConstant( | 3608 | .is_const = small.is_const, |
| 3492 | inferred_alloc_ty, | 3609 | } }, |
| 3493 | try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }), | 3610 | }); |
| 3494 | ); | 3611 | try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{}); |
| 3495 | try block.instructions.append(sema.gpa, Air.refToIndex(result).?); | 3612 | return Air.indexToRef(result_index); |
| 3496 | try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {}); | ||
| 3497 | return result; | ||
| 3498 | } | 3613 | } |
| 3499 | 3614 | ||
| 3500 | fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 3615 | fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -3508,11 +3623,12 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -3508,11 +3623,12 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 3508 | } | 3623 | } |
| 3509 | 3624 | ||
| 3510 | fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 3625 | fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 3626 | const mod = sema.mod; | ||
| 3511 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 3627 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3512 | const alloc = try sema.resolveInst(inst_data.operand); | 3628 | const alloc = try sema.resolveInst(inst_data.operand); |
| 3513 | const alloc_ty = sema.typeOf(alloc); | 3629 | const alloc_ty = sema.typeOf(alloc); |
| 3514 | 3630 | ||
| 3515 | var ptr_info = alloc_ty.ptrInfo().data; | 3631 | var ptr_info = alloc_ty.ptrInfo(mod); |
| 3516 | const elem_ty = ptr_info.pointee_type; | 3632 | const elem_ty = ptr_info.pointee_type; |
| 3517 | 3633 | ||
| 3518 | // Detect if all stores to an `.alloc` were comptime-known. | 3634 | // Detect if all stores to an `.alloc` were comptime-known. |
| ... | @@ -3558,8 +3674,8 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro | ... | @@ -3558,8 +3674,8 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 3558 | var anon_decl = try block.startAnonDecl(); | 3674 | var anon_decl = try block.startAnonDecl(); |
| 3559 | defer anon_decl.deinit(); | 3675 | defer anon_decl.deinit(); |
| 3560 | return sema.analyzeDeclRef(try anon_decl.finish( | 3676 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 3561 | try elem_ty.copy(anon_decl.arena()), | 3677 | elem_ty, |
| 3562 | try store_val.copy(anon_decl.arena()), | 3678 | store_val, |
| 3563 | ptr_info.@"align", | 3679 | ptr_info.@"align", |
| 3564 | )); | 3680 | )); |
| 3565 | } | 3681 | } |
| ... | @@ -3568,15 +3684,16 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro | ... | @@ -3568,15 +3684,16 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 3568 | } | 3684 | } |
| 3569 | 3685 | ||
| 3570 | fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref { | 3686 | fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref { |
| 3687 | const mod = sema.mod; | ||
| 3571 | const alloc_ty = sema.typeOf(alloc); | 3688 | const alloc_ty = sema.typeOf(alloc); |
| 3572 | 3689 | ||
| 3573 | var ptr_info = alloc_ty.ptrInfo().data; | 3690 | var ptr_info = alloc_ty.ptrInfo(mod); |
| 3574 | ptr_info.mutable = false; | 3691 | ptr_info.mutable = false; |
| 3575 | const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); | 3692 | const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); |
| 3576 | 3693 | ||
| 3577 | // Detect if a comptime value simply needs to have its type changed. | 3694 | // Detect if a comptime value simply needs to have its type changed. |
| 3578 | if (try sema.resolveMaybeUndefVal(alloc)) |val| { | 3695 | if (try sema.resolveMaybeUndefVal(alloc)) |val| { |
| 3579 | return sema.addConstant(const_ptr_ty, val); | 3696 | return sema.addConstant(const_ptr_ty, try mod.getCoerced(val, const_ptr_ty)); |
| 3580 | } | 3697 | } |
| 3581 | 3698 | ||
| 3582 | return block.addBitCast(const_ptr_ty, alloc); | 3699 | return block.addBitCast(const_ptr_ty, alloc); |
| ... | @@ -3585,18 +3702,22 @@ fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Ai | ... | @@ -3585,18 +3702,22 @@ fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Ai |
| 3585 | fn zirAllocInferredComptime( | 3702 | fn zirAllocInferredComptime( |
| 3586 | sema: *Sema, | 3703 | sema: *Sema, |
| 3587 | inst: Zir.Inst.Index, | 3704 | inst: Zir.Inst.Index, |
| 3588 | inferred_alloc_ty: Type, | 3705 | is_const: bool, |
| 3589 | ) CompileError!Air.Inst.Ref { | 3706 | ) CompileError!Air.Inst.Ref { |
| 3707 | const gpa = sema.gpa; | ||
| 3590 | const src_node = sema.code.instructions.items(.data)[inst].node; | 3708 | const src_node = sema.code.instructions.items(.data)[inst].node; |
| 3591 | const src = LazySrcLoc.nodeOffset(src_node); | 3709 | const src = LazySrcLoc.nodeOffset(src_node); |
| 3592 | sema.src = src; | 3710 | sema.src = src; |
| 3593 | return sema.addConstant( | 3711 | |
| 3594 | inferred_alloc_ty, | 3712 | try sema.air_instructions.append(gpa, .{ |
| 3595 | try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ | 3713 | .tag = .inferred_alloc_comptime, |
| 3714 | .data = .{ .inferred_alloc_comptime = .{ | ||
| 3596 | .decl_index = undefined, | 3715 | .decl_index = undefined, |
| 3597 | .alignment = 0, | 3716 | .alignment = .none, |
| 3598 | }), | 3717 | .is_const = is_const, |
| 3599 | ); | 3718 | } }, |
| 3719 | }); | ||
| 3720 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); | ||
| 3600 | } | 3721 | } |
| 3601 | 3722 | ||
| 3602 | fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 3723 | fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -3642,104 +3763,103 @@ fn zirAllocInferred( | ... | @@ -3642,104 +3763,103 @@ fn zirAllocInferred( |
| 3642 | sema: *Sema, | 3763 | sema: *Sema, |
| 3643 | block: *Block, | 3764 | block: *Block, |
| 3644 | inst: Zir.Inst.Index, | 3765 | inst: Zir.Inst.Index, |
| 3645 | inferred_alloc_ty: Type, | 3766 | is_const: bool, |
| 3646 | ) CompileError!Air.Inst.Ref { | 3767 | ) CompileError!Air.Inst.Ref { |
| 3647 | const tracy = trace(@src()); | 3768 | const tracy = trace(@src()); |
| 3648 | defer tracy.end(); | 3769 | defer tracy.end(); |
| 3649 | 3770 | ||
| 3771 | const gpa = sema.gpa; | ||
| 3650 | const src_node = sema.code.instructions.items(.data)[inst].node; | 3772 | const src_node = sema.code.instructions.items(.data)[inst].node; |
| 3651 | const src = LazySrcLoc.nodeOffset(src_node); | 3773 | const src = LazySrcLoc.nodeOffset(src_node); |
| 3652 | sema.src = src; | 3774 | sema.src = src; |
| 3653 | 3775 | ||
| 3654 | if (block.is_comptime) { | 3776 | if (block.is_comptime) { |
| 3655 | return sema.addConstant( | 3777 | try sema.air_instructions.append(gpa, .{ |
| 3656 | inferred_alloc_ty, | 3778 | .tag = .inferred_alloc_comptime, |
| 3657 | try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{ | 3779 | .data = .{ .inferred_alloc_comptime = .{ |
| 3658 | .decl_index = undefined, | 3780 | .decl_index = undefined, |
| 3659 | .alignment = 0, | 3781 | .alignment = .none, |
| 3660 | }), | 3782 | .is_const = is_const, |
| 3661 | ); | 3783 | } }, |
| 3784 | }); | ||
| 3785 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); | ||
| 3662 | } | 3786 | } |
| 3663 | 3787 | ||
| 3664 | // `Sema.addConstant` does not add the instruction to the block because it is | 3788 | const result_index = try block.addInstAsIndex(.{ |
| 3665 | // not needed in the case of constant values. However here, we plan to "downgrade" | 3789 | .tag = .inferred_alloc, |
| 3666 | // to a normal instruction when we hit `resolve_inferred_alloc`. So we append | 3790 | .data = .{ .inferred_alloc = .{ |
| 3667 | // to the block even though it is currently a `.constant`. | 3791 | .alignment = .none, |
| 3668 | const result = try sema.addConstant( | 3792 | .is_const = is_const, |
| 3669 | inferred_alloc_ty, | 3793 | } }, |
| 3670 | try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }), | 3794 | }); |
| 3671 | ); | 3795 | try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{}); |
| 3672 | try block.instructions.append(sema.gpa, Air.refToIndex(result).?); | 3796 | return Air.indexToRef(result_index); |
| 3673 | try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {}); | ||
| 3674 | return result; | ||
| 3675 | } | 3797 | } |
| 3676 | 3798 | ||
| 3677 | fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 3799 | fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 3678 | const tracy = trace(@src()); | 3800 | const tracy = trace(@src()); |
| 3679 | defer tracy.end(); | 3801 | defer tracy.end(); |
| 3680 | 3802 | ||
| 3803 | const mod = sema.mod; | ||
| 3681 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 3804 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3682 | const src = inst_data.src(); | 3805 | const src = inst_data.src(); |
| 3683 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; | 3806 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node }; |
| 3684 | const ptr = try sema.resolveInst(inst_data.operand); | 3807 | const ptr = try sema.resolveInst(inst_data.operand); |
| 3685 | const ptr_inst = Air.refToIndex(ptr).?; | 3808 | const ptr_inst = Air.refToIndex(ptr).?; |
| 3686 | assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant); | 3809 | const target = mod.getTarget(); |
| 3687 | const value_index = sema.air_instructions.items(.data)[ptr_inst].ty_pl.payload; | ||
| 3688 | const ptr_val = sema.air_values.items[value_index]; | ||
| 3689 | const var_is_mut = switch (sema.typeOf(ptr).tag()) { | ||
| 3690 | .inferred_alloc_const => false, | ||
| 3691 | .inferred_alloc_mut => true, | ||
| 3692 | else => unreachable, | ||
| 3693 | }; | ||
| 3694 | const target = sema.mod.getTarget(); | ||
| 3695 | 3810 | ||
| 3696 | switch (ptr_val.tag()) { | 3811 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { |
| 3697 | .inferred_alloc_comptime => { | 3812 | .inferred_alloc_comptime => { |
| 3698 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; | 3813 | const iac = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime; |
| 3699 | const decl_index = iac.data.decl_index; | 3814 | const decl_index = iac.decl_index; |
| 3700 | try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); | 3815 | try mod.declareDeclDependency(sema.owner_decl_index, decl_index); |
| 3701 | 3816 | ||
| 3702 | const decl = sema.mod.declPtr(decl_index); | 3817 | const decl = mod.declPtr(decl_index); |
| 3703 | const final_elem_ty = try decl.ty.copy(sema.arena); | 3818 | if (iac.is_const) try decl.intern(mod); |
| 3704 | const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 3819 | const final_elem_ty = decl.ty; |
| 3705 | .pointee_type = final_elem_ty, | 3820 | const final_ptr_ty = try mod.ptrType(.{ |
| 3706 | .mutable = true, | 3821 | .child = final_elem_ty.toIntern(), |
| 3707 | .@"align" = iac.data.alignment, | 3822 | .flags = .{ |
| 3708 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 3823 | .is_const = false, |
| 3824 | .alignment = iac.alignment, | ||
| 3825 | .address_space = target_util.defaultAddressSpace(target, .local), | ||
| 3826 | }, | ||
| 3709 | }); | 3827 | }); |
| 3710 | const final_ptr_ty_inst = try sema.addType(final_ptr_ty); | ||
| 3711 | sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst; | ||
| 3712 | 3828 | ||
| 3713 | try sema.maybeQueueFuncBodyAnalysis(decl_index); | 3829 | try sema.maybeQueueFuncBodyAnalysis(decl_index); |
| 3714 | if (var_is_mut) { | 3830 | // Change it to an interned. |
| 3715 | sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{ | 3831 | sema.air_instructions.set(ptr_inst, .{ |
| 3716 | .decl_index = decl_index, | 3832 | .tag = .interned, |
| 3717 | .runtime_index = block.runtime_index, | 3833 | .data = .{ .interned = try mod.intern(.{ .ptr = .{ |
| 3718 | }); | 3834 | .ty = final_ptr_ty.toIntern(), |
| 3719 | } else { | 3835 | .addr = if (!iac.is_const) .{ .mut_decl = .{ |
| 3720 | sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, decl_index); | 3836 | .decl = decl_index, |
| 3721 | } | 3837 | .runtime_index = block.runtime_index, |
| 3838 | } } else .{ .decl = decl_index }, | ||
| 3839 | } }) }, | ||
| 3840 | }); | ||
| 3722 | }, | 3841 | }, |
| 3723 | .inferred_alloc => { | 3842 | .inferred_alloc => { |
| 3724 | assert(sema.unresolved_inferred_allocs.remove(ptr_inst)); | 3843 | const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc; |
| 3725 | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; | 3844 | const ia2 = sema.unresolved_inferred_allocs.fetchRemove(ptr_inst).?.value; |
| 3726 | const peer_inst_list = inferred_alloc.data.prongs.items(.stored_inst); | 3845 | const peer_inst_list = ia2.prongs.items(.stored_inst); |
| 3727 | const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none); | 3846 | const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none); |
| 3728 | 3847 | ||
| 3729 | const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 3848 | const final_ptr_ty = try mod.ptrType(.{ |
| 3730 | .pointee_type = final_elem_ty, | 3849 | .child = final_elem_ty.toIntern(), |
| 3731 | .mutable = true, | 3850 | .flags = .{ |
| 3732 | .@"align" = inferred_alloc.data.alignment, | 3851 | .alignment = ia1.alignment, |
| 3733 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 3852 | .address_space = target_util.defaultAddressSpace(target, .local), |
| 3853 | }, | ||
| 3734 | }); | 3854 | }); |
| 3735 | 3855 | ||
| 3736 | if (var_is_mut) { | 3856 | if (!ia1.is_const) { |
| 3737 | try sema.validateVarType(block, ty_src, final_elem_ty, false); | 3857 | try sema.validateVarType(block, ty_src, final_elem_ty, false); |
| 3738 | } else ct: { | 3858 | } else ct: { |
| 3739 | // Detect if the value is comptime-known. In such case, the | 3859 | // Detect if the value is comptime-known. In such case, the |
| 3740 | // last 3 AIR instructions of the block will look like this: | 3860 | // last 3 AIR instructions of the block will look like this: |
| 3741 | // | 3861 | // |
| 3742 | // %a = constant | 3862 | // %a = inferred_alloc |
| 3743 | // %b = bitcast(%a) | 3863 | // %b = bitcast(%a) |
| 3744 | // %c = store(%b, %d) | 3864 | // %c = store(%b, %d) |
| 3745 | // | 3865 | // |
| ... | @@ -3779,43 +3899,46 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -3779,43 +3899,46 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3779 | } | 3899 | } |
| 3780 | }; | 3900 | }; |
| 3781 | 3901 | ||
| 3782 | const const_inst = while (true) { | 3902 | while (true) { |
| 3783 | if (search_index == 0) break :ct; | 3903 | if (search_index == 0) break :ct; |
| 3784 | search_index -= 1; | 3904 | search_index -= 1; |
| 3785 | 3905 | ||
| 3786 | const candidate = block.instructions.items[search_index]; | 3906 | const candidate = block.instructions.items[search_index]; |
| 3907 | if (candidate == ptr_inst) break; | ||
| 3787 | switch (air_tags[candidate]) { | 3908 | switch (air_tags[candidate]) { |
| 3788 | .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, | 3909 | .dbg_stmt, .dbg_block_begin, .dbg_block_end => continue, |
| 3789 | .constant => break candidate, | ||
| 3790 | else => break :ct, | 3910 | else => break :ct, |
| 3791 | } | 3911 | } |
| 3792 | }; | 3912 | } |
| 3793 | 3913 | ||
| 3794 | const store_op = air_datas[store_inst].bin_op; | 3914 | const store_op = air_datas[store_inst].bin_op; |
| 3795 | const store_val = (try sema.resolveMaybeUndefVal(store_op.rhs)) orelse break :ct; | 3915 | const store_val = (try sema.resolveMaybeUndefVal(store_op.rhs)) orelse break :ct; |
| 3796 | if (store_op.lhs != Air.indexToRef(bitcast_inst)) break :ct; | 3916 | if (store_op.lhs != Air.indexToRef(bitcast_inst)) break :ct; |
| 3797 | if (air_datas[bitcast_inst].ty_op.operand != Air.indexToRef(const_inst)) break :ct; | 3917 | if (air_datas[bitcast_inst].ty_op.operand != ptr) break :ct; |
| 3798 | 3918 | ||
| 3799 | const new_decl_index = d: { | 3919 | const new_decl_index = d: { |
| 3800 | var anon_decl = try block.startAnonDecl(); | 3920 | var anon_decl = try block.startAnonDecl(); |
| 3801 | defer anon_decl.deinit(); | 3921 | defer anon_decl.deinit(); |
| 3802 | const new_decl_index = try anon_decl.finish( | 3922 | const new_decl_index = try anon_decl.finish( |
| 3803 | try final_elem_ty.copy(anon_decl.arena()), | 3923 | final_elem_ty, |
| 3804 | try store_val.copy(anon_decl.arena()), | 3924 | store_val, |
| 3805 | inferred_alloc.data.alignment, | 3925 | ia1.alignment.toByteUnits(0), |
| 3806 | ); | 3926 | ); |
| 3807 | break :d new_decl_index; | 3927 | break :d new_decl_index; |
| 3808 | }; | 3928 | }; |
| 3809 | try sema.mod.declareDeclDependency(sema.owner_decl_index, new_decl_index); | 3929 | try mod.declareDeclDependency(sema.owner_decl_index, new_decl_index); |
| 3810 | 3930 | ||
| 3811 | // Even though we reuse the constant instruction, we still remove it from the | 3931 | // Even though we reuse the constant instruction, we still remove it from the |
| 3812 | // block so that codegen does not see it. | 3932 | // block so that codegen does not see it. |
| 3813 | block.instructions.shrinkRetainingCapacity(search_index); | 3933 | block.instructions.shrinkRetainingCapacity(search_index); |
| 3814 | try sema.maybeQueueFuncBodyAnalysis(new_decl_index); | 3934 | try sema.maybeQueueFuncBodyAnalysis(new_decl_index); |
| 3815 | sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, new_decl_index); | 3935 | sema.air_instructions.set(ptr_inst, .{ |
| 3816 | // if bitcast ty ref needs to be made const, make_ptr_const | 3936 | .tag = .interned, |
| 3817 | // ZIR handles it later, so we can just use the ty ref here. | 3937 | .data = .{ .interned = try mod.intern(.{ .ptr = .{ |
| 3818 | air_datas[ptr_inst].ty_pl.ty = air_datas[bitcast_inst].ty_op.ty; | 3938 | .ty = final_ptr_ty.toIntern(), |
| 3939 | .addr = .{ .decl = new_decl_index }, | ||
| 3940 | } }) }, | ||
| 3941 | }); | ||
| 3819 | 3942 | ||
| 3820 | // Unless the block is comptime, `alloc_inferred` always produces | 3943 | // Unless the block is comptime, `alloc_inferred` always produces |
| 3821 | // a runtime constant. The final inferred type needs to be | 3944 | // a runtime constant. The final inferred type needs to be |
| ... | @@ -3836,18 +3959,19 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -3836,18 +3959,19 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3836 | // Now we need to go back over all the coerce_result_ptr instructions, which | 3959 | // Now we need to go back over all the coerce_result_ptr instructions, which |
| 3837 | // previously inserted a bitcast as a placeholder, and do the logic as if | 3960 | // previously inserted a bitcast as a placeholder, and do the logic as if |
| 3838 | // the new result ptr type was available. | 3961 | // the new result ptr type was available. |
| 3839 | const placeholders = inferred_alloc.data.prongs.items(.placeholder); | 3962 | const placeholders = ia2.prongs.items(.placeholder); |
| 3840 | const gpa = sema.gpa; | 3963 | const gpa = sema.gpa; |
| 3841 | 3964 | ||
| 3842 | var trash_block = block.makeSubBlock(); | 3965 | var trash_block = block.makeSubBlock(); |
| 3843 | trash_block.is_comptime = false; | 3966 | trash_block.is_comptime = false; |
| 3844 | defer trash_block.instructions.deinit(gpa); | 3967 | defer trash_block.instructions.deinit(gpa); |
| 3845 | 3968 | ||
| 3846 | const mut_final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 3969 | const mut_final_ptr_ty = try mod.ptrType(.{ |
| 3847 | .pointee_type = final_elem_ty, | 3970 | .child = final_elem_ty.toIntern(), |
| 3848 | .mutable = true, | 3971 | .flags = .{ |
| 3849 | .@"align" = inferred_alloc.data.alignment, | 3972 | .alignment = ia1.alignment, |
| 3850 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 3973 | .address_space = target_util.defaultAddressSpace(target, .local), |
| 3974 | }, | ||
| 3851 | }); | 3975 | }); |
| 3852 | const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty); | 3976 | const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty); |
| 3853 | const empty_trash_count = trash_block.instructions.items.len; | 3977 | const empty_trash_count = trash_block.instructions.items.len; |
| ... | @@ -3855,7 +3979,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -3855,7 +3979,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3855 | for (peer_inst_list, placeholders) |peer_inst, placeholder_inst| { | 3979 | for (peer_inst_list, placeholders) |peer_inst, placeholder_inst| { |
| 3856 | const sub_ptr_ty = sema.typeOf(Air.indexToRef(placeholder_inst)); | 3980 | const sub_ptr_ty = sema.typeOf(Air.indexToRef(placeholder_inst)); |
| 3857 | 3981 | ||
| 3858 | if (mut_final_ptr_ty.eql(sub_ptr_ty, sema.mod)) { | 3982 | if (mut_final_ptr_ty.eql(sub_ptr_ty, mod)) { |
| 3859 | // New result location type is the same as the old one; nothing | 3983 | // New result location type is the same as the old one; nothing |
| 3860 | // to do here. | 3984 | // to do here. |
| 3861 | continue; | 3985 | continue; |
| ... | @@ -3920,27 +4044,28 @@ fn zirArrayBasePtr( | ... | @@ -3920,27 +4044,28 @@ fn zirArrayBasePtr( |
| 3920 | block: *Block, | 4044 | block: *Block, |
| 3921 | inst: Zir.Inst.Index, | 4045 | inst: Zir.Inst.Index, |
| 3922 | ) CompileError!Air.Inst.Ref { | 4046 | ) CompileError!Air.Inst.Ref { |
| 4047 | const mod = sema.mod; | ||
| 3923 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 4048 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3924 | const src = inst_data.src(); | 4049 | const src = inst_data.src(); |
| 3925 | 4050 | ||
| 3926 | const start_ptr = try sema.resolveInst(inst_data.operand); | 4051 | const start_ptr = try sema.resolveInst(inst_data.operand); |
| 3927 | var base_ptr = start_ptr; | 4052 | var base_ptr = start_ptr; |
| 3928 | while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) { | 4053 | while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) { |
| 3929 | .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), | 4054 | .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), |
| 3930 | .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), | 4055 | .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), |
| 3931 | else => break, | 4056 | else => break, |
| 3932 | }; | 4057 | }; |
| 3933 | 4058 | ||
| 3934 | const elem_ty = sema.typeOf(base_ptr).childType(); | 4059 | const elem_ty = sema.typeOf(base_ptr).childType(mod); |
| 3935 | switch (elem_ty.zigTypeTag()) { | 4060 | switch (elem_ty.zigTypeTag(mod)) { |
| 3936 | .Array, .Vector => return base_ptr, | 4061 | .Array, .Vector => return base_ptr, |
| 3937 | .Struct => if (elem_ty.isTuple()) { | 4062 | .Struct => if (elem_ty.isTuple(mod)) { |
| 3938 | // TODO validate element count | 4063 | // TODO validate element count |
| 3939 | return base_ptr; | 4064 | return base_ptr; |
| 3940 | }, | 4065 | }, |
| 3941 | else => {}, | 4066 | else => {}, |
| 3942 | } | 4067 | } |
| 3943 | return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType()); | 4068 | return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType(mod)); |
| 3944 | } | 4069 | } |
| 3945 | 4070 | ||
| 3946 | fn zirFieldBasePtr( | 4071 | fn zirFieldBasePtr( |
| ... | @@ -3948,27 +4073,30 @@ fn zirFieldBasePtr( | ... | @@ -3948,27 +4073,30 @@ fn zirFieldBasePtr( |
| 3948 | block: *Block, | 4073 | block: *Block, |
| 3949 | inst: Zir.Inst.Index, | 4074 | inst: Zir.Inst.Index, |
| 3950 | ) CompileError!Air.Inst.Ref { | 4075 | ) CompileError!Air.Inst.Ref { |
| 4076 | const mod = sema.mod; | ||
| 3951 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 4077 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 3952 | const src = inst_data.src(); | 4078 | const src = inst_data.src(); |
| 3953 | 4079 | ||
| 3954 | const start_ptr = try sema.resolveInst(inst_data.operand); | 4080 | const start_ptr = try sema.resolveInst(inst_data.operand); |
| 3955 | var base_ptr = start_ptr; | 4081 | var base_ptr = start_ptr; |
| 3956 | while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) { | 4082 | while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) { |
| 3957 | .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), | 4083 | .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), |
| 3958 | .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), | 4084 | .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), |
| 3959 | else => break, | 4085 | else => break, |
| 3960 | }; | 4086 | }; |
| 3961 | 4087 | ||
| 3962 | const elem_ty = sema.typeOf(base_ptr).childType(); | 4088 | const elem_ty = sema.typeOf(base_ptr).childType(mod); |
| 3963 | switch (elem_ty.zigTypeTag()) { | 4089 | switch (elem_ty.zigTypeTag(mod)) { |
| 3964 | .Struct, .Union => return base_ptr, | 4090 | .Struct, .Union => return base_ptr, |
| 3965 | else => {}, | 4091 | else => {}, |
| 3966 | } | 4092 | } |
| 3967 | return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType()); | 4093 | return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType(mod)); |
| 3968 | } | 4094 | } |
| 3969 | 4095 | ||
| 3970 | fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 4096 | fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 4097 | const mod = sema.mod; | ||
| 3971 | const gpa = sema.gpa; | 4098 | const gpa = sema.gpa; |
| 4099 | const ip = &mod.intern_pool; | ||
| 3972 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 4100 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 3973 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); | 4101 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); |
| 3974 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); | 4102 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); |
| ... | @@ -3991,7 +4119,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -3991,7 +4119,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 3991 | const object_ty = sema.typeOf(object); | 4119 | const object_ty = sema.typeOf(object); |
| 3992 | // Each arg could be an indexable, or a range, in which case the length | 4120 | // Each arg could be an indexable, or a range, in which case the length |
| 3993 | // is passed directly as an integer. | 4121 | // is passed directly as an integer. |
| 3994 | const is_int = switch (object_ty.zigTypeTag()) { | 4122 | const is_int = switch (object_ty.zigTypeTag(mod)) { |
| 3995 | .Int, .ComptimeInt => true, | 4123 | .Int, .ComptimeInt => true, |
| 3996 | else => false, | 4124 | else => false, |
| 3997 | }; | 4125 | }; |
| ... | @@ -4000,7 +4128,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -4000,7 +4128,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 4000 | .input_index = i, | 4128 | .input_index = i, |
| 4001 | } }; | 4129 | } }; |
| 4002 | const arg_len_uncoerced = if (is_int) object else l: { | 4130 | const arg_len_uncoerced = if (is_int) object else l: { |
| 4003 | if (!object_ty.isIndexable()) { | 4131 | if (!object_ty.isIndexable(mod)) { |
| 4004 | // Instead of using checkIndexable we customize this error. | 4132 | // Instead of using checkIndexable we customize this error. |
| 4005 | const msg = msg: { | 4133 | const msg = msg: { |
| 4006 | const msg = try sema.errMsg(block, arg_src, "type '{}' is not indexable and not a range", .{object_ty.fmt(sema.mod)}); | 4134 | const msg = try sema.errMsg(block, arg_src, "type '{}' is not indexable and not a range", .{object_ty.fmt(sema.mod)}); |
| ... | @@ -4010,9 +4138,9 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -4010,9 +4138,9 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 4010 | }; | 4138 | }; |
| 4011 | return sema.failWithOwnedErrorMsg(msg); | 4139 | return sema.failWithOwnedErrorMsg(msg); |
| 4012 | } | 4140 | } |
| 4013 | if (!object_ty.indexableHasLen()) continue; | 4141 | if (!object_ty.indexableHasLen(mod)) continue; |
| 4014 | 4142 | ||
| 4015 | break :l try sema.fieldVal(block, arg_src, object, "len", arg_src); | 4143 | break :l try sema.fieldVal(block, arg_src, object, try ip.getOrPutString(gpa, "len"), arg_src); |
| 4016 | }; | 4144 | }; |
| 4017 | const arg_len = try sema.coerce(block, Type.usize, arg_len_uncoerced, arg_src); | 4145 | const arg_len = try sema.coerce(block, Type.usize, arg_len_uncoerced, arg_src); |
| 4018 | if (len == .none) { | 4146 | if (len == .none) { |
| ... | @@ -4061,7 +4189,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -4061,7 +4189,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 4061 | const object_ty = sema.typeOf(object); | 4189 | const object_ty = sema.typeOf(object); |
| 4062 | // Each arg could be an indexable, or a range, in which case the length | 4190 | // Each arg could be an indexable, or a range, in which case the length |
| 4063 | // is passed directly as an integer. | 4191 | // is passed directly as an integer. |
| 4064 | switch (object_ty.zigTypeTag()) { | 4192 | switch (object_ty.zigTypeTag(mod)) { |
| 4065 | .Int, .ComptimeInt => continue, | 4193 | .Int, .ComptimeInt => continue, |
| 4066 | else => {}, | 4194 | else => {}, |
| 4067 | } | 4195 | } |
| ... | @@ -4096,15 +4224,16 @@ fn validateArrayInitTy( | ... | @@ -4096,15 +4224,16 @@ fn validateArrayInitTy( |
| 4096 | block: *Block, | 4224 | block: *Block, |
| 4097 | inst: Zir.Inst.Index, | 4225 | inst: Zir.Inst.Index, |
| 4098 | ) CompileError!void { | 4226 | ) CompileError!void { |
| 4227 | const mod = sema.mod; | ||
| 4099 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 4228 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 4100 | const src = inst_data.src(); | 4229 | const src = inst_data.src(); |
| 4101 | const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node }; | 4230 | const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node }; |
| 4102 | const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; | 4231 | const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; |
| 4103 | const ty = try sema.resolveType(block, ty_src, extra.ty); | 4232 | const ty = try sema.resolveType(block, ty_src, extra.ty); |
| 4104 | 4233 | ||
| 4105 | switch (ty.zigTypeTag()) { | 4234 | switch (ty.zigTypeTag(mod)) { |
| 4106 | .Array => { | 4235 | .Array => { |
| 4107 | const array_len = ty.arrayLen(); | 4236 | const array_len = ty.arrayLen(mod); |
| 4108 | if (extra.init_count != array_len) { | 4237 | if (extra.init_count != array_len) { |
| 4109 | return sema.fail(block, src, "expected {d} array elements; found {d}", .{ | 4238 | return sema.fail(block, src, "expected {d} array elements; found {d}", .{ |
| 4110 | array_len, extra.init_count, | 4239 | array_len, extra.init_count, |
| ... | @@ -4113,7 +4242,7 @@ fn validateArrayInitTy( | ... | @@ -4113,7 +4242,7 @@ fn validateArrayInitTy( |
| 4113 | return; | 4242 | return; |
| 4114 | }, | 4243 | }, |
| 4115 | .Vector => { | 4244 | .Vector => { |
| 4116 | const array_len = ty.arrayLen(); | 4245 | const array_len = ty.arrayLen(mod); |
| 4117 | if (extra.init_count != array_len) { | 4246 | if (extra.init_count != array_len) { |
| 4118 | return sema.fail(block, src, "expected {d} vector elements; found {d}", .{ | 4247 | return sema.fail(block, src, "expected {d} vector elements; found {d}", .{ |
| 4119 | array_len, extra.init_count, | 4248 | array_len, extra.init_count, |
| ... | @@ -4121,9 +4250,9 @@ fn validateArrayInitTy( | ... | @@ -4121,9 +4250,9 @@ fn validateArrayInitTy( |
| 4121 | } | 4250 | } |
| 4122 | return; | 4251 | return; |
| 4123 | }, | 4252 | }, |
| 4124 | .Struct => if (ty.isTuple()) { | 4253 | .Struct => if (ty.isTuple(mod)) { |
| 4125 | _ = try sema.resolveTypeFields(ty); | 4254 | _ = try sema.resolveTypeFields(ty); |
| 4126 | const array_len = ty.arrayLen(); | 4255 | const array_len = ty.arrayLen(mod); |
| 4127 | if (extra.init_count > array_len) { | 4256 | if (extra.init_count > array_len) { |
| 4128 | return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ | 4257 | return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ |
| 4129 | array_len, extra.init_count, | 4258 | array_len, extra.init_count, |
| ... | @@ -4141,11 +4270,12 @@ fn validateStructInitTy( | ... | @@ -4141,11 +4270,12 @@ fn validateStructInitTy( |
| 4141 | block: *Block, | 4270 | block: *Block, |
| 4142 | inst: Zir.Inst.Index, | 4271 | inst: Zir.Inst.Index, |
| 4143 | ) CompileError!void { | 4272 | ) CompileError!void { |
| 4273 | const mod = sema.mod; | ||
| 4144 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 4274 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 4145 | const src = inst_data.src(); | 4275 | const src = inst_data.src(); |
| 4146 | const ty = try sema.resolveType(block, src, inst_data.operand); | 4276 | const ty = try sema.resolveType(block, src, inst_data.operand); |
| 4147 | 4277 | ||
| 4148 | switch (ty.zigTypeTag()) { | 4278 | switch (ty.zigTypeTag(mod)) { |
| 4149 | .Struct, .Union => return, | 4279 | .Struct, .Union => return, |
| 4150 | else => {}, | 4280 | else => {}, |
| 4151 | } | 4281 | } |
| ... | @@ -4160,6 +4290,7 @@ fn zirValidateStructInit( | ... | @@ -4160,6 +4290,7 @@ fn zirValidateStructInit( |
| 4160 | const tracy = trace(@src()); | 4290 | const tracy = trace(@src()); |
| 4161 | defer tracy.end(); | 4291 | defer tracy.end(); |
| 4162 | 4292 | ||
| 4293 | const mod = sema.mod; | ||
| 4163 | const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; | 4294 | const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; |
| 4164 | const init_src = validate_inst.src(); | 4295 | const init_src = validate_inst.src(); |
| 4165 | const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); | 4296 | const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); |
| ... | @@ -4167,8 +4298,8 @@ fn zirValidateStructInit( | ... | @@ -4167,8 +4298,8 @@ fn zirValidateStructInit( |
| 4167 | const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; | 4298 | const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; |
| 4168 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; | 4299 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 4169 | const object_ptr = try sema.resolveInst(field_ptr_extra.lhs); | 4300 | const object_ptr = try sema.resolveInst(field_ptr_extra.lhs); |
| 4170 | const agg_ty = sema.typeOf(object_ptr).childType(); | 4301 | const agg_ty = sema.typeOf(object_ptr).childType(mod); |
| 4171 | switch (agg_ty.zigTypeTag()) { | 4302 | switch (agg_ty.zigTypeTag(mod)) { |
| 4172 | .Struct => return sema.validateStructInit( | 4303 | .Struct => return sema.validateStructInit( |
| 4173 | block, | 4304 | block, |
| 4174 | agg_ty, | 4305 | agg_ty, |
| ... | @@ -4194,6 +4325,9 @@ fn validateUnionInit( | ... | @@ -4194,6 +4325,9 @@ fn validateUnionInit( |
| 4194 | instrs: []const Zir.Inst.Index, | 4325 | instrs: []const Zir.Inst.Index, |
| 4195 | union_ptr: Air.Inst.Ref, | 4326 | union_ptr: Air.Inst.Ref, |
| 4196 | ) CompileError!void { | 4327 | ) CompileError!void { |
| 4328 | const mod = sema.mod; | ||
| 4329 | const gpa = sema.gpa; | ||
| 4330 | |||
| 4197 | if (instrs.len != 1) { | 4331 | if (instrs.len != 1) { |
| 4198 | const msg = msg: { | 4332 | const msg = msg: { |
| 4199 | const msg = try sema.errMsg( | 4333 | const msg = try sema.errMsg( |
| ... | @@ -4202,7 +4336,7 @@ fn validateUnionInit( | ... | @@ -4202,7 +4336,7 @@ fn validateUnionInit( |
| 4202 | "cannot initialize multiple union fields at once; unions can only have one active field", | 4336 | "cannot initialize multiple union fields at once; unions can only have one active field", |
| 4203 | .{}, | 4337 | .{}, |
| 4204 | ); | 4338 | ); |
| 4205 | errdefer msg.destroy(sema.gpa); | 4339 | errdefer msg.destroy(gpa); |
| 4206 | 4340 | ||
| 4207 | for (instrs[1..]) |inst| { | 4341 | for (instrs[1..]) |inst| { |
| 4208 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 4342 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| ... | @@ -4226,7 +4360,7 @@ fn validateUnionInit( | ... | @@ -4226,7 +4360,7 @@ fn validateUnionInit( |
| 4226 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; | 4360 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; |
| 4227 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; | 4361 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; |
| 4228 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; | 4362 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 4229 | const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); | 4363 | const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_ptr_extra.field_name_start)); |
| 4230 | // Validate the field access but ignore the index since we want the tag enum field index. | 4364 | // Validate the field access but ignore the index since we want the tag enum field index. |
| 4231 | _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src); | 4365 | _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src); |
| 4232 | const air_tags = sema.air_instructions.items(.tag); | 4366 | const air_tags = sema.air_instructions.items(.tag); |
| ... | @@ -4291,21 +4425,25 @@ fn validateUnionInit( | ... | @@ -4291,21 +4425,25 @@ fn validateUnionInit( |
| 4291 | break; | 4425 | break; |
| 4292 | } | 4426 | } |
| 4293 | 4427 | ||
| 4294 | const tag_ty = union_ty.unionTagTypeHypothetical(); | 4428 | const tag_ty = union_ty.unionTagTypeHypothetical(mod); |
| 4295 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); | 4429 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); |
| 4296 | const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); | 4430 | const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); |
| 4297 | 4431 | ||
| 4298 | if (init_val) |val| { | 4432 | if (init_val) |val| { |
| 4299 | // Our task is to delete all the `field_ptr` and `store` instructions, and insert | 4433 | // Our task is to delete all the `field_ptr` and `store` instructions, and insert |
| 4300 | // instead a single `store` to the result ptr with a comptime union value. | 4434 | // instead a single `store` to the result ptr with a comptime union value. |
| 4301 | block.instructions.shrinkRetainingCapacity(first_block_index); | 4435 | block.instructions.shrinkRetainingCapacity(first_block_index); |
| 4302 | 4436 | ||
| 4303 | var union_val = try Value.Tag.@"union".create(sema.arena, .{ | 4437 | var union_val = try mod.intern(.{ .un = .{ |
| 4304 | .tag = tag_val, | 4438 | .ty = union_ty.toIntern(), |
| 4305 | .val = val, | 4439 | .tag = tag_val.toIntern(), |
| 4306 | }); | 4440 | .val = val.toIntern(), |
| 4307 | if (make_runtime) union_val = try Value.Tag.runtime_value.create(sema.arena, union_val); | 4441 | } }); |
| 4308 | const union_init = try sema.addConstant(union_ty, union_val); | 4442 | if (make_runtime) union_val = try mod.intern(.{ .runtime_value = .{ |
| 4443 | .ty = union_ty.toIntern(), | ||
| 4444 | .val = union_val, | ||
| 4445 | } }); | ||
| 4446 | const union_init = try sema.addConstant(union_ty, union_val.toValue()); | ||
| 4309 | try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store); | 4447 | try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store); |
| 4310 | return; | 4448 | return; |
| 4311 | } else if (try sema.typeRequiresComptime(union_ty)) { | 4449 | } else if (try sema.typeRequiresComptime(union_ty)) { |
| ... | @@ -4323,10 +4461,12 @@ fn validateStructInit( | ... | @@ -4323,10 +4461,12 @@ fn validateStructInit( |
| 4323 | init_src: LazySrcLoc, | 4461 | init_src: LazySrcLoc, |
| 4324 | instrs: []const Zir.Inst.Index, | 4462 | instrs: []const Zir.Inst.Index, |
| 4325 | ) CompileError!void { | 4463 | ) CompileError!void { |
| 4464 | const mod = sema.mod; | ||
| 4326 | const gpa = sema.gpa; | 4465 | const gpa = sema.gpa; |
| 4466 | const ip = &mod.intern_pool; | ||
| 4327 | 4467 | ||
| 4328 | // Maps field index to field_ptr index of where it was already initialized. | 4468 | // Maps field index to field_ptr index of where it was already initialized. |
| 4329 | const found_fields = try gpa.alloc(Zir.Inst.Index, struct_ty.structFieldCount()); | 4469 | const found_fields = try gpa.alloc(Zir.Inst.Index, struct_ty.structFieldCount(mod)); |
| 4330 | defer gpa.free(found_fields); | 4470 | defer gpa.free(found_fields); |
| 4331 | @memset(found_fields, 0); | 4471 | @memset(found_fields, 0); |
| 4332 | 4472 | ||
| ... | @@ -4337,8 +4477,11 @@ fn validateStructInit( | ... | @@ -4337,8 +4477,11 @@ fn validateStructInit( |
| 4337 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; | 4477 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; |
| 4338 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; | 4478 | const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; |
| 4339 | struct_ptr_zir_ref = field_ptr_extra.lhs; | 4479 | struct_ptr_zir_ref = field_ptr_extra.lhs; |
| 4340 | const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); | 4480 | const field_name = try ip.getOrPutString( |
| 4341 | const field_index = if (struct_ty.isTuple()) | 4481 | gpa, |
| 4482 | sema.code.nullTerminatedString(field_ptr_extra.field_name_start), | ||
| 4483 | ); | ||
| 4484 | const field_index = if (struct_ty.isTuple(mod)) | ||
| 4342 | try sema.tupleFieldIndex(block, struct_ty, field_name, field_src) | 4485 | try sema.tupleFieldIndex(block, struct_ty, field_name, field_src) |
| 4343 | else | 4486 | else |
| 4344 | try sema.structFieldIndex(block, struct_ty, field_name, field_src); | 4487 | try sema.structFieldIndex(block, struct_ty, field_name, field_src); |
| ... | @@ -4371,9 +4514,9 @@ fn validateStructInit( | ... | @@ -4371,9 +4514,9 @@ fn validateStructInit( |
| 4371 | for (found_fields, 0..) |field_ptr, i| { | 4514 | for (found_fields, 0..) |field_ptr, i| { |
| 4372 | if (field_ptr != 0) continue; | 4515 | if (field_ptr != 0) continue; |
| 4373 | 4516 | ||
| 4374 | const default_val = struct_ty.structFieldDefaultValue(i); | 4517 | const default_val = struct_ty.structFieldDefaultValue(i, mod); |
| 4375 | if (default_val.tag() == .unreachable_value) { | 4518 | if (default_val.toIntern() == .unreachable_value) { |
| 4376 | if (struct_ty.isTuple()) { | 4519 | if (struct_ty.isTuple(mod)) { |
| 4377 | const template = "missing tuple field with index {d}"; | 4520 | const template = "missing tuple field with index {d}"; |
| 4378 | if (root_msg) |msg| { | 4521 | if (root_msg) |msg| { |
| 4379 | try sema.errNote(block, init_src, msg, template, .{i}); | 4522 | try sema.errNote(block, init_src, msg, template, .{i}); |
| ... | @@ -4382,9 +4525,9 @@ fn validateStructInit( | ... | @@ -4382,9 +4525,9 @@ fn validateStructInit( |
| 4382 | } | 4525 | } |
| 4383 | continue; | 4526 | continue; |
| 4384 | } | 4527 | } |
| 4385 | const field_name = struct_ty.structFieldName(i); | 4528 | const field_name = struct_ty.structFieldName(i, mod); |
| 4386 | const template = "missing struct field: {s}"; | 4529 | const template = "missing struct field: {}"; |
| 4387 | const args = .{field_name}; | 4530 | const args = .{field_name.fmt(ip)}; |
| 4388 | if (root_msg) |msg| { | 4531 | if (root_msg) |msg| { |
| 4389 | try sema.errNote(block, init_src, msg, template, args); | 4532 | try sema.errNote(block, init_src, msg, template, args); |
| 4390 | } else { | 4533 | } else { |
| ... | @@ -4394,25 +4537,23 @@ fn validateStructInit( | ... | @@ -4394,25 +4537,23 @@ fn validateStructInit( |
| 4394 | } | 4537 | } |
| 4395 | 4538 | ||
| 4396 | const field_src = init_src; // TODO better source location | 4539 | const field_src = init_src; // TODO better source location |
| 4397 | const default_field_ptr = if (struct_ty.isTuple()) | 4540 | const default_field_ptr = if (struct_ty.isTuple(mod)) |
| 4398 | try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) | 4541 | try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) |
| 4399 | else | 4542 | else |
| 4400 | try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); | 4543 | try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); |
| 4401 | const field_ty = sema.typeOf(default_field_ptr).childType(); | 4544 | const field_ty = sema.typeOf(default_field_ptr).childType(mod); |
| 4402 | const init = try sema.addConstant(field_ty, default_val); | 4545 | const init = try sema.addConstant(field_ty, default_val); |
| 4403 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); | 4546 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); |
| 4404 | } | 4547 | } |
| 4405 | 4548 | ||
| 4406 | if (root_msg) |msg| { | 4549 | if (root_msg) |msg| { |
| 4407 | if (struct_ty.castTag(.@"struct")) |struct_obj| { | 4550 | if (mod.typeToStruct(struct_ty)) |struct_obj| { |
| 4408 | const mod = sema.mod; | 4551 | const fqn = try struct_obj.getFullyQualifiedName(mod); |
| 4409 | const fqn = try struct_obj.data.getFullyQualifiedName(mod); | ||
| 4410 | defer gpa.free(fqn); | ||
| 4411 | try mod.errNoteNonLazy( | 4552 | try mod.errNoteNonLazy( |
| 4412 | struct_obj.data.srcLoc(mod), | 4553 | struct_obj.srcLoc(mod), |
| 4413 | msg, | 4554 | msg, |
| 4414 | "struct '{s}' declared here", | 4555 | "struct '{}' declared here", |
| 4415 | .{fqn}, | 4556 | .{fqn.fmt(ip)}, |
| 4416 | ); | 4557 | ); |
| 4417 | } | 4558 | } |
| 4418 | root_msg = null; | 4559 | root_msg = null; |
| ... | @@ -4432,14 +4573,14 @@ fn validateStructInit( | ... | @@ -4432,14 +4573,14 @@ fn validateStructInit( |
| 4432 | 4573 | ||
| 4433 | // We collect the comptime field values in case the struct initialization | 4574 | // We collect the comptime field values in case the struct initialization |
| 4434 | // ends up being comptime-known. | 4575 | // ends up being comptime-known. |
| 4435 | const field_values = try sema.arena.alloc(Value, struct_ty.structFieldCount()); | 4576 | const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(mod)); |
| 4436 | 4577 | ||
| 4437 | field: for (found_fields, 0..) |field_ptr, i| { | 4578 | field: for (found_fields, 0..) |field_ptr, i| { |
| 4438 | if (field_ptr != 0) { | 4579 | if (field_ptr != 0) { |
| 4439 | // Determine whether the value stored to this pointer is comptime-known. | 4580 | // Determine whether the value stored to this pointer is comptime-known. |
| 4440 | const field_ty = struct_ty.structFieldType(i); | 4581 | const field_ty = struct_ty.structFieldType(i, mod); |
| 4441 | if (try sema.typeHasOnePossibleValue(field_ty)) |opv| { | 4582 | if (try sema.typeHasOnePossibleValue(field_ty)) |opv| { |
| 4442 | field_values[i] = opv; | 4583 | field_values[i] = opv.toIntern(); |
| 4443 | continue; | 4584 | continue; |
| 4444 | } | 4585 | } |
| 4445 | 4586 | ||
| ... | @@ -4504,7 +4645,7 @@ fn validateStructInit( | ... | @@ -4504,7 +4645,7 @@ fn validateStructInit( |
| 4504 | first_block_index = @min(first_block_index, block_index); | 4645 | first_block_index = @min(first_block_index, block_index); |
| 4505 | } | 4646 | } |
| 4506 | if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| { | 4647 | if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| { |
| 4507 | field_values[i] = val; | 4648 | field_values[i] = val.toIntern(); |
| 4508 | } else if (require_comptime) { | 4649 | } else if (require_comptime) { |
| 4509 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; | 4650 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; |
| 4510 | return sema.failWithNeededComptime(block, field_ptr_data.src(), "initializer of comptime only struct must be comptime-known"); | 4651 | return sema.failWithNeededComptime(block, field_ptr_data.src(), "initializer of comptime only struct must be comptime-known"); |
| ... | @@ -4517,9 +4658,9 @@ fn validateStructInit( | ... | @@ -4517,9 +4658,9 @@ fn validateStructInit( |
| 4517 | continue :field; | 4658 | continue :field; |
| 4518 | } | 4659 | } |
| 4519 | 4660 | ||
| 4520 | const default_val = struct_ty.structFieldDefaultValue(i); | 4661 | const default_val = struct_ty.structFieldDefaultValue(i, mod); |
| 4521 | if (default_val.tag() == .unreachable_value) { | 4662 | if (default_val.toIntern() == .unreachable_value) { |
| 4522 | if (struct_ty.isTuple()) { | 4663 | if (struct_ty.isTuple(mod)) { |
| 4523 | const template = "missing tuple field with index {d}"; | 4664 | const template = "missing tuple field with index {d}"; |
| 4524 | if (root_msg) |msg| { | 4665 | if (root_msg) |msg| { |
| 4525 | try sema.errNote(block, init_src, msg, template, .{i}); | 4666 | try sema.errNote(block, init_src, msg, template, .{i}); |
| ... | @@ -4528,9 +4669,9 @@ fn validateStructInit( | ... | @@ -4528,9 +4669,9 @@ fn validateStructInit( |
| 4528 | } | 4669 | } |
| 4529 | continue; | 4670 | continue; |
| 4530 | } | 4671 | } |
| 4531 | const field_name = struct_ty.structFieldName(i); | 4672 | const field_name = struct_ty.structFieldName(i, mod); |
| 4532 | const template = "missing struct field: {s}"; | 4673 | const template = "missing struct field: {}"; |
| 4533 | const args = .{field_name}; | 4674 | const args = .{field_name.fmt(ip)}; |
| 4534 | if (root_msg) |msg| { | 4675 | if (root_msg) |msg| { |
| 4535 | try sema.errNote(block, init_src, msg, template, args); | 4676 | try sema.errNote(block, init_src, msg, template, args); |
| 4536 | } else { | 4677 | } else { |
| ... | @@ -4538,18 +4679,17 @@ fn validateStructInit( | ... | @@ -4538,18 +4679,17 @@ fn validateStructInit( |
| 4538 | } | 4679 | } |
| 4539 | continue; | 4680 | continue; |
| 4540 | } | 4681 | } |
| 4541 | field_values[i] = default_val; | 4682 | field_values[i] = default_val.toIntern(); |
| 4542 | } | 4683 | } |
| 4543 | 4684 | ||
| 4544 | if (root_msg) |msg| { | 4685 | if (root_msg) |msg| { |
| 4545 | if (struct_ty.castTag(.@"struct")) |struct_obj| { | 4686 | if (mod.typeToStruct(struct_ty)) |struct_obj| { |
| 4546 | const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod); | 4687 | const fqn = try struct_obj.getFullyQualifiedName(mod); |
| 4547 | defer gpa.free(fqn); | 4688 | try mod.errNoteNonLazy( |
| 4548 | try sema.mod.errNoteNonLazy( | 4689 | struct_obj.srcLoc(mod), |
| 4549 | struct_obj.data.srcLoc(sema.mod), | ||
| 4550 | msg, | 4690 | msg, |
| 4551 | "struct '{s}' declared here", | 4691 | "struct '{}' declared here", |
| 4552 | .{fqn}, | 4692 | .{fqn.fmt(ip)}, |
| 4553 | ); | 4693 | ); |
| 4554 | } | 4694 | } |
| 4555 | root_msg = null; | 4695 | root_msg = null; |
| ... | @@ -4561,9 +4701,15 @@ fn validateStructInit( | ... | @@ -4561,9 +4701,15 @@ fn validateStructInit( |
| 4561 | // instead a single `store` to the struct_ptr with a comptime struct value. | 4701 | // instead a single `store` to the struct_ptr with a comptime struct value. |
| 4562 | 4702 | ||
| 4563 | block.instructions.shrinkRetainingCapacity(first_block_index); | 4703 | block.instructions.shrinkRetainingCapacity(first_block_index); |
| 4564 | var struct_val = try Value.Tag.aggregate.create(sema.arena, field_values); | 4704 | var struct_val = try mod.intern(.{ .aggregate = .{ |
| 4565 | if (make_runtime) struct_val = try Value.Tag.runtime_value.create(sema.arena, struct_val); | 4705 | .ty = struct_ty.toIntern(), |
| 4566 | const struct_init = try sema.addConstant(struct_ty, struct_val); | 4706 | .storage = .{ .elems = field_values }, |
| 4707 | } }); | ||
| 4708 | if (make_runtime) struct_val = try mod.intern(.{ .runtime_value = .{ | ||
| 4709 | .ty = struct_ty.toIntern(), | ||
| 4710 | .val = struct_val, | ||
| 4711 | } }); | ||
| 4712 | const struct_init = try sema.addConstant(struct_ty, struct_val.toValue()); | ||
| 4567 | try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store); | 4713 | try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store); |
| 4568 | return; | 4714 | return; |
| 4569 | } | 4715 | } |
| ... | @@ -4574,12 +4720,12 @@ fn validateStructInit( | ... | @@ -4574,12 +4720,12 @@ fn validateStructInit( |
| 4574 | if (field_ptr != 0) continue; | 4720 | if (field_ptr != 0) continue; |
| 4575 | 4721 | ||
| 4576 | const field_src = init_src; // TODO better source location | 4722 | const field_src = init_src; // TODO better source location |
| 4577 | const default_field_ptr = if (struct_ty.isTuple()) | 4723 | const default_field_ptr = if (struct_ty.isTuple(mod)) |
| 4578 | try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) | 4724 | try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true) |
| 4579 | else | 4725 | else |
| 4580 | try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); | 4726 | try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); |
| 4581 | const field_ty = sema.typeOf(default_field_ptr).childType(); | 4727 | const field_ty = sema.typeOf(default_field_ptr).childType(mod); |
| 4582 | const init = try sema.addConstant(field_ty, field_values[i]); | 4728 | const init = try sema.addConstant(field_ty, field_values[i].toValue()); |
| 4583 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); | 4729 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); |
| 4584 | } | 4730 | } |
| 4585 | } | 4731 | } |
| ... | @@ -4589,6 +4735,7 @@ fn zirValidateArrayInit( | ... | @@ -4589,6 +4735,7 @@ fn zirValidateArrayInit( |
| 4589 | block: *Block, | 4735 | block: *Block, |
| 4590 | inst: Zir.Inst.Index, | 4736 | inst: Zir.Inst.Index, |
| 4591 | ) CompileError!void { | 4737 | ) CompileError!void { |
| 4738 | const mod = sema.mod; | ||
| 4592 | const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; | 4739 | const validate_inst = sema.code.instructions.items(.data)[inst].pl_node; |
| 4593 | const init_src = validate_inst.src(); | 4740 | const init_src = validate_inst.src(); |
| 4594 | const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); | 4741 | const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); |
| ... | @@ -4596,18 +4743,18 @@ fn zirValidateArrayInit( | ... | @@ -4596,18 +4743,18 @@ fn zirValidateArrayInit( |
| 4596 | const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; | 4743 | const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node; |
| 4597 | const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data; | 4744 | const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data; |
| 4598 | const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr); | 4745 | const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr); |
| 4599 | const array_ty = sema.typeOf(array_ptr).childType(); | 4746 | const array_ty = sema.typeOf(array_ptr).childType(mod); |
| 4600 | const array_len = array_ty.arrayLen(); | 4747 | const array_len = array_ty.arrayLen(mod); |
| 4601 | 4748 | ||
| 4602 | if (instrs.len != array_len) switch (array_ty.zigTypeTag()) { | 4749 | if (instrs.len != array_len) switch (array_ty.zigTypeTag(mod)) { |
| 4603 | .Struct => { | 4750 | .Struct => { |
| 4604 | var root_msg: ?*Module.ErrorMsg = null; | 4751 | var root_msg: ?*Module.ErrorMsg = null; |
| 4605 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); | 4752 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 4606 | 4753 | ||
| 4607 | var i = instrs.len; | 4754 | var i = instrs.len; |
| 4608 | while (i < array_len) : (i += 1) { | 4755 | while (i < array_len) : (i += 1) { |
| 4609 | const default_val = array_ty.structFieldDefaultValue(i); | 4756 | const default_val = array_ty.structFieldDefaultValue(i, mod); |
| 4610 | if (default_val.tag() == .unreachable_value) { | 4757 | if (default_val.toIntern() == .unreachable_value) { |
| 4611 | const template = "missing tuple field with index {d}"; | 4758 | const template = "missing tuple field with index {d}"; |
| 4612 | if (root_msg) |msg| { | 4759 | if (root_msg) |msg| { |
| 4613 | try sema.errNote(block, init_src, msg, template, .{i}); | 4760 | try sema.errNote(block, init_src, msg, template, .{i}); |
| ... | @@ -4642,39 +4789,41 @@ fn zirValidateArrayInit( | ... | @@ -4642,39 +4789,41 @@ fn zirValidateArrayInit( |
| 4642 | // at comptime so we have almost nothing to do here. However, in case of a | 4789 | // at comptime so we have almost nothing to do here. However, in case of a |
| 4643 | // sentinel-terminated array, the sentinel will not have been populated by | 4790 | // sentinel-terminated array, the sentinel will not have been populated by |
| 4644 | // any ZIR instructions at comptime; we need to do that here. | 4791 | // any ZIR instructions at comptime; we need to do that here. |
| 4645 | if (array_ty.sentinel()) |sentinel_val| { | 4792 | if (array_ty.sentinel(mod)) |sentinel_val| { |
| 4646 | const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len); | 4793 | const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len); |
| 4647 | const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true); | 4794 | const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true); |
| 4648 | const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val); | 4795 | const sentinel = try sema.addConstant(array_ty.childType(mod), sentinel_val); |
| 4649 | try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store); | 4796 | try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store); |
| 4650 | } | 4797 | } |
| 4651 | return; | 4798 | return; |
| 4652 | } | 4799 | } |
| 4653 | 4800 | ||
| 4801 | // If the array has one possible value, the value is always comptime-known. | ||
| 4802 | if (try sema.typeHasOnePossibleValue(array_ty)) |array_opv| { | ||
| 4803 | const array_init = try sema.addConstant(array_ty, array_opv); | ||
| 4804 | try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store); | ||
| 4805 | return; | ||
| 4806 | } | ||
| 4807 | |||
| 4654 | var array_is_comptime = true; | 4808 | var array_is_comptime = true; |
| 4655 | var first_block_index = block.instructions.items.len; | 4809 | var first_block_index = block.instructions.items.len; |
| 4656 | var make_runtime = false; | 4810 | var make_runtime = false; |
| 4657 | 4811 | ||
| 4658 | // Collect the comptime element values in case the array literal ends up | 4812 | // Collect the comptime element values in case the array literal ends up |
| 4659 | // being comptime-known. | 4813 | // being comptime-known. |
| 4660 | const array_len_s = try sema.usizeCast(block, init_src, array_ty.arrayLenIncludingSentinel()); | 4814 | const element_vals = try sema.arena.alloc( |
| 4661 | const element_vals = try sema.arena.alloc(Value, array_len_s); | 4815 | InternPool.Index, |
| 4662 | const opt_opv = try sema.typeHasOnePossibleValue(array_ty); | 4816 | try sema.usizeCast(block, init_src, array_len), |
| 4817 | ); | ||
| 4663 | const air_tags = sema.air_instructions.items(.tag); | 4818 | const air_tags = sema.air_instructions.items(.tag); |
| 4664 | const air_datas = sema.air_instructions.items(.data); | 4819 | const air_datas = sema.air_instructions.items(.data); |
| 4665 | 4820 | ||
| 4666 | outer: for (instrs, 0..) |elem_ptr, i| { | 4821 | outer: for (instrs, 0..) |elem_ptr, i| { |
| 4667 | // Determine whether the value stored to this pointer is comptime-known. | 4822 | // Determine whether the value stored to this pointer is comptime-known. |
| 4668 | 4823 | ||
| 4669 | if (array_ty.isTuple()) { | 4824 | if (array_ty.isTuple(mod)) { |
| 4670 | if (array_ty.structFieldValueComptime(i)) |opv| { | 4825 | if (try array_ty.structFieldValueComptime(mod, i)) |opv| { |
| 4671 | element_vals[i] = opv; | 4826 | element_vals[i] = opv.toIntern(); |
| 4672 | continue; | ||
| 4673 | } | ||
| 4674 | } else { | ||
| 4675 | // Array has one possible value, so value is always comptime-known | ||
| 4676 | if (opt_opv) |opv| { | ||
| 4677 | element_vals[i] = opv; | ||
| 4678 | continue; | 4827 | continue; |
| 4679 | } | 4828 | } |
| 4680 | } | 4829 | } |
| ... | @@ -4735,7 +4884,7 @@ fn zirValidateArrayInit( | ... | @@ -4735,7 +4884,7 @@ fn zirValidateArrayInit( |
| 4735 | first_block_index = @min(first_block_index, block_index); | 4884 | first_block_index = @min(first_block_index, block_index); |
| 4736 | } | 4885 | } |
| 4737 | if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| { | 4886 | if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| { |
| 4738 | element_vals[i] = val; | 4887 | element_vals[i] = val.toIntern(); |
| 4739 | } else { | 4888 | } else { |
| 4740 | array_is_comptime = false; | 4889 | array_is_comptime = false; |
| 4741 | } | 4890 | } |
| ... | @@ -4747,50 +4896,55 @@ fn zirValidateArrayInit( | ... | @@ -4747,50 +4896,55 @@ fn zirValidateArrayInit( |
| 4747 | 4896 | ||
| 4748 | if (array_is_comptime) { | 4897 | if (array_is_comptime) { |
| 4749 | if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| { | 4898 | if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| { |
| 4750 | if (ptr_val.tag() == .comptime_field_ptr) { | 4899 | switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { |
| 4751 | // This store was validated by the individual elem ptrs. | 4900 | .ptr => |ptr| switch (ptr.addr) { |
| 4752 | return; | 4901 | .comptime_field => return, // This store was validated by the individual elem ptrs. |
| 4902 | else => {}, | ||
| 4903 | }, | ||
| 4904 | else => {}, | ||
| 4753 | } | 4905 | } |
| 4754 | } | 4906 | } |
| 4755 | 4907 | ||
| 4756 | // Our task is to delete all the `elem_ptr` and `store` instructions, and insert | 4908 | // Our task is to delete all the `elem_ptr` and `store` instructions, and insert |
| 4757 | // instead a single `store` to the array_ptr with a comptime struct value. | 4909 | // instead a single `store` to the array_ptr with a comptime struct value. |
| 4758 | // Also to populate the sentinel value, if any. | ||
| 4759 | if (array_ty.sentinel()) |sentinel_val| { | ||
| 4760 | element_vals[instrs.len] = sentinel_val; | ||
| 4761 | } | ||
| 4762 | |||
| 4763 | block.instructions.shrinkRetainingCapacity(first_block_index); | 4910 | block.instructions.shrinkRetainingCapacity(first_block_index); |
| 4764 | 4911 | ||
| 4765 | var array_val = try Value.Tag.aggregate.create(sema.arena, element_vals); | 4912 | var array_val = try mod.intern(.{ .aggregate = .{ |
| 4766 | if (make_runtime) array_val = try Value.Tag.runtime_value.create(sema.arena, array_val); | 4913 | .ty = array_ty.toIntern(), |
| 4767 | const array_init = try sema.addConstant(array_ty, array_val); | 4914 | .storage = .{ .elems = element_vals }, |
| 4915 | } }); | ||
| 4916 | if (make_runtime) array_val = try mod.intern(.{ .runtime_value = .{ | ||
| 4917 | .ty = array_ty.toIntern(), | ||
| 4918 | .val = array_val, | ||
| 4919 | } }); | ||
| 4920 | const array_init = try sema.addConstant(array_ty, array_val.toValue()); | ||
| 4768 | try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store); | 4921 | try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store); |
| 4769 | } | 4922 | } |
| 4770 | } | 4923 | } |
| 4771 | 4924 | ||
| 4772 | fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 4925 | fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 4926 | const mod = sema.mod; | ||
| 4773 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 4927 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 4774 | const src = inst_data.src(); | 4928 | const src = inst_data.src(); |
| 4775 | const operand = try sema.resolveInst(inst_data.operand); | 4929 | const operand = try sema.resolveInst(inst_data.operand); |
| 4776 | const operand_ty = sema.typeOf(operand); | 4930 | const operand_ty = sema.typeOf(operand); |
| 4777 | 4931 | ||
| 4778 | if (operand_ty.zigTypeTag() != .Pointer) { | 4932 | if (operand_ty.zigTypeTag(mod) != .Pointer) { |
| 4779 | return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(sema.mod)}); | 4933 | return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(mod)}); |
| 4780 | } else switch (operand_ty.ptrSize()) { | 4934 | } else switch (operand_ty.ptrSize(mod)) { |
| 4781 | .One, .C => {}, | 4935 | .One, .C => {}, |
| 4782 | .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(sema.mod)}), | 4936 | .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(mod)}), |
| 4783 | .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(sema.mod)}), | 4937 | .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(mod)}), |
| 4784 | } | 4938 | } |
| 4785 | 4939 | ||
| 4786 | if ((try sema.typeHasOnePossibleValue(operand_ty.childType())) != null) { | 4940 | if ((try sema.typeHasOnePossibleValue(operand_ty.childType(mod))) != null) { |
| 4787 | // No need to validate the actual pointer value, we don't need it! | 4941 | // No need to validate the actual pointer value, we don't need it! |
| 4788 | return; | 4942 | return; |
| 4789 | } | 4943 | } |
| 4790 | 4944 | ||
| 4791 | const elem_ty = operand_ty.elemType2(); | 4945 | const elem_ty = operand_ty.elemType2(mod); |
| 4792 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 4946 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 4793 | if (val.isUndef()) { | 4947 | if (val.isUndef(mod)) { |
| 4794 | return sema.fail(block, src, "cannot dereference undefined value", .{}); | 4948 | return sema.fail(block, src, "cannot dereference undefined value", .{}); |
| 4795 | } | 4949 | } |
| 4796 | } else if (!(try sema.validateRunTimeType(elem_ty, false))) { | 4950 | } else if (!(try sema.validateRunTimeType(elem_ty, false))) { |
| ... | @@ -4799,12 +4953,12 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -4799,12 +4953,12 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 4799 | block, | 4953 | block, |
| 4800 | src, | 4954 | src, |
| 4801 | "values of type '{}' must be comptime-known, but operand value is runtime-known", | 4955 | "values of type '{}' must be comptime-known, but operand value is runtime-known", |
| 4802 | .{elem_ty.fmt(sema.mod)}, | 4956 | .{elem_ty.fmt(mod)}, |
| 4803 | ); | 4957 | ); |
| 4804 | errdefer msg.destroy(sema.gpa); | 4958 | errdefer msg.destroy(sema.gpa); |
| 4805 | 4959 | ||
| 4806 | const src_decl = sema.mod.declPtr(block.src_decl); | 4960 | const src_decl = mod.declPtr(block.src_decl); |
| 4807 | try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl), elem_ty); | 4961 | try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), elem_ty); |
| 4808 | break :msg msg; | 4962 | break :msg msg; |
| 4809 | }; | 4963 | }; |
| 4810 | return sema.failWithOwnedErrorMsg(msg); | 4964 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -4816,23 +4970,24 @@ fn failWithBadMemberAccess( | ... | @@ -4816,23 +4970,24 @@ fn failWithBadMemberAccess( |
| 4816 | block: *Block, | 4970 | block: *Block, |
| 4817 | agg_ty: Type, | 4971 | agg_ty: Type, |
| 4818 | field_src: LazySrcLoc, | 4972 | field_src: LazySrcLoc, |
| 4819 | field_name: []const u8, | 4973 | field_name: InternPool.NullTerminatedString, |
| 4820 | ) CompileError { | 4974 | ) CompileError { |
| 4821 | const kw_name = switch (agg_ty.zigTypeTag()) { | 4975 | const mod = sema.mod; |
| 4976 | const kw_name = switch (agg_ty.zigTypeTag(mod)) { | ||
| 4822 | .Union => "union", | 4977 | .Union => "union", |
| 4823 | .Struct => "struct", | 4978 | .Struct => "struct", |
| 4824 | .Opaque => "opaque", | 4979 | .Opaque => "opaque", |
| 4825 | .Enum => "enum", | 4980 | .Enum => "enum", |
| 4826 | else => unreachable, | 4981 | else => unreachable, |
| 4827 | }; | 4982 | }; |
| 4828 | if (agg_ty.getOwnerDeclOrNull()) |some| if (sema.mod.declIsRoot(some)) { | 4983 | if (agg_ty.getOwnerDeclOrNull(mod)) |some| if (mod.declIsRoot(some)) { |
| 4829 | return sema.fail(block, field_src, "root struct of file '{}' has no member named '{s}'", .{ | 4984 | return sema.fail(block, field_src, "root struct of file '{}' has no member named '{}'", .{ |
| 4830 | agg_ty.fmt(sema.mod), field_name, | 4985 | agg_ty.fmt(mod), field_name.fmt(&mod.intern_pool), |
| 4831 | }); | 4986 | }); |
| 4832 | }; | 4987 | }; |
| 4833 | const msg = msg: { | 4988 | const msg = msg: { |
| 4834 | const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{ | 4989 | const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{}'", .{ |
| 4835 | kw_name, agg_ty.fmt(sema.mod), field_name, | 4990 | kw_name, agg_ty.fmt(mod), field_name.fmt(&mod.intern_pool), |
| 4836 | }); | 4991 | }); |
| 4837 | errdefer msg.destroy(sema.gpa); | 4992 | errdefer msg.destroy(sema.gpa); |
| 4838 | try sema.addDeclaredHereNote(msg, agg_ty); | 4993 | try sema.addDeclaredHereNote(msg, agg_ty); |
| ... | @@ -4846,22 +5001,22 @@ fn failWithBadStructFieldAccess( | ... | @@ -4846,22 +5001,22 @@ fn failWithBadStructFieldAccess( |
| 4846 | block: *Block, | 5001 | block: *Block, |
| 4847 | struct_obj: *Module.Struct, | 5002 | struct_obj: *Module.Struct, |
| 4848 | field_src: LazySrcLoc, | 5003 | field_src: LazySrcLoc, |
| 4849 | field_name: []const u8, | 5004 | field_name: InternPool.NullTerminatedString, |
| 4850 | ) CompileError { | 5005 | ) CompileError { |
| 5006 | const mod = sema.mod; | ||
| 4851 | const gpa = sema.gpa; | 5007 | const gpa = sema.gpa; |
| 4852 | 5008 | ||
| 4853 | const fqn = try struct_obj.getFullyQualifiedName(sema.mod); | 5009 | const fqn = try struct_obj.getFullyQualifiedName(mod); |
| 4854 | defer gpa.free(fqn); | ||
| 4855 | 5010 | ||
| 4856 | const msg = msg: { | 5011 | const msg = msg: { |
| 4857 | const msg = try sema.errMsg( | 5012 | const msg = try sema.errMsg( |
| 4858 | block, | 5013 | block, |
| 4859 | field_src, | 5014 | field_src, |
| 4860 | "no field named '{s}' in struct '{s}'", | 5015 | "no field named '{}' in struct '{}'", |
| 4861 | .{ field_name, fqn }, | 5016 | .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) }, |
| 4862 | ); | 5017 | ); |
| 4863 | errdefer msg.destroy(gpa); | 5018 | errdefer msg.destroy(gpa); |
| 4864 | try sema.mod.errNoteNonLazy(struct_obj.srcLoc(sema.mod), msg, "struct declared here", .{}); | 5019 | try mod.errNoteNonLazy(struct_obj.srcLoc(mod), msg, "struct declared here", .{}); |
| 4865 | break :msg msg; | 5020 | break :msg msg; |
| 4866 | }; | 5021 | }; |
| 4867 | return sema.failWithOwnedErrorMsg(msg); | 5022 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -4872,30 +5027,31 @@ fn failWithBadUnionFieldAccess( | ... | @@ -4872,30 +5027,31 @@ fn failWithBadUnionFieldAccess( |
| 4872 | block: *Block, | 5027 | block: *Block, |
| 4873 | union_obj: *Module.Union, | 5028 | union_obj: *Module.Union, |
| 4874 | field_src: LazySrcLoc, | 5029 | field_src: LazySrcLoc, |
| 4875 | field_name: []const u8, | 5030 | field_name: InternPool.NullTerminatedString, |
| 4876 | ) CompileError { | 5031 | ) CompileError { |
| 5032 | const mod = sema.mod; | ||
| 4877 | const gpa = sema.gpa; | 5033 | const gpa = sema.gpa; |
| 4878 | 5034 | ||
| 4879 | const fqn = try union_obj.getFullyQualifiedName(sema.mod); | 5035 | const fqn = try union_obj.getFullyQualifiedName(mod); |
| 4880 | defer gpa.free(fqn); | ||
| 4881 | 5036 | ||
| 4882 | const msg = msg: { | 5037 | const msg = msg: { |
| 4883 | const msg = try sema.errMsg( | 5038 | const msg = try sema.errMsg( |
| 4884 | block, | 5039 | block, |
| 4885 | field_src, | 5040 | field_src, |
| 4886 | "no field named '{s}' in union '{s}'", | 5041 | "no field named '{}' in union '{}'", |
| 4887 | .{ field_name, fqn }, | 5042 | .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) }, |
| 4888 | ); | 5043 | ); |
| 4889 | errdefer msg.destroy(gpa); | 5044 | errdefer msg.destroy(gpa); |
| 4890 | try sema.mod.errNoteNonLazy(union_obj.srcLoc(sema.mod), msg, "union declared here", .{}); | 5045 | try mod.errNoteNonLazy(union_obj.srcLoc(mod), msg, "union declared here", .{}); |
| 4891 | break :msg msg; | 5046 | break :msg msg; |
| 4892 | }; | 5047 | }; |
| 4893 | return sema.failWithOwnedErrorMsg(msg); | 5048 | return sema.failWithOwnedErrorMsg(msg); |
| 4894 | } | 5049 | } |
| 4895 | 5050 | ||
| 4896 | fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !void { | 5051 | fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !void { |
| 4897 | const src_loc = decl_ty.declSrcLocOrNull(sema.mod) orelse return; | 5052 | const mod = sema.mod; |
| 4898 | const category = switch (decl_ty.zigTypeTag()) { | 5053 | const src_loc = decl_ty.declSrcLocOrNull(mod) orelse return; |
| 5054 | const category = switch (decl_ty.zigTypeTag(mod)) { | ||
| 4899 | .Union => "union", | 5055 | .Union => "union", |
| 4900 | .Struct => "struct", | 5056 | .Struct => "struct", |
| 4901 | .Enum => "enum", | 5057 | .Enum => "enum", |
| ... | @@ -4903,7 +5059,7 @@ fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !vo | ... | @@ -4903,7 +5059,7 @@ fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !vo |
| 4903 | .ErrorSet => "error set", | 5059 | .ErrorSet => "error set", |
| 4904 | else => unreachable, | 5060 | else => unreachable, |
| 4905 | }; | 5061 | }; |
| 4906 | try sema.mod.errNoteNonLazy(src_loc, parent, "{s} declared here", .{category}); | 5062 | try mod.errNoteNonLazy(src_loc, parent, "{s} declared here", .{category}); |
| 4907 | } | 5063 | } |
| 4908 | 5064 | ||
| 4909 | fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 5065 | fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| ... | @@ -4919,17 +5075,14 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -4919,17 +5075,14 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 4919 | const src: LazySrcLoc = sema.src; | 5075 | const src: LazySrcLoc = sema.src; |
| 4920 | blk: { | 5076 | blk: { |
| 4921 | const ptr_inst = Air.refToIndex(ptr) orelse break :blk; | 5077 | const ptr_inst = Air.refToIndex(ptr) orelse break :blk; |
| 4922 | if (sema.air_instructions.items(.tag)[ptr_inst] != .constant) break :blk; | 5078 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { |
| 4923 | const air_datas = sema.air_instructions.items(.data); | ||
| 4924 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; | ||
| 4925 | switch (ptr_val.tag()) { | ||
| 4926 | .inferred_alloc_comptime => { | 5079 | .inferred_alloc_comptime => { |
| 4927 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; | 5080 | const iac = &sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime; |
| 4928 | return sema.storeToInferredAllocComptime(block, src, operand, iac); | 5081 | return sema.storeToInferredAllocComptime(block, src, operand, iac); |
| 4929 | }, | 5082 | }, |
| 4930 | .inferred_alloc => { | 5083 | .inferred_alloc => { |
| 4931 | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; | 5084 | const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; |
| 4932 | return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc); | 5085 | return sema.storeToInferredAlloc(block, ptr, operand, ia); |
| 4933 | }, | 5086 | }, |
| 4934 | else => break :blk, | 5087 | else => break :blk, |
| 4935 | } | 5088 | } |
| ... | @@ -4947,18 +5100,16 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi | ... | @@ -4947,18 +5100,16 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi |
| 4947 | const ptr = try sema.resolveInst(bin_inst.lhs); | 5100 | const ptr = try sema.resolveInst(bin_inst.lhs); |
| 4948 | const operand = try sema.resolveInst(bin_inst.rhs); | 5101 | const operand = try sema.resolveInst(bin_inst.rhs); |
| 4949 | const ptr_inst = Air.refToIndex(ptr).?; | 5102 | const ptr_inst = Air.refToIndex(ptr).?; |
| 4950 | assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant); | ||
| 4951 | const air_datas = sema.air_instructions.items(.data); | 5103 | const air_datas = sema.air_instructions.items(.data); |
| 4952 | const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload]; | ||
| 4953 | 5104 | ||
| 4954 | switch (ptr_val.tag()) { | 5105 | switch (sema.air_instructions.items(.tag)[ptr_inst]) { |
| 4955 | .inferred_alloc_comptime => { | 5106 | .inferred_alloc_comptime => { |
| 4956 | const iac = ptr_val.castTag(.inferred_alloc_comptime).?; | 5107 | const iac = &air_datas[ptr_inst].inferred_alloc_comptime; |
| 4957 | return sema.storeToInferredAllocComptime(block, src, operand, iac); | 5108 | return sema.storeToInferredAllocComptime(block, src, operand, iac); |
| 4958 | }, | 5109 | }, |
| 4959 | .inferred_alloc => { | 5110 | .inferred_alloc => { |
| 4960 | const inferred_alloc = ptr_val.castTag(.inferred_alloc).?; | 5111 | const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; |
| 4961 | return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc); | 5112 | return sema.storeToInferredAlloc(block, ptr, operand, ia); |
| 4962 | }, | 5113 | }, |
| 4963 | else => unreachable, | 5114 | else => unreachable, |
| 4964 | } | 5115 | } |
| ... | @@ -4969,14 +5120,14 @@ fn storeToInferredAlloc( | ... | @@ -4969,14 +5120,14 @@ fn storeToInferredAlloc( |
| 4969 | block: *Block, | 5120 | block: *Block, |
| 4970 | ptr: Air.Inst.Ref, | 5121 | ptr: Air.Inst.Ref, |
| 4971 | operand: Air.Inst.Ref, | 5122 | operand: Air.Inst.Ref, |
| 4972 | inferred_alloc: *Value.Payload.InferredAlloc, | 5123 | inferred_alloc: *InferredAlloc, |
| 4973 | ) CompileError!void { | 5124 | ) CompileError!void { |
| 4974 | // Create a store instruction as a placeholder. This will be replaced by a | 5125 | // Create a store instruction as a placeholder. This will be replaced by a |
| 4975 | // proper store sequence once we know the stored type. | 5126 | // proper store sequence once we know the stored type. |
| 4976 | const dummy_store = try block.addBinOp(.store, ptr, operand); | 5127 | const dummy_store = try block.addBinOp(.store, ptr, operand); |
| 4977 | // Add the stored instruction to the set we will use to resolve peer types | 5128 | // Add the stored instruction to the set we will use to resolve peer types |
| 4978 | // for the inferred allocation. | 5129 | // for the inferred allocation. |
| 4979 | try inferred_alloc.data.prongs.append(sema.arena, .{ | 5130 | try inferred_alloc.prongs.append(sema.arena, .{ |
| 4980 | .stored_inst = operand, | 5131 | .stored_inst = operand, |
| 4981 | .placeholder = Air.refToIndex(dummy_store).?, | 5132 | .placeholder = Air.refToIndex(dummy_store).?, |
| 4982 | }); | 5133 | }); |
| ... | @@ -4987,20 +5138,21 @@ fn storeToInferredAllocComptime( | ... | @@ -4987,20 +5138,21 @@ fn storeToInferredAllocComptime( |
| 4987 | block: *Block, | 5138 | block: *Block, |
| 4988 | src: LazySrcLoc, | 5139 | src: LazySrcLoc, |
| 4989 | operand: Air.Inst.Ref, | 5140 | operand: Air.Inst.Ref, |
| 4990 | iac: *Value.Payload.InferredAllocComptime, | 5141 | iac: *Air.Inst.Data.InferredAllocComptime, |
| 4991 | ) CompileError!void { | 5142 | ) CompileError!void { |
| 4992 | const operand_ty = sema.typeOf(operand); | 5143 | const operand_ty = sema.typeOf(operand); |
| 4993 | // There will be only one store_to_inferred_ptr because we are running at comptime. | 5144 | // There will be only one store_to_inferred_ptr because we are running at comptime. |
| 4994 | // The alloc will turn into a Decl. | 5145 | // The alloc will turn into a Decl. |
| 4995 | if (try sema.resolveMaybeUndefValAllowVariables(operand)) |operand_val| store: { | 5146 | if (try sema.resolveMaybeUndefValAllowVariables(operand)) |operand_val| store: { |
| 4996 | if (operand_val.tag() == .variable) break :store; | 5147 | if (operand_val.getVariable(sema.mod) != null) break :store; |
| 4997 | var anon_decl = try block.startAnonDecl(); | 5148 | var anon_decl = try block.startAnonDecl(); |
| 4998 | defer anon_decl.deinit(); | 5149 | defer anon_decl.deinit(); |
| 4999 | iac.data.decl_index = try anon_decl.finish( | 5150 | iac.decl_index = try anon_decl.finish( |
| 5000 | try operand_ty.copy(anon_decl.arena()), | 5151 | operand_ty, |
| 5001 | try operand_val.copy(anon_decl.arena()), | 5152 | operand_val, |
| 5002 | iac.data.alignment, | 5153 | iac.alignment.toByteUnits(0), |
| 5003 | ); | 5154 | ); |
| 5155 | try sema.comptime_mutable_decls.append(iac.decl_index); | ||
| 5004 | return; | 5156 | return; |
| 5005 | } | 5157 | } |
| 5006 | 5158 | ||
| ... | @@ -5028,6 +5180,7 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v | ... | @@ -5028,6 +5180,7 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v |
| 5028 | const tracy = trace(@src()); | 5180 | const tracy = trace(@src()); |
| 5029 | defer tracy.end(); | 5181 | defer tracy.end(); |
| 5030 | 5182 | ||
| 5183 | const mod = sema.mod; | ||
| 5031 | const zir_tags = sema.code.instructions.items(.tag); | 5184 | const zir_tags = sema.code.instructions.items(.tag); |
| 5032 | const zir_datas = sema.code.instructions.items(.data); | 5185 | const zir_datas = sema.code.instructions.items(.data); |
| 5033 | const inst_data = zir_datas[inst].pl_node; | 5186 | const inst_data = zir_datas[inst].pl_node; |
| ... | @@ -5046,9 +5199,9 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v | ... | @@ -5046,9 +5199,9 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v |
| 5046 | // %b = store(%a, %c) | 5199 | // %b = store(%a, %c) |
| 5047 | // Where %c is an error union or error set. In such case we need to add | 5200 | // Where %c is an error union or error set. In such case we need to add |
| 5048 | // to the current function's inferred error set, if any. | 5201 | // to the current function's inferred error set, if any. |
| 5049 | if (is_ret and (sema.typeOf(operand).zigTypeTag() == .ErrorUnion or | 5202 | if (is_ret and (sema.typeOf(operand).zigTypeTag(mod) == .ErrorUnion or |
| 5050 | sema.typeOf(operand).zigTypeTag() == .ErrorSet) and | 5203 | sema.typeOf(operand).zigTypeTag(mod) == .ErrorSet) and |
| 5051 | sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) | 5204 | sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion) |
| 5052 | { | 5205 | { |
| 5053 | try sema.addToInferredErrorSet(operand); | 5206 | try sema.addToInferredErrorSet(operand); |
| 5054 | } | 5207 | } |
| ... | @@ -5072,47 +5225,30 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -5072,47 +5225,30 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 5072 | return sema.addStrLit(block, bytes); | 5225 | return sema.addStrLit(block, bytes); |
| 5073 | } | 5226 | } |
| 5074 | 5227 | ||
| 5075 | fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air.Inst.Ref { | 5228 | fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Inst.Ref { |
| 5076 | // `zir_bytes` references memory inside the ZIR module, which can get deallocated | ||
| 5077 | // after semantic analysis is complete, for example in the case of the initialization | ||
| 5078 | // expression of a variable declaration. | ||
| 5079 | const mod = sema.mod; | 5229 | const mod = sema.mod; |
| 5080 | const gpa = sema.gpa; | 5230 | const gpa = sema.gpa; |
| 5081 | const string_bytes = &mod.string_literal_bytes; | 5231 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 5082 | const StringLiteralAdapter = Module.StringLiteralAdapter; | 5232 | const duped_bytes = try sema.arena.dupe(u8, bytes); |
| 5083 | const StringLiteralContext = Module.StringLiteralContext; | 5233 | const ty = try mod.arrayType(.{ |
| 5084 | try string_bytes.ensureUnusedCapacity(gpa, zir_bytes.len); | 5234 | .len = bytes.len, |
| 5085 | const gop = try mod.string_literal_table.getOrPutContextAdapted(gpa, zir_bytes, StringLiteralAdapter{ | 5235 | .child = .u8_type, |
| 5086 | .bytes = string_bytes, | 5236 | .sentinel = .zero_u8, |
| 5087 | }, StringLiteralContext{ | ||
| 5088 | .bytes = string_bytes, | ||
| 5089 | }); | 5237 | }); |
| 5238 | const val = try mod.intern(.{ .aggregate = .{ | ||
| 5239 | .ty = ty.toIntern(), | ||
| 5240 | .storage = .{ .bytes = duped_bytes }, | ||
| 5241 | } }); | ||
| 5242 | const gop = try mod.memoized_decls.getOrPut(gpa, val); | ||
| 5090 | if (!gop.found_existing) { | 5243 | if (!gop.found_existing) { |
| 5091 | gop.key_ptr.* = .{ | 5244 | const new_decl_index = try mod.createAnonymousDecl(block, .{ |
| 5092 | .index = @intCast(u32, string_bytes.items.len), | 5245 | .ty = ty, |
| 5093 | .len = @intCast(u32, zir_bytes.len), | 5246 | .val = val.toValue(), |
| 5094 | }; | 5247 | }); |
| 5095 | string_bytes.appendSliceAssumeCapacity(zir_bytes); | 5248 | gop.value_ptr.* = new_decl_index; |
| 5096 | gop.value_ptr.* = .none; | 5249 | try mod.finalizeAnonDecl(new_decl_index); |
| 5097 | } | 5250 | } |
| 5098 | const decl_index = gop.value_ptr.unwrap() orelse di: { | 5251 | return sema.analyzeDeclRef(gop.value_ptr.*); |
| 5099 | var anon_decl = try block.startAnonDecl(); | ||
| 5100 | defer anon_decl.deinit(); | ||
| 5101 | |||
| 5102 | const decl_index = try anon_decl.finish( | ||
| 5103 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), gop.key_ptr.len), | ||
| 5104 | try Value.Tag.str_lit.create(anon_decl.arena(), gop.key_ptr.*), | ||
| 5105 | 0, // default alignment | ||
| 5106 | ); | ||
| 5107 | |||
| 5108 | // Needed so that `Decl.clearValues` will additionally set the corresponding | ||
| 5109 | // string literal table value back to `Decl.OptionalIndex.none`. | ||
| 5110 | mod.declPtr(decl_index).owns_tv = true; | ||
| 5111 | |||
| 5112 | gop.value_ptr.* = decl_index.toOptional(); | ||
| 5113 | break :di decl_index; | ||
| 5114 | }; | ||
| 5115 | return sema.analyzeDeclRef(decl_index); | ||
| 5116 | } | 5252 | } |
| 5117 | 5253 | ||
| 5118 | fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 5254 | fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -5121,7 +5257,7 @@ fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -5121,7 +5257,7 @@ fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 5121 | defer tracy.end(); | 5257 | defer tracy.end(); |
| 5122 | 5258 | ||
| 5123 | const int = sema.code.instructions.items(.data)[inst].int; | 5259 | const int = sema.code.instructions.items(.data)[inst].int; |
| 5124 | return sema.addIntUnsigned(Type.initTag(.comptime_int), int); | 5260 | return sema.addIntUnsigned(Type.comptime_int, int); |
| 5125 | } | 5261 | } |
| 5126 | 5262 | ||
| 5127 | fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 5263 | fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -5129,38 +5265,43 @@ fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -5129,38 +5265,43 @@ fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 5129 | const tracy = trace(@src()); | 5265 | const tracy = trace(@src()); |
| 5130 | defer tracy.end(); | 5266 | defer tracy.end(); |
| 5131 | 5267 | ||
| 5132 | const arena = sema.arena; | 5268 | const mod = sema.mod; |
| 5133 | const int = sema.code.instructions.items(.data)[inst].str; | 5269 | const int = sema.code.instructions.items(.data)[inst].str; |
| 5134 | const byte_count = int.len * @sizeOf(std.math.big.Limb); | 5270 | const byte_count = int.len * @sizeOf(std.math.big.Limb); |
| 5135 | const limb_bytes = sema.code.string_bytes[int.start..][0..byte_count]; | 5271 | const limb_bytes = sema.code.string_bytes[int.start..][0..byte_count]; |
| 5136 | const limbs = try arena.alloc(std.math.big.Limb, int.len); | 5272 | |
| 5273 | // TODO: this allocation and copy is only needed because the limbs may be unaligned. | ||
| 5274 | // If ZIR is adjusted so that big int limbs are guaranteed to be aligned, these | ||
| 5275 | // two lines can be removed. | ||
| 5276 | const limbs = try sema.arena.alloc(std.math.big.Limb, int.len); | ||
| 5137 | @memcpy(mem.sliceAsBytes(limbs), limb_bytes); | 5277 | @memcpy(mem.sliceAsBytes(limbs), limb_bytes); |
| 5138 | 5278 | ||
| 5139 | return sema.addConstant( | 5279 | return sema.addConstant( |
| 5140 | Type.initTag(.comptime_int), | 5280 | Type.comptime_int, |
| 5141 | try Value.Tag.int_big_positive.create(arena, limbs), | 5281 | try mod.intValue_big(Type.comptime_int, .{ |
| 5282 | .limbs = limbs, | ||
| 5283 | .positive = true, | ||
| 5284 | }), | ||
| 5142 | ); | 5285 | ); |
| 5143 | } | 5286 | } |
| 5144 | 5287 | ||
| 5145 | fn zirFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 5288 | fn zirFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 5146 | _ = block; | 5289 | _ = block; |
| 5147 | const arena = sema.arena; | ||
| 5148 | const number = sema.code.instructions.items(.data)[inst].float; | 5290 | const number = sema.code.instructions.items(.data)[inst].float; |
| 5149 | return sema.addConstant( | 5291 | return sema.addConstant( |
| 5150 | Type.initTag(.comptime_float), | 5292 | Type.comptime_float, |
| 5151 | try Value.Tag.float_64.create(arena, number), | 5293 | try sema.mod.floatValue(Type.comptime_float, number), |
| 5152 | ); | 5294 | ); |
| 5153 | } | 5295 | } |
| 5154 | 5296 | ||
| 5155 | fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 5297 | fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 5156 | _ = block; | 5298 | _ = block; |
| 5157 | const arena = sema.arena; | ||
| 5158 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 5299 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 5159 | const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; | 5300 | const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; |
| 5160 | const number = extra.get(); | 5301 | const number = extra.get(); |
| 5161 | return sema.addConstant( | 5302 | return sema.addConstant( |
| 5162 | Type.initTag(.comptime_float), | 5303 | Type.comptime_float, |
| 5163 | try Value.Tag.float_128.create(arena, number), | 5304 | try sema.mod.floatValue(Type.comptime_float, number), |
| 5164 | ); | 5305 | ); |
| 5165 | } | 5306 | } |
| 5166 | 5307 | ||
| ... | @@ -5179,7 +5320,9 @@ fn zirCompileLog( | ... | @@ -5179,7 +5320,9 @@ fn zirCompileLog( |
| 5179 | sema: *Sema, | 5320 | sema: *Sema, |
| 5180 | extended: Zir.Inst.Extended.InstData, | 5321 | extended: Zir.Inst.Extended.InstData, |
| 5181 | ) CompileError!Air.Inst.Ref { | 5322 | ) CompileError!Air.Inst.Ref { |
| 5182 | var managed = sema.mod.compile_log_text.toManaged(sema.gpa); | 5323 | const mod = sema.mod; |
| 5324 | |||
| 5325 | var managed = mod.compile_log_text.toManaged(sema.gpa); | ||
| 5183 | defer sema.mod.compile_log_text = managed.moveToUnmanaged(); | 5326 | defer sema.mod.compile_log_text = managed.moveToUnmanaged(); |
| 5184 | const writer = managed.writer(); | 5327 | const writer = managed.writer(); |
| 5185 | 5328 | ||
| ... | @@ -5192,19 +5335,18 @@ fn zirCompileLog( | ... | @@ -5192,19 +5335,18 @@ fn zirCompileLog( |
| 5192 | 5335 | ||
| 5193 | const arg = try sema.resolveInst(arg_ref); | 5336 | const arg = try sema.resolveInst(arg_ref); |
| 5194 | const arg_ty = sema.typeOf(arg); | 5337 | const arg_ty = sema.typeOf(arg); |
| 5195 | if (try sema.resolveMaybeUndefVal(arg)) |val| { | 5338 | if (try sema.resolveMaybeUndefLazyVal(arg)) |val| { |
| 5196 | try sema.resolveLazyValue(val); | ||
| 5197 | try writer.print("@as({}, {})", .{ | 5339 | try writer.print("@as({}, {})", .{ |
| 5198 | arg_ty.fmt(sema.mod), val.fmtValue(arg_ty, sema.mod), | 5340 | arg_ty.fmt(mod), val.fmtValue(arg_ty, mod), |
| 5199 | }); | 5341 | }); |
| 5200 | } else { | 5342 | } else { |
| 5201 | try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(sema.mod)}); | 5343 | try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(mod)}); |
| 5202 | } | 5344 | } |
| 5203 | } | 5345 | } |
| 5204 | try writer.print("\n", .{}); | 5346 | try writer.print("\n", .{}); |
| 5205 | 5347 | ||
| 5206 | const decl_index = if (sema.func) |some| some.owner_decl else sema.owner_decl_index; | 5348 | const decl_index = if (sema.func) |some| some.owner_decl else sema.owner_decl_index; |
| 5207 | const gop = try sema.mod.compile_log_decls.getOrPut(sema.gpa, decl_index); | 5349 | const gop = try mod.compile_log_decls.getOrPut(sema.gpa, decl_index); |
| 5208 | if (!gop.found_existing) { | 5350 | if (!gop.found_existing) { |
| 5209 | gop.value_ptr.* = src_node; | 5351 | gop.value_ptr.* = src_node; |
| 5210 | } | 5352 | } |
| ... | @@ -5235,6 +5377,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -5235,6 +5377,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError |
| 5235 | const tracy = trace(@src()); | 5377 | const tracy = trace(@src()); |
| 5236 | defer tracy.end(); | 5378 | defer tracy.end(); |
| 5237 | 5379 | ||
| 5380 | const mod = sema.mod; | ||
| 5238 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 5381 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 5239 | const src = inst_data.src(); | 5382 | const src = inst_data.src(); |
| 5240 | const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); | 5383 | const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); |
| ... | @@ -5284,7 +5427,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -5284,7 +5427,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError |
| 5284 | try sema.analyzeBody(&loop_block, body); | 5427 | try sema.analyzeBody(&loop_block, body); |
| 5285 | 5428 | ||
| 5286 | const loop_block_len = loop_block.instructions.items.len; | 5429 | const loop_block_len = loop_block.instructions.items.len; |
| 5287 | if (loop_block_len > 0 and sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block_len - 1])).isNoReturn()) { | 5430 | if (loop_block_len > 0 and sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block_len - 1])).isNoReturn(mod)) { |
| 5288 | // If the loop ended with a noreturn terminator, then there is no way for it to loop, | 5431 | // If the loop ended with a noreturn terminator, then there is no way for it to loop, |
| 5289 | // so we can just use the block instead. | 5432 | // so we can just use the block instead. |
| 5290 | try child_block.instructions.appendSlice(gpa, loop_block.instructions.items); | 5433 | try child_block.instructions.appendSlice(gpa, loop_block.instructions.items); |
| ... | @@ -5311,7 +5454,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -5311,7 +5454,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 5311 | 5454 | ||
| 5312 | // we check this here to avoid undefined symbols | 5455 | // we check this here to avoid undefined symbols |
| 5313 | if (!@import("build_options").have_llvm) | 5456 | if (!@import("build_options").have_llvm) |
| 5314 | return sema.fail(parent_block, src, "cannot do C import on Zig compiler not built with LLVM-extension", .{}); | 5457 | return sema.fail(parent_block, src, "C import unavailable; Zig compiler built without LLVM extensions", .{}); |
| 5315 | 5458 | ||
| 5316 | var c_import_buf = std.ArrayList(u8).init(sema.gpa); | 5459 | var c_import_buf = std.ArrayList(u8).init(sema.gpa); |
| 5317 | defer c_import_buf.deinit(); | 5460 | defer c_import_buf.deinit(); |
| ... | @@ -5354,7 +5497,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -5354,7 +5497,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 5354 | if (!mod.comp.bin_file.options.link_libc) | 5497 | if (!mod.comp.bin_file.options.link_libc) |
| 5355 | try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{}); | 5498 | try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{}); |
| 5356 | 5499 | ||
| 5357 | const gop = try sema.mod.cimport_errors.getOrPut(sema.gpa, sema.owner_decl_index); | 5500 | const gop = try mod.cimport_errors.getOrPut(sema.gpa, sema.owner_decl_index); |
| 5358 | if (!gop.found_existing) { | 5501 | if (!gop.found_existing) { |
| 5359 | var errs = try std.ArrayListUnmanaged(Module.CImportError).initCapacity(sema.gpa, c_import_res.errors.len); | 5502 | var errs = try std.ArrayListUnmanaged(Module.CImportError).initCapacity(sema.gpa, c_import_res.errors.len); |
| 5360 | errdefer { | 5503 | errdefer { |
| ... | @@ -5537,7 +5680,7 @@ fn analyzeBlockBody( | ... | @@ -5537,7 +5680,7 @@ fn analyzeBlockBody( |
| 5537 | 5680 | ||
| 5538 | // Blocks must terminate with noreturn instruction. | 5681 | // Blocks must terminate with noreturn instruction. |
| 5539 | assert(child_block.instructions.items.len != 0); | 5682 | assert(child_block.instructions.items.len != 0); |
| 5540 | assert(sema.typeOf(Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn()); | 5683 | assert(sema.typeOf(Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn(mod)); |
| 5541 | 5684 | ||
| 5542 | if (merges.results.items.len == 0) { | 5685 | if (merges.results.items.len == 0) { |
| 5543 | // No need for a block instruction. We can put the new instructions | 5686 | // No need for a block instruction. We can put the new instructions |
| ... | @@ -5578,7 +5721,7 @@ fn analyzeBlockBody( | ... | @@ -5578,7 +5721,7 @@ fn analyzeBlockBody( |
| 5578 | try sema.errNote(child_block, runtime_src, msg, "runtime control flow here", .{}); | 5721 | try sema.errNote(child_block, runtime_src, msg, "runtime control flow here", .{}); |
| 5579 | 5722 | ||
| 5580 | const child_src_decl = mod.declPtr(child_block.src_decl); | 5723 | const child_src_decl = mod.declPtr(child_block.src_decl); |
| 5581 | try sema.explainWhyTypeIsComptime(msg, type_src.toSrcLoc(child_src_decl), resolved_ty); | 5724 | try sema.explainWhyTypeIsComptime(msg, type_src.toSrcLoc(child_src_decl, mod), resolved_ty); |
| 5582 | 5725 | ||
| 5583 | break :msg msg; | 5726 | break :msg msg; |
| 5584 | }; | 5727 | }; |
| ... | @@ -5649,15 +5792,16 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -5649,15 +5792,16 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 5649 | const tracy = trace(@src()); | 5792 | const tracy = trace(@src()); |
| 5650 | defer tracy.end(); | 5793 | defer tracy.end(); |
| 5651 | 5794 | ||
| 5795 | const mod = sema.mod; | ||
| 5652 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 5796 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 5653 | const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; | 5797 | const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; |
| 5654 | const src = inst_data.src(); | 5798 | const src = inst_data.src(); |
| 5655 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 5799 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 5656 | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 5800 | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 5657 | const decl_name = sema.code.nullTerminatedString(extra.decl_name); | 5801 | const decl_name = try mod.intern_pool.getOrPutString(mod.gpa, sema.code.nullTerminatedString(extra.decl_name)); |
| 5658 | const decl_index = if (extra.namespace != .none) index_blk: { | 5802 | const decl_index = if (extra.namespace != .none) index_blk: { |
| 5659 | const container_ty = try sema.resolveType(block, operand_src, extra.namespace); | 5803 | const container_ty = try sema.resolveType(block, operand_src, extra.namespace); |
| 5660 | const container_namespace = container_ty.getNamespace().?; | 5804 | const container_namespace = container_ty.getNamespaceIndex(mod).unwrap().?; |
| 5661 | 5805 | ||
| 5662 | const maybe_index = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false); | 5806 | const maybe_index = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false); |
| 5663 | break :index_blk maybe_index orelse | 5807 | break :index_blk maybe_index orelse |
| ... | @@ -5671,10 +5815,10 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -5671,10 +5815,10 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 5671 | else => |e| return e, | 5815 | else => |e| return e, |
| 5672 | }; | 5816 | }; |
| 5673 | { | 5817 | { |
| 5674 | try sema.mod.ensureDeclAnalyzed(decl_index); | 5818 | try mod.ensureDeclAnalyzed(decl_index); |
| 5675 | const exported_decl = sema.mod.declPtr(decl_index); | 5819 | const exported_decl = mod.declPtr(decl_index); |
| 5676 | if (exported_decl.val.castTag(.function)) |some| { | 5820 | if (exported_decl.val.getFunction(mod)) |function| { |
| 5677 | return sema.analyzeExport(block, src, options, some.data.owner_decl); | 5821 | return sema.analyzeExport(block, src, options, function.owner_decl); |
| 5678 | } | 5822 | } |
| 5679 | } | 5823 | } |
| 5680 | try sema.analyzeExport(block, src, options, decl_index); | 5824 | try sema.analyzeExport(block, src, options, decl_index); |
| ... | @@ -5697,17 +5841,14 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -5697,17 +5841,14 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 5697 | }, | 5841 | }, |
| 5698 | else => |e| return e, | 5842 | else => |e| return e, |
| 5699 | }; | 5843 | }; |
| 5700 | const decl_index = switch (operand.val.tag()) { | 5844 | const decl_index = if (operand.val.getFunction(sema.mod)) |function| function.owner_decl else blk: { |
| 5701 | .function => operand.val.castTag(.function).?.data.owner_decl, | 5845 | var anon_decl = try block.startAnonDecl(); |
| 5702 | else => blk: { | 5846 | defer anon_decl.deinit(); |
| 5703 | var anon_decl = try block.startAnonDecl(); | 5847 | break :blk try anon_decl.finish( |
| 5704 | defer anon_decl.deinit(); | 5848 | operand.ty, |
| 5705 | break :blk try anon_decl.finish( | 5849 | operand.val, |
| 5706 | try operand.ty.copy(anon_decl.arena()), | 5850 | 0, |
| 5707 | try operand.val.copy(anon_decl.arena()), | 5851 | ); |
| 5708 | 0, | ||
| 5709 | ); | ||
| 5710 | }, | ||
| 5711 | }; | 5852 | }; |
| 5712 | try sema.analyzeExport(block, src, options, decl_index); | 5853 | try sema.analyzeExport(block, src, options, decl_index); |
| 5713 | } | 5854 | } |
| ... | @@ -5716,13 +5857,13 @@ pub fn analyzeExport( | ... | @@ -5716,13 +5857,13 @@ pub fn analyzeExport( |
| 5716 | sema: *Sema, | 5857 | sema: *Sema, |
| 5717 | block: *Block, | 5858 | block: *Block, |
| 5718 | src: LazySrcLoc, | 5859 | src: LazySrcLoc, |
| 5719 | borrowed_options: std.builtin.ExportOptions, | 5860 | options: Module.Export.Options, |
| 5720 | exported_decl_index: Decl.Index, | 5861 | exported_decl_index: Decl.Index, |
| 5721 | ) !void { | 5862 | ) !void { |
| 5722 | const Export = Module.Export; | 5863 | const Export = Module.Export; |
| 5723 | const mod = sema.mod; | 5864 | const mod = sema.mod; |
| 5724 | 5865 | ||
| 5725 | if (borrowed_options.linkage == .Internal) { | 5866 | if (options.linkage == .Internal) { |
| 5726 | return; | 5867 | return; |
| 5727 | } | 5868 | } |
| 5728 | 5869 | ||
| ... | @@ -5731,11 +5872,11 @@ pub fn analyzeExport( | ... | @@ -5731,11 +5872,11 @@ pub fn analyzeExport( |
| 5731 | 5872 | ||
| 5732 | if (!try sema.validateExternType(exported_decl.ty, .other)) { | 5873 | if (!try sema.validateExternType(exported_decl.ty, .other)) { |
| 5733 | const msg = msg: { | 5874 | const msg = msg: { |
| 5734 | const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)}); | 5875 | const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(mod)}); |
| 5735 | errdefer msg.destroy(sema.gpa); | 5876 | errdefer msg.destroy(sema.gpa); |
| 5736 | 5877 | ||
| 5737 | const src_decl = sema.mod.declPtr(block.src_decl); | 5878 | const src_decl = mod.declPtr(block.src_decl); |
| 5738 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), exported_decl.ty, .other); | 5879 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), exported_decl.ty, .other); |
| 5739 | 5880 | ||
| 5740 | try sema.addDeclaredHereNote(msg, exported_decl.ty); | 5881 | try sema.addDeclaredHereNote(msg, exported_decl.ty); |
| 5741 | break :msg msg; | 5882 | break :msg msg; |
| ... | @@ -5744,15 +5885,15 @@ pub fn analyzeExport( | ... | @@ -5744,15 +5885,15 @@ pub fn analyzeExport( |
| 5744 | } | 5885 | } |
| 5745 | 5886 | ||
| 5746 | // TODO: some backends might support re-exporting extern decls | 5887 | // TODO: some backends might support re-exporting extern decls |
| 5747 | if (exported_decl.isExtern()) { | 5888 | if (exported_decl.isExtern(mod)) { |
| 5748 | return sema.fail(block, src, "export target cannot be extern", .{}); | 5889 | return sema.fail(block, src, "export target cannot be extern", .{}); |
| 5749 | } | 5890 | } |
| 5750 | 5891 | ||
| 5751 | // This decl is alive no matter what, since it's being exported | 5892 | // This decl is alive no matter what, since it's being exported |
| 5752 | mod.markDeclAlive(exported_decl); | 5893 | try mod.markDeclAlive(exported_decl); |
| 5753 | try sema.maybeQueueFuncBodyAnalysis(exported_decl_index); | 5894 | try sema.maybeQueueFuncBodyAnalysis(exported_decl_index); |
| 5754 | 5895 | ||
| 5755 | const gpa = mod.gpa; | 5896 | const gpa = sema.gpa; |
| 5756 | 5897 | ||
| 5757 | try mod.decl_exports.ensureUnusedCapacity(gpa, 1); | 5898 | try mod.decl_exports.ensureUnusedCapacity(gpa, 1); |
| 5758 | try mod.export_owners.ensureUnusedCapacity(gpa, 1); | 5899 | try mod.export_owners.ensureUnusedCapacity(gpa, 1); |
| ... | @@ -5760,19 +5901,8 @@ pub fn analyzeExport( | ... | @@ -5760,19 +5901,8 @@ pub fn analyzeExport( |
| 5760 | const new_export = try gpa.create(Export); | 5901 | const new_export = try gpa.create(Export); |
| 5761 | errdefer gpa.destroy(new_export); | 5902 | errdefer gpa.destroy(new_export); |
| 5762 | 5903 | ||
| 5763 | const symbol_name = try gpa.dupe(u8, borrowed_options.name); | ||
| 5764 | errdefer gpa.free(symbol_name); | ||
| 5765 | |||
| 5766 | const section: ?[]const u8 = if (borrowed_options.section) |s| try gpa.dupe(u8, s) else null; | ||
| 5767 | errdefer if (section) |s| gpa.free(s); | ||
| 5768 | |||
| 5769 | new_export.* = .{ | 5904 | new_export.* = .{ |
| 5770 | .options = .{ | 5905 | .opts = options, |
| 5771 | .name = symbol_name, | ||
| 5772 | .linkage = borrowed_options.linkage, | ||
| 5773 | .section = section, | ||
| 5774 | .visibility = borrowed_options.visibility, | ||
| 5775 | }, | ||
| 5776 | .src = src, | 5906 | .src = src, |
| 5777 | .owner_decl = sema.owner_decl_index, | 5907 | .owner_decl = sema.owner_decl_index, |
| 5778 | .src_decl = block.src_decl, | 5908 | .src_decl = block.src_decl, |
| ... | @@ -5798,6 +5928,7 @@ pub fn analyzeExport( | ... | @@ -5798,6 +5928,7 @@ pub fn analyzeExport( |
| 5798 | } | 5928 | } |
| 5799 | 5929 | ||
| 5800 | fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { | 5930 | fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { |
| 5931 | const mod = sema.mod; | ||
| 5801 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | 5932 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 5802 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 5933 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 5803 | const src = LazySrcLoc.nodeOffset(extra.node); | 5934 | const src = LazySrcLoc.nodeOffset(extra.node); |
| ... | @@ -5807,11 +5938,12 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst | ... | @@ -5807,11 +5938,12 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 5807 | alignment, | 5938 | alignment, |
| 5808 | }); | 5939 | }); |
| 5809 | } | 5940 | } |
| 5810 | const func = sema.func orelse | 5941 | const func_index = sema.func_index.unwrap() orelse |
| 5811 | return sema.fail(block, src, "@setAlignStack outside function body", .{}); | 5942 | return sema.fail(block, src, "@setAlignStack outside function body", .{}); |
| 5943 | const func = mod.funcPtr(func_index); | ||
| 5812 | 5944 | ||
| 5813 | const fn_owner_decl = sema.mod.declPtr(func.owner_decl); | 5945 | const fn_owner_decl = mod.declPtr(func.owner_decl); |
| 5814 | switch (fn_owner_decl.ty.fnCallingConvention()) { | 5946 | switch (fn_owner_decl.ty.fnCallingConvention(mod)) { |
| 5815 | .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}), | 5947 | .Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}), |
| 5816 | .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}), | 5948 | .Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}), |
| 5817 | else => if (block.inlining != null) { | 5949 | else => if (block.inlining != null) { |
| ... | @@ -5819,7 +5951,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst | ... | @@ -5819,7 +5951,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 5819 | }, | 5951 | }, |
| 5820 | } | 5952 | } |
| 5821 | 5953 | ||
| 5822 | const gop = try sema.mod.align_stack_fns.getOrPut(sema.mod.gpa, func); | 5954 | const gop = try mod.align_stack_fns.getOrPut(sema.gpa, func_index); |
| 5823 | if (gop.found_existing) { | 5955 | if (gop.found_existing) { |
| 5824 | const msg = msg: { | 5956 | const msg = msg: { |
| 5825 | const msg = try sema.errMsg(block, src, "multiple @setAlignStack in the same function body", .{}); | 5957 | const msg = try sema.errMsg(block, src, "multiple @setAlignStack in the same function body", .{}); |
| ... | @@ -5971,10 +6103,11 @@ fn addDbgVar( | ... | @@ -5971,10 +6103,11 @@ fn addDbgVar( |
| 5971 | air_tag: Air.Inst.Tag, | 6103 | air_tag: Air.Inst.Tag, |
| 5972 | name: []const u8, | 6104 | name: []const u8, |
| 5973 | ) CompileError!void { | 6105 | ) CompileError!void { |
| 6106 | const mod = sema.mod; | ||
| 5974 | const operand_ty = sema.typeOf(operand); | 6107 | const operand_ty = sema.typeOf(operand); |
| 5975 | switch (air_tag) { | 6108 | switch (air_tag) { |
| 5976 | .dbg_var_ptr => { | 6109 | .dbg_var_ptr => { |
| 5977 | if (!(try sema.typeHasRuntimeBits(operand_ty.childType()))) return; | 6110 | if (!(try sema.typeHasRuntimeBits(operand_ty.childType(mod)))) return; |
| 5978 | }, | 6111 | }, |
| 5979 | .dbg_var_val => { | 6112 | .dbg_var_val => { |
| 5980 | if (!(try sema.typeHasRuntimeBits(operand_ty))) return; | 6113 | if (!(try sema.typeHasRuntimeBits(operand_ty))) return; |
| ... | @@ -6003,29 +6136,32 @@ fn addDbgVar( | ... | @@ -6003,29 +6136,32 @@ fn addDbgVar( |
| 6003 | } | 6136 | } |
| 6004 | 6137 | ||
| 6005 | fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 6138 | fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 6139 | const mod = sema.mod; | ||
| 6006 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | 6140 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 6007 | const src = inst_data.src(); | 6141 | const src = inst_data.src(); |
| 6008 | const decl_name = inst_data.get(sema.code); | 6142 | const decl_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); |
| 6009 | const decl_index = try sema.lookupIdentifier(block, src, decl_name); | 6143 | const decl_index = try sema.lookupIdentifier(block, src, decl_name); |
| 6010 | try sema.addReferencedBy(block, src, decl_index); | 6144 | try sema.addReferencedBy(block, src, decl_index); |
| 6011 | return sema.analyzeDeclRef(decl_index); | 6145 | return sema.analyzeDeclRef(decl_index); |
| 6012 | } | 6146 | } |
| 6013 | 6147 | ||
| 6014 | fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 6148 | fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 6149 | const mod = sema.mod; | ||
| 6015 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | 6150 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 6016 | const src = inst_data.src(); | 6151 | const src = inst_data.src(); |
| 6017 | const decl_name = inst_data.get(sema.code); | 6152 | const decl_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); |
| 6018 | const decl = try sema.lookupIdentifier(block, src, decl_name); | 6153 | const decl = try sema.lookupIdentifier(block, src, decl_name); |
| 6019 | return sema.analyzeDeclVal(block, src, decl); | 6154 | return sema.analyzeDeclVal(block, src, decl); |
| 6020 | } | 6155 | } |
| 6021 | 6156 | ||
| 6022 | fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: []const u8) !Decl.Index { | 6157 | fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: InternPool.NullTerminatedString) !Decl.Index { |
| 6158 | const mod = sema.mod; | ||
| 6023 | var namespace = block.namespace; | 6159 | var namespace = block.namespace; |
| 6024 | while (true) { | 6160 | while (true) { |
| 6025 | if (try sema.lookupInNamespace(block, src, namespace, name, false)) |decl_index| { | 6161 | if (try sema.lookupInNamespace(block, src, namespace, name, false)) |decl_index| { |
| 6026 | return decl_index; | 6162 | return decl_index; |
| 6027 | } | 6163 | } |
| 6028 | namespace = namespace.parent orelse break; | 6164 | namespace = mod.namespacePtr(namespace).parent.unwrap() orelse break; |
| 6029 | } | 6165 | } |
| 6030 | unreachable; // AstGen detects use of undeclared identifier errors. | 6166 | unreachable; // AstGen detects use of undeclared identifier errors. |
| 6031 | } | 6167 | } |
| ... | @@ -6036,21 +6172,22 @@ fn lookupInNamespace( | ... | @@ -6036,21 +6172,22 @@ fn lookupInNamespace( |
| 6036 | sema: *Sema, | 6172 | sema: *Sema, |
| 6037 | block: *Block, | 6173 | block: *Block, |
| 6038 | src: LazySrcLoc, | 6174 | src: LazySrcLoc, |
| 6039 | namespace: *Namespace, | 6175 | namespace_index: Namespace.Index, |
| 6040 | ident_name: []const u8, | 6176 | ident_name: InternPool.NullTerminatedString, |
| 6041 | observe_usingnamespace: bool, | 6177 | observe_usingnamespace: bool, |
| 6042 | ) CompileError!?Decl.Index { | 6178 | ) CompileError!?Decl.Index { |
| 6043 | const mod = sema.mod; | 6179 | const mod = sema.mod; |
| 6044 | 6180 | ||
| 6045 | const namespace_decl_index = namespace.getDeclIndex(); | 6181 | const namespace = mod.namespacePtr(namespace_index); |
| 6046 | const namespace_decl = sema.mod.declPtr(namespace_decl_index); | 6182 | const namespace_decl_index = namespace.getDeclIndex(mod); |
| 6183 | const namespace_decl = mod.declPtr(namespace_decl_index); | ||
| 6047 | if (namespace_decl.analysis == .file_failure) { | 6184 | if (namespace_decl.analysis == .file_failure) { |
| 6048 | try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index); | 6185 | try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index); |
| 6049 | return error.AnalysisFail; | 6186 | return error.AnalysisFail; |
| 6050 | } | 6187 | } |
| 6051 | 6188 | ||
| 6052 | if (observe_usingnamespace and namespace.usingnamespace_set.count() != 0) { | 6189 | if (observe_usingnamespace and namespace.usingnamespace_set.count() != 0) { |
| 6053 | const src_file = block.namespace.file_scope; | 6190 | const src_file = mod.namespacePtr(block.namespace).file_scope; |
| 6054 | 6191 | ||
| 6055 | const gpa = sema.gpa; | 6192 | const gpa = sema.gpa; |
| 6056 | var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, bool) = .{}; | 6193 | var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, bool) = .{}; |
| ... | @@ -6069,7 +6206,7 @@ fn lookupInNamespace( | ... | @@ -6069,7 +6206,7 @@ fn lookupInNamespace( |
| 6069 | // Skip decls which are not marked pub, which are in a different | 6206 | // Skip decls which are not marked pub, which are in a different |
| 6070 | // file than the `a.b`/`@hasDecl` syntax. | 6207 | // file than the `a.b`/`@hasDecl` syntax. |
| 6071 | const decl = mod.declPtr(decl_index); | 6208 | const decl = mod.declPtr(decl_index); |
| 6072 | if (decl.is_pub or (src_file == decl.getFileScope() and checked_namespaces.values()[check_i])) { | 6209 | if (decl.is_pub or (src_file == decl.getFileScope(mod) and checked_namespaces.values()[check_i])) { |
| 6073 | try candidates.append(gpa, decl_index); | 6210 | try candidates.append(gpa, decl_index); |
| 6074 | } | 6211 | } |
| 6075 | } | 6212 | } |
| ... | @@ -6080,15 +6217,15 @@ fn lookupInNamespace( | ... | @@ -6080,15 +6217,15 @@ fn lookupInNamespace( |
| 6080 | if (sub_usingnamespace_decl_index == sema.owner_decl_index) continue; | 6217 | if (sub_usingnamespace_decl_index == sema.owner_decl_index) continue; |
| 6081 | const sub_usingnamespace_decl = mod.declPtr(sub_usingnamespace_decl_index); | 6218 | const sub_usingnamespace_decl = mod.declPtr(sub_usingnamespace_decl_index); |
| 6082 | const sub_is_pub = entry.value_ptr.*; | 6219 | const sub_is_pub = entry.value_ptr.*; |
| 6083 | if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScope()) { | 6220 | if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScope(mod)) { |
| 6084 | // Skip usingnamespace decls which are not marked pub, which are in | 6221 | // Skip usingnamespace decls which are not marked pub, which are in |
| 6085 | // a different file than the `a.b`/`@hasDecl` syntax. | 6222 | // a different file than the `a.b`/`@hasDecl` syntax. |
| 6086 | continue; | 6223 | continue; |
| 6087 | } | 6224 | } |
| 6088 | try sema.ensureDeclAnalyzed(sub_usingnamespace_decl_index); | 6225 | try sema.ensureDeclAnalyzed(sub_usingnamespace_decl_index); |
| 6089 | const ns_ty = sub_usingnamespace_decl.val.castTag(.ty).?.data; | 6226 | const ns_ty = sub_usingnamespace_decl.val.toType(); |
| 6090 | const sub_ns = ns_ty.getNamespace().?; | 6227 | const sub_ns = ns_ty.getNamespace(mod).?; |
| 6091 | try checked_namespaces.put(gpa, sub_ns, src_file == sub_usingnamespace_decl.getFileScope()); | 6228 | try checked_namespaces.put(gpa, sub_ns, src_file == sub_usingnamespace_decl.getFileScope(mod)); |
| 6092 | } | 6229 | } |
| 6093 | } | 6230 | } |
| 6094 | 6231 | ||
| ... | @@ -6116,7 +6253,7 @@ fn lookupInNamespace( | ... | @@ -6116,7 +6253,7 @@ fn lookupInNamespace( |
| 6116 | errdefer msg.destroy(gpa); | 6253 | errdefer msg.destroy(gpa); |
| 6117 | for (candidates.items) |candidate_index| { | 6254 | for (candidates.items) |candidate_index| { |
| 6118 | const candidate = mod.declPtr(candidate_index); | 6255 | const candidate = mod.declPtr(candidate_index); |
| 6119 | const src_loc = candidate.srcLoc(); | 6256 | const src_loc = candidate.srcLoc(mod); |
| 6120 | try mod.errNoteNonLazy(src_loc, msg, "declared here", .{}); | 6257 | try mod.errNoteNonLazy(src_loc, msg, "declared here", .{}); |
| 6121 | } | 6258 | } |
| 6122 | break :msg msg; | 6259 | break :msg msg; |
| ... | @@ -6129,9 +6266,6 @@ fn lookupInNamespace( | ... | @@ -6129,9 +6266,6 @@ fn lookupInNamespace( |
| 6129 | return decl_index; | 6266 | return decl_index; |
| 6130 | } | 6267 | } |
| 6131 | 6268 | ||
| 6132 | log.debug("{*} ({s}) depends on non-existence of '{s}' in {*} ({s})", .{ | ||
| 6133 | sema.owner_decl, sema.owner_decl.name, ident_name, namespace_decl, namespace_decl.name, | ||
| 6134 | }); | ||
| 6135 | // TODO This dependency is too strong. Really, it should only be a dependency | 6269 | // TODO This dependency is too strong. Really, it should only be a dependency |
| 6136 | // on the non-existence of `ident_name` in the namespace. We can lessen the number of | 6270 | // on the non-existence of `ident_name` in the namespace. We can lessen the number of |
| 6137 | // outdated declarations by making this dependency more sophisticated. | 6271 | // outdated declarations by making this dependency more sophisticated. |
| ... | @@ -6140,22 +6274,28 @@ fn lookupInNamespace( | ... | @@ -6140,22 +6274,28 @@ fn lookupInNamespace( |
| 6140 | } | 6274 | } |
| 6141 | 6275 | ||
| 6142 | fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl { | 6276 | fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl { |
| 6277 | const mod = sema.mod; | ||
| 6143 | const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null; | 6278 | const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null; |
| 6144 | if (func_val.isUndef()) return null; | 6279 | if (func_val.isUndef(mod)) return null; |
| 6145 | const owner_decl_index = switch (func_val.tag()) { | 6280 | const owner_decl_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { |
| 6146 | .extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl, | 6281 | .extern_func => |extern_func| extern_func.decl, |
| 6147 | .function => func_val.castTag(.function).?.data.owner_decl, | 6282 | .func => |func| mod.funcPtr(func.index).owner_decl, |
| 6148 | .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl, | 6283 | .ptr => |ptr| switch (ptr.addr) { |
| 6284 | .decl => |decl| mod.declPtr(decl).val.getFunction(mod).?.owner_decl, | ||
| 6285 | else => return null, | ||
| 6286 | }, | ||
| 6149 | else => return null, | 6287 | else => return null, |
| 6150 | }; | 6288 | }; |
| 6151 | return sema.mod.declPtr(owner_decl_index); | 6289 | return mod.declPtr(owner_decl_index); |
| 6152 | } | 6290 | } |
| 6153 | 6291 | ||
| 6154 | pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { | 6292 | pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { |
| 6293 | const mod = sema.mod; | ||
| 6294 | const gpa = sema.gpa; | ||
| 6155 | const src = sema.src; | 6295 | const src = sema.src; |
| 6156 | 6296 | ||
| 6157 | if (!sema.mod.backendSupportsFeature(.error_return_trace)) return .none; | 6297 | if (!mod.backendSupportsFeature(.error_return_trace)) return .none; |
| 6158 | if (!sema.mod.comp.bin_file.options.error_return_tracing) return .none; | 6298 | if (!mod.comp.bin_file.options.error_return_tracing) return .none; |
| 6159 | 6299 | ||
| 6160 | if (block.is_comptime) | 6300 | if (block.is_comptime) |
| 6161 | return .none; | 6301 | return .none; |
| ... | @@ -6168,7 +6308,8 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref | ... | @@ -6168,7 +6308,8 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref |
| 6168 | error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, | 6308 | error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, |
| 6169 | else => |e| return e, | 6309 | else => |e| return e, |
| 6170 | }; | 6310 | }; |
| 6171 | const field_index = sema.structFieldIndex(block, stack_trace_ty, "index", src) catch |err| switch (err) { | 6311 | const field_name = try mod.intern_pool.getOrPutString(gpa, "index"); |
| 6312 | const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, src) catch |err| switch (err) { | ||
| 6172 | error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, | 6313 | error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, |
| 6173 | else => |e| return e, | 6314 | else => |e| return e, |
| 6174 | }; | 6315 | }; |
| ... | @@ -6191,6 +6332,8 @@ fn popErrorReturnTrace( | ... | @@ -6191,6 +6332,8 @@ fn popErrorReturnTrace( |
| 6191 | operand: Air.Inst.Ref, | 6332 | operand: Air.Inst.Ref, |
| 6192 | saved_error_trace_index: Air.Inst.Ref, | 6333 | saved_error_trace_index: Air.Inst.Ref, |
| 6193 | ) CompileError!void { | 6334 | ) CompileError!void { |
| 6335 | const mod = sema.mod; | ||
| 6336 | const gpa = sema.gpa; | ||
| 6194 | var is_non_error: ?bool = null; | 6337 | var is_non_error: ?bool = null; |
| 6195 | var is_non_error_inst: Air.Inst.Ref = undefined; | 6338 | var is_non_error_inst: Air.Inst.Ref = undefined; |
| 6196 | if (operand != .none) { | 6339 | if (operand != .none) { |
| ... | @@ -6205,15 +6348,16 @@ fn popErrorReturnTrace( | ... | @@ -6205,15 +6348,16 @@ fn popErrorReturnTrace( |
| 6205 | 6348 | ||
| 6206 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); | 6349 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 6207 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); | 6350 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); |
| 6208 | const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); | 6351 | const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); |
| 6209 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); | 6352 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 6210 | const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, "index", src, stack_trace_ty, true); | 6353 | const field_name = try mod.intern_pool.getOrPutString(gpa, "index"); |
| 6354 | const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty, true); | ||
| 6211 | try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); | 6355 | try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); |
| 6212 | } else if (is_non_error == null) { | 6356 | } else if (is_non_error == null) { |
| 6213 | // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need | 6357 | // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need |
| 6214 | // to pop any error trace that may have been propagated from our arguments. | 6358 | // to pop any error trace that may have been propagated from our arguments. |
| 6215 | 6359 | ||
| 6216 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Block).Struct.fields.len); | 6360 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len); |
| 6217 | const cond_block_inst = try block.addInstAsIndex(.{ | 6361 | const cond_block_inst = try block.addInstAsIndex(.{ |
| 6218 | .tag = .block, | 6362 | .tag = .block, |
| 6219 | .data = .{ | 6363 | .data = .{ |
| ... | @@ -6225,28 +6369,29 @@ fn popErrorReturnTrace( | ... | @@ -6225,28 +6369,29 @@ fn popErrorReturnTrace( |
| 6225 | }); | 6369 | }); |
| 6226 | 6370 | ||
| 6227 | var then_block = block.makeSubBlock(); | 6371 | var then_block = block.makeSubBlock(); |
| 6228 | defer then_block.instructions.deinit(sema.gpa); | 6372 | defer then_block.instructions.deinit(gpa); |
| 6229 | 6373 | ||
| 6230 | // If non-error, then pop the error return trace by restoring the index. | 6374 | // If non-error, then pop the error return trace by restoring the index. |
| 6231 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); | 6375 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 6232 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); | 6376 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); |
| 6233 | const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); | 6377 | const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); |
| 6234 | const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); | 6378 | const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 6235 | const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, "index", src, stack_trace_ty, true); | 6379 | const field_name = try mod.intern_pool.getOrPutString(gpa, "index"); |
| 6380 | const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty, true); | ||
| 6236 | try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); | 6381 | try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); |
| 6237 | _ = try then_block.addBr(cond_block_inst, Air.Inst.Ref.void_value); | 6382 | _ = try then_block.addBr(cond_block_inst, Air.Inst.Ref.void_value); |
| 6238 | 6383 | ||
| 6239 | // Otherwise, do nothing | 6384 | // Otherwise, do nothing |
| 6240 | var else_block = block.makeSubBlock(); | 6385 | var else_block = block.makeSubBlock(); |
| 6241 | defer else_block.instructions.deinit(sema.gpa); | 6386 | defer else_block.instructions.deinit(gpa); |
| 6242 | _ = try else_block.addBr(cond_block_inst, Air.Inst.Ref.void_value); | 6387 | _ = try else_block.addBr(cond_block_inst, Air.Inst.Ref.void_value); |
| 6243 | 6388 | ||
| 6244 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.CondBr).Struct.fields.len + | 6389 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + |
| 6245 | then_block.instructions.items.len + else_block.instructions.items.len + | 6390 | then_block.instructions.items.len + else_block.instructions.items.len + |
| 6246 | @typeInfo(Air.Block).Struct.fields.len + 1); // +1 for the sole .cond_br instruction in the .block | 6391 | @typeInfo(Air.Block).Struct.fields.len + 1); // +1 for the sole .cond_br instruction in the .block |
| 6247 | 6392 | ||
| 6248 | const cond_br_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); | 6393 | const cond_br_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); |
| 6249 | try sema.air_instructions.append(sema.gpa, .{ .tag = .cond_br, .data = .{ .pl_op = .{ | 6394 | try sema.air_instructions.append(gpa, .{ .tag = .cond_br, .data = .{ .pl_op = .{ |
| 6250 | .operand = is_non_error_inst, | 6395 | .operand = is_non_error_inst, |
| 6251 | .payload = sema.addExtraAssumeCapacity(Air.CondBr{ | 6396 | .payload = sema.addExtraAssumeCapacity(Air.CondBr{ |
| 6252 | .then_body_len = @intCast(u32, then_block.instructions.items.len), | 6397 | .then_body_len = @intCast(u32, then_block.instructions.items.len), |
| ... | @@ -6270,6 +6415,7 @@ fn zirCall( | ... | @@ -6270,6 +6415,7 @@ fn zirCall( |
| 6270 | const tracy = trace(@src()); | 6415 | const tracy = trace(@src()); |
| 6271 | defer tracy.end(); | 6416 | defer tracy.end(); |
| 6272 | 6417 | ||
| 6418 | const mod = sema.mod; | ||
| 6273 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 6419 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 6274 | const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; | 6420 | const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; |
| 6275 | const call_src = inst_data.src(); | 6421 | const call_src = inst_data.src(); |
| ... | @@ -6288,7 +6434,7 @@ fn zirCall( | ... | @@ -6288,7 +6434,7 @@ fn zirCall( |
| 6288 | .direct => .{ .direct = try sema.resolveInst(extra.data.callee) }, | 6434 | .direct => .{ .direct = try sema.resolveInst(extra.data.callee) }, |
| 6289 | .field => blk: { | 6435 | .field => blk: { |
| 6290 | const object_ptr = try sema.resolveInst(extra.data.obj_ptr); | 6436 | const object_ptr = try sema.resolveInst(extra.data.obj_ptr); |
| 6291 | const field_name = sema.code.nullTerminatedString(extra.data.field_name_start); | 6437 | const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.data.field_name_start)); |
| 6292 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; | 6438 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 6293 | break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src); | 6439 | break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src); |
| 6294 | }, | 6440 | }, |
| ... | @@ -6320,8 +6466,7 @@ fn zirCall( | ... | @@ -6320,8 +6466,7 @@ fn zirCall( |
| 6320 | var input_is_error = false; | 6466 | var input_is_error = false; |
| 6321 | const block_index = @intCast(Air.Inst.Index, block.instructions.items.len); | 6467 | const block_index = @intCast(Air.Inst.Index, block.instructions.items.len); |
| 6322 | 6468 | ||
| 6323 | const func_ty_info = func_ty.fnInfo(); | 6469 | const fn_params_len = mod.typeToFunc(func_ty).?.param_types.len; |
| 6324 | const fn_params_len = func_ty_info.param_types.len; | ||
| 6325 | const parent_comptime = block.is_comptime; | 6470 | const parent_comptime = block.is_comptime; |
| 6326 | // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument. | 6471 | // `extra_index` and `arg_index` are separate since the bound function is passed as the first argument. |
| 6327 | var extra_index: usize = 0; | 6472 | var extra_index: usize = 0; |
| ... | @@ -6330,32 +6475,33 @@ fn zirCall( | ... | @@ -6330,32 +6475,33 @@ fn zirCall( |
| 6330 | extra_index += 1; | 6475 | extra_index += 1; |
| 6331 | arg_index += 1; | 6476 | arg_index += 1; |
| 6332 | }) { | 6477 | }) { |
| 6478 | const func_ty_info = mod.typeToFunc(func_ty).?; | ||
| 6333 | const arg_end = sema.code.extra[extra.end + extra_index]; | 6479 | const arg_end = sema.code.extra[extra.end + extra_index]; |
| 6334 | defer arg_start = arg_end; | 6480 | defer arg_start = arg_end; |
| 6335 | 6481 | ||
| 6336 | // Generate args to comptime params in comptime block. | 6482 | // Generate args to comptime params in comptime block. |
| 6337 | defer block.is_comptime = parent_comptime; | 6483 | defer block.is_comptime = parent_comptime; |
| 6338 | if (arg_index < fn_params_len and func_ty_info.comptime_params[arg_index]) { | 6484 | if (arg_index < @min(fn_params_len, 32) and func_ty_info.paramIsComptime(@intCast(u5, arg_index))) { |
| 6339 | block.is_comptime = true; | 6485 | block.is_comptime = true; |
| 6340 | // TODO set comptime_reason | 6486 | // TODO set comptime_reason |
| 6341 | } | 6487 | } |
| 6342 | 6488 | ||
| 6343 | sema.inst_map.putAssumeCapacity(inst, inst: { | 6489 | sema.inst_map.putAssumeCapacity(inst, inst: { |
| 6344 | if (arg_index >= fn_params_len) | 6490 | if (arg_index >= fn_params_len) |
| 6345 | break :inst Air.Inst.Ref.var_args_param; | 6491 | break :inst Air.Inst.Ref.var_args_param_type; |
| 6346 | 6492 | ||
| 6347 | if (func_ty_info.param_types[arg_index].tag() == .generic_poison) | 6493 | if (func_ty_info.param_types[arg_index] == .generic_poison_type) |
| 6348 | break :inst Air.Inst.Ref.generic_poison_type; | 6494 | break :inst Air.Inst.Ref.generic_poison_type; |
| 6349 | 6495 | ||
| 6350 | break :inst try sema.addType(func_ty_info.param_types[arg_index]); | 6496 | break :inst try sema.addType(func_ty_info.param_types[arg_index].toType()); |
| 6351 | }); | 6497 | }); |
| 6352 | 6498 | ||
| 6353 | const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); | 6499 | const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); |
| 6354 | const resolved_ty = sema.typeOf(resolved); | 6500 | const resolved_ty = sema.typeOf(resolved); |
| 6355 | if (resolved_ty.zigTypeTag() == .NoReturn) { | 6501 | if (resolved_ty.zigTypeTag(mod) == .NoReturn) { |
| 6356 | return resolved; | 6502 | return resolved; |
| 6357 | } | 6503 | } |
| 6358 | if (resolved_ty.isError()) { | 6504 | if (resolved_ty.isError(mod)) { |
| 6359 | input_is_error = true; | 6505 | input_is_error = true; |
| 6360 | } | 6506 | } |
| 6361 | resolved_args[arg_index] = resolved; | 6507 | resolved_args[arg_index] = resolved; |
| ... | @@ -6367,7 +6513,7 @@ fn zirCall( | ... | @@ -6367,7 +6513,7 @@ fn zirCall( |
| 6367 | // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction. | 6513 | // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction. |
| 6368 | const call_dbg_node = inst - 1; | 6514 | const call_dbg_node = inst - 1; |
| 6369 | 6515 | ||
| 6370 | if (sema.mod.backendSupportsFeature(.error_return_trace) and sema.mod.comp.bin_file.options.error_return_tracing and | 6516 | if (mod.backendSupportsFeature(.error_return_trace) and mod.comp.bin_file.options.error_return_tracing and |
| 6371 | !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace)) | 6517 | !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace)) |
| 6372 | { | 6518 | { |
| 6373 | const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: { | 6519 | const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: { |
| ... | @@ -6375,15 +6521,16 @@ fn zirCall( | ... | @@ -6375,15 +6521,16 @@ fn zirCall( |
| 6375 | }; | 6521 | }; |
| 6376 | 6522 | ||
| 6377 | const return_ty = sema.typeOf(call_inst); | 6523 | const return_ty = sema.typeOf(call_inst); |
| 6378 | if (modifier != .always_tail and return_ty.isNoReturn()) | 6524 | if (modifier != .always_tail and return_ty.isNoReturn(mod)) |
| 6379 | return call_inst; // call to "fn(...) noreturn", don't pop | 6525 | return call_inst; // call to "fn(...) noreturn", don't pop |
| 6380 | 6526 | ||
| 6381 | // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only | 6527 | // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only |
| 6382 | // need to clean-up our own trace if we were passed to a non-error-handling expression. | 6528 | // need to clean-up our own trace if we were passed to a non-error-handling expression. |
| 6383 | if (input_is_error or (pop_error_return_trace and modifier != .always_tail and return_ty.isError())) { | 6529 | if (input_is_error or (pop_error_return_trace and modifier != .always_tail and return_ty.isError(mod))) { |
| 6384 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); | 6530 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 6385 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); | 6531 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); |
| 6386 | const field_index = try sema.structFieldIndex(block, stack_trace_ty, "index", call_src); | 6532 | const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index"); |
| 6533 | const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src); | ||
| 6387 | 6534 | ||
| 6388 | // Insert a save instruction before the arg resolution + call instructions we just generated | 6535 | // Insert a save instruction before the arg resolution + call instructions we just generated |
| 6389 | const save_inst = try block.insertInst(block_index, .{ | 6536 | const save_inst = try block.insertInst(block_index, .{ |
| ... | @@ -6417,24 +6564,24 @@ fn checkCallArgumentCount( | ... | @@ -6417,24 +6564,24 @@ fn checkCallArgumentCount( |
| 6417 | total_args: usize, | 6564 | total_args: usize, |
| 6418 | member_fn: bool, | 6565 | member_fn: bool, |
| 6419 | ) !Type { | 6566 | ) !Type { |
| 6567 | const mod = sema.mod; | ||
| 6420 | const func_ty = func_ty: { | 6568 | const func_ty = func_ty: { |
| 6421 | switch (callee_ty.zigTypeTag()) { | 6569 | switch (callee_ty.zigTypeTag(mod)) { |
| 6422 | .Fn => break :func_ty callee_ty, | 6570 | .Fn => break :func_ty callee_ty, |
| 6423 | .Pointer => { | 6571 | .Pointer => { |
| 6424 | const ptr_info = callee_ty.ptrInfo().data; | 6572 | const ptr_info = callee_ty.ptrInfo(mod); |
| 6425 | if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) { | 6573 | if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Fn) { |
| 6426 | break :func_ty ptr_info.pointee_type; | 6574 | break :func_ty ptr_info.pointee_type; |
| 6427 | } | 6575 | } |
| 6428 | }, | 6576 | }, |
| 6429 | .Optional => { | 6577 | .Optional => { |
| 6430 | var buf: Type.Payload.ElemType = undefined; | 6578 | const opt_child = callee_ty.optionalChild(mod); |
| 6431 | const opt_child = callee_ty.optionalChild(&buf); | 6579 | if (opt_child.zigTypeTag(mod) == .Fn or (opt_child.isSinglePointer(mod) and |
| 6432 | if (opt_child.zigTypeTag() == .Fn or (opt_child.isSinglePointer() and | 6580 | opt_child.childType(mod).zigTypeTag(mod) == .Fn)) |
| 6433 | opt_child.childType().zigTypeTag() == .Fn)) | ||
| 6434 | { | 6581 | { |
| 6435 | const msg = msg: { | 6582 | const msg = msg: { |
| 6436 | const msg = try sema.errMsg(block, func_src, "cannot call optional type '{}'", .{ | 6583 | const msg = try sema.errMsg(block, func_src, "cannot call optional type '{}'", .{ |
| 6437 | callee_ty.fmt(sema.mod), | 6584 | callee_ty.fmt(mod), |
| 6438 | }); | 6585 | }); |
| 6439 | errdefer msg.destroy(sema.gpa); | 6586 | errdefer msg.destroy(sema.gpa); |
| 6440 | try sema.errNote(block, func_src, msg, "consider using '.?', 'orelse' or 'if'", .{}); | 6587 | try sema.errNote(block, func_src, msg, "consider using '.?', 'orelse' or 'if'", .{}); |
| ... | @@ -6445,10 +6592,10 @@ fn checkCallArgumentCount( | ... | @@ -6445,10 +6592,10 @@ fn checkCallArgumentCount( |
| 6445 | }, | 6592 | }, |
| 6446 | else => {}, | 6593 | else => {}, |
| 6447 | } | 6594 | } |
| 6448 | return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)}); | 6595 | return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(mod)}); |
| 6449 | }; | 6596 | }; |
| 6450 | 6597 | ||
| 6451 | const func_ty_info = func_ty.fnInfo(); | 6598 | const func_ty_info = mod.typeToFunc(func_ty).?; |
| 6452 | const fn_params_len = func_ty_info.param_types.len; | 6599 | const fn_params_len = func_ty_info.param_types.len; |
| 6453 | const args_len = total_args - @boolToInt(member_fn); | 6600 | const args_len = total_args - @boolToInt(member_fn); |
| 6454 | if (func_ty_info.is_var_args) { | 6601 | if (func_ty_info.is_var_args) { |
| ... | @@ -6475,7 +6622,7 @@ fn checkCallArgumentCount( | ... | @@ -6475,7 +6622,7 @@ fn checkCallArgumentCount( |
| 6475 | ); | 6622 | ); |
| 6476 | errdefer msg.destroy(sema.gpa); | 6623 | errdefer msg.destroy(sema.gpa); |
| 6477 | 6624 | ||
| 6478 | if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(), msg, "function declared here", .{}); | 6625 | if (maybe_decl) |fn_decl| try mod.errNoteNonLazy(fn_decl.srcLoc(mod), msg, "function declared here", .{}); |
| 6479 | break :msg msg; | 6626 | break :msg msg; |
| 6480 | }; | 6627 | }; |
| 6481 | return sema.failWithOwnedErrorMsg(msg); | 6628 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -6488,22 +6635,23 @@ fn callBuiltin( | ... | @@ -6488,22 +6635,23 @@ fn callBuiltin( |
| 6488 | modifier: std.builtin.CallModifier, | 6635 | modifier: std.builtin.CallModifier, |
| 6489 | args: []const Air.Inst.Ref, | 6636 | args: []const Air.Inst.Ref, |
| 6490 | ) !void { | 6637 | ) !void { |
| 6638 | const mod = sema.mod; | ||
| 6491 | const callee_ty = sema.typeOf(builtin_fn); | 6639 | const callee_ty = sema.typeOf(builtin_fn); |
| 6492 | const func_ty = func_ty: { | 6640 | const func_ty = func_ty: { |
| 6493 | switch (callee_ty.zigTypeTag()) { | 6641 | switch (callee_ty.zigTypeTag(mod)) { |
| 6494 | .Fn => break :func_ty callee_ty, | 6642 | .Fn => break :func_ty callee_ty, |
| 6495 | .Pointer => { | 6643 | .Pointer => { |
| 6496 | const ptr_info = callee_ty.ptrInfo().data; | 6644 | const ptr_info = callee_ty.ptrInfo(mod); |
| 6497 | if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) { | 6645 | if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Fn) { |
| 6498 | break :func_ty ptr_info.pointee_type; | 6646 | break :func_ty ptr_info.pointee_type; |
| 6499 | } | 6647 | } |
| 6500 | }, | 6648 | }, |
| 6501 | else => {}, | 6649 | else => {}, |
| 6502 | } | 6650 | } |
| 6503 | std.debug.panic("type '{}' is not a function calling builtin fn", .{callee_ty.fmt(sema.mod)}); | 6651 | std.debug.panic("type '{}' is not a function calling builtin fn", .{callee_ty.fmt(mod)}); |
| 6504 | }; | 6652 | }; |
| 6505 | 6653 | ||
| 6506 | const func_ty_info = func_ty.fnInfo(); | 6654 | const func_ty_info = mod.typeToFunc(func_ty).?; |
| 6507 | const fn_params_len = func_ty_info.param_types.len; | 6655 | const fn_params_len = func_ty_info.param_types.len; |
| 6508 | if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) { | 6656 | if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) { |
| 6509 | std.debug.panic("parameter count mismatch calling builtin fn, expected {d}, found {d}", .{ fn_params_len, args.len }); | 6657 | std.debug.panic("parameter count mismatch calling builtin fn, expected {d}, found {d}", .{ fn_params_len, args.len }); |
| ... | @@ -6511,76 +6659,6 @@ fn callBuiltin( | ... | @@ -6511,76 +6659,6 @@ fn callBuiltin( |
| 6511 | _ = try sema.analyzeCall(block, builtin_fn, func_ty, sema.src, sema.src, modifier, false, args, null, null); | 6659 | _ = try sema.analyzeCall(block, builtin_fn, func_ty, sema.src, sema.src, modifier, false, args, null, null); |
| 6512 | } | 6660 | } |
| 6513 | 6661 | ||
| 6514 | const GenericCallAdapter = struct { | ||
| 6515 | generic_fn: *Module.Fn, | ||
| 6516 | precomputed_hash: u64, | ||
| 6517 | func_ty_info: Type.Payload.Function.Data, | ||
| 6518 | args: []const Arg, | ||
| 6519 | module: *Module, | ||
| 6520 | |||
| 6521 | const Arg = struct { | ||
| 6522 | ty: Type, | ||
| 6523 | val: Value, | ||
| 6524 | is_anytype: bool, | ||
| 6525 | }; | ||
| 6526 | |||
| 6527 | pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool { | ||
| 6528 | _ = adapted_key; | ||
| 6529 | // Checking for equality may happen on an item that has been inserted | ||
| 6530 | // into the map but is not yet fully initialized. In such case, the | ||
| 6531 | // two initialized fields are `hash` and `generic_owner_decl`. | ||
| 6532 | if (ctx.generic_fn.owner_decl != other_key.generic_owner_decl.unwrap().?) return false; | ||
| 6533 | |||
| 6534 | const other_comptime_args = other_key.comptime_args.?; | ||
| 6535 | for (other_comptime_args[0..ctx.func_ty_info.param_types.len], 0..) |other_arg, i| { | ||
| 6536 | const this_arg = ctx.args[i]; | ||
| 6537 | const this_is_comptime = this_arg.val.tag() != .generic_poison; | ||
| 6538 | const other_is_comptime = other_arg.val.tag() != .generic_poison; | ||
| 6539 | const this_is_anytype = this_arg.is_anytype; | ||
| 6540 | const other_is_anytype = other_key.isAnytypeParam(ctx.module, @intCast(u32, i)); | ||
| 6541 | |||
| 6542 | if (other_is_anytype != this_is_anytype) return false; | ||
| 6543 | if (other_is_comptime != this_is_comptime) return false; | ||
| 6544 | |||
| 6545 | if (this_is_anytype) { | ||
| 6546 | // Both are anytype parameters. | ||
| 6547 | if (!this_arg.ty.eql(other_arg.ty, ctx.module)) { | ||
| 6548 | return false; | ||
| 6549 | } | ||
| 6550 | if (this_is_comptime) { | ||
| 6551 | // Both are comptime and anytype parameters with matching types. | ||
| 6552 | if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.module)) { | ||
| 6553 | return false; | ||
| 6554 | } | ||
| 6555 | } | ||
| 6556 | } else if (this_is_comptime) { | ||
| 6557 | // Both are comptime parameters but not anytype parameters. | ||
| 6558 | // We assert no error is possible here because any lazy values must be resolved | ||
| 6559 | // before inserting into the generic function hash map. | ||
| 6560 | const is_eql = Value.eqlAdvanced( | ||
| 6561 | this_arg.val, | ||
| 6562 | this_arg.ty, | ||
| 6563 | other_arg.val, | ||
| 6564 | other_arg.ty, | ||
| 6565 | ctx.module, | ||
| 6566 | null, | ||
| 6567 | ) catch unreachable; | ||
| 6568 | if (!is_eql) { | ||
| 6569 | return false; | ||
| 6570 | } | ||
| 6571 | } | ||
| 6572 | } | ||
| 6573 | return true; | ||
| 6574 | } | ||
| 6575 | |||
| 6576 | /// The implementation of the hash is in semantic analysis of function calls, so | ||
| 6577 | /// that any errors when computing the hash can be properly reported. | ||
| 6578 | pub fn hash(ctx: @This(), adapted_key: void) u64 { | ||
| 6579 | _ = adapted_key; | ||
| 6580 | return ctx.precomputed_hash; | ||
| 6581 | } | ||
| 6582 | }; | ||
| 6583 | |||
| 6584 | fn analyzeCall( | 6662 | fn analyzeCall( |
| 6585 | sema: *Sema, | 6663 | sema: *Sema, |
| 6586 | block: *Block, | 6664 | block: *Block, |
| ... | @@ -6597,7 +6675,7 @@ fn analyzeCall( | ... | @@ -6597,7 +6675,7 @@ fn analyzeCall( |
| 6597 | const mod = sema.mod; | 6675 | const mod = sema.mod; |
| 6598 | 6676 | ||
| 6599 | const callee_ty = sema.typeOf(func); | 6677 | const callee_ty = sema.typeOf(func); |
| 6600 | const func_ty_info = func_ty.fnInfo(); | 6678 | const func_ty_info = mod.typeToFunc(func_ty).?; |
| 6601 | const fn_params_len = func_ty_info.param_types.len; | 6679 | const fn_params_len = func_ty_info.param_types.len; |
| 6602 | const cc = func_ty_info.cc; | 6680 | const cc = func_ty_info.cc; |
| 6603 | if (cc == .Naked) { | 6681 | if (cc == .Naked) { |
| ... | @@ -6611,7 +6689,7 @@ fn analyzeCall( | ... | @@ -6611,7 +6689,7 @@ fn analyzeCall( |
| 6611 | ); | 6689 | ); |
| 6612 | errdefer msg.destroy(sema.gpa); | 6690 | errdefer msg.destroy(sema.gpa); |
| 6613 | 6691 | ||
| 6614 | if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(), msg, "function declared here", .{}); | 6692 | if (maybe_decl) |fn_decl| try mod.errNoteNonLazy(fn_decl.srcLoc(mod), msg, "function declared here", .{}); |
| 6615 | break :msg msg; | 6693 | break :msg msg; |
| 6616 | }; | 6694 | }; |
| 6617 | return sema.failWithOwnedErrorMsg(msg); | 6695 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -6645,7 +6723,7 @@ fn analyzeCall( | ... | @@ -6645,7 +6723,7 @@ fn analyzeCall( |
| 6645 | var comptime_reason_buf: Block.ComptimeReason = undefined; | 6723 | var comptime_reason_buf: Block.ComptimeReason = undefined; |
| 6646 | var comptime_reason: ?*const Block.ComptimeReason = null; | 6724 | var comptime_reason: ?*const Block.ComptimeReason = null; |
| 6647 | if (!is_comptime_call) { | 6725 | if (!is_comptime_call) { |
| 6648 | if (sema.typeRequiresComptime(func_ty_info.return_type)) |ct| { | 6726 | if (sema.typeRequiresComptime(func_ty_info.return_type.toType())) |ct| { |
| 6649 | is_comptime_call = ct; | 6727 | is_comptime_call = ct; |
| 6650 | if (ct) { | 6728 | if (ct) { |
| 6651 | // stage1 can't handle doing this directly | 6729 | // stage1 can't handle doing this directly |
| ... | @@ -6653,7 +6731,7 @@ fn analyzeCall( | ... | @@ -6653,7 +6731,7 @@ fn analyzeCall( |
| 6653 | .block = block, | 6731 | .block = block, |
| 6654 | .func = func, | 6732 | .func = func, |
| 6655 | .func_src = func_src, | 6733 | .func_src = func_src, |
| 6656 | .return_ty = func_ty_info.return_type, | 6734 | .return_ty = func_ty_info.return_type.toType(), |
| 6657 | } }; | 6735 | } }; |
| 6658 | comptime_reason = &comptime_reason_buf; | 6736 | comptime_reason = &comptime_reason_buf; |
| 6659 | } | 6737 | } |
| ... | @@ -6671,7 +6749,7 @@ fn analyzeCall( | ... | @@ -6671,7 +6749,7 @@ fn analyzeCall( |
| 6671 | func, | 6749 | func, |
| 6672 | func_src, | 6750 | func_src, |
| 6673 | call_src, | 6751 | call_src, |
| 6674 | func_ty_info, | 6752 | func_ty, |
| 6675 | ensure_result_used, | 6753 | ensure_result_used, |
| 6676 | uncasted_args, | 6754 | uncasted_args, |
| 6677 | call_tag, | 6755 | call_tag, |
| ... | @@ -6691,7 +6769,7 @@ fn analyzeCall( | ... | @@ -6691,7 +6769,7 @@ fn analyzeCall( |
| 6691 | .block = block, | 6769 | .block = block, |
| 6692 | .func = func, | 6770 | .func = func, |
| 6693 | .func_src = func_src, | 6771 | .func_src = func_src, |
| 6694 | .return_ty = func_ty_info.return_type, | 6772 | .return_ty = func_ty_info.return_type.toType(), |
| 6695 | } }; | 6773 | } }; |
| 6696 | comptime_reason = &comptime_reason_buf; | 6774 | comptime_reason = &comptime_reason_buf; |
| 6697 | }, | 6775 | }, |
| ... | @@ -6708,18 +6786,21 @@ fn analyzeCall( | ... | @@ -6708,18 +6786,21 @@ fn analyzeCall( |
| 6708 | if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err); | 6786 | if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err); |
| 6709 | return err; | 6787 | return err; |
| 6710 | }; | 6788 | }; |
| 6711 | const module_fn = switch (func_val.tag()) { | 6789 | const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { |
| 6712 | .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data, | 6790 | .extern_func => return sema.fail(block, call_src, "{s} call of extern function", .{ |
| 6713 | .function => func_val.castTag(.function).?.data, | ||
| 6714 | .extern_fn => return sema.fail(block, call_src, "{s} call of extern function", .{ | ||
| 6715 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), | 6791 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), |
| 6716 | }), | 6792 | }), |
| 6717 | else => { | 6793 | .func => |function| function.index, |
| 6718 | assert(callee_ty.isPtrAtRuntime()); | 6794 | .ptr => |ptr| switch (ptr.addr) { |
| 6719 | return sema.fail(block, call_src, "{s} call of function pointer", .{ | 6795 | .decl => |decl| mod.declPtr(decl).val.getFunctionIndex(mod).unwrap().?, |
| 6720 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), | 6796 | else => { |
| 6721 | }); | 6797 | assert(callee_ty.isPtrAtRuntime(mod)); |
| 6798 | return sema.fail(block, call_src, "{s} call of function pointer", .{ | ||
| 6799 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), | ||
| 6800 | }); | ||
| 6801 | }, | ||
| 6722 | }, | 6802 | }, |
| 6803 | else => unreachable, | ||
| 6723 | }; | 6804 | }; |
| 6724 | if (func_ty_info.is_var_args) { | 6805 | if (func_ty_info.is_var_args) { |
| 6725 | return sema.fail(block, call_src, "{s} call of variadic function", .{ | 6806 | return sema.fail(block, call_src, "{s} call of variadic function", .{ |
| ... | @@ -6752,8 +6833,9 @@ fn analyzeCall( | ... | @@ -6752,8 +6833,9 @@ fn analyzeCall( |
| 6752 | // In order to save a bit of stack space, directly modify Sema rather | 6833 | // In order to save a bit of stack space, directly modify Sema rather |
| 6753 | // than create a child one. | 6834 | // than create a child one. |
| 6754 | const parent_zir = sema.code; | 6835 | const parent_zir = sema.code; |
| 6836 | const module_fn = mod.funcPtr(module_fn_index); | ||
| 6755 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); | 6837 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 6756 | sema.code = fn_owner_decl.getFileScope().zir; | 6838 | sema.code = fn_owner_decl.getFileScope(mod).zir; |
| 6757 | defer sema.code = parent_zir; | 6839 | defer sema.code = parent_zir; |
| 6758 | 6840 | ||
| 6759 | try mod.declareDeclDependencyType(sema.owner_decl_index, module_fn.owner_decl, .function_body); | 6841 | try mod.declareDeclDependencyType(sema.owner_decl_index, module_fn.owner_decl, .function_body); |
| ... | @@ -6767,14 +6849,17 @@ fn analyzeCall( | ... | @@ -6767,14 +6849,17 @@ fn analyzeCall( |
| 6767 | } | 6849 | } |
| 6768 | 6850 | ||
| 6769 | const parent_func = sema.func; | 6851 | const parent_func = sema.func; |
| 6852 | const parent_func_index = sema.func_index; | ||
| 6770 | sema.func = module_fn; | 6853 | sema.func = module_fn; |
| 6854 | sema.func_index = module_fn_index.toOptional(); | ||
| 6771 | defer sema.func = parent_func; | 6855 | defer sema.func = parent_func; |
| 6856 | defer sema.func_index = parent_func_index; | ||
| 6772 | 6857 | ||
| 6773 | const parent_err_ret_index = sema.error_return_trace_index_on_fn_entry; | 6858 | const parent_err_ret_index = sema.error_return_trace_index_on_fn_entry; |
| 6774 | sema.error_return_trace_index_on_fn_entry = block.error_return_trace_index; | 6859 | sema.error_return_trace_index_on_fn_entry = block.error_return_trace_index; |
| 6775 | defer sema.error_return_trace_index_on_fn_entry = parent_err_ret_index; | 6860 | defer sema.error_return_trace_index_on_fn_entry = parent_err_ret_index; |
| 6776 | 6861 | ||
| 6777 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, fn_owner_decl.src_scope); | 6862 | var wip_captures = try WipCaptureScope.init(gpa, fn_owner_decl.src_scope); |
| 6778 | defer wip_captures.deinit(); | 6863 | defer wip_captures.deinit(); |
| 6779 | 6864 | ||
| 6780 | var child_block: Block = .{ | 6865 | var child_block: Block = .{ |
| ... | @@ -6797,28 +6882,18 @@ fn analyzeCall( | ... | @@ -6797,28 +6882,18 @@ fn analyzeCall( |
| 6797 | defer child_block.instructions.deinit(gpa); | 6882 | defer child_block.instructions.deinit(gpa); |
| 6798 | defer merges.deinit(gpa); | 6883 | defer merges.deinit(gpa); |
| 6799 | 6884 | ||
| 6800 | // If it's a comptime function call, we need to memoize it as long as no external | ||
| 6801 | // comptime memory is mutated. | ||
| 6802 | var memoized_call_key: Module.MemoizedCall.Key = undefined; | ||
| 6803 | var delete_memoized_call_key = false; | ||
| 6804 | defer if (delete_memoized_call_key) gpa.free(memoized_call_key.args); | ||
| 6805 | if (is_comptime_call) { | ||
| 6806 | memoized_call_key = .{ | ||
| 6807 | .func = module_fn, | ||
| 6808 | .args = try gpa.alloc(TypedValue, func_ty_info.param_types.len), | ||
| 6809 | }; | ||
| 6810 | delete_memoized_call_key = true; | ||
| 6811 | } | ||
| 6812 | |||
| 6813 | try sema.emitBackwardBranch(block, call_src); | 6885 | try sema.emitBackwardBranch(block, call_src); |
| 6814 | 6886 | ||
| 6815 | // Whether this call should be memoized, set to false if the call can mutate | 6887 | // Whether this call should be memoized, set to false if the call can mutate comptime state. |
| 6816 | // comptime state. | ||
| 6817 | var should_memoize = true; | 6888 | var should_memoize = true; |
| 6818 | 6889 | ||
| 6819 | var new_fn_info = fn_owner_decl.ty.fnInfo(); | 6890 | // If it's a comptime function call, we need to memoize it as long as no external |
| 6820 | new_fn_info.param_types = try sema.arena.alloc(Type, new_fn_info.param_types.len); | 6891 | // comptime memory is mutated. |
| 6821 | new_fn_info.comptime_params = (try sema.arena.alloc(bool, new_fn_info.param_types.len)).ptr; | 6892 | const memoized_arg_values = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); |
| 6893 | |||
| 6894 | var new_fn_info = mod.typeToFunc(fn_owner_decl.ty).?; | ||
| 6895 | new_fn_info.param_types = try sema.arena.alloc(InternPool.Index, new_fn_info.param_types.len); | ||
| 6896 | new_fn_info.comptime_bits = 0; | ||
| 6822 | 6897 | ||
| 6823 | // This will have return instructions analyzed as break instructions to | 6898 | // This will have return instructions analyzed as break instructions to |
| 6824 | // the block_inst above. Here we are performing "comptime/inline semantic analysis" | 6899 | // the block_inst above. Here we are performing "comptime/inline semantic analysis" |
| ... | @@ -6837,31 +6912,31 @@ fn analyzeCall( | ... | @@ -6837,31 +6912,31 @@ fn analyzeCall( |
| 6837 | &child_block, | 6912 | &child_block, |
| 6838 | .unneeded, | 6913 | .unneeded, |
| 6839 | inst, | 6914 | inst, |
| 6840 | new_fn_info, | 6915 | &new_fn_info, |
| 6841 | &arg_i, | 6916 | &arg_i, |
| 6842 | uncasted_args, | 6917 | uncasted_args, |
| 6843 | is_comptime_call, | 6918 | is_comptime_call, |
| 6844 | &should_memoize, | 6919 | &should_memoize, |
| 6845 | memoized_call_key, | 6920 | memoized_arg_values, |
| 6846 | func_ty_info.param_types, | 6921 | mod.typeToFunc(func_ty).?.param_types, |
| 6847 | func, | 6922 | func, |
| 6848 | &has_comptime_args, | 6923 | &has_comptime_args, |
| 6849 | ) catch |err| switch (err) { | 6924 | ) catch |err| switch (err) { |
| 6850 | error.NeededSourceLocation => { | 6925 | error.NeededSourceLocation => { |
| 6851 | _ = sema.inst_map.remove(inst); | 6926 | _ = sema.inst_map.remove(inst); |
| 6852 | const decl = sema.mod.declPtr(block.src_decl); | 6927 | const decl = mod.declPtr(block.src_decl); |
| 6853 | try sema.analyzeInlineCallArg( | 6928 | try sema.analyzeInlineCallArg( |
| 6854 | block, | 6929 | block, |
| 6855 | &child_block, | 6930 | &child_block, |
| 6856 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, arg_i, bound_arg_src), | 6931 | mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src), |
| 6857 | inst, | 6932 | inst, |
| 6858 | new_fn_info, | 6933 | &new_fn_info, |
| 6859 | &arg_i, | 6934 | &arg_i, |
| 6860 | uncasted_args, | 6935 | uncasted_args, |
| 6861 | is_comptime_call, | 6936 | is_comptime_call, |
| 6862 | &should_memoize, | 6937 | &should_memoize, |
| 6863 | memoized_call_key, | 6938 | memoized_arg_values, |
| 6864 | func_ty_info.param_types, | 6939 | mod.typeToFunc(func_ty).?.param_types, |
| 6865 | func, | 6940 | func, |
| 6866 | &has_comptime_args, | 6941 | &has_comptime_args, |
| 6867 | ); | 6942 | ); |
| ... | @@ -6897,21 +6972,15 @@ fn analyzeCall( | ... | @@ -6897,21 +6972,15 @@ fn analyzeCall( |
| 6897 | // Create a fresh inferred error set type for inline/comptime calls. | 6972 | // Create a fresh inferred error set type for inline/comptime calls. |
| 6898 | const fn_ret_ty = blk: { | 6973 | const fn_ret_ty = blk: { |
| 6899 | if (module_fn.hasInferredErrorSet(mod)) { | 6974 | if (module_fn.hasInferredErrorSet(mod)) { |
| 6900 | const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode); | 6975 | const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{ |
| 6901 | node.data = .{ .func = module_fn }; | 6976 | .func = module_fn_index, |
| 6902 | if (parent_func) |some| { | ||
| 6903 | some.inferred_error_sets.prepend(node); | ||
| 6904 | } | ||
| 6905 | |||
| 6906 | const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data); | ||
| 6907 | break :blk try Type.Tag.error_union.create(sema.arena, .{ | ||
| 6908 | .error_set = error_set_ty, | ||
| 6909 | .payload = bare_return_type, | ||
| 6910 | }); | 6977 | }); |
| 6978 | const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index }); | ||
| 6979 | break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type); | ||
| 6911 | } | 6980 | } |
| 6912 | break :blk bare_return_type; | 6981 | break :blk bare_return_type; |
| 6913 | }; | 6982 | }; |
| 6914 | new_fn_info.return_type = fn_ret_ty; | 6983 | new_fn_info.return_type = fn_ret_ty.toIntern(); |
| 6915 | const parent_fn_ret_ty = sema.fn_ret_ty; | 6984 | const parent_fn_ret_ty = sema.fn_ret_ty; |
| 6916 | sema.fn_ret_ty = fn_ret_ty; | 6985 | sema.fn_ret_ty = fn_ret_ty; |
| 6917 | defer sema.fn_ret_ty = parent_fn_ret_ty; | 6986 | defer sema.fn_ret_ty = parent_fn_ret_ty; |
| ... | @@ -6920,23 +6989,22 @@ fn analyzeCall( | ... | @@ -6920,23 +6989,22 @@ fn analyzeCall( |
| 6920 | // bug generating invalid LLVM IR. | 6989 | // bug generating invalid LLVM IR. |
| 6921 | const res2: Air.Inst.Ref = res2: { | 6990 | const res2: Air.Inst.Ref = res2: { |
| 6922 | if (should_memoize and is_comptime_call) { | 6991 | if (should_memoize and is_comptime_call) { |
| 6923 | if (mod.memoized_calls.getContext(memoized_call_key, .{ .module = mod })) |result| { | 6992 | if (mod.intern_pool.getIfExists(.{ .memoized_call = .{ |
| 6924 | const ty_inst = try sema.addType(fn_ret_ty); | 6993 | .func = module_fn_index, |
| 6925 | try sema.air_values.append(gpa, result.val); | 6994 | .arg_values = memoized_arg_values, |
| 6926 | sema.air_instructions.set(block_inst, .{ | 6995 | .result = .none, |
| 6927 | .tag = .constant, | 6996 | } })) |memoized_call_index| { |
| 6928 | .data = .{ .ty_pl = .{ | 6997 | const memoized_call = mod.intern_pool.indexToKey(memoized_call_index).memoized_call; |
| 6929 | .ty = ty_inst, | 6998 | break :res2 try sema.addConstant( |
| 6930 | .payload = @intCast(u32, sema.air_values.items.len - 1), | 6999 | mod.intern_pool.typeOf(memoized_call.result).toType(), |
| 6931 | } }, | 7000 | memoized_call.result.toValue(), |
| 6932 | }); | 7001 | ); |
| 6933 | break :res2 Air.indexToRef(block_inst); | ||
| 6934 | } | 7002 | } |
| 6935 | } | 7003 | } |
| 6936 | 7004 | ||
| 6937 | const new_func_resolved_ty = try Type.Tag.function.create(sema.arena, new_fn_info); | 7005 | const new_func_resolved_ty = try mod.funcType(new_fn_info); |
| 6938 | if (!is_comptime_call and !block.is_typeof) { | 7006 | if (!is_comptime_call and !block.is_typeof) { |
| 6939 | try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin); | 7007 | try sema.emitDbgInline(block, parent_func_index.unwrap().?, module_fn_index, new_func_resolved_ty, .dbg_inline_begin); |
| 6940 | 7008 | ||
| 6941 | const zir_tags = sema.code.instructions.items(.tag); | 7009 | const zir_tags = sema.code.instructions.items(.tag); |
| 6942 | for (fn_info.param_body) |param| switch (zir_tags[param]) { | 7010 | for (fn_info.param_body) |param| switch (zir_tags[param]) { |
| ... | @@ -6968,7 +7036,7 @@ fn analyzeCall( | ... | @@ -6968,7 +7036,7 @@ fn analyzeCall( |
| 6968 | error.ComptimeReturn => break :result inlining.comptime_result, | 7036 | error.ComptimeReturn => break :result inlining.comptime_result, |
| 6969 | error.AnalysisFail => { | 7037 | error.AnalysisFail => { |
| 6970 | const err_msg = sema.err orelse return err; | 7038 | const err_msg = sema.err orelse return err; |
| 6971 | if (std.mem.eql(u8, err_msg.msg, recursive_msg)) return err; | 7039 | if (mem.eql(u8, err_msg.msg, recursive_msg)) return err; |
| 6972 | try sema.errNote(block, call_src, err_msg, "called from here", .{}); | 7040 | try sema.errNote(block, call_src, err_msg, "called from here", .{}); |
| 6973 | err_msg.clearTrace(sema.gpa); | 7041 | err_msg.clearTrace(sema.gpa); |
| 6974 | return err; | 7042 | return err; |
| ... | @@ -6978,11 +7046,11 @@ fn analyzeCall( | ... | @@ -6978,11 +7046,11 @@ fn analyzeCall( |
| 6978 | break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges); | 7046 | break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges); |
| 6979 | }; | 7047 | }; |
| 6980 | 7048 | ||
| 6981 | if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag() != .NoReturn) { | 7049 | if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag(mod) != .NoReturn) { |
| 6982 | try sema.emitDbgInline( | 7050 | try sema.emitDbgInline( |
| 6983 | block, | 7051 | block, |
| 6984 | module_fn, | 7052 | module_fn_index, |
| 6985 | parent_func.?, | 7053 | parent_func_index.unwrap().?, |
| 6986 | mod.declPtr(parent_func.?.owner_decl).ty, | 7054 | mod.declPtr(parent_func.?.owner_decl).ty, |
| 6987 | .dbg_inline_end, | 7055 | .dbg_inline_end, |
| 6988 | ); | 7056 | ); |
| ... | @@ -6993,23 +7061,11 @@ fn analyzeCall( | ... | @@ -6993,23 +7061,11 @@ fn analyzeCall( |
| 6993 | 7061 | ||
| 6994 | // TODO: check whether any external comptime memory was mutated by the | 7062 | // TODO: check whether any external comptime memory was mutated by the |
| 6995 | // comptime function call. If so, then do not memoize the call here. | 7063 | // comptime function call. If so, then do not memoize the call here. |
| 6996 | // TODO: re-evaluate whether memoized_calls needs its own arena. I think | 7064 | _ = try mod.intern(.{ .memoized_call = .{ |
| 6997 | // it should be fine to use the Decl arena for the function. | 7065 | .func = module_fn_index, |
| 6998 | { | 7066 | .arg_values = memoized_arg_values, |
| 6999 | var arena_allocator = std.heap.ArenaAllocator.init(gpa); | 7067 | .result = try result_val.intern(fn_ret_ty, mod), |
| 7000 | errdefer arena_allocator.deinit(); | 7068 | } }); |
| 7001 | const arena = arena_allocator.allocator(); | ||
| 7002 | |||
| 7003 | for (memoized_call_key.args) |*arg| { | ||
| 7004 | arg.* = try arg.*.copy(arena); | ||
| 7005 | } | ||
| 7006 | |||
| 7007 | try mod.memoized_calls.putContext(gpa, memoized_call_key, .{ | ||
| 7008 | .val = try result_val.copy(arena), | ||
| 7009 | .arena = arena_allocator.state, | ||
| 7010 | }, .{ .module = mod }); | ||
| 7011 | delete_memoized_call_key = false; | ||
| 7012 | } | ||
| 7013 | } | 7069 | } |
| 7014 | 7070 | ||
| 7015 | break :res2 result; | 7071 | break :res2 result; |
| ... | @@ -7028,7 +7084,7 @@ fn analyzeCall( | ... | @@ -7028,7 +7084,7 @@ fn analyzeCall( |
| 7028 | .func_inst = func, | 7084 | .func_inst = func, |
| 7029 | .param_i = @intCast(u32, i), | 7085 | .param_i = @intCast(u32, i), |
| 7030 | } }; | 7086 | } }; |
| 7031 | const param_ty = func_ty.fnParamType(i); | 7087 | const param_ty = mod.typeToFunc(func_ty).?.param_types[i].toType(); |
| 7032 | args[i] = sema.analyzeCallArg( | 7088 | args[i] = sema.analyzeCallArg( |
| 7033 | block, | 7089 | block, |
| 7034 | .unneeded, | 7090 | .unneeded, |
| ... | @@ -7037,10 +7093,10 @@ fn analyzeCall( | ... | @@ -7037,10 +7093,10 @@ fn analyzeCall( |
| 7037 | opts, | 7093 | opts, |
| 7038 | ) catch |err| switch (err) { | 7094 | ) catch |err| switch (err) { |
| 7039 | error.NeededSourceLocation => { | 7095 | error.NeededSourceLocation => { |
| 7040 | const decl = sema.mod.declPtr(block.src_decl); | 7096 | const decl = mod.declPtr(block.src_decl); |
| 7041 | _ = try sema.analyzeCallArg( | 7097 | _ = try sema.analyzeCallArg( |
| 7042 | block, | 7098 | block, |
| 7043 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src), | 7099 | mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src), |
| 7044 | param_ty, | 7100 | param_ty, |
| 7045 | uncasted_arg, | 7101 | uncasted_arg, |
| 7046 | opts, | 7102 | opts, |
| ... | @@ -7052,11 +7108,11 @@ fn analyzeCall( | ... | @@ -7052,11 +7108,11 @@ fn analyzeCall( |
| 7052 | } else { | 7108 | } else { |
| 7053 | args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) { | 7109 | args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) { |
| 7054 | error.NeededSourceLocation => { | 7110 | error.NeededSourceLocation => { |
| 7055 | const decl = sema.mod.declPtr(block.src_decl); | 7111 | const decl = mod.declPtr(block.src_decl); |
| 7056 | _ = try sema.coerceVarArgParam( | 7112 | _ = try sema.coerceVarArgParam( |
| 7057 | block, | 7113 | block, |
| 7058 | uncasted_arg, | 7114 | uncasted_arg, |
| 7059 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src), | 7115 | mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src), |
| 7060 | ); | 7116 | ); |
| 7061 | unreachable; | 7117 | unreachable; |
| 7062 | }, | 7118 | }, |
| ... | @@ -7067,14 +7123,14 @@ fn analyzeCall( | ... | @@ -7067,14 +7123,14 @@ fn analyzeCall( |
| 7067 | 7123 | ||
| 7068 | if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); | 7124 | if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); |
| 7069 | 7125 | ||
| 7070 | try sema.queueFullTypeResolution(func_ty_info.return_type); | 7126 | try sema.queueFullTypeResolution(func_ty_info.return_type.toType()); |
| 7071 | if (sema.owner_func != null and func_ty_info.return_type.isError()) { | 7127 | if (sema.owner_func != null and func_ty_info.return_type.toType().isError(mod)) { |
| 7072 | sema.owner_func.?.calls_or_awaits_errorable_fn = true; | 7128 | sema.owner_func.?.calls_or_awaits_errorable_fn = true; |
| 7073 | } | 7129 | } |
| 7074 | 7130 | ||
| 7075 | if (try sema.resolveMaybeUndefVal(func)) |func_val| { | 7131 | if (try sema.resolveMaybeUndefVal(func)) |func_val| { |
| 7076 | if (func_val.castTag(.function)) |func_obj| { | 7132 | if (mod.intern_pool.indexToFunc(func_val.toIntern()).unwrap()) |func_index| { |
| 7077 | try sema.mod.ensureFuncBodyAnalysisQueued(func_obj.data); | 7133 | try mod.ensureFuncBodyAnalysisQueued(func_index); |
| 7078 | } | 7134 | } |
| 7079 | } | 7135 | } |
| 7080 | 7136 | ||
| ... | @@ -7096,23 +7152,24 @@ fn analyzeCall( | ... | @@ -7096,23 +7152,24 @@ fn analyzeCall( |
| 7096 | try sema.ensureResultUsed(block, sema.typeOf(func_inst), call_src); | 7152 | try sema.ensureResultUsed(block, sema.typeOf(func_inst), call_src); |
| 7097 | } | 7153 | } |
| 7098 | return sema.handleTailCall(block, call_src, func_ty, func_inst); | 7154 | return sema.handleTailCall(block, call_src, func_ty, func_inst); |
| 7099 | } else if (block.wantSafety() and func_ty_info.return_type.isNoReturn()) { | 7155 | } |
| 7156 | if (block.wantSafety() and func_ty_info.return_type == .noreturn_type) skip_safety: { | ||
| 7100 | // Function pointers and extern functions aren't guaranteed to | 7157 | // Function pointers and extern functions aren't guaranteed to |
| 7101 | // actually be noreturn so we add a safety check for them. | 7158 | // actually be noreturn so we add a safety check for them. |
| 7102 | check: { | 7159 | if (try sema.resolveMaybeUndefVal(func)) |func_val| { |
| 7103 | var func_val = (try sema.resolveMaybeUndefVal(func)) orelse break :check; | 7160 | switch (mod.intern_pool.indexToKey(func_val.toIntern())) { |
| 7104 | switch (func_val.tag()) { | 7161 | .func => break :skip_safety, |
| 7105 | .function, .decl_ref => { | 7162 | .ptr => |ptr| switch (ptr.addr) { |
| 7106 | _ = try block.addNoOp(.unreach); | 7163 | .decl => |decl| if (!mod.declPtr(decl).isExtern(mod)) break :skip_safety, |
| 7107 | return Air.Inst.Ref.unreachable_value; | 7164 | else => {}, |
| 7108 | }, | 7165 | }, |
| 7109 | else => break :check, | 7166 | else => {}, |
| 7110 | } | 7167 | } |
| 7111 | } | 7168 | } |
| 7112 | |||
| 7113 | try sema.safetyPanic(block, .noreturn_returned); | 7169 | try sema.safetyPanic(block, .noreturn_returned); |
| 7114 | return Air.Inst.Ref.unreachable_value; | 7170 | return Air.Inst.Ref.unreachable_value; |
| 7115 | } else if (func_ty_info.return_type.isNoReturn()) { | 7171 | } |
| 7172 | if (func_ty_info.return_type == .noreturn_type) { | ||
| 7116 | _ = try block.addNoOp(.unreach); | 7173 | _ = try block.addNoOp(.unreach); |
| 7117 | return Air.Inst.Ref.unreachable_value; | 7174 | return Air.Inst.Ref.unreachable_value; |
| 7118 | } | 7175 | } |
| ... | @@ -7126,17 +7183,18 @@ fn analyzeCall( | ... | @@ -7126,17 +7183,18 @@ fn analyzeCall( |
| 7126 | } | 7183 | } |
| 7127 | 7184 | ||
| 7128 | fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { | 7185 | fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { |
| 7129 | const target = sema.mod.getTarget(); | 7186 | const mod = sema.mod; |
| 7130 | const backend = sema.mod.comp.getZigBackend(); | 7187 | const target = mod.getTarget(); |
| 7188 | const backend = mod.comp.getZigBackend(); | ||
| 7131 | if (!target_util.supportsTailCall(target, backend)) { | 7189 | if (!target_util.supportsTailCall(target, backend)) { |
| 7132 | return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{ | 7190 | return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{ |
| 7133 | @tagName(backend), @tagName(target.cpu.arch), | 7191 | @tagName(backend), @tagName(target.cpu.arch), |
| 7134 | }); | 7192 | }); |
| 7135 | } | 7193 | } |
| 7136 | const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl); | 7194 | const func_decl = mod.declPtr(sema.owner_func.?.owner_decl); |
| 7137 | if (!func_ty.eql(func_decl.ty, sema.mod)) { | 7195 | if (!func_ty.eql(func_decl.ty, mod)) { |
| 7138 | return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ | 7196 | return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{ |
| 7139 | func_ty.fmt(sema.mod), func_decl.ty.fmt(sema.mod), | 7197 | func_ty.fmt(mod), func_decl.ty.fmt(mod), |
| 7140 | }); | 7198 | }); |
| 7141 | } | 7199 | } |
| 7142 | _ = try block.addUnOp(.ret, result); | 7200 | _ = try block.addUnOp(.ret, result); |
| ... | @@ -7149,16 +7207,17 @@ fn analyzeInlineCallArg( | ... | @@ -7149,16 +7207,17 @@ fn analyzeInlineCallArg( |
| 7149 | param_block: *Block, | 7207 | param_block: *Block, |
| 7150 | arg_src: LazySrcLoc, | 7208 | arg_src: LazySrcLoc, |
| 7151 | inst: Zir.Inst.Index, | 7209 | inst: Zir.Inst.Index, |
| 7152 | new_fn_info: Type.Payload.Function.Data, | 7210 | new_fn_info: *InternPool.Key.FuncType, |
| 7153 | arg_i: *usize, | 7211 | arg_i: *usize, |
| 7154 | uncasted_args: []const Air.Inst.Ref, | 7212 | uncasted_args: []const Air.Inst.Ref, |
| 7155 | is_comptime_call: bool, | 7213 | is_comptime_call: bool, |
| 7156 | should_memoize: *bool, | 7214 | should_memoize: *bool, |
| 7157 | memoized_call_key: Module.MemoizedCall.Key, | 7215 | memoized_arg_values: []InternPool.Index, |
| 7158 | raw_param_types: []const Type, | 7216 | raw_param_types: []const InternPool.Index, |
| 7159 | func_inst: Air.Inst.Ref, | 7217 | func_inst: Air.Inst.Ref, |
| 7160 | has_comptime_args: *bool, | 7218 | has_comptime_args: *bool, |
| 7161 | ) !void { | 7219 | ) !void { |
| 7220 | const mod = sema.mod; | ||
| 7162 | const zir_tags = sema.code.instructions.items(.tag); | 7221 | const zir_tags = sema.code.instructions.items(.tag); |
| 7163 | switch (zir_tags[inst]) { | 7222 | switch (zir_tags[inst]) { |
| 7164 | .param_comptime, .param_anytype_comptime => has_comptime_args.* = true, | 7223 | .param_comptime, .param_anytype_comptime => has_comptime_args.* = true, |
| ... | @@ -7174,13 +7233,14 @@ fn analyzeInlineCallArg( | ... | @@ -7174,13 +7233,14 @@ fn analyzeInlineCallArg( |
| 7174 | const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; | 7233 | const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 7175 | const param_ty = param_ty: { | 7234 | const param_ty = param_ty: { |
| 7176 | const raw_param_ty = raw_param_types[arg_i.*]; | 7235 | const raw_param_ty = raw_param_types[arg_i.*]; |
| 7177 | if (raw_param_ty.tag() != .generic_poison) break :param_ty raw_param_ty; | 7236 | if (raw_param_ty != .generic_poison_type) break :param_ty raw_param_ty; |
| 7178 | const param_ty_inst = try sema.resolveBody(param_block, param_body, inst); | 7237 | const param_ty_inst = try sema.resolveBody(param_block, param_body, inst); |
| 7179 | break :param_ty try sema.analyzeAsType(param_block, param_src, param_ty_inst); | 7238 | const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst); |
| 7239 | break :param_ty param_ty.toIntern(); | ||
| 7180 | }; | 7240 | }; |
| 7181 | new_fn_info.param_types[arg_i.*] = param_ty; | 7241 | new_fn_info.param_types[arg_i.*] = param_ty; |
| 7182 | const uncasted_arg = uncasted_args[arg_i.*]; | 7242 | const uncasted_arg = uncasted_args[arg_i.*]; |
| 7183 | if (try sema.typeRequiresComptime(param_ty)) { | 7243 | if (try sema.typeRequiresComptime(param_ty.toType())) { |
| 7184 | _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| { | 7244 | _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| { |
| 7185 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); | 7245 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); |
| 7186 | return err; | 7246 | return err; |
| ... | @@ -7188,7 +7248,7 @@ fn analyzeInlineCallArg( | ... | @@ -7188,7 +7248,7 @@ fn analyzeInlineCallArg( |
| 7188 | } else if (!is_comptime_call and zir_tags[inst] == .param_comptime) { | 7248 | } else if (!is_comptime_call and zir_tags[inst] == .param_comptime) { |
| 7189 | _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); | 7249 | _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); |
| 7190 | } | 7250 | } |
| 7191 | const casted_arg = sema.coerceExtra(arg_block, param_ty, uncasted_arg, arg_src, .{ .param_src = .{ | 7251 | const casted_arg = sema.coerceExtra(arg_block, param_ty.toType(), uncasted_arg, arg_src, .{ .param_src = .{ |
| 7192 | .func_inst = func_inst, | 7252 | .func_inst = func_inst, |
| 7193 | .param_i = @intCast(u32, arg_i.*), | 7253 | .param_i = @intCast(u32, arg_i.*), |
| 7194 | } }) catch |err| switch (err) { | 7254 | } }) catch |err| switch (err) { |
| ... | @@ -7202,24 +7262,20 @@ fn analyzeInlineCallArg( | ... | @@ -7202,24 +7262,20 @@ fn analyzeInlineCallArg( |
| 7202 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); | 7262 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); |
| 7203 | return err; | 7263 | return err; |
| 7204 | }; | 7264 | }; |
| 7205 | switch (arg_val.tag()) { | 7265 | switch (arg_val.toIntern()) { |
| 7206 | .generic_poison, .generic_poison_type => { | 7266 | .generic_poison, .generic_poison_type => { |
| 7207 | // This function is currently evaluated as part of an as-of-yet unresolvable | 7267 | // This function is currently evaluated as part of an as-of-yet unresolvable |
| 7208 | // parameter or return type. | 7268 | // parameter or return type. |
| 7209 | return error.GenericPoison; | 7269 | return error.GenericPoison; |
| 7210 | }, | 7270 | }, |
| 7211 | else => { | 7271 | else => {}, |
| 7212 | // Needed so that lazy values do not trigger | ||
| 7213 | // assertion due to type not being resolved | ||
| 7214 | // when the hash function is called. | ||
| 7215 | try sema.resolveLazyValue(arg_val); | ||
| 7216 | }, | ||
| 7217 | } | 7272 | } |
| 7218 | should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(); | 7273 | // Needed so that lazy values do not trigger |
| 7219 | memoized_call_key.args[arg_i.*] = .{ | 7274 | // assertion due to type not being resolved |
| 7220 | .ty = param_ty, | 7275 | // when the hash function is called. |
| 7221 | .val = arg_val, | 7276 | const resolved_arg_val = try sema.resolveLazyValue(arg_val); |
| 7222 | }; | 7277 | should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod); |
| 7278 | memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(param_ty.toType(), mod); | ||
| 7223 | } else { | 7279 | } else { |
| 7224 | sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg); | 7280 | sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg); |
| 7225 | } | 7281 | } |
| ... | @@ -7233,7 +7289,7 @@ fn analyzeInlineCallArg( | ... | @@ -7233,7 +7289,7 @@ fn analyzeInlineCallArg( |
| 7233 | .param_anytype, .param_anytype_comptime => { | 7289 | .param_anytype, .param_anytype_comptime => { |
| 7234 | // No coercion needed. | 7290 | // No coercion needed. |
| 7235 | const uncasted_arg = uncasted_args[arg_i.*]; | 7291 | const uncasted_arg = uncasted_args[arg_i.*]; |
| 7236 | new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg); | 7292 | new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg).toIntern(); |
| 7237 | 7293 | ||
| 7238 | if (is_comptime_call) { | 7294 | if (is_comptime_call) { |
| 7239 | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); | 7295 | sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg); |
| ... | @@ -7241,24 +7297,20 @@ fn analyzeInlineCallArg( | ... | @@ -7241,24 +7297,20 @@ fn analyzeInlineCallArg( |
| 7241 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); | 7297 | if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err); |
| 7242 | return err; | 7298 | return err; |
| 7243 | }; | 7299 | }; |
| 7244 | switch (arg_val.tag()) { | 7300 | switch (arg_val.toIntern()) { |
| 7245 | .generic_poison, .generic_poison_type => { | 7301 | .generic_poison, .generic_poison_type => { |
| 7246 | // This function is currently evaluated as part of an as-of-yet unresolvable | 7302 | // This function is currently evaluated as part of an as-of-yet unresolvable |
| 7247 | // parameter or return type. | 7303 | // parameter or return type. |
| 7248 | return error.GenericPoison; | 7304 | return error.GenericPoison; |
| 7249 | }, | 7305 | }, |
| 7250 | else => { | 7306 | else => {}, |
| 7251 | // Needed so that lazy values do not trigger | ||
| 7252 | // assertion due to type not being resolved | ||
| 7253 | // when the hash function is called. | ||
| 7254 | try sema.resolveLazyValue(arg_val); | ||
| 7255 | }, | ||
| 7256 | } | 7307 | } |
| 7257 | should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(); | 7308 | // Needed so that lazy values do not trigger |
| 7258 | memoized_call_key.args[arg_i.*] = .{ | 7309 | // assertion due to type not being resolved |
| 7259 | .ty = sema.typeOf(uncasted_arg), | 7310 | // when the hash function is called. |
| 7260 | .val = arg_val, | 7311 | const resolved_arg_val = try sema.resolveLazyValue(arg_val); |
| 7261 | }; | 7312 | should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod); |
| 7313 | memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(sema.typeOf(uncasted_arg), mod); | ||
| 7262 | } else { | 7314 | } else { |
| 7263 | if (zir_tags[inst] == .param_anytype_comptime) { | 7315 | if (zir_tags[inst] == .param_anytype_comptime) { |
| 7264 | _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); | 7316 | _ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime"); |
| ... | @@ -7298,14 +7350,15 @@ fn analyzeGenericCallArg( | ... | @@ -7298,14 +7350,15 @@ fn analyzeGenericCallArg( |
| 7298 | uncasted_arg: Air.Inst.Ref, | 7350 | uncasted_arg: Air.Inst.Ref, |
| 7299 | comptime_arg: TypedValue, | 7351 | comptime_arg: TypedValue, |
| 7300 | runtime_args: []Air.Inst.Ref, | 7352 | runtime_args: []Air.Inst.Ref, |
| 7301 | new_fn_info: Type.Payload.Function.Data, | 7353 | new_fn_info: InternPool.Key.FuncType, |
| 7302 | runtime_i: *u32, | 7354 | runtime_i: *u32, |
| 7303 | ) !void { | 7355 | ) !void { |
| 7304 | const is_runtime = comptime_arg.val.tag() == .generic_poison and | 7356 | const mod = sema.mod; |
| 7305 | comptime_arg.ty.hasRuntimeBits() and | 7357 | const is_runtime = comptime_arg.val.isGenericPoison() and |
| 7358 | comptime_arg.ty.hasRuntimeBits(mod) and | ||
| 7306 | !(try sema.typeRequiresComptime(comptime_arg.ty)); | 7359 | !(try sema.typeRequiresComptime(comptime_arg.ty)); |
| 7307 | if (is_runtime) { | 7360 | if (is_runtime) { |
| 7308 | const param_ty = new_fn_info.param_types[runtime_i.*]; | 7361 | const param_ty = new_fn_info.param_types[runtime_i.*].toType(); |
| 7309 | const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); | 7362 | const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| 7310 | try sema.queueFullTypeResolution(param_ty); | 7363 | try sema.queueFullTypeResolution(param_ty); |
| 7311 | runtime_args[runtime_i.*] = casted_arg; | 7364 | runtime_args[runtime_i.*] = casted_arg; |
| ... | @@ -7315,10 +7368,16 @@ fn analyzeGenericCallArg( | ... | @@ -7315,10 +7368,16 @@ fn analyzeGenericCallArg( |
| 7315 | } | 7368 | } |
| 7316 | } | 7369 | } |
| 7317 | 7370 | ||
| 7318 | fn analyzeGenericCallArgVal(sema: *Sema, block: *Block, arg_src: LazySrcLoc, uncasted_arg: Air.Inst.Ref) !Value { | 7371 | fn analyzeGenericCallArgVal( |
| 7319 | const arg_val = try sema.resolveValue(block, arg_src, uncasted_arg, "parameter is comptime"); | 7372 | sema: *Sema, |
| 7320 | try sema.resolveLazyValue(arg_val); | 7373 | block: *Block, |
| 7321 | return arg_val; | 7374 | arg_src: LazySrcLoc, |
| 7375 | arg_ty: Type, | ||
| 7376 | uncasted_arg: Air.Inst.Ref, | ||
| 7377 | reason: []const u8, | ||
| 7378 | ) !Value { | ||
| 7379 | const casted_arg = try sema.coerce(block, arg_ty, uncasted_arg, arg_src); | ||
| 7380 | return sema.resolveLazyValue(try sema.resolveValue(block, arg_src, casted_arg, reason)); | ||
| 7322 | } | 7381 | } |
| 7323 | 7382 | ||
| 7324 | fn instantiateGenericCall( | 7383 | fn instantiateGenericCall( |
| ... | @@ -7327,7 +7386,7 @@ fn instantiateGenericCall( | ... | @@ -7327,7 +7386,7 @@ fn instantiateGenericCall( |
| 7327 | func: Air.Inst.Ref, | 7386 | func: Air.Inst.Ref, |
| 7328 | func_src: LazySrcLoc, | 7387 | func_src: LazySrcLoc, |
| 7329 | call_src: LazySrcLoc, | 7388 | call_src: LazySrcLoc, |
| 7330 | func_ty_info: Type.Payload.Function.Data, | 7389 | generic_func_ty: Type, |
| 7331 | ensure_result_used: bool, | 7390 | ensure_result_used: bool, |
| 7332 | uncasted_args: []const Air.Inst.Ref, | 7391 | uncasted_args: []const Air.Inst.Ref, |
| 7333 | call_tag: Air.Inst.Tag, | 7392 | call_tag: Air.Inst.Tag, |
| ... | @@ -7338,46 +7397,41 @@ fn instantiateGenericCall( | ... | @@ -7338,46 +7397,41 @@ fn instantiateGenericCall( |
| 7338 | const gpa = sema.gpa; | 7397 | const gpa = sema.gpa; |
| 7339 | 7398 | ||
| 7340 | const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime-known"); | 7399 | const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime-known"); |
| 7341 | const module_fn = switch (func_val.tag()) { | 7400 | const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) { |
| 7342 | .function => func_val.castTag(.function).?.data, | 7401 | .func => |function| function.index, |
| 7343 | .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data, | 7402 | .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.getFunctionIndex(mod).unwrap().?, |
| 7344 | else => unreachable, | 7403 | else => unreachable, |
| 7345 | }; | 7404 | }; |
| 7405 | const module_fn = mod.funcPtr(module_fn_index); | ||
| 7346 | // Check the Module's generic function map with an adapted context, so that we | 7406 | // Check the Module's generic function map with an adapted context, so that we |
| 7347 | // can match against `uncasted_args` rather than doing the work below to create a | 7407 | // can match against `uncasted_args` rather than doing the work below to create a |
| 7348 | // generic Scope only to junk it if it matches an existing instantiation. | 7408 | // generic Scope only to junk it if it matches an existing instantiation. |
| 7349 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); | 7409 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 7350 | const namespace = fn_owner_decl.src_namespace; | 7410 | const namespace_index = fn_owner_decl.src_namespace; |
| 7411 | const namespace = mod.namespacePtr(namespace_index); | ||
| 7351 | const fn_zir = namespace.file_scope.zir; | 7412 | const fn_zir = namespace.file_scope.zir; |
| 7352 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); | 7413 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); |
| 7353 | const zir_tags = fn_zir.instructions.items(.tag); | 7414 | const zir_tags = fn_zir.instructions.items(.tag); |
| 7354 | 7415 | ||
| 7355 | // This hash must match `Module.MonomorphedFuncsContext.hash`. | 7416 | const monomorphed_args = try sema.arena.alloc(InternPool.Index, mod.typeToFunc(generic_func_ty).?.param_types.len); |
| 7356 | // For parameters explicitly marked comptime and simple parameter type expressions, | 7417 | const callee_index = callee: { |
| 7357 | // we know whether a parameter is elided from a monomorphed function, and can | 7418 | var arg_i: usize = 0; |
| 7358 | // use it in the hash here. However, for parameter type expressions that are not | 7419 | var monomorphed_arg_i: u32 = 0; |
| 7359 | // explicitly marked comptime and rely on previous parameter comptime values, we | 7420 | var known_unique = false; |
| 7360 | // don't find out until after generating a monomorphed function whether the parameter | ||
| 7361 | // type ended up being a "must-be-comptime-known" type. | ||
| 7362 | var hasher = std.hash.Wyhash.init(0); | ||
| 7363 | std.hash.autoHash(&hasher, module_fn.owner_decl); | ||
| 7364 | |||
| 7365 | const generic_args = try sema.arena.alloc(GenericCallAdapter.Arg, func_ty_info.param_types.len); | ||
| 7366 | { | ||
| 7367 | var i: usize = 0; | ||
| 7368 | for (fn_info.param_body) |inst| { | 7421 | for (fn_info.param_body) |inst| { |
| 7422 | const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?; | ||
| 7369 | var is_comptime = false; | 7423 | var is_comptime = false; |
| 7370 | var is_anytype = false; | 7424 | var is_anytype = false; |
| 7371 | switch (zir_tags[inst]) { | 7425 | switch (zir_tags[inst]) { |
| 7372 | .param => { | 7426 | .param => { |
| 7373 | is_comptime = func_ty_info.paramIsComptime(i); | 7427 | is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i)); |
| 7374 | }, | 7428 | }, |
| 7375 | .param_comptime => { | 7429 | .param_comptime => { |
| 7376 | is_comptime = true; | 7430 | is_comptime = true; |
| 7377 | }, | 7431 | }, |
| 7378 | .param_anytype => { | 7432 | .param_anytype => { |
| 7379 | is_anytype = true; | 7433 | is_anytype = true; |
| 7380 | is_comptime = func_ty_info.paramIsComptime(i); | 7434 | is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i)); |
| 7381 | }, | 7435 | }, |
| 7382 | .param_anytype_comptime => { | 7436 | .param_anytype_comptime => { |
| 7383 | is_anytype = true; | 7437 | is_anytype = true; |
| ... | @@ -7386,87 +7440,90 @@ fn instantiateGenericCall( | ... | @@ -7386,87 +7440,90 @@ fn instantiateGenericCall( |
| 7386 | else => continue, | 7440 | else => continue, |
| 7387 | } | 7441 | } |
| 7388 | 7442 | ||
| 7389 | const arg_ty = sema.typeOf(uncasted_args[i]); | 7443 | defer arg_i += 1; |
| 7444 | const param_ty = generic_func_ty_info.param_types[arg_i]; | ||
| 7445 | const is_generic = !is_anytype and param_ty == .generic_poison_type; | ||
| 7446 | |||
| 7447 | if (known_unique) { | ||
| 7448 | if (is_comptime or is_anytype or is_generic) { | ||
| 7449 | monomorphed_arg_i += 1; | ||
| 7450 | } | ||
| 7451 | continue; | ||
| 7452 | } | ||
| 7453 | |||
| 7454 | const uncasted_arg = uncasted_args[arg_i]; | ||
| 7455 | const arg_ty = if (is_generic) mod.monomorphed_funcs.getAdapted( | ||
| 7456 | Module.MonomorphedFuncAdaptedKey{ | ||
| 7457 | .func = module_fn_index, | ||
| 7458 | .args = monomorphed_args[0..monomorphed_arg_i], | ||
| 7459 | }, | ||
| 7460 | Module.MonomorphedFuncsAdaptedContext{ .mod = mod }, | ||
| 7461 | ) orelse { | ||
| 7462 | known_unique = true; | ||
| 7463 | monomorphed_arg_i += 1; | ||
| 7464 | continue; | ||
| 7465 | } else if (is_anytype) sema.typeOf(uncasted_arg).toIntern() else param_ty; | ||
| 7466 | const was_comptime = is_comptime; | ||
| 7467 | if (!is_comptime and try sema.typeRequiresComptime(arg_ty.toType())) is_comptime = true; | ||
| 7390 | if (is_comptime or is_anytype) { | 7468 | if (is_comptime or is_anytype) { |
| 7391 | // Tuple default values are a part of the type and need to be | 7469 | // Tuple default values are a part of the type and need to be |
| 7392 | // resolved to hash the type. | 7470 | // resolved to hash the type. |
| 7393 | try sema.resolveTupleLazyValues(block, call_src, arg_ty); | 7471 | try sema.resolveTupleLazyValues(block, call_src, arg_ty.toType()); |
| 7394 | } | 7472 | } |
| 7395 | 7473 | ||
| 7396 | if (is_comptime) { | 7474 | if (is_comptime) { |
| 7397 | const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) { | 7475 | const casted_arg = sema.analyzeGenericCallArgVal(block, .unneeded, arg_ty.toType(), uncasted_arg, "") catch |err| switch (err) { |
| 7398 | error.NeededSourceLocation => { | 7476 | error.NeededSourceLocation => { |
| 7399 | const decl = sema.mod.declPtr(block.src_decl); | 7477 | const decl = mod.declPtr(block.src_decl); |
| 7400 | const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src); | 7478 | const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src); |
| 7401 | _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[i]); | 7479 | _ = try sema.analyzeGenericCallArgVal( |
| 7480 | block, | ||
| 7481 | arg_src, | ||
| 7482 | arg_ty.toType(), | ||
| 7483 | uncasted_arg, | ||
| 7484 | if (was_comptime) | ||
| 7485 | "parameter is comptime" | ||
| 7486 | else | ||
| 7487 | "argument to parameter with comptime-only type must be comptime-known", | ||
| 7488 | ); | ||
| 7402 | unreachable; | 7489 | unreachable; |
| 7403 | }, | 7490 | }, |
| 7404 | else => |e| return e, | 7491 | else => |e| return e, |
| 7405 | }; | 7492 | }; |
| 7406 | arg_val.hashUncoerced(arg_ty, &hasher, mod); | 7493 | monomorphed_args[monomorphed_arg_i] = casted_arg.toIntern(); |
| 7407 | if (is_anytype) { | 7494 | monomorphed_arg_i += 1; |
| 7408 | arg_ty.hashWithHasher(&hasher, mod); | 7495 | } else if (is_anytype or is_generic) { |
| 7409 | generic_args[i] = .{ | 7496 | monomorphed_args[monomorphed_arg_i] = try mod.intern(.{ .undef = arg_ty }); |
| 7410 | .ty = arg_ty, | 7497 | monomorphed_arg_i += 1; |
| 7411 | .val = arg_val, | ||
| 7412 | .is_anytype = true, | ||
| 7413 | }; | ||
| 7414 | } else { | ||
| 7415 | generic_args[i] = .{ | ||
| 7416 | .ty = arg_ty, | ||
| 7417 | .val = arg_val, | ||
| 7418 | .is_anytype = false, | ||
| 7419 | }; | ||
| 7420 | } | ||
| 7421 | } else if (is_anytype) { | ||
| 7422 | arg_ty.hashWithHasher(&hasher, mod); | ||
| 7423 | generic_args[i] = .{ | ||
| 7424 | .ty = arg_ty, | ||
| 7425 | .val = Value.initTag(.generic_poison), | ||
| 7426 | .is_anytype = true, | ||
| 7427 | }; | ||
| 7428 | } else { | ||
| 7429 | generic_args[i] = .{ | ||
| 7430 | .ty = arg_ty, | ||
| 7431 | .val = Value.initTag(.generic_poison), | ||
| 7432 | .is_anytype = false, | ||
| 7433 | }; | ||
| 7434 | } | 7498 | } |
| 7435 | |||
| 7436 | i += 1; | ||
| 7437 | } | 7499 | } |
| 7438 | } | ||
| 7439 | 7500 | ||
| 7440 | const precomputed_hash = hasher.final(); | 7501 | if (!known_unique) { |
| 7502 | if (mod.monomorphed_funcs.getAdapted( | ||
| 7503 | Module.MonomorphedFuncAdaptedKey{ | ||
| 7504 | .func = module_fn_index, | ||
| 7505 | .args = monomorphed_args[0..monomorphed_arg_i], | ||
| 7506 | }, | ||
| 7507 | Module.MonomorphedFuncsAdaptedContext{ .mod = mod }, | ||
| 7508 | )) |callee_func| break :callee mod.intern_pool.indexToKey(callee_func).func.index; | ||
| 7509 | } | ||
| 7441 | 7510 | ||
| 7442 | const adapter: GenericCallAdapter = .{ | 7511 | const new_module_func_index = try mod.createFunc(undefined); |
| 7443 | .generic_fn = module_fn, | 7512 | const new_module_func = mod.funcPtr(new_module_func_index); |
| 7444 | .precomputed_hash = precomputed_hash, | ||
| 7445 | .func_ty_info = func_ty_info, | ||
| 7446 | .args = generic_args, | ||
| 7447 | .module = mod, | ||
| 7448 | }; | ||
| 7449 | const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter); | ||
| 7450 | const callee = if (!gop.found_existing) callee: { | ||
| 7451 | const new_module_func = try gpa.create(Module.Fn); | ||
| 7452 | 7513 | ||
| 7453 | // This ensures that we can operate on the hash map before the Module.Fn | ||
| 7454 | // struct is fully initialized. | ||
| 7455 | new_module_func.hash = precomputed_hash; | ||
| 7456 | new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional(); | 7514 | new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional(); |
| 7457 | new_module_func.comptime_args = null; | 7515 | new_module_func.comptime_args = null; |
| 7458 | gop.key_ptr.* = new_module_func; | ||
| 7459 | 7516 | ||
| 7460 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); | 7517 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); |
| 7461 | 7518 | ||
| 7462 | // Create a Decl for the new function. | 7519 | // Create a Decl for the new function. |
| 7463 | const src_decl_index = namespace.getDeclIndex(); | 7520 | const src_decl_index = namespace.getDeclIndex(mod); |
| 7464 | const src_decl = mod.declPtr(src_decl_index); | 7521 | const src_decl = mod.declPtr(src_decl_index); |
| 7465 | const new_decl_index = try mod.allocateNewDecl(namespace, fn_owner_decl.src_node, src_decl.src_scope); | 7522 | const new_decl_index = try mod.allocateNewDecl(namespace_index, fn_owner_decl.src_node, src_decl.src_scope); |
| 7466 | const new_decl = mod.declPtr(new_decl_index); | 7523 | const new_decl = mod.declPtr(new_decl_index); |
| 7467 | // TODO better names for generic function instantiations | 7524 | // TODO better names for generic function instantiations |
| 7468 | const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{ | 7525 | const decl_name = try mod.intern_pool.getOrPutStringFmt(gpa, "{}__anon_{d}", .{ |
| 7469 | fn_owner_decl.name, @enumToInt(new_decl_index), | 7526 | fn_owner_decl.name.fmt(&mod.intern_pool), @enumToInt(new_decl_index), |
| 7470 | }); | 7527 | }); |
| 7471 | new_decl.name = decl_name; | 7528 | new_decl.name = decl_name; |
| 7472 | new_decl.src_line = fn_owner_decl.src_line; | 7529 | new_decl.src_line = fn_owner_decl.src_line; |
| ... | @@ -7488,25 +7545,21 @@ fn instantiateGenericCall( | ... | @@ -7488,25 +7545,21 @@ fn instantiateGenericCall( |
| 7488 | assert(new_decl.dependencies.keys().len == 0); | 7545 | assert(new_decl.dependencies.keys().len == 0); |
| 7489 | try mod.declareDeclDependencyType(new_decl_index, module_fn.owner_decl, .function_body); | 7546 | try mod.declareDeclDependencyType(new_decl_index, module_fn.owner_decl, .function_body); |
| 7490 | 7547 | ||
| 7491 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | ||
| 7492 | const new_decl_arena_allocator = new_decl_arena.allocator(); | ||
| 7493 | |||
| 7494 | const new_func = sema.resolveGenericInstantiationType( | 7548 | const new_func = sema.resolveGenericInstantiationType( |
| 7495 | block, | 7549 | block, |
| 7496 | new_decl_arena_allocator, | ||
| 7497 | fn_zir, | 7550 | fn_zir, |
| 7498 | new_decl, | 7551 | new_decl, |
| 7499 | new_decl_index, | 7552 | new_decl_index, |
| 7500 | uncasted_args, | 7553 | uncasted_args, |
| 7501 | module_fn, | 7554 | monomorphed_arg_i, |
| 7502 | new_module_func, | 7555 | module_fn_index, |
| 7503 | namespace, | 7556 | new_module_func_index, |
| 7504 | func_ty_info, | 7557 | namespace_index, |
| 7558 | generic_func_ty, | ||
| 7505 | call_src, | 7559 | call_src, |
| 7506 | bound_arg_src, | 7560 | bound_arg_src, |
| 7507 | ) catch |err| switch (err) { | 7561 | ) catch |err| switch (err) { |
| 7508 | error.GenericPoison, error.ComptimeReturn => { | 7562 | error.GenericPoison, error.ComptimeReturn => { |
| 7509 | new_decl_arena.deinit(); | ||
| 7510 | // Resolving the new function type below will possibly declare more decl dependencies | 7563 | // Resolving the new function type below will possibly declare more decl dependencies |
| 7511 | // and so we remove them all here in case of error. | 7564 | // and so we remove them all here in case of error. |
| 7512 | for (new_decl.dependencies.keys()) |dep_index| { | 7565 | for (new_decl.dependencies.keys()) |dep_index| { |
| ... | @@ -7515,16 +7568,10 @@ fn instantiateGenericCall( | ... | @@ -7515,16 +7568,10 @@ fn instantiateGenericCall( |
| 7515 | } | 7568 | } |
| 7516 | assert(namespace.anon_decls.orderedRemove(new_decl_index)); | 7569 | assert(namespace.anon_decls.orderedRemove(new_decl_index)); |
| 7517 | mod.destroyDecl(new_decl_index); | 7570 | mod.destroyDecl(new_decl_index); |
| 7518 | assert(mod.monomorphed_funcs.remove(new_module_func)); | 7571 | mod.destroyFunc(new_module_func_index); |
| 7519 | gpa.destroy(new_module_func); | ||
| 7520 | return err; | 7572 | return err; |
| 7521 | }, | 7573 | }, |
| 7522 | else => { | 7574 | else => { |
| 7523 | assert(mod.monomorphed_funcs.remove(new_module_func)); | ||
| 7524 | { | ||
| 7525 | errdefer new_decl_arena.deinit(); | ||
| 7526 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 7527 | } | ||
| 7528 | // TODO look up the compile error that happened here and attach a note to it | 7575 | // TODO look up the compile error that happened here and attach a note to it |
| 7529 | // pointing here, at the generic instantiation callsite. | 7576 | // pointing here, at the generic instantiation callsite. |
| 7530 | if (sema.owner_func) |owner_func| { | 7577 | if (sema.owner_func) |owner_func| { |
| ... | @@ -7535,12 +7582,10 @@ fn instantiateGenericCall( | ... | @@ -7535,12 +7582,10 @@ fn instantiateGenericCall( |
| 7535 | return err; | 7582 | return err; |
| 7536 | }, | 7583 | }, |
| 7537 | }; | 7584 | }; |
| 7538 | errdefer new_decl_arena.deinit(); | ||
| 7539 | 7585 | ||
| 7540 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 7541 | break :callee new_func; | 7586 | break :callee new_func; |
| 7542 | } else gop.key_ptr.*; | 7587 | }; |
| 7543 | 7588 | const callee = mod.funcPtr(callee_index); | |
| 7544 | callee.branch_quota = @max(callee.branch_quota, sema.branch_quota); | 7589 | callee.branch_quota = @max(callee.branch_quota, sema.branch_quota); |
| 7545 | 7590 | ||
| 7546 | const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl); | 7591 | const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl); |
| ... | @@ -7548,8 +7593,7 @@ fn instantiateGenericCall( | ... | @@ -7548,8 +7593,7 @@ fn instantiateGenericCall( |
| 7548 | // Make a runtime call to the new function, making sure to omit the comptime args. | 7593 | // Make a runtime call to the new function, making sure to omit the comptime args. |
| 7549 | const comptime_args = callee.comptime_args.?; | 7594 | const comptime_args = callee.comptime_args.?; |
| 7550 | const func_ty = mod.declPtr(callee.owner_decl).ty; | 7595 | const func_ty = mod.declPtr(callee.owner_decl).ty; |
| 7551 | const new_fn_info = func_ty.fnInfo(); | 7596 | const runtime_args_len = @intCast(u32, mod.typeToFunc(func_ty).?.param_types.len); |
| 7552 | const runtime_args_len = @intCast(u32, new_fn_info.param_types.len); | ||
| 7553 | const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len); | 7597 | const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len); |
| 7554 | { | 7598 | { |
| 7555 | var runtime_i: u32 = 0; | 7599 | var runtime_i: u32 = 0; |
| ... | @@ -7565,18 +7609,18 @@ fn instantiateGenericCall( | ... | @@ -7565,18 +7609,18 @@ fn instantiateGenericCall( |
| 7565 | uncasted_args[total_i], | 7609 | uncasted_args[total_i], |
| 7566 | comptime_args[total_i], | 7610 | comptime_args[total_i], |
| 7567 | runtime_args, | 7611 | runtime_args, |
| 7568 | new_fn_info, | 7612 | mod.typeToFunc(func_ty).?, |
| 7569 | &runtime_i, | 7613 | &runtime_i, |
| 7570 | ) catch |err| switch (err) { | 7614 | ) catch |err| switch (err) { |
| 7571 | error.NeededSourceLocation => { | 7615 | error.NeededSourceLocation => { |
| 7572 | const decl = sema.mod.declPtr(block.src_decl); | 7616 | const decl = mod.declPtr(block.src_decl); |
| 7573 | _ = try sema.analyzeGenericCallArg( | 7617 | _ = try sema.analyzeGenericCallArg( |
| 7574 | block, | 7618 | block, |
| 7575 | Module.argSrc(call_src.node_offset.x, sema.gpa, decl, total_i, bound_arg_src), | 7619 | mod.argSrc(call_src.node_offset.x, decl, total_i, bound_arg_src), |
| 7576 | uncasted_args[total_i], | 7620 | uncasted_args[total_i], |
| 7577 | comptime_args[total_i], | 7621 | comptime_args[total_i], |
| 7578 | runtime_args, | 7622 | runtime_args, |
| 7579 | new_fn_info, | 7623 | mod.typeToFunc(func_ty).?, |
| 7580 | &runtime_i, | 7624 | &runtime_i, |
| 7581 | ); | 7625 | ); |
| 7582 | unreachable; | 7626 | unreachable; |
| ... | @@ -7586,16 +7630,16 @@ fn instantiateGenericCall( | ... | @@ -7586,16 +7630,16 @@ fn instantiateGenericCall( |
| 7586 | total_i += 1; | 7630 | total_i += 1; |
| 7587 | } | 7631 | } |
| 7588 | 7632 | ||
| 7589 | try sema.queueFullTypeResolution(new_fn_info.return_type); | 7633 | try sema.queueFullTypeResolution(mod.typeToFunc(func_ty).?.return_type.toType()); |
| 7590 | } | 7634 | } |
| 7591 | 7635 | ||
| 7592 | if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); | 7636 | if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); |
| 7593 | 7637 | ||
| 7594 | if (sema.owner_func != null and new_fn_info.return_type.isError()) { | 7638 | if (sema.owner_func != null and mod.typeToFunc(func_ty).?.return_type.toType().isError(mod)) { |
| 7595 | sema.owner_func.?.calls_or_awaits_errorable_fn = true; | 7639 | sema.owner_func.?.calls_or_awaits_errorable_fn = true; |
| 7596 | } | 7640 | } |
| 7597 | 7641 | ||
| 7598 | try sema.mod.ensureFuncBodyAnalysisQueued(callee); | 7642 | try mod.ensureFuncBodyAnalysisQueued(callee_index); |
| 7599 | 7643 | ||
| 7600 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + | 7644 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 7601 | runtime_args_len); | 7645 | runtime_args_len); |
| ... | @@ -7616,7 +7660,7 @@ fn instantiateGenericCall( | ... | @@ -7616,7 +7660,7 @@ fn instantiateGenericCall( |
| 7616 | if (call_tag == .call_always_tail) { | 7660 | if (call_tag == .call_always_tail) { |
| 7617 | return sema.handleTailCall(block, call_src, func_ty, result); | 7661 | return sema.handleTailCall(block, call_src, func_ty, result); |
| 7618 | } | 7662 | } |
| 7619 | if (new_fn_info.return_type.isNoReturn()) { | 7663 | if (func_ty.fnReturnType(mod).isNoReturn(mod)) { |
| 7620 | _ = try block.addNoOp(.unreach); | 7664 | _ = try block.addNoOp(.unreach); |
| 7621 | return Air.Inst.Ref.unreachable_value; | 7665 | return Air.Inst.Ref.unreachable_value; |
| 7622 | } | 7666 | } |
| ... | @@ -7626,22 +7670,23 @@ fn instantiateGenericCall( | ... | @@ -7626,22 +7670,23 @@ fn instantiateGenericCall( |
| 7626 | fn resolveGenericInstantiationType( | 7670 | fn resolveGenericInstantiationType( |
| 7627 | sema: *Sema, | 7671 | sema: *Sema, |
| 7628 | block: *Block, | 7672 | block: *Block, |
| 7629 | new_decl_arena_allocator: Allocator, | ||
| 7630 | fn_zir: Zir, | 7673 | fn_zir: Zir, |
| 7631 | new_decl: *Decl, | 7674 | new_decl: *Decl, |
| 7632 | new_decl_index: Decl.Index, | 7675 | new_decl_index: Decl.Index, |
| 7633 | uncasted_args: []const Air.Inst.Ref, | 7676 | uncasted_args: []const Air.Inst.Ref, |
| 7634 | module_fn: *Module.Fn, | 7677 | monomorphed_args_len: u32, |
| 7635 | new_module_func: *Module.Fn, | 7678 | module_fn_index: Module.Fn.Index, |
| 7636 | namespace: *Namespace, | 7679 | new_module_func: Module.Fn.Index, |
| 7637 | func_ty_info: Type.Payload.Function.Data, | 7680 | namespace: Namespace.Index, |
| 7681 | generic_func_ty: Type, | ||
| 7638 | call_src: LazySrcLoc, | 7682 | call_src: LazySrcLoc, |
| 7639 | bound_arg_src: ?LazySrcLoc, | 7683 | bound_arg_src: ?LazySrcLoc, |
| 7640 | ) !*Module.Fn { | 7684 | ) !Module.Fn.Index { |
| 7641 | const mod = sema.mod; | 7685 | const mod = sema.mod; |
| 7642 | const gpa = sema.gpa; | 7686 | const gpa = sema.gpa; |
| 7643 | 7687 | ||
| 7644 | const zir_tags = fn_zir.instructions.items(.tag); | 7688 | const zir_tags = fn_zir.instructions.items(.tag); |
| 7689 | const module_fn = mod.funcPtr(module_fn_index); | ||
| 7645 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); | 7690 | const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst); |
| 7646 | 7691 | ||
| 7647 | // Re-run the block that creates the function, with the comptime parameters | 7692 | // Re-run the block that creates the function, with the comptime parameters |
| ... | @@ -7652,23 +7697,26 @@ fn resolveGenericInstantiationType( | ... | @@ -7652,23 +7697,26 @@ fn resolveGenericInstantiationType( |
| 7652 | .mod = mod, | 7697 | .mod = mod, |
| 7653 | .gpa = gpa, | 7698 | .gpa = gpa, |
| 7654 | .arena = sema.arena, | 7699 | .arena = sema.arena, |
| 7655 | .perm_arena = new_decl_arena_allocator, | ||
| 7656 | .code = fn_zir, | 7700 | .code = fn_zir, |
| 7657 | .owner_decl = new_decl, | 7701 | .owner_decl = new_decl, |
| 7658 | .owner_decl_index = new_decl_index, | 7702 | .owner_decl_index = new_decl_index, |
| 7659 | .func = null, | 7703 | .func = null, |
| 7704 | .func_index = .none, | ||
| 7660 | .fn_ret_ty = Type.void, | 7705 | .fn_ret_ty = Type.void, |
| 7661 | .owner_func = null, | 7706 | .owner_func = null, |
| 7662 | .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len), | 7707 | .owner_func_index = .none, |
| 7708 | // TODO: fully migrate functions into InternPool | ||
| 7709 | .comptime_args = try mod.tmp_hack_arena.allocator().alloc(TypedValue, uncasted_args.len), | ||
| 7663 | .comptime_args_fn_inst = module_fn.zir_body_inst, | 7710 | .comptime_args_fn_inst = module_fn.zir_body_inst, |
| 7664 | .preallocated_new_func = new_module_func, | 7711 | .preallocated_new_func = new_module_func.toOptional(), |
| 7665 | .is_generic_instantiation = true, | 7712 | .is_generic_instantiation = true, |
| 7666 | .branch_quota = sema.branch_quota, | 7713 | .branch_quota = sema.branch_quota, |
| 7667 | .branch_count = sema.branch_count, | 7714 | .branch_count = sema.branch_count, |
| 7715 | .comptime_mutable_decls = sema.comptime_mutable_decls, | ||
| 7668 | }; | 7716 | }; |
| 7669 | defer child_sema.deinit(); | 7717 | defer child_sema.deinit(); |
| 7670 | 7718 | ||
| 7671 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope); | 7719 | var wip_captures = try WipCaptureScope.init(gpa, new_decl.src_scope); |
| 7672 | defer wip_captures.deinit(); | 7720 | defer wip_captures.deinit(); |
| 7673 | 7721 | ||
| 7674 | var child_block: Block = .{ | 7722 | var child_block: Block = .{ |
| ... | @@ -7690,18 +7738,19 @@ fn resolveGenericInstantiationType( | ... | @@ -7690,18 +7738,19 @@ fn resolveGenericInstantiationType( |
| 7690 | 7738 | ||
| 7691 | var arg_i: usize = 0; | 7739 | var arg_i: usize = 0; |
| 7692 | for (fn_info.param_body) |inst| { | 7740 | for (fn_info.param_body) |inst| { |
| 7741 | const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?; | ||
| 7693 | var is_comptime = false; | 7742 | var is_comptime = false; |
| 7694 | var is_anytype = false; | 7743 | var is_anytype = false; |
| 7695 | switch (zir_tags[inst]) { | 7744 | switch (zir_tags[inst]) { |
| 7696 | .param => { | 7745 | .param => { |
| 7697 | is_comptime = func_ty_info.paramIsComptime(arg_i); | 7746 | is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i)); |
| 7698 | }, | 7747 | }, |
| 7699 | .param_comptime => { | 7748 | .param_comptime => { |
| 7700 | is_comptime = true; | 7749 | is_comptime = true; |
| 7701 | }, | 7750 | }, |
| 7702 | .param_anytype => { | 7751 | .param_anytype => { |
| 7703 | is_anytype = true; | 7752 | is_anytype = true; |
| 7704 | is_comptime = func_ty_info.paramIsComptime(arg_i); | 7753 | is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i)); |
| 7705 | }, | 7754 | }, |
| 7706 | .param_anytype_comptime => { | 7755 | .param_anytype_comptime => { |
| 7707 | is_anytype = true; | 7756 | is_anytype = true; |
| ... | @@ -7719,8 +7768,8 @@ fn resolveGenericInstantiationType( | ... | @@ -7719,8 +7768,8 @@ fn resolveGenericInstantiationType( |
| 7719 | if (try sema.typeRequiresComptime(arg_ty)) { | 7768 | if (try sema.typeRequiresComptime(arg_ty)) { |
| 7720 | const arg_val = sema.resolveConstValue(block, .unneeded, arg, "") catch |err| switch (err) { | 7769 | const arg_val = sema.resolveConstValue(block, .unneeded, arg, "") catch |err| switch (err) { |
| 7721 | error.NeededSourceLocation => { | 7770 | error.NeededSourceLocation => { |
| 7722 | const decl = sema.mod.declPtr(block.src_decl); | 7771 | const decl = mod.declPtr(block.src_decl); |
| 7723 | const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, arg_i, bound_arg_src); | 7772 | const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src); |
| 7724 | _ = try sema.resolveConstValue(block, arg_src, arg, "argument to parameter with comptime-only type must be comptime-known"); | 7773 | _ = try sema.resolveConstValue(block, arg_src, arg, "argument to parameter with comptime-only type must be comptime-known"); |
| 7725 | unreachable; | 7774 | unreachable; |
| 7726 | }, | 7775 | }, |
| ... | @@ -7752,50 +7801,61 @@ fn resolveGenericInstantiationType( | ... | @@ -7752,50 +7801,61 @@ fn resolveGenericInstantiationType( |
| 7752 | 7801 | ||
| 7753 | const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst); | 7802 | const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst); |
| 7754 | const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable; | 7803 | const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable; |
| 7755 | const new_func = new_func_val.castTag(.function).?.data; | 7804 | const new_func = new_func_val.getFunctionIndex(mod).unwrap().?; |
| 7756 | errdefer new_func.deinit(gpa); | ||
| 7757 | assert(new_func == new_module_func); | 7805 | assert(new_func == new_module_func); |
| 7758 | 7806 | ||
| 7807 | const monomorphed_args_index = @intCast(u32, mod.monomorphed_func_keys.items.len); | ||
| 7808 | const monomorphed_args = try mod.monomorphed_func_keys.addManyAsSlice(gpa, monomorphed_args_len); | ||
| 7809 | var monomorphed_arg_i: u32 = 0; | ||
| 7810 | try mod.monomorphed_funcs.ensureUnusedCapacityContext(gpa, monomorphed_args_len + 1, .{ .mod = mod }); | ||
| 7811 | |||
| 7759 | arg_i = 0; | 7812 | arg_i = 0; |
| 7760 | for (fn_info.param_body) |inst| { | 7813 | for (fn_info.param_body) |inst| { |
| 7814 | const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?; | ||
| 7761 | var is_comptime = false; | 7815 | var is_comptime = false; |
| 7816 | var is_anytype = false; | ||
| 7762 | switch (zir_tags[inst]) { | 7817 | switch (zir_tags[inst]) { |
| 7763 | .param => { | 7818 | .param => { |
| 7764 | is_comptime = func_ty_info.paramIsComptime(arg_i); | 7819 | is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i)); |
| 7765 | }, | 7820 | }, |
| 7766 | .param_comptime => { | 7821 | .param_comptime => { |
| 7767 | is_comptime = true; | 7822 | is_comptime = true; |
| 7768 | }, | 7823 | }, |
| 7769 | .param_anytype => { | 7824 | .param_anytype => { |
| 7770 | is_comptime = func_ty_info.paramIsComptime(arg_i); | 7825 | is_anytype = true; |
| 7826 | is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i)); | ||
| 7771 | }, | 7827 | }, |
| 7772 | .param_anytype_comptime => { | 7828 | .param_anytype_comptime => { |
| 7829 | is_anytype = true; | ||
| 7773 | is_comptime = true; | 7830 | is_comptime = true; |
| 7774 | }, | 7831 | }, |
| 7775 | else => continue, | 7832 | else => continue, |
| 7776 | } | 7833 | } |
| 7777 | 7834 | ||
| 7778 | // We populate the Type here regardless because it is needed by | 7835 | const param_ty = generic_func_ty_info.param_types[arg_i]; |
| 7779 | // `GenericCallAdapter.eql` as well as function body analysis. | 7836 | const is_generic = !is_anytype and param_ty == .generic_poison_type; |
| 7780 | // Whether it is anytype is communicated by `isAnytypeParam`. | 7837 | |
| 7781 | const arg = child_sema.inst_map.get(inst).?; | 7838 | const arg = child_sema.inst_map.get(inst).?; |
| 7782 | const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator); | 7839 | const arg_ty = child_sema.typeOf(arg); |
| 7783 | 7840 | ||
| 7784 | if (try sema.typeRequiresComptime(copied_arg_ty)) { | 7841 | if (is_generic) if (mod.monomorphed_funcs.fetchPutAssumeCapacityContext(.{ |
| 7785 | is_comptime = true; | 7842 | .func = module_fn_index, |
| 7786 | } | 7843 | .args_index = monomorphed_args_index, |
| 7844 | .args_len = monomorphed_arg_i, | ||
| 7845 | }, arg_ty.toIntern(), .{ .mod = mod })) |kv| assert(kv.value == arg_ty.toIntern()); | ||
| 7846 | if (!is_comptime and try sema.typeRequiresComptime(arg_ty)) is_comptime = true; | ||
| 7787 | 7847 | ||
| 7788 | if (is_comptime) { | 7848 | if (is_comptime) { |
| 7789 | const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?; | 7849 | const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?; |
| 7790 | child_sema.comptime_args[arg_i] = .{ | 7850 | monomorphed_args[monomorphed_arg_i] = arg_val.toIntern(); |
| 7791 | .ty = copied_arg_ty, | 7851 | monomorphed_arg_i += 1; |
| 7792 | .val = try arg_val.copy(new_decl_arena_allocator), | 7852 | child_sema.comptime_args[arg_i] = .{ .ty = arg_ty, .val = arg_val }; |
| 7793 | }; | ||
| 7794 | } else { | 7853 | } else { |
| 7795 | child_sema.comptime_args[arg_i] = .{ | 7854 | if (is_anytype or is_generic) { |
| 7796 | .ty = copied_arg_ty, | 7855 | monomorphed_args[monomorphed_arg_i] = try mod.intern(.{ .undef = arg_ty.toIntern() }); |
| 7797 | .val = Value.initTag(.generic_poison), | 7856 | monomorphed_arg_i += 1; |
| 7798 | }; | 7857 | } |
| 7858 | child_sema.comptime_args[arg_i] = .{ .ty = arg_ty, .val = Value.generic_poison }; | ||
| 7799 | } | 7859 | } |
| 7800 | 7860 | ||
| 7801 | arg_i += 1; | 7861 | arg_i += 1; |
| ... | @@ -7804,11 +7864,11 @@ fn resolveGenericInstantiationType( | ... | @@ -7804,11 +7864,11 @@ fn resolveGenericInstantiationType( |
| 7804 | try wip_captures.finalize(); | 7864 | try wip_captures.finalize(); |
| 7805 | 7865 | ||
| 7806 | // Populate the Decl ty/val with the function and its type. | 7866 | // Populate the Decl ty/val with the function and its type. |
| 7807 | new_decl.ty = try child_sema.typeOf(new_func_inst).copy(new_decl_arena_allocator); | 7867 | new_decl.ty = child_sema.typeOf(new_func_inst); |
| 7808 | // If the call evaluated to a return type that requires comptime, never mind | 7868 | // If the call evaluated to a return type that requires comptime, never mind |
| 7809 | // our generic instantiation. Instead we need to perform a comptime call. | 7869 | // our generic instantiation. Instead we need to perform a comptime call. |
| 7810 | const new_fn_info = new_decl.ty.fnInfo(); | 7870 | const new_fn_info = mod.typeToFunc(new_decl.ty).?; |
| 7811 | if (try sema.typeRequiresComptime(new_fn_info.return_type)) { | 7871 | if (try sema.typeRequiresComptime(new_fn_info.return_type.toType())) { |
| 7812 | return error.ComptimeReturn; | 7872 | return error.ComptimeReturn; |
| 7813 | } | 7873 | } |
| 7814 | // Similarly, if the call evaluated to a generic type we need to instead | 7874 | // Similarly, if the call evaluated to a generic type we need to instead |
| ... | @@ -7817,15 +7877,20 @@ fn resolveGenericInstantiationType( | ... | @@ -7817,15 +7877,20 @@ fn resolveGenericInstantiationType( |
| 7817 | return error.GenericPoison; | 7877 | return error.GenericPoison; |
| 7818 | } | 7878 | } |
| 7819 | 7879 | ||
| 7820 | new_decl.val = try Value.Tag.function.create(new_decl_arena_allocator, new_func); | 7880 | new_decl.val = (try mod.intern(.{ .func = .{ |
| 7881 | .ty = new_decl.ty.toIntern(), | ||
| 7882 | .index = new_func, | ||
| 7883 | } })).toValue(); | ||
| 7821 | new_decl.@"align" = 0; | 7884 | new_decl.@"align" = 0; |
| 7822 | new_decl.has_tv = true; | 7885 | new_decl.has_tv = true; |
| 7823 | new_decl.owns_tv = true; | 7886 | new_decl.owns_tv = true; |
| 7824 | new_decl.analysis = .complete; | 7887 | new_decl.analysis = .complete; |
| 7825 | 7888 | ||
| 7826 | log.debug("generic function '{s}' instantiated with type {}", .{ | 7889 | mod.monomorphed_funcs.putAssumeCapacityNoClobberContext(.{ |
| 7827 | new_decl.name, new_decl.ty.fmtDebug(), | 7890 | .func = module_fn_index, |
| 7828 | }); | 7891 | .args_index = monomorphed_args_index, |
| 7892 | .args_len = monomorphed_arg_i, | ||
| 7893 | }, new_decl.val.toIntern(), .{ .mod = mod }); | ||
| 7829 | 7894 | ||
| 7830 | // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field | 7895 | // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field |
| 7831 | // will be populated, ensuring it will have `analyzeBody` called with the ZIR | 7896 | // will be populated, ensuring it will have `analyzeBody` called with the ZIR |
| ... | @@ -7835,46 +7900,46 @@ fn resolveGenericInstantiationType( | ... | @@ -7835,46 +7900,46 @@ fn resolveGenericInstantiationType( |
| 7835 | } | 7900 | } |
| 7836 | 7901 | ||
| 7837 | fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { | 7902 | fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { |
| 7838 | if (!ty.isSimpleTupleOrAnonStruct()) return; | 7903 | const mod = sema.mod; |
| 7839 | const tuple = ty.tupleFields(); | 7904 | const tuple = switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 7840 | for (tuple.values, 0..) |field_val, i| { | 7905 | .anon_struct_type => |tuple| tuple, |
| 7841 | try sema.resolveTupleLazyValues(block, src, tuple.types[i]); | 7906 | else => return, |
| 7842 | if (field_val.tag() == .unreachable_value) continue; | 7907 | }; |
| 7843 | try sema.resolveLazyValue(field_val); | 7908 | for (tuple.types, tuple.values) |field_ty, field_val| { |
| 7909 | try sema.resolveTupleLazyValues(block, src, field_ty.toType()); | ||
| 7910 | if (field_val == .none) continue; | ||
| 7911 | // TODO: mutate in intern pool | ||
| 7912 | _ = try sema.resolveLazyValue(field_val.toValue()); | ||
| 7844 | } | 7913 | } |
| 7845 | } | 7914 | } |
| 7846 | 7915 | ||
| 7847 | fn emitDbgInline( | 7916 | fn emitDbgInline( |
| 7848 | sema: *Sema, | 7917 | sema: *Sema, |
| 7849 | block: *Block, | 7918 | block: *Block, |
| 7850 | old_func: *Module.Fn, | 7919 | old_func: Module.Fn.Index, |
| 7851 | new_func: *Module.Fn, | 7920 | new_func: Module.Fn.Index, |
| 7852 | new_func_ty: Type, | 7921 | new_func_ty: Type, |
| 7853 | tag: Air.Inst.Tag, | 7922 | tag: Air.Inst.Tag, |
| 7854 | ) CompileError!void { | 7923 | ) CompileError!void { |
| 7855 | if (sema.mod.comp.bin_file.options.strip) return; | 7924 | const mod = sema.mod; |
| 7925 | if (mod.comp.bin_file.options.strip) return; | ||
| 7856 | 7926 | ||
| 7857 | // Recursive inline call; no dbg_inline needed. | 7927 | // Recursive inline call; no dbg_inline needed. |
| 7858 | if (old_func == new_func) return; | 7928 | if (old_func == new_func) return; |
| 7859 | 7929 | ||
| 7860 | try sema.air_values.append(sema.gpa, try Value.Tag.function.create(sema.arena, new_func)); | ||
| 7861 | _ = try block.addInst(.{ | 7930 | _ = try block.addInst(.{ |
| 7862 | .tag = tag, | 7931 | .tag = tag, |
| 7863 | .data = .{ .ty_pl = .{ | 7932 | .data = .{ .ty_fn = .{ |
| 7864 | .ty = try sema.addType(new_func_ty), | 7933 | .ty = try sema.addType(new_func_ty), |
| 7865 | .payload = @intCast(u32, sema.air_values.items.len - 1), | 7934 | .func = new_func, |
| 7866 | } }, | 7935 | } }, |
| 7867 | }); | 7936 | }); |
| 7868 | } | 7937 | } |
| 7869 | 7938 | ||
| 7870 | fn zirIntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 7939 | fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 7871 | _ = block; | 7940 | const mod = sema.mod; |
| 7872 | const tracy = trace(@src()); | ||
| 7873 | defer tracy.end(); | ||
| 7874 | |||
| 7875 | const int_type = sema.code.instructions.items(.data)[inst].int_type; | 7941 | const int_type = sema.code.instructions.items(.data)[inst].int_type; |
| 7876 | const ty = try Module.makeIntType(sema.arena, int_type.signedness, int_type.bit_count); | 7942 | const ty = try mod.intType(int_type.signedness, int_type.bit_count); |
| 7877 | |||
| 7878 | return sema.addType(ty); | 7943 | return sema.addType(ty); |
| 7879 | } | 7944 | } |
| 7880 | 7945 | ||
| ... | @@ -7882,43 +7947,46 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro | ... | @@ -7882,43 +7947,46 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 7882 | const tracy = trace(@src()); | 7947 | const tracy = trace(@src()); |
| 7883 | defer tracy.end(); | 7948 | defer tracy.end(); |
| 7884 | 7949 | ||
| 7950 | const mod = sema.mod; | ||
| 7885 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 7951 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 7886 | const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; | 7952 | const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; |
| 7887 | const child_type = try sema.resolveType(block, operand_src, inst_data.operand); | 7953 | const child_type = try sema.resolveType(block, operand_src, inst_data.operand); |
| 7888 | if (child_type.zigTypeTag() == .Opaque) { | 7954 | if (child_type.zigTypeTag(mod) == .Opaque) { |
| 7889 | return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); | 7955 | return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(mod)}); |
| 7890 | } else if (child_type.zigTypeTag() == .Null) { | 7956 | } else if (child_type.zigTypeTag(mod) == .Null) { |
| 7891 | return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)}); | 7957 | return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(mod)}); |
| 7892 | } | 7958 | } |
| 7893 | const opt_type = try Type.optional(sema.arena, child_type); | 7959 | const opt_type = try Type.optional(sema.arena, child_type, mod); |
| 7894 | 7960 | ||
| 7895 | return sema.addType(opt_type); | 7961 | return sema.addType(opt_type); |
| 7896 | } | 7962 | } |
| 7897 | 7963 | ||
| 7898 | fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 7964 | fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 7965 | const mod = sema.mod; | ||
| 7899 | const bin = sema.code.instructions.items(.data)[inst].bin; | 7966 | const bin = sema.code.instructions.items(.data)[inst].bin; |
| 7900 | const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs); | 7967 | const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs); |
| 7901 | assert(indexable_ty.isIndexable()); // validated by a previous instruction | 7968 | assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction |
| 7902 | if (indexable_ty.zigTypeTag() == .Struct) { | 7969 | if (indexable_ty.zigTypeTag(mod) == .Struct) { |
| 7903 | const elem_type = indexable_ty.structFieldType(@enumToInt(bin.rhs)); | 7970 | const elem_type = indexable_ty.structFieldType(@enumToInt(bin.rhs), mod); |
| 7904 | return sema.addType(elem_type); | 7971 | return sema.addType(elem_type); |
| 7905 | } else { | 7972 | } else { |
| 7906 | const elem_type = indexable_ty.elemType2(); | 7973 | const elem_type = indexable_ty.elemType2(mod); |
| 7907 | return sema.addType(elem_type); | 7974 | return sema.addType(elem_type); |
| 7908 | } | 7975 | } |
| 7909 | } | 7976 | } |
| 7910 | 7977 | ||
| 7911 | fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 7978 | fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 7979 | const mod = sema.mod; | ||
| 7912 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 7980 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 7913 | const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 7981 | const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 7914 | const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 7982 | const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 7915 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 7983 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 7916 | const len = try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector length must be comptime-known"); | 7984 | const len = @intCast(u32, try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector length must be comptime-known")); |
| 7917 | const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs); | 7985 | const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs); |
| 7918 | try sema.checkVectorElemType(block, elem_type_src, elem_type); | 7986 | try sema.checkVectorElemType(block, elem_type_src, elem_type); |
| 7919 | const vector_type = try Type.Tag.vector.create(sema.arena, .{ | 7987 | const vector_type = try mod.vectorType(.{ |
| 7920 | .len = @intCast(u32, len), | 7988 | .len = len, |
| 7921 | .elem_type = elem_type, | 7989 | .child = elem_type.toIntern(), |
| 7922 | }); | 7990 | }); |
| 7923 | return sema.addType(vector_type); | 7991 | return sema.addType(vector_type); |
| 7924 | } | 7992 | } |
| ... | @@ -7960,9 +8028,10 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil | ... | @@ -7960,9 +8028,10 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil |
| 7960 | } | 8028 | } |
| 7961 | 8029 | ||
| 7962 | fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src: LazySrcLoc) !void { | 8030 | fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src: LazySrcLoc) !void { |
| 7963 | if (elem_type.zigTypeTag() == .Opaque) { | 8031 | const mod = sema.mod; |
| 7964 | return sema.fail(block, elem_src, "array of opaque type '{}' not allowed", .{elem_type.fmt(sema.mod)}); | 8032 | if (elem_type.zigTypeTag(mod) == .Opaque) { |
| 7965 | } else if (elem_type.zigTypeTag() == .NoReturn) { | 8033 | return sema.fail(block, elem_src, "array of opaque type '{}' not allowed", .{elem_type.fmt(mod)}); |
| 8034 | } else if (elem_type.zigTypeTag(mod) == .NoReturn) { | ||
| 7966 | return sema.fail(block, elem_src, "array of 'noreturn' not allowed", .{}); | 8035 | return sema.fail(block, elem_src, "array of 'noreturn' not allowed", .{}); |
| 7967 | } | 8036 | } |
| 7968 | } | 8037 | } |
| ... | @@ -7975,9 +8044,10 @@ fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro | ... | @@ -7975,9 +8044,10 @@ fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 7975 | if (true) { | 8044 | if (true) { |
| 7976 | return sema.failWithUseOfAsync(block, inst_data.src()); | 8045 | return sema.failWithUseOfAsync(block, inst_data.src()); |
| 7977 | } | 8046 | } |
| 8047 | const mod = sema.mod; | ||
| 7978 | const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node }; | 8048 | const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node }; |
| 7979 | const return_type = try sema.resolveType(block, operand_src, inst_data.operand); | 8049 | const return_type = try sema.resolveType(block, operand_src, inst_data.operand); |
| 7980 | const anyframe_type = try Type.Tag.anyframe_T.create(sema.arena, return_type); | 8050 | const anyframe_type = try mod.anyframeType(return_type); |
| 7981 | 8051 | ||
| 7982 | return sema.addType(anyframe_type); | 8052 | return sema.addType(anyframe_type); |
| 7983 | } | 8053 | } |
| ... | @@ -7986,6 +8056,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -7986,6 +8056,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 7986 | const tracy = trace(@src()); | 8056 | const tracy = trace(@src()); |
| 7987 | defer tracy.end(); | 8057 | defer tracy.end(); |
| 7988 | 8058 | ||
| 8059 | const mod = sema.mod; | ||
| 7989 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 8060 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 7990 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 8061 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 7991 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | 8062 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| ... | @@ -7993,50 +8064,48 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -7993,50 +8064,48 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 7993 | const error_set = try sema.resolveType(block, lhs_src, extra.lhs); | 8064 | const error_set = try sema.resolveType(block, lhs_src, extra.lhs); |
| 7994 | const payload = try sema.resolveType(block, rhs_src, extra.rhs); | 8065 | const payload = try sema.resolveType(block, rhs_src, extra.rhs); |
| 7995 | 8066 | ||
| 7996 | if (error_set.zigTypeTag() != .ErrorSet) { | 8067 | if (error_set.zigTypeTag(mod) != .ErrorSet) { |
| 7997 | return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{ | 8068 | return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{ |
| 7998 | error_set.fmt(sema.mod), | 8069 | error_set.fmt(mod), |
| 7999 | }); | 8070 | }); |
| 8000 | } | 8071 | } |
| 8001 | try sema.validateErrorUnionPayloadType(block, payload, rhs_src); | 8072 | try sema.validateErrorUnionPayloadType(block, payload, rhs_src); |
| 8002 | const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod); | 8073 | const err_union_ty = try mod.errorUnionType(error_set, payload); |
| 8003 | return sema.addType(err_union_ty); | 8074 | return sema.addType(err_union_ty); |
| 8004 | } | 8075 | } |
| 8005 | 8076 | ||
| 8006 | fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, payload_src: LazySrcLoc) !void { | 8077 | fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, payload_src: LazySrcLoc) !void { |
| 8007 | if (payload_ty.zigTypeTag() == .Opaque) { | 8078 | const mod = sema.mod; |
| 8079 | if (payload_ty.zigTypeTag(mod) == .Opaque) { | ||
| 8008 | return sema.fail(block, payload_src, "error union with payload of opaque type '{}' not allowed", .{ | 8080 | return sema.fail(block, payload_src, "error union with payload of opaque type '{}' not allowed", .{ |
| 8009 | payload_ty.fmt(sema.mod), | 8081 | payload_ty.fmt(mod), |
| 8010 | }); | 8082 | }); |
| 8011 | } else if (payload_ty.zigTypeTag() == .ErrorSet) { | 8083 | } else if (payload_ty.zigTypeTag(mod) == .ErrorSet) { |
| 8012 | return sema.fail(block, payload_src, "error union with payload of error set type '{}' not allowed", .{ | 8084 | return sema.fail(block, payload_src, "error union with payload of error set type '{}' not allowed", .{ |
| 8013 | payload_ty.fmt(sema.mod), | 8085 | payload_ty.fmt(mod), |
| 8014 | }); | 8086 | }); |
| 8015 | } | 8087 | } |
| 8016 | } | 8088 | } |
| 8017 | 8089 | ||
| 8018 | fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 8090 | fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8019 | _ = block; | 8091 | _ = block; |
| 8020 | const tracy = trace(@src()); | 8092 | const mod = sema.mod; |
| 8021 | defer tracy.end(); | ||
| 8022 | |||
| 8023 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | 8093 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 8024 | 8094 | const name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); | |
| 8025 | // Create an anonymous error set type with only this error value, and return the value. | 8095 | _ = try mod.getErrorValue(name); |
| 8026 | const kv = try sema.mod.getErrorValue(inst_data.get(sema.code)); | 8096 | // Create an error set type with only this error value, and return the value. |
| 8027 | const result_type = try Type.Tag.error_set_single.create(sema.arena, kv.key); | 8097 | const error_set_type = try mod.singleErrorSetType(name); |
| 8028 | return sema.addConstant( | 8098 | return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ |
| 8029 | result_type, | 8099 | .ty = error_set_type.toIntern(), |
| 8030 | try Value.Tag.@"error".create(sema.arena, .{ | 8100 | .name = name, |
| 8031 | .name = kv.key, | 8101 | } })).toValue()); |
| 8032 | }), | ||
| 8033 | ); | ||
| 8034 | } | 8102 | } |
| 8035 | 8103 | ||
| 8036 | fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 8104 | fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 8037 | const tracy = trace(@src()); | 8105 | const tracy = trace(@src()); |
| 8038 | defer tracy.end(); | 8106 | defer tracy.end(); |
| 8039 | 8107 | ||
| 8108 | const mod = sema.mod; | ||
| 8040 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | 8109 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 8041 | const src = LazySrcLoc.nodeOffset(extra.node); | 8110 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 8042 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 8111 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| ... | @@ -8044,34 +8113,26 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -8044,34 +8113,26 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 8044 | const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src); | 8113 | const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src); |
| 8045 | 8114 | ||
| 8046 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 8115 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 8047 | if (val.isUndef()) { | 8116 | if (val.isUndef(mod)) { |
| 8048 | return sema.addConstUndef(Type.err_int); | 8117 | return sema.addConstUndef(Type.err_int); |
| 8049 | } | 8118 | } |
| 8050 | switch (val.tag()) { | 8119 | const err_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; |
| 8051 | .@"error" => { | 8120 | return sema.addConstant(Type.err_int, try mod.intValue( |
| 8052 | const payload = try sema.arena.create(Value.Payload.U64); | 8121 | Type.err_int, |
| 8053 | payload.* = .{ | 8122 | try mod.getErrorValue(err_name), |
| 8054 | .base = .{ .tag = .int_u64 }, | 8123 | )); |
| 8055 | .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value, | ||
| 8056 | }; | ||
| 8057 | return sema.addConstant(Type.err_int, Value.initPayload(&payload.base)); | ||
| 8058 | }, | ||
| 8059 | |||
| 8060 | // This is not a valid combination with the type `anyerror`. | ||
| 8061 | .the_only_possible_value => unreachable, | ||
| 8062 | |||
| 8063 | // Assume it's already encoded as an integer. | ||
| 8064 | else => return sema.addConstant(Type.err_int, val), | ||
| 8065 | } | ||
| 8066 | } | 8124 | } |
| 8067 | 8125 | ||
| 8068 | const op_ty = sema.typeOf(uncasted_operand); | 8126 | const op_ty = sema.typeOf(uncasted_operand); |
| 8069 | try sema.resolveInferredErrorSetTy(block, src, op_ty); | 8127 | try sema.resolveInferredErrorSetTy(block, src, op_ty); |
| 8070 | if (!op_ty.isAnyError()) { | 8128 | if (!op_ty.isAnyError(mod)) { |
| 8071 | const names = op_ty.errorSetNames(); | 8129 | const names = op_ty.errorSetNames(mod); |
| 8072 | switch (names.len) { | 8130 | switch (names.len) { |
| 8073 | 0 => return sema.addConstant(Type.err_int, Value.zero), | 8131 | 0 => return sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 0)), |
| 8074 | 1 => return sema.addIntUnsigned(Type.err_int, sema.mod.global_error_set.get(names[0]).?), | 8132 | 1 => { |
| 8133 | const int = @intCast(Module.ErrorInt, mod.global_error_set.getIndex(names[0]).?); | ||
| 8134 | return sema.addIntUnsigned(Type.err_int, int); | ||
| 8135 | }, | ||
| 8075 | else => {}, | 8136 | else => {}, |
| 8076 | } | 8137 | } |
| 8077 | } | 8138 | } |
| ... | @@ -8084,28 +8145,26 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -8084,28 +8145,26 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 8084 | const tracy = trace(@src()); | 8145 | const tracy = trace(@src()); |
| 8085 | defer tracy.end(); | 8146 | defer tracy.end(); |
| 8086 | 8147 | ||
| 8148 | const mod = sema.mod; | ||
| 8087 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | 8149 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 8088 | const src = LazySrcLoc.nodeOffset(extra.node); | 8150 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 8089 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 8151 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 8090 | const uncasted_operand = try sema.resolveInst(extra.operand); | 8152 | const uncasted_operand = try sema.resolveInst(extra.operand); |
| 8091 | const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src); | 8153 | const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src); |
| 8092 | const target = sema.mod.getTarget(); | ||
| 8093 | 8154 | ||
| 8094 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { | 8155 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { |
| 8095 | const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(target)); | 8156 | const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(mod)); |
| 8096 | if (int > sema.mod.global_error_set.count() or int == 0) | 8157 | if (int > mod.global_error_set.count() or int == 0) |
| 8097 | return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int}); | 8158 | return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int}); |
| 8098 | const payload = try sema.arena.create(Value.Payload.Error); | 8159 | return sema.addConstant(Type.anyerror, (try mod.intern(.{ .err = .{ |
| 8099 | payload.* = .{ | 8160 | .ty = .anyerror_type, |
| 8100 | .base = .{ .tag = .@"error" }, | 8161 | .name = mod.global_error_set.keys()[int], |
| 8101 | .data = .{ .name = sema.mod.error_name_list.items[int] }, | 8162 | } })).toValue()); |
| 8102 | }; | ||
| 8103 | return sema.addConstant(Type.anyerror, Value.initPayload(&payload.base)); | ||
| 8104 | } | 8163 | } |
| 8105 | try sema.requireRuntimeBlock(block, src, operand_src); | 8164 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 8106 | if (block.wantSafety()) { | 8165 | if (block.wantSafety()) { |
| 8107 | const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand); | 8166 | const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand); |
| 8108 | const zero_val = try sema.addConstant(Type.err_int, Value.zero); | 8167 | const zero_val = try sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 0)); |
| 8109 | const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val); | 8168 | const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val); |
| 8110 | const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero); | 8169 | const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero); |
| 8111 | try sema.addSafetyCheck(block, ok, .invalid_error_code); | 8170 | try sema.addSafetyCheck(block, ok, .invalid_error_code); |
| ... | @@ -8123,6 +8182,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -8123,6 +8182,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 8123 | const tracy = trace(@src()); | 8182 | const tracy = trace(@src()); |
| 8124 | defer tracy.end(); | 8183 | defer tracy.end(); |
| 8125 | 8184 | ||
| 8185 | const mod = sema.mod; | ||
| 8126 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 8186 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 8127 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 8187 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 8128 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 8188 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| ... | @@ -8130,7 +8190,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -8130,7 +8190,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 8130 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | 8190 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| 8131 | const lhs = try sema.resolveInst(extra.lhs); | 8191 | const lhs = try sema.resolveInst(extra.lhs); |
| 8132 | const rhs = try sema.resolveInst(extra.rhs); | 8192 | const rhs = try sema.resolveInst(extra.rhs); |
| 8133 | if (sema.typeOf(lhs).zigTypeTag() == .Bool and sema.typeOf(rhs).zigTypeTag() == .Bool) { | 8193 | if (sema.typeOf(lhs).zigTypeTag(mod) == .Bool and sema.typeOf(rhs).zigTypeTag(mod) == .Bool) { |
| 8134 | const msg = msg: { | 8194 | const msg = msg: { |
| 8135 | const msg = try sema.errMsg(block, lhs_src, "expected error set type, found 'bool'", .{}); | 8195 | const msg = try sema.errMsg(block, lhs_src, "expected error set type, found 'bool'", .{}); |
| 8136 | errdefer msg.destroy(sema.gpa); | 8196 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -8141,32 +8201,32 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -8141,32 +8201,32 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 8141 | } | 8201 | } |
| 8142 | const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs); | 8202 | const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs); |
| 8143 | const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs); | 8203 | const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs); |
| 8144 | if (lhs_ty.zigTypeTag() != .ErrorSet) | 8204 | if (lhs_ty.zigTypeTag(mod) != .ErrorSet) |
| 8145 | return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(sema.mod)}); | 8205 | return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(mod)}); |
| 8146 | if (rhs_ty.zigTypeTag() != .ErrorSet) | 8206 | if (rhs_ty.zigTypeTag(mod) != .ErrorSet) |
| 8147 | return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(sema.mod)}); | 8207 | return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(mod)}); |
| 8148 | 8208 | ||
| 8149 | // Anything merged with anyerror is anyerror. | 8209 | // Anything merged with anyerror is anyerror. |
| 8150 | if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror) { | 8210 | if (lhs_ty.toIntern() == .anyerror_type or rhs_ty.toIntern() == .anyerror_type) { |
| 8151 | return Air.Inst.Ref.anyerror_type; | 8211 | return Air.Inst.Ref.anyerror_type; |
| 8152 | } | 8212 | } |
| 8153 | 8213 | ||
| 8154 | if (lhs_ty.castTag(.error_set_inferred)) |payload| { | 8214 | if (mod.typeToInferredErrorSetIndex(lhs_ty).unwrap()) |ies_index| { |
| 8155 | try sema.resolveInferredErrorSet(block, src, payload.data); | 8215 | try sema.resolveInferredErrorSet(block, src, ies_index); |
| 8156 | // isAnyError might have changed from a false negative to a true positive after resolution. | 8216 | // isAnyError might have changed from a false negative to a true positive after resolution. |
| 8157 | if (lhs_ty.isAnyError()) { | 8217 | if (lhs_ty.isAnyError(mod)) { |
| 8158 | return Air.Inst.Ref.anyerror_type; | 8218 | return Air.Inst.Ref.anyerror_type; |
| 8159 | } | 8219 | } |
| 8160 | } | 8220 | } |
| 8161 | if (rhs_ty.castTag(.error_set_inferred)) |payload| { | 8221 | if (mod.typeToInferredErrorSetIndex(rhs_ty).unwrap()) |ies_index| { |
| 8162 | try sema.resolveInferredErrorSet(block, src, payload.data); | 8222 | try sema.resolveInferredErrorSet(block, src, ies_index); |
| 8163 | // isAnyError might have changed from a false negative to a true positive after resolution. | 8223 | // isAnyError might have changed from a false negative to a true positive after resolution. |
| 8164 | if (rhs_ty.isAnyError()) { | 8224 | if (rhs_ty.isAnyError(mod)) { |
| 8165 | return Air.Inst.Ref.anyerror_type; | 8225 | return Air.Inst.Ref.anyerror_type; |
| 8166 | } | 8226 | } |
| 8167 | } | 8227 | } |
| 8168 | 8228 | ||
| 8169 | const err_set_ty = try lhs_ty.errorSetMerge(sema.arena, rhs_ty); | 8229 | const err_set_ty = try sema.errorSetMerge(lhs_ty, rhs_ty); |
| 8170 | return sema.addType(err_set_ty); | 8230 | return sema.addType(err_set_ty); |
| 8171 | } | 8231 | } |
| 8172 | 8232 | ||
| ... | @@ -8175,27 +8235,27 @@ fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -8175,27 +8235,27 @@ fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8175 | const tracy = trace(@src()); | 8235 | const tracy = trace(@src()); |
| 8176 | defer tracy.end(); | 8236 | defer tracy.end(); |
| 8177 | 8237 | ||
| 8238 | const mod = sema.mod; | ||
| 8178 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | 8239 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 8179 | const duped_name = try sema.arena.dupe(u8, inst_data.get(sema.code)); | 8240 | const name = inst_data.get(sema.code); |
| 8180 | return sema.addConstant( | 8241 | return sema.addConstant(.{ .ip_index = .enum_literal_type }, (try mod.intern(.{ |
| 8181 | Type.initTag(.enum_literal), | 8242 | .enum_literal = try mod.intern_pool.getOrPutString(sema.gpa, name), |
| 8182 | try Value.Tag.enum_literal.create(sema.arena, duped_name), | 8243 | })).toValue()); |
| 8183 | ); | ||
| 8184 | } | 8244 | } |
| 8185 | 8245 | ||
| 8186 | fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 8246 | fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8187 | const arena = sema.arena; | 8247 | const mod = sema.mod; |
| 8188 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 8248 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 8189 | const src = inst_data.src(); | 8249 | const src = inst_data.src(); |
| 8190 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 8250 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 8191 | const operand = try sema.resolveInst(inst_data.operand); | 8251 | const operand = try sema.resolveInst(inst_data.operand); |
| 8192 | const operand_ty = sema.typeOf(operand); | 8252 | const operand_ty = sema.typeOf(operand); |
| 8193 | 8253 | ||
| 8194 | const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag()) { | 8254 | const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(mod)) { |
| 8195 | .Enum => operand, | 8255 | .Enum => operand, |
| 8196 | .Union => blk: { | 8256 | .Union => blk: { |
| 8197 | const union_ty = try sema.resolveTypeFields(operand_ty); | 8257 | const union_ty = try sema.resolveTypeFields(operand_ty); |
| 8198 | const tag_ty = union_ty.unionTagType() orelse { | 8258 | const tag_ty = union_ty.unionTagType(mod) orelse { |
| 8199 | return sema.fail( | 8259 | return sema.fail( |
| 8200 | block, | 8260 | block, |
| 8201 | operand_src, | 8261 | operand_src, |
| ... | @@ -8207,22 +8267,20 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -8207,22 +8267,20 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8207 | }, | 8267 | }, |
| 8208 | else => { | 8268 | else => { |
| 8209 | return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{ | 8269 | return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{ |
| 8210 | operand_ty.fmt(sema.mod), | 8270 | operand_ty.fmt(mod), |
| 8211 | }); | 8271 | }); |
| 8212 | }, | 8272 | }, |
| 8213 | }; | 8273 | }; |
| 8214 | const enum_tag_ty = sema.typeOf(enum_tag); | 8274 | const enum_tag_ty = sema.typeOf(enum_tag); |
| 8215 | 8275 | ||
| 8216 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | 8276 | const int_tag_ty = enum_tag_ty.intTagType(mod); |
| 8217 | const int_tag_ty = try enum_tag_ty.intTagType(&int_tag_type_buffer).copy(arena); | ||
| 8218 | 8277 | ||
| 8219 | if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| { | 8278 | if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| { |
| 8220 | return sema.addConstant(int_tag_ty, opv); | 8279 | return sema.addConstant(int_tag_ty, try mod.getCoerced(opv, int_tag_ty)); |
| 8221 | } | 8280 | } |
| 8222 | 8281 | ||
| 8223 | if (try sema.resolveMaybeUndefVal(enum_tag)) |enum_tag_val| { | 8282 | if (try sema.resolveMaybeUndefVal(enum_tag)) |enum_tag_val| { |
| 8224 | var buffer: Value.Payload.U64 = undefined; | 8283 | const val = try enum_tag_val.enumToInt(enum_tag_ty, mod); |
| 8225 | const val = enum_tag_val.enumToInt(enum_tag_ty, &buffer); | ||
| 8226 | return sema.addConstant(int_tag_ty, try val.copy(sema.arena)); | 8284 | return sema.addConstant(int_tag_ty, try val.copy(sema.arena)); |
| 8227 | } | 8285 | } |
| 8228 | 8286 | ||
| ... | @@ -8231,6 +8289,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -8231,6 +8289,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8231 | } | 8289 | } |
| 8232 | 8290 | ||
| 8233 | fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 8291 | fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8292 | const mod = sema.mod; | ||
| 8234 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 8293 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 8235 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 8294 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 8236 | const src = inst_data.src(); | 8295 | const src = inst_data.src(); |
| ... | @@ -8239,24 +8298,23 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -8239,24 +8298,23 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8239 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); | 8298 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 8240 | const operand = try sema.resolveInst(extra.rhs); | 8299 | const operand = try sema.resolveInst(extra.rhs); |
| 8241 | 8300 | ||
| 8242 | if (dest_ty.zigTypeTag() != .Enum) { | 8301 | if (dest_ty.zigTypeTag(mod) != .Enum) { |
| 8243 | return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(sema.mod)}); | 8302 | return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(mod)}); |
| 8244 | } | 8303 | } |
| 8245 | _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand)); | 8304 | _ = try sema.checkIntType(block, operand_src, sema.typeOf(operand)); |
| 8246 | 8305 | ||
| 8247 | if (try sema.resolveMaybeUndefVal(operand)) |int_val| { | 8306 | if (try sema.resolveMaybeUndefVal(operand)) |int_val| { |
| 8248 | if (dest_ty.isNonexhaustiveEnum()) { | 8307 | if (dest_ty.isNonexhaustiveEnum(mod)) { |
| 8249 | var buffer: Type.Payload.Bits = undefined; | 8308 | const int_tag_ty = dest_ty.intTagType(mod); |
| 8250 | const int_tag_ty = dest_ty.intTagType(&buffer); | ||
| 8251 | if (try sema.intFitsInType(int_val, int_tag_ty, null)) { | 8309 | if (try sema.intFitsInType(int_val, int_tag_ty, null)) { |
| 8252 | return sema.addConstant(dest_ty, int_val); | 8310 | return sema.addConstant(dest_ty, try mod.getCoerced(int_val, dest_ty)); |
| 8253 | } | 8311 | } |
| 8254 | const msg = msg: { | 8312 | const msg = msg: { |
| 8255 | const msg = try sema.errMsg( | 8313 | const msg = try sema.errMsg( |
| 8256 | block, | 8314 | block, |
| 8257 | src, | 8315 | src, |
| 8258 | "int value '{}' out of range of non-exhaustive enum '{}'", | 8316 | "int value '{}' out of range of non-exhaustive enum '{}'", |
| 8259 | .{ int_val.fmtValue(sema.typeOf(operand), sema.mod), dest_ty.fmt(sema.mod) }, | 8317 | .{ int_val.fmtValue(sema.typeOf(operand), mod), dest_ty.fmt(mod) }, |
| 8260 | ); | 8318 | ); |
| 8261 | errdefer msg.destroy(sema.gpa); | 8319 | errdefer msg.destroy(sema.gpa); |
| 8262 | try sema.addDeclaredHereNote(msg, dest_ty); | 8320 | try sema.addDeclaredHereNote(msg, dest_ty); |
| ... | @@ -8264,7 +8322,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -8264,7 +8322,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8264 | }; | 8322 | }; |
| 8265 | return sema.failWithOwnedErrorMsg(msg); | 8323 | return sema.failWithOwnedErrorMsg(msg); |
| 8266 | } | 8324 | } |
| 8267 | if (int_val.isUndef()) { | 8325 | if (int_val.isUndef(mod)) { |
| 8268 | return sema.failWithUseOfUndef(block, operand_src); | 8326 | return sema.failWithUseOfUndef(block, operand_src); |
| 8269 | } | 8327 | } |
| 8270 | if (!(try sema.enumHasInt(dest_ty, int_val))) { | 8328 | if (!(try sema.enumHasInt(dest_ty, int_val))) { |
| ... | @@ -8273,7 +8331,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -8273,7 +8331,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8273 | block, | 8331 | block, |
| 8274 | src, | 8332 | src, |
| 8275 | "enum '{}' has no tag with value '{}'", | 8333 | "enum '{}' has no tag with value '{}'", |
| 8276 | .{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) }, | 8334 | .{ dest_ty.fmt(mod), int_val.fmtValue(sema.typeOf(operand), mod) }, |
| 8277 | ); | 8335 | ); |
| 8278 | errdefer msg.destroy(sema.gpa); | 8336 | errdefer msg.destroy(sema.gpa); |
| 8279 | try sema.addDeclaredHereNote(msg, dest_ty); | 8337 | try sema.addDeclaredHereNote(msg, dest_ty); |
| ... | @@ -8281,7 +8339,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -8281,7 +8339,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8281 | }; | 8339 | }; |
| 8282 | return sema.failWithOwnedErrorMsg(msg); | 8340 | return sema.failWithOwnedErrorMsg(msg); |
| 8283 | } | 8341 | } |
| 8284 | return sema.addConstant(dest_ty, int_val); | 8342 | return sema.addConstant(dest_ty, try mod.getCoerced(int_val, dest_ty)); |
| 8285 | } | 8343 | } |
| 8286 | 8344 | ||
| 8287 | if (try sema.typeHasOnePossibleValue(dest_ty)) |opv| { | 8345 | if (try sema.typeHasOnePossibleValue(dest_ty)) |opv| { |
| ... | @@ -8295,8 +8353,8 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -8295,8 +8353,8 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 8295 | 8353 | ||
| 8296 | try sema.requireRuntimeBlock(block, src, operand_src); | 8354 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 8297 | const result = try block.addTyOp(.intcast, dest_ty, operand); | 8355 | const result = try block.addTyOp(.intcast, dest_ty, operand); |
| 8298 | if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and | 8356 | if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum(mod) and |
| 8299 | sema.mod.backendSupportsFeature(.is_named_enum_value)) | 8357 | mod.backendSupportsFeature(.is_named_enum_value)) |
| 8300 | { | 8358 | { |
| 8301 | const ok = try block.addUnOp(.is_named_enum_value, result); | 8359 | const ok = try block.addUnOp(.is_named_enum_value, result); |
| 8302 | try sema.addSafetyCheck(block, ok, .invalid_enum_value); | 8360 | try sema.addSafetyCheck(block, ok, .invalid_enum_value); |
| ... | @@ -8329,49 +8387,44 @@ fn analyzeOptionalPayloadPtr( | ... | @@ -8329,49 +8387,44 @@ fn analyzeOptionalPayloadPtr( |
| 8329 | safety_check: bool, | 8387 | safety_check: bool, |
| 8330 | initializing: bool, | 8388 | initializing: bool, |
| 8331 | ) CompileError!Air.Inst.Ref { | 8389 | ) CompileError!Air.Inst.Ref { |
| 8390 | const mod = sema.mod; | ||
| 8332 | const optional_ptr_ty = sema.typeOf(optional_ptr); | 8391 | const optional_ptr_ty = sema.typeOf(optional_ptr); |
| 8333 | assert(optional_ptr_ty.zigTypeTag() == .Pointer); | 8392 | assert(optional_ptr_ty.zigTypeTag(mod) == .Pointer); |
| 8334 | 8393 | ||
| 8335 | const opt_type = optional_ptr_ty.elemType(); | 8394 | const opt_type = optional_ptr_ty.childType(mod); |
| 8336 | if (opt_type.zigTypeTag() != .Optional) { | 8395 | if (opt_type.zigTypeTag(mod) != .Optional) { |
| 8337 | return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(sema.mod)}); | 8396 | return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(mod)}); |
| 8338 | } | 8397 | } |
| 8339 | 8398 | ||
| 8340 | const child_type = try opt_type.optionalChildAlloc(sema.arena); | 8399 | const child_type = opt_type.optionalChild(mod); |
| 8341 | const child_pointer = try Type.ptr(sema.arena, sema.mod, .{ | 8400 | const child_pointer = try Type.ptr(sema.arena, mod, .{ |
| 8342 | .pointee_type = child_type, | 8401 | .pointee_type = child_type, |
| 8343 | .mutable = !optional_ptr_ty.isConstPtr(), | 8402 | .mutable = !optional_ptr_ty.isConstPtr(mod), |
| 8344 | .@"addrspace" = optional_ptr_ty.ptrAddressSpace(), | 8403 | .@"addrspace" = optional_ptr_ty.ptrAddressSpace(mod), |
| 8345 | }); | 8404 | }); |
| 8346 | 8405 | ||
| 8347 | if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| { | 8406 | if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| { |
| 8348 | if (initializing) { | 8407 | if (initializing) { |
| 8349 | if (!ptr_val.isComptimeMutablePtr()) { | 8408 | if (!ptr_val.isComptimeMutablePtr(mod)) { |
| 8350 | // If the pointer resulting from this function was stored at comptime, | 8409 | // If the pointer resulting from this function was stored at comptime, |
| 8351 | // the optional non-null bit would be set that way. But in this case, | 8410 | // the optional non-null bit would be set that way. But in this case, |
| 8352 | // we need to emit a runtime instruction to do it. | 8411 | // we need to emit a runtime instruction to do it. |
| 8353 | _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr); | 8412 | _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr); |
| 8354 | } | 8413 | } |
| 8355 | return sema.addConstant( | 8414 | return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{ |
| 8356 | child_pointer, | 8415 | .ty = child_pointer.toIntern(), |
| 8357 | try Value.Tag.opt_payload_ptr.create(sema.arena, .{ | 8416 | .addr = .{ .opt_payload = ptr_val.toIntern() }, |
| 8358 | .container_ptr = ptr_val, | 8417 | } })).toValue()); |
| 8359 | .container_ty = optional_ptr_ty.childType(), | ||
| 8360 | }), | ||
| 8361 | ); | ||
| 8362 | } | 8418 | } |
| 8363 | if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| { | 8419 | if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| { |
| 8364 | if (val.isNull()) { | 8420 | if (val.isNull(mod)) { |
| 8365 | return sema.fail(block, src, "unable to unwrap null", .{}); | 8421 | return sema.fail(block, src, "unable to unwrap null", .{}); |
| 8366 | } | 8422 | } |
| 8367 | // The same Value represents the pointer to the optional and the payload. | 8423 | // The same Value represents the pointer to the optional and the payload. |
| 8368 | return sema.addConstant( | 8424 | return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{ |
| 8369 | child_pointer, | 8425 | .ty = child_pointer.toIntern(), |
| 8370 | try Value.Tag.opt_payload_ptr.create(sema.arena, .{ | 8426 | .addr = .{ .opt_payload = ptr_val.toIntern() }, |
| 8371 | .container_ptr = ptr_val, | 8427 | } })).toValue()); |
| 8372 | .container_ty = optional_ptr_ty.childType(), | ||
| 8373 | }), | ||
| 8374 | ); | ||
| 8375 | } | 8428 | } |
| 8376 | } | 8429 | } |
| 8377 | 8430 | ||
| ... | @@ -8397,21 +8450,22 @@ fn zirOptionalPayload( | ... | @@ -8397,21 +8450,22 @@ fn zirOptionalPayload( |
| 8397 | const tracy = trace(@src()); | 8450 | const tracy = trace(@src()); |
| 8398 | defer tracy.end(); | 8451 | defer tracy.end(); |
| 8399 | 8452 | ||
| 8453 | const mod = sema.mod; | ||
| 8400 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 8454 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 8401 | const src = inst_data.src(); | 8455 | const src = inst_data.src(); |
| 8402 | const operand = try sema.resolveInst(inst_data.operand); | 8456 | const operand = try sema.resolveInst(inst_data.operand); |
| 8403 | const operand_ty = sema.typeOf(operand); | 8457 | const operand_ty = sema.typeOf(operand); |
| 8404 | const result_ty = switch (operand_ty.zigTypeTag()) { | 8458 | const result_ty = switch (operand_ty.zigTypeTag(mod)) { |
| 8405 | .Optional => try operand_ty.optionalChildAlloc(sema.arena), | 8459 | .Optional => operand_ty.optionalChild(mod), |
| 8406 | .Pointer => t: { | 8460 | .Pointer => t: { |
| 8407 | if (operand_ty.ptrSize() != .C) { | 8461 | if (operand_ty.ptrSize(mod) != .C) { |
| 8408 | return sema.failWithExpectedOptionalType(block, src, operand_ty); | 8462 | return sema.failWithExpectedOptionalType(block, src, operand_ty); |
| 8409 | } | 8463 | } |
| 8410 | // TODO https://github.com/ziglang/zig/issues/6597 | 8464 | // TODO https://github.com/ziglang/zig/issues/6597 |
| 8411 | if (true) break :t operand_ty; | 8465 | if (true) break :t operand_ty; |
| 8412 | const ptr_info = operand_ty.ptrInfo().data; | 8466 | const ptr_info = operand_ty.ptrInfo(mod); |
| 8413 | break :t try Type.ptr(sema.arena, sema.mod, .{ | 8467 | break :t try Type.ptr(sema.arena, mod, .{ |
| 8414 | .pointee_type = try ptr_info.pointee_type.copy(sema.arena), | 8468 | .pointee_type = ptr_info.pointee_type, |
| 8415 | .@"align" = ptr_info.@"align", | 8469 | .@"align" = ptr_info.@"align", |
| 8416 | .@"addrspace" = ptr_info.@"addrspace", | 8470 | .@"addrspace" = ptr_info.@"addrspace", |
| 8417 | .mutable = ptr_info.mutable, | 8471 | .mutable = ptr_info.mutable, |
| ... | @@ -8424,13 +8478,10 @@ fn zirOptionalPayload( | ... | @@ -8424,13 +8478,10 @@ fn zirOptionalPayload( |
| 8424 | }; | 8478 | }; |
| 8425 | 8479 | ||
| 8426 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { | 8480 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { |
| 8427 | if (val.isNull()) { | 8481 | return if (val.optionalValue(mod)) |payload| |
| 8428 | return sema.fail(block, src, "unable to unwrap null", .{}); | 8482 | sema.addConstant(result_ty, payload) |
| 8429 | } | 8483 | else |
| 8430 | if (val.castTag(.opt_payload)) |payload| { | 8484 | sema.fail(block, src, "unable to unwrap null", .{}); |
| 8431 | return sema.addConstant(result_ty, payload.data); | ||
| 8432 | } | ||
| 8433 | return sema.addConstant(result_ty, val); | ||
| 8434 | } | 8485 | } |
| 8435 | 8486 | ||
| 8436 | try sema.requireRuntimeBlock(block, src, null); | 8487 | try sema.requireRuntimeBlock(block, src, null); |
| ... | @@ -8450,14 +8501,15 @@ fn zirErrUnionPayload( | ... | @@ -8450,14 +8501,15 @@ fn zirErrUnionPayload( |
| 8450 | const tracy = trace(@src()); | 8501 | const tracy = trace(@src()); |
| 8451 | defer tracy.end(); | 8502 | defer tracy.end(); |
| 8452 | 8503 | ||
| 8504 | const mod = sema.mod; | ||
| 8453 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 8505 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 8454 | const src = inst_data.src(); | 8506 | const src = inst_data.src(); |
| 8455 | const operand = try sema.resolveInst(inst_data.operand); | 8507 | const operand = try sema.resolveInst(inst_data.operand); |
| 8456 | const operand_src = src; | 8508 | const operand_src = src; |
| 8457 | const err_union_ty = sema.typeOf(operand); | 8509 | const err_union_ty = sema.typeOf(operand); |
| 8458 | if (err_union_ty.zigTypeTag() != .ErrorUnion) { | 8510 | if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) { |
| 8459 | return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ | 8511 | return sema.fail(block, operand_src, "expected error union type, found '{}'", .{ |
| 8460 | err_union_ty.fmt(sema.mod), | 8512 | err_union_ty.fmt(mod), |
| 8461 | }); | 8513 | }); |
| 8462 | } | 8514 | } |
| 8463 | return sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false); | 8515 | return sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false); |
| ... | @@ -8468,24 +8520,27 @@ fn analyzeErrUnionPayload( | ... | @@ -8468,24 +8520,27 @@ fn analyzeErrUnionPayload( |
| 8468 | block: *Block, | 8520 | block: *Block, |
| 8469 | src: LazySrcLoc, | 8521 | src: LazySrcLoc, |
| 8470 | err_union_ty: Type, | 8522 | err_union_ty: Type, |
| 8471 | operand: Zir.Inst.Ref, | 8523 | operand: Air.Inst.Ref, |
| 8472 | operand_src: LazySrcLoc, | 8524 | operand_src: LazySrcLoc, |
| 8473 | safety_check: bool, | 8525 | safety_check: bool, |
| 8474 | ) CompileError!Air.Inst.Ref { | 8526 | ) CompileError!Air.Inst.Ref { |
| 8475 | const payload_ty = err_union_ty.errorUnionPayload(); | 8527 | const mod = sema.mod; |
| 8528 | const payload_ty = err_union_ty.errorUnionPayload(mod); | ||
| 8476 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { | 8529 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { |
| 8477 | if (val.getError()) |name| { | 8530 | if (val.getErrorName(mod).unwrap()) |name| { |
| 8478 | return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); | 8531 | return sema.fail(block, src, "caught unexpected error '{}'", .{name.fmt(&mod.intern_pool)}); |
| 8479 | } | 8532 | } |
| 8480 | const data = val.castTag(.eu_payload).?.data; | 8533 | return sema.addConstant( |
| 8481 | return sema.addConstant(payload_ty, data); | 8534 | payload_ty, |
| 8535 | mod.intern_pool.indexToKey(val.toIntern()).error_union.val.payload.toValue(), | ||
| 8536 | ); | ||
| 8482 | } | 8537 | } |
| 8483 | 8538 | ||
| 8484 | try sema.requireRuntimeBlock(block, src, null); | 8539 | try sema.requireRuntimeBlock(block, src, null); |
| 8485 | 8540 | ||
| 8486 | // If the error set has no fields then no safety check is needed. | 8541 | // If the error set has no fields then no safety check is needed. |
| 8487 | if (safety_check and block.wantSafety() and | 8542 | if (safety_check and block.wantSafety() and |
| 8488 | !err_union_ty.errorUnionSet().errorSetIsEmpty()) | 8543 | !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) |
| 8489 | { | 8544 | { |
| 8490 | try sema.panicUnwrapError(block, operand, .unwrap_errunion_err, .is_non_err); | 8545 | try sema.panicUnwrapError(block, operand, .unwrap_errunion_err, .is_non_err); |
| 8491 | } | 8546 | } |
| ... | @@ -8517,52 +8572,46 @@ fn analyzeErrUnionPayloadPtr( | ... | @@ -8517,52 +8572,46 @@ fn analyzeErrUnionPayloadPtr( |
| 8517 | safety_check: bool, | 8572 | safety_check: bool, |
| 8518 | initializing: bool, | 8573 | initializing: bool, |
| 8519 | ) CompileError!Air.Inst.Ref { | 8574 | ) CompileError!Air.Inst.Ref { |
| 8575 | const mod = sema.mod; | ||
| 8520 | const operand_ty = sema.typeOf(operand); | 8576 | const operand_ty = sema.typeOf(operand); |
| 8521 | assert(operand_ty.zigTypeTag() == .Pointer); | 8577 | assert(operand_ty.zigTypeTag(mod) == .Pointer); |
| 8522 | 8578 | ||
| 8523 | if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) { | 8579 | if (operand_ty.childType(mod).zigTypeTag(mod) != .ErrorUnion) { |
| 8524 | return sema.fail(block, src, "expected error union type, found '{}'", .{ | 8580 | return sema.fail(block, src, "expected error union type, found '{}'", .{ |
| 8525 | operand_ty.elemType().fmt(sema.mod), | 8581 | operand_ty.childType(mod).fmt(mod), |
| 8526 | }); | 8582 | }); |
| 8527 | } | 8583 | } |
| 8528 | 8584 | ||
| 8529 | const err_union_ty = operand_ty.elemType(); | 8585 | const err_union_ty = operand_ty.childType(mod); |
| 8530 | const payload_ty = err_union_ty.errorUnionPayload(); | 8586 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 8531 | const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{ | 8587 | const operand_pointer_ty = try Type.ptr(sema.arena, mod, .{ |
| 8532 | .pointee_type = payload_ty, | 8588 | .pointee_type = payload_ty, |
| 8533 | .mutable = !operand_ty.isConstPtr(), | 8589 | .mutable = !operand_ty.isConstPtr(mod), |
| 8534 | .@"addrspace" = operand_ty.ptrAddressSpace(), | 8590 | .@"addrspace" = operand_ty.ptrAddressSpace(mod), |
| 8535 | }); | 8591 | }); |
| 8536 | 8592 | ||
| 8537 | if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| { | 8593 | if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| { |
| 8538 | if (initializing) { | 8594 | if (initializing) { |
| 8539 | if (!ptr_val.isComptimeMutablePtr()) { | 8595 | if (!ptr_val.isComptimeMutablePtr(mod)) { |
| 8540 | // If the pointer resulting from this function was stored at comptime, | 8596 | // If the pointer resulting from this function was stored at comptime, |
| 8541 | // the error union error code would be set that way. But in this case, | 8597 | // the error union error code would be set that way. But in this case, |
| 8542 | // we need to emit a runtime instruction to do it. | 8598 | // we need to emit a runtime instruction to do it. |
| 8543 | try sema.requireRuntimeBlock(block, src, null); | 8599 | try sema.requireRuntimeBlock(block, src, null); |
| 8544 | _ = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand); | 8600 | _ = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand); |
| 8545 | } | 8601 | } |
| 8546 | return sema.addConstant( | 8602 | return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{ |
| 8547 | operand_pointer_ty, | 8603 | .ty = operand_pointer_ty.toIntern(), |
| 8548 | try Value.Tag.eu_payload_ptr.create(sema.arena, .{ | 8604 | .addr = .{ .eu_payload = ptr_val.toIntern() }, |
| 8549 | .container_ptr = ptr_val, | 8605 | } })).toValue()); |
| 8550 | .container_ty = operand_ty.elemType(), | ||
| 8551 | }), | ||
| 8552 | ); | ||
| 8553 | } | 8606 | } |
| 8554 | if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| { | 8607 | if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| { |
| 8555 | if (val.getError()) |name| { | 8608 | if (val.getErrorName(mod).unwrap()) |name| { |
| 8556 | return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); | 8609 | return sema.fail(block, src, "caught unexpected error '{}'", .{name.fmt(&mod.intern_pool)}); |
| 8557 | } | 8610 | } |
| 8558 | 8611 | return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{ | |
| 8559 | return sema.addConstant( | 8612 | .ty = operand_pointer_ty.toIntern(), |
| 8560 | operand_pointer_ty, | 8613 | .addr = .{ .eu_payload = ptr_val.toIntern() }, |
| 8561 | try Value.Tag.eu_payload_ptr.create(sema.arena, .{ | 8614 | } })).toValue()); |
| 8562 | .container_ptr = ptr_val, | ||
| 8563 | .container_ty = operand_ty.elemType(), | ||
| 8564 | }), | ||
| 8565 | ); | ||
| 8566 | } | 8615 | } |
| 8567 | } | 8616 | } |
| 8568 | 8617 | ||
| ... | @@ -8570,7 +8619,7 @@ fn analyzeErrUnionPayloadPtr( | ... | @@ -8570,7 +8619,7 @@ fn analyzeErrUnionPayloadPtr( |
| 8570 | 8619 | ||
| 8571 | // If the error set has no fields then no safety check is needed. | 8620 | // If the error set has no fields then no safety check is needed. |
| 8572 | if (safety_check and block.wantSafety() and | 8621 | if (safety_check and block.wantSafety() and |
| 8573 | !err_union_ty.errorUnionSet().errorSetIsEmpty()) | 8622 | !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) |
| 8574 | { | 8623 | { |
| 8575 | try sema.panicUnwrapError(block, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr); | 8624 | try sema.panicUnwrapError(block, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr); |
| 8576 | } | 8625 | } |
| ... | @@ -8594,18 +8643,21 @@ fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro | ... | @@ -8594,18 +8643,21 @@ fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 8594 | } | 8643 | } |
| 8595 | 8644 | ||
| 8596 | fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) CompileError!Air.Inst.Ref { | 8645 | fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) CompileError!Air.Inst.Ref { |
| 8646 | const mod = sema.mod; | ||
| 8597 | const operand_ty = sema.typeOf(operand); | 8647 | const operand_ty = sema.typeOf(operand); |
| 8598 | if (operand_ty.zigTypeTag() != .ErrorUnion) { | 8648 | if (operand_ty.zigTypeTag(mod) != .ErrorUnion) { |
| 8599 | return sema.fail(block, src, "expected error union type, found '{}'", .{ | 8649 | return sema.fail(block, src, "expected error union type, found '{}'", .{ |
| 8600 | operand_ty.fmt(sema.mod), | 8650 | operand_ty.fmt(mod), |
| 8601 | }); | 8651 | }); |
| 8602 | } | 8652 | } |
| 8603 | 8653 | ||
| 8604 | const result_ty = operand_ty.errorUnionSet(); | 8654 | const result_ty = operand_ty.errorUnionSet(mod); |
| 8605 | 8655 | ||
| 8606 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { | 8656 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { |
| 8607 | assert(val.getError() != null); | 8657 | return sema.addConstant(result_ty, (try mod.intern(.{ .err = .{ |
| 8608 | return sema.addConstant(result_ty, val); | 8658 | .ty = result_ty.toIntern(), |
| 8659 | .name = mod.intern_pool.indexToKey(val.toIntern()).error_union.val.err_name, | ||
| 8660 | } })).toValue()); | ||
| 8609 | } | 8661 | } |
| 8610 | 8662 | ||
| 8611 | try sema.requireRuntimeBlock(block, src, null); | 8663 | try sema.requireRuntimeBlock(block, src, null); |
| ... | @@ -8617,23 +8669,24 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -8617,23 +8669,24 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 8617 | const tracy = trace(@src()); | 8669 | const tracy = trace(@src()); |
| 8618 | defer tracy.end(); | 8670 | defer tracy.end(); |
| 8619 | 8671 | ||
| 8672 | const mod = sema.mod; | ||
| 8620 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 8673 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 8621 | const src = inst_data.src(); | 8674 | const src = inst_data.src(); |
| 8622 | const operand = try sema.resolveInst(inst_data.operand); | 8675 | const operand = try sema.resolveInst(inst_data.operand); |
| 8623 | const operand_ty = sema.typeOf(operand); | 8676 | const operand_ty = sema.typeOf(operand); |
| 8624 | assert(operand_ty.zigTypeTag() == .Pointer); | 8677 | assert(operand_ty.zigTypeTag(mod) == .Pointer); |
| 8625 | 8678 | ||
| 8626 | if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) { | 8679 | if (operand_ty.childType(mod).zigTypeTag(mod) != .ErrorUnion) { |
| 8627 | return sema.fail(block, src, "expected error union type, found '{}'", .{ | 8680 | return sema.fail(block, src, "expected error union type, found '{}'", .{ |
| 8628 | operand_ty.elemType().fmt(sema.mod), | 8681 | operand_ty.childType(mod).fmt(mod), |
| 8629 | }); | 8682 | }); |
| 8630 | } | 8683 | } |
| 8631 | 8684 | ||
| 8632 | const result_ty = operand_ty.elemType().errorUnionSet(); | 8685 | const result_ty = operand_ty.childType(mod).errorUnionSet(mod); |
| 8633 | 8686 | ||
| 8634 | if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { | 8687 | if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { |
| 8635 | if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| { | 8688 | if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| { |
| 8636 | assert(val.getError() != null); | 8689 | assert(val.getErrorName(mod) != .none); |
| 8637 | return sema.addConstant(result_ty, val); | 8690 | return sema.addConstant(result_ty, val); |
| 8638 | } | 8691 | } |
| 8639 | } | 8692 | } |
| ... | @@ -8667,7 +8720,7 @@ fn zirFunc( | ... | @@ -8667,7 +8720,7 @@ fn zirFunc( |
| 8667 | break :blk ret_ty; | 8720 | break :blk ret_ty; |
| 8668 | } else |err| switch (err) { | 8721 | } else |err| switch (err) { |
| 8669 | error.GenericPoison => { | 8722 | error.GenericPoison => { |
| 8670 | break :blk Type.initTag(.generic_poison); | 8723 | break :blk Type.generic_poison; |
| 8671 | }, | 8724 | }, |
| 8672 | else => |e| return e, | 8725 | else => |e| return e, |
| 8673 | } | 8726 | } |
| ... | @@ -8677,8 +8730,7 @@ fn zirFunc( | ... | @@ -8677,8 +8730,7 @@ fn zirFunc( |
| 8677 | extra_index += ret_ty_body.len; | 8730 | extra_index += ret_ty_body.len; |
| 8678 | 8731 | ||
| 8679 | const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, "return type must be comptime-known"); | 8732 | const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, "return type must be comptime-known"); |
| 8680 | var buffer: Value.ToTypeBuffer = undefined; | 8733 | break :blk ret_ty_val.toType(); |
| 8681 | break :blk try ret_ty_val.toType(&buffer).copy(sema.arena); | ||
| 8682 | }, | 8734 | }, |
| 8683 | }; | 8735 | }; |
| 8684 | 8736 | ||
| ... | @@ -8745,10 +8797,10 @@ fn resolveGenericBody( | ... | @@ -8745,10 +8797,10 @@ fn resolveGenericBody( |
| 8745 | }; | 8797 | }; |
| 8746 | switch (err) { | 8798 | switch (err) { |
| 8747 | error.GenericPoison => { | 8799 | error.GenericPoison => { |
| 8748 | if (dest_ty.tag() == .type) { | 8800 | if (dest_ty.toIntern() == .type_type) { |
| 8749 | return Value.initTag(.generic_poison_type); | 8801 | return Value.generic_poison_type; |
| 8750 | } else { | 8802 | } else { |
| 8751 | return Value.initTag(.generic_poison); | 8803 | return Value.generic_poison; |
| 8752 | } | 8804 | } |
| 8753 | }, | 8805 | }, |
| 8754 | else => |e| return e, | 8806 | else => |e| return e, |
| ... | @@ -8822,7 +8874,7 @@ fn handleExternLibName( | ... | @@ -8822,7 +8874,7 @@ fn handleExternLibName( |
| 8822 | const FuncLinkSection = union(enum) { | 8874 | const FuncLinkSection = union(enum) { |
| 8823 | generic, | 8875 | generic, |
| 8824 | default, | 8876 | default, |
| 8825 | explicit: []const u8, | 8877 | explicit: InternPool.NullTerminatedString, |
| 8826 | }; | 8878 | }; |
| 8827 | 8879 | ||
| 8828 | fn funcCommon( | 8880 | fn funcCommon( |
| ... | @@ -8849,11 +8901,13 @@ fn funcCommon( | ... | @@ -8849,11 +8901,13 @@ fn funcCommon( |
| 8849 | noalias_bits: u32, | 8901 | noalias_bits: u32, |
| 8850 | is_noinline: bool, | 8902 | is_noinline: bool, |
| 8851 | ) CompileError!Air.Inst.Ref { | 8903 | ) CompileError!Air.Inst.Ref { |
| 8904 | const mod = sema.mod; | ||
| 8905 | const gpa = sema.gpa; | ||
| 8852 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; | 8906 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset }; |
| 8853 | const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset }; | 8907 | const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset }; |
| 8854 | const func_src = LazySrcLoc.nodeOffset(src_node_offset); | 8908 | const func_src = LazySrcLoc.nodeOffset(src_node_offset); |
| 8855 | 8909 | ||
| 8856 | var is_generic = bare_return_type.tag() == .generic_poison or | 8910 | var is_generic = bare_return_type.isGenericPoison() or |
| 8857 | alignment == null or | 8911 | alignment == null or |
| 8858 | address_space == null or | 8912 | address_space == null or |
| 8859 | section == .generic or | 8913 | section == .generic or |
| ... | @@ -8869,70 +8923,42 @@ fn funcCommon( | ... | @@ -8869,70 +8923,42 @@ fn funcCommon( |
| 8869 | } | 8923 | } |
| 8870 | 8924 | ||
| 8871 | var destroy_fn_on_error = false; | 8925 | var destroy_fn_on_error = false; |
| 8872 | const new_func: *Module.Fn = new_func: { | 8926 | const new_func_index = new_func: { |
| 8873 | if (!has_body) break :new_func undefined; | 8927 | if (!has_body) break :new_func undefined; |
| 8874 | if (sema.comptime_args_fn_inst == func_inst) { | 8928 | if (sema.comptime_args_fn_inst == func_inst) { |
| 8875 | const new_func = sema.preallocated_new_func.?; | 8929 | const new_func_index = sema.preallocated_new_func.unwrap().?; |
| 8876 | sema.preallocated_new_func = null; // take ownership | 8930 | sema.preallocated_new_func = .none; // take ownership |
| 8877 | break :new_func new_func; | 8931 | break :new_func new_func_index; |
| 8878 | } | 8932 | } |
| 8879 | destroy_fn_on_error = true; | 8933 | destroy_fn_on_error = true; |
| 8880 | const new_func = try sema.gpa.create(Module.Fn); | 8934 | var new_func: Module.Fn = undefined; |
| 8881 | // Set this here so that the inferred return type can be printed correctly if it appears in an error. | 8935 | // Set this here so that the inferred return type can be printed correctly if it appears in an error. |
| 8882 | new_func.owner_decl = sema.owner_decl_index; | 8936 | new_func.owner_decl = sema.owner_decl_index; |
| 8883 | break :new_func new_func; | 8937 | const new_func_index = try mod.createFunc(new_func); |
| 8938 | break :new_func new_func_index; | ||
| 8884 | }; | 8939 | }; |
| 8885 | errdefer if (destroy_fn_on_error) sema.gpa.destroy(new_func); | 8940 | errdefer if (destroy_fn_on_error) mod.destroyFunc(new_func_index); |
| 8886 | |||
| 8887 | var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null; | ||
| 8888 | errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node); | ||
| 8889 | // Note: no need to errdefer since this will still be in its default state at the end of the function. | ||
| 8890 | 8941 | ||
| 8891 | const target = sema.mod.getTarget(); | 8942 | const target = mod.getTarget(); |
| 8892 | const fn_ty: Type = fn_ty: { | 8943 | const fn_ty: Type = fn_ty: { |
| 8893 | // Hot path for some common function types. | ||
| 8894 | // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated. | ||
| 8895 | if (!is_generic and block.params.items.len == 0 and !var_args and !inferred_error_set and | ||
| 8896 | alignment.? == 0 and | ||
| 8897 | address_space.? == target_util.defaultAddressSpace(target, .function) and | ||
| 8898 | section == .default and | ||
| 8899 | !is_noinline) | ||
| 8900 | { | ||
| 8901 | if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Unspecified) { | ||
| 8902 | break :fn_ty Type.initTag(.fn_noreturn_no_args); | ||
| 8903 | } | ||
| 8904 | |||
| 8905 | if (bare_return_type.zigTypeTag() == .Void and cc.? == .Unspecified) { | ||
| 8906 | break :fn_ty Type.initTag(.fn_void_no_args); | ||
| 8907 | } | ||
| 8908 | |||
| 8909 | if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Naked) { | ||
| 8910 | break :fn_ty Type.initTag(.fn_naked_noreturn_no_args); | ||
| 8911 | } | ||
| 8912 | |||
| 8913 | if (bare_return_type.zigTypeTag() == .Void and cc.? == .C) { | ||
| 8914 | break :fn_ty Type.initTag(.fn_ccc_void_no_args); | ||
| 8915 | } | ||
| 8916 | } | ||
| 8917 | |||
| 8918 | // In the case of generic calling convention, or generic alignment, we use | 8944 | // In the case of generic calling convention, or generic alignment, we use |
| 8919 | // default values which are only meaningful for the generic function, *not* | 8945 | // default values which are only meaningful for the generic function, *not* |
| 8920 | // the instantiation, which can depend on comptime parameters. | 8946 | // the instantiation, which can depend on comptime parameters. |
| 8921 | // Related proposal: https://github.com/ziglang/zig/issues/11834 | 8947 | // Related proposal: https://github.com/ziglang/zig/issues/11834 |
| 8922 | const cc_resolved = cc orelse .Unspecified; | 8948 | const cc_resolved = cc orelse .Unspecified; |
| 8923 | const param_types = try sema.arena.alloc(Type, block.params.items.len); | 8949 | const param_types = try sema.arena.alloc(InternPool.Index, block.params.items.len); |
| 8924 | const comptime_params = try sema.arena.alloc(bool, block.params.items.len); | 8950 | var comptime_bits: u32 = 0; |
| 8925 | for (block.params.items, 0..) |param, i| { | 8951 | for (param_types, block.params.items, 0..) |*dest_param_ty, param, i| { |
| 8926 | const is_noalias = blk: { | 8952 | const is_noalias = blk: { |
| 8927 | const index = std.math.cast(u5, i) orelse break :blk false; | 8953 | const index = std.math.cast(u5, i) orelse break :blk false; |
| 8928 | break :blk @truncate(u1, noalias_bits >> index) != 0; | 8954 | break :blk @truncate(u1, noalias_bits >> index) != 0; |
| 8929 | }; | 8955 | }; |
| 8930 | param_types[i] = param.ty; | 8956 | dest_param_ty.* = param.ty.toIntern(); |
| 8931 | sema.analyzeParameter( | 8957 | sema.analyzeParameter( |
| 8932 | block, | 8958 | block, |
| 8933 | .unneeded, | 8959 | .unneeded, |
| 8934 | param, | 8960 | param, |
| 8935 | comptime_params, | 8961 | &comptime_bits, |
| 8936 | i, | 8962 | i, |
| 8937 | &is_generic, | 8963 | &is_generic, |
| 8938 | cc_resolved, | 8964 | cc_resolved, |
| ... | @@ -8940,12 +8966,12 @@ fn funcCommon( | ... | @@ -8940,12 +8966,12 @@ fn funcCommon( |
| 8940 | is_noalias, | 8966 | is_noalias, |
| 8941 | ) catch |err| switch (err) { | 8967 | ) catch |err| switch (err) { |
| 8942 | error.NeededSourceLocation => { | 8968 | error.NeededSourceLocation => { |
| 8943 | const decl = sema.mod.declPtr(block.src_decl); | 8969 | const decl = mod.declPtr(block.src_decl); |
| 8944 | try sema.analyzeParameter( | 8970 | try sema.analyzeParameter( |
| 8945 | block, | 8971 | block, |
| 8946 | Module.paramSrc(src_node_offset, sema.gpa, decl, i), | 8972 | Module.paramSrc(src_node_offset, mod, decl, i), |
| 8947 | param, | 8973 | param, |
| 8948 | comptime_params, | 8974 | &comptime_bits, |
| 8949 | i, | 8975 | i, |
| 8950 | &is_generic, | 8976 | &is_generic, |
| 8951 | cc_resolved, | 8977 | cc_resolved, |
| ... | @@ -8961,7 +8987,7 @@ fn funcCommon( | ... | @@ -8961,7 +8987,7 @@ fn funcCommon( |
| 8961 | var ret_ty_requires_comptime = false; | 8987 | var ret_ty_requires_comptime = false; |
| 8962 | const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: { | 8988 | const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: { |
| 8963 | ret_ty_requires_comptime = ret_comptime; | 8989 | ret_ty_requires_comptime = ret_comptime; |
| 8964 | break :rp bare_return_type.tag() == .generic_poison; | 8990 | break :rp bare_return_type.isGenericPoison(); |
| 8965 | } else |err| switch (err) { | 8991 | } else |err| switch (err) { |
| 8966 | error.GenericPoison => rp: { | 8992 | error.GenericPoison => rp: { |
| 8967 | is_generic = true; | 8993 | is_generic = true; |
| ... | @@ -8970,43 +8996,41 @@ fn funcCommon( | ... | @@ -8970,43 +8996,41 @@ fn funcCommon( |
| 8970 | else => |e| return e, | 8996 | else => |e| return e, |
| 8971 | }; | 8997 | }; |
| 8972 | 8998 | ||
| 8973 | const return_type = if (!inferred_error_set or ret_poison) | 8999 | const return_type: Type = if (!inferred_error_set or ret_poison) |
| 8974 | bare_return_type | 9000 | bare_return_type |
| 8975 | else blk: { | 9001 | else blk: { |
| 8976 | try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src); | 9002 | try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src); |
| 8977 | const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode); | 9003 | const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{ |
| 8978 | node.data = .{ .func = new_func }; | 9004 | .func = new_func_index, |
| 8979 | maybe_inferred_error_set_node = node; | ||
| 8980 | |||
| 8981 | const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data); | ||
| 8982 | break :blk try Type.Tag.error_union.create(sema.arena, .{ | ||
| 8983 | .error_set = error_set_ty, | ||
| 8984 | .payload = bare_return_type, | ||
| 8985 | }); | 9005 | }); |
| 9006 | const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index }); | ||
| 9007 | break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type); | ||
| 8986 | }; | 9008 | }; |
| 8987 | 9009 | ||
| 8988 | if (!return_type.isValidReturnType()) { | 9010 | if (!return_type.isValidReturnType(mod)) { |
| 8989 | const opaque_str = if (return_type.zigTypeTag() == .Opaque) "opaque " else ""; | 9011 | const opaque_str = if (return_type.zigTypeTag(mod) == .Opaque) "opaque " else ""; |
| 8990 | const msg = msg: { | 9012 | const msg = msg: { |
| 8991 | const msg = try sema.errMsg(block, ret_ty_src, "{s}return type '{}' not allowed", .{ | 9013 | const msg = try sema.errMsg(block, ret_ty_src, "{s}return type '{}' not allowed", .{ |
| 8992 | opaque_str, return_type.fmt(sema.mod), | 9014 | opaque_str, return_type.fmt(mod), |
| 8993 | }); | 9015 | }); |
| 8994 | errdefer msg.destroy(sema.gpa); | 9016 | errdefer msg.destroy(gpa); |
| 8995 | 9017 | ||
| 8996 | try sema.addDeclaredHereNote(msg, return_type); | 9018 | try sema.addDeclaredHereNote(msg, return_type); |
| 8997 | break :msg msg; | 9019 | break :msg msg; |
| 8998 | }; | 9020 | }; |
| 8999 | return sema.failWithOwnedErrorMsg(msg); | 9021 | return sema.failWithOwnedErrorMsg(msg); |
| 9000 | } | 9022 | } |
| 9001 | if (!ret_poison and !Type.fnCallingConventionAllowsZigTypes(target, cc_resolved) and !try sema.validateExternType(return_type, .ret_ty)) { | 9023 | if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(target, cc_resolved) and |
| 9024 | !try sema.validateExternType(return_type, .ret_ty)) | ||
| 9025 | { | ||
| 9002 | const msg = msg: { | 9026 | const msg = msg: { |
| 9003 | const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ | 9027 | const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ |
| 9004 | return_type.fmt(sema.mod), @tagName(cc_resolved), | 9028 | return_type.fmt(mod), @tagName(cc_resolved), |
| 9005 | }); | 9029 | }); |
| 9006 | errdefer msg.destroy(sema.gpa); | 9030 | errdefer msg.destroy(gpa); |
| 9007 | 9031 | ||
| 9008 | const src_decl = sema.mod.declPtr(block.src_decl); | 9032 | const src_decl = mod.declPtr(block.src_decl); |
| 9009 | try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl), return_type, .ret_ty); | 9033 | try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl, mod), return_type, .ret_ty); |
| 9010 | 9034 | ||
| 9011 | try sema.addDeclaredHereNote(msg, return_type); | 9035 | try sema.addDeclaredHereNote(msg, return_type); |
| 9012 | break :msg msg; | 9036 | break :msg msg; |
| ... | @@ -9024,9 +9048,9 @@ fn funcCommon( | ... | @@ -9024,9 +9048,9 @@ fn funcCommon( |
| 9024 | block, | 9048 | block, |
| 9025 | ret_ty_src, | 9049 | ret_ty_src, |
| 9026 | "function with comptime-only return type '{}' requires all parameters to be comptime", | 9050 | "function with comptime-only return type '{}' requires all parameters to be comptime", |
| 9027 | .{return_type.fmt(sema.mod)}, | 9051 | .{return_type.fmt(mod)}, |
| 9028 | ); | 9052 | ); |
| 9029 | try sema.explainWhyTypeIsComptime(msg, ret_ty_src.toSrcLoc(sema.owner_decl), return_type); | 9053 | try sema.explainWhyTypeIsComptime(msg, ret_ty_src.toSrcLoc(sema.owner_decl, mod), return_type); |
| 9030 | 9054 | ||
| 9031 | const tags = sema.code.instructions.items(.tag); | 9055 | const tags = sema.code.instructions.items(.tag); |
| 9032 | const data = sema.code.instructions.items(.data); | 9056 | const data = sema.code.instructions.items(.data); |
| ... | @@ -9049,7 +9073,7 @@ fn funcCommon( | ... | @@ -9049,7 +9073,7 @@ fn funcCommon( |
| 9049 | return sema.failWithOwnedErrorMsg(msg); | 9073 | return sema.failWithOwnedErrorMsg(msg); |
| 9050 | } | 9074 | } |
| 9051 | 9075 | ||
| 9052 | const arch = sema.mod.getTarget().cpu.arch; | 9076 | const arch = mod.getTarget().cpu.arch; |
| 9053 | if (switch (cc_resolved) { | 9077 | if (switch (cc_resolved) { |
| 9054 | .Unspecified, .C, .Naked, .Async, .Inline => null, | 9078 | .Unspecified, .C, .Naked, .Async, .Inline => null, |
| 9055 | .Interrupt => switch (arch) { | 9079 | .Interrupt => switch (arch) { |
| ... | @@ -9092,8 +9116,7 @@ fn funcCommon( | ... | @@ -9092,8 +9116,7 @@ fn funcCommon( |
| 9092 | return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{}); | 9116 | return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{}); |
| 9093 | } | 9117 | } |
| 9094 | if (is_generic and sema.no_partial_func_ty) return error.GenericPoison; | 9118 | if (is_generic and sema.no_partial_func_ty) return error.GenericPoison; |
| 9095 | for (comptime_params) |ct| is_generic = is_generic or ct; | 9119 | is_generic = is_generic or comptime_bits != 0 or ret_ty_requires_comptime; |
| 9096 | is_generic = is_generic or ret_ty_requires_comptime; | ||
| 9097 | 9120 | ||
| 9098 | if (!is_generic and sema.wantErrorReturnTracing(return_type)) { | 9121 | if (!is_generic and sema.wantErrorReturnTracing(return_type)) { |
| 9099 | // Make sure that StackTrace's fields are resolved so that the backend can | 9122 | // Make sure that StackTrace's fields are resolved so that the backend can |
| ... | @@ -9102,68 +9125,58 @@ fn funcCommon( | ... | @@ -9102,68 +9125,58 @@ fn funcCommon( |
| 9102 | _ = try sema.resolveTypeFields(unresolved_stack_trace_ty); | 9125 | _ = try sema.resolveTypeFields(unresolved_stack_trace_ty); |
| 9103 | } | 9126 | } |
| 9104 | 9127 | ||
| 9105 | break :fn_ty try Type.Tag.function.create(sema.arena, .{ | 9128 | break :fn_ty try mod.funcType(.{ |
| 9106 | .param_types = param_types, | 9129 | .param_types = param_types, |
| 9107 | .comptime_params = comptime_params.ptr, | 9130 | .noalias_bits = noalias_bits, |
| 9108 | .return_type = return_type, | 9131 | .comptime_bits = comptime_bits, |
| 9132 | .return_type = return_type.toIntern(), | ||
| 9109 | .cc = cc_resolved, | 9133 | .cc = cc_resolved, |
| 9110 | .cc_is_generic = cc == null, | 9134 | .cc_is_generic = cc == null, |
| 9111 | .alignment = alignment orelse 0, | 9135 | .alignment = if (alignment) |a| InternPool.Alignment.fromByteUnits(a) else .none, |
| 9112 | .align_is_generic = alignment == null, | 9136 | .align_is_generic = alignment == null, |
| 9113 | .section_is_generic = section == .generic, | 9137 | .section_is_generic = section == .generic, |
| 9114 | .addrspace_is_generic = address_space == null, | 9138 | .addrspace_is_generic = address_space == null, |
| 9115 | .is_var_args = var_args, | 9139 | .is_var_args = var_args, |
| 9116 | .is_generic = is_generic, | 9140 | .is_generic = is_generic, |
| 9117 | .is_noinline = is_noinline, | 9141 | .is_noinline = is_noinline, |
| 9118 | .noalias_bits = noalias_bits, | ||
| 9119 | }); | 9142 | }); |
| 9120 | }; | 9143 | }; |
| 9121 | 9144 | ||
| 9122 | sema.owner_decl.@"linksection" = switch (section) { | 9145 | sema.owner_decl.@"linksection" = switch (section) { |
| 9123 | .generic => undefined, | 9146 | .generic => .none, |
| 9124 | .default => null, | 9147 | .default => .none, |
| 9125 | .explicit => |section_name| try sema.perm_arena.dupeZ(u8, section_name), | 9148 | .explicit => |section_name| section_name.toOptional(), |
| 9126 | }; | 9149 | }; |
| 9127 | sema.owner_decl.@"align" = alignment orelse 0; | 9150 | sema.owner_decl.@"align" = alignment orelse 0; |
| 9128 | sema.owner_decl.@"addrspace" = address_space orelse .generic; | 9151 | sema.owner_decl.@"addrspace" = address_space orelse .generic; |
| 9129 | 9152 | ||
| 9130 | if (is_extern) { | 9153 | if (is_extern) { |
| 9131 | const new_extern_fn = try sema.gpa.create(Module.ExternFn); | 9154 | return sema.addConstant(fn_ty, (try mod.intern(.{ .extern_func = .{ |
| 9132 | errdefer sema.gpa.destroy(new_extern_fn); | 9155 | .ty = fn_ty.toIntern(), |
| 9133 | 9156 | .decl = sema.owner_decl_index, | |
| 9134 | new_extern_fn.* = Module.ExternFn{ | 9157 | .lib_name = if (opt_lib_name) |lib_name| (try mod.intern_pool.getOrPutString( |
| 9135 | .owner_decl = sema.owner_decl_index, | 9158 | gpa, |
| 9136 | .lib_name = null, | 9159 | try sema.handleExternLibName(block, .{ |
| 9137 | }; | 9160 | .node_offset_lib_name = src_node_offset, |
| 9138 | 9161 | }, lib_name), | |
| 9139 | if (opt_lib_name) |lib_name| { | 9162 | )).toOptional() else .none, |
| 9140 | new_extern_fn.lib_name = try sema.handleExternLibName(block, .{ | 9163 | } })).toValue()); |
| 9141 | .node_offset_lib_name = src_node_offset, | ||
| 9142 | }, lib_name); | ||
| 9143 | } | ||
| 9144 | |||
| 9145 | const extern_fn_payload = try sema.arena.create(Value.Payload.ExternFn); | ||
| 9146 | extern_fn_payload.* = .{ | ||
| 9147 | .base = .{ .tag = .extern_fn }, | ||
| 9148 | .data = new_extern_fn, | ||
| 9149 | }; | ||
| 9150 | return sema.addConstant(fn_ty, Value.initPayload(&extern_fn_payload.base)); | ||
| 9151 | } | 9164 | } |
| 9152 | 9165 | ||
| 9153 | if (!has_body) { | 9166 | if (!has_body) { |
| 9154 | return sema.addType(fn_ty); | 9167 | return sema.addType(fn_ty); |
| 9155 | } | 9168 | } |
| 9156 | 9169 | ||
| 9157 | const is_inline = fn_ty.fnCallingConvention() == .Inline; | 9170 | const is_inline = fn_ty.fnCallingConvention(mod) == .Inline; |
| 9158 | const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .none; | 9171 | const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .none; |
| 9159 | 9172 | ||
| 9160 | const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: { | 9173 | const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: { |
| 9161 | break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr; | 9174 | break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr; |
| 9162 | } else null; | 9175 | } else null; |
| 9163 | 9176 | ||
| 9177 | const new_func = mod.funcPtr(new_func_index); | ||
| 9164 | const hash = new_func.hash; | 9178 | const hash = new_func.hash; |
| 9165 | const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl; | 9179 | const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl; |
| 9166 | const fn_payload = try sema.arena.create(Value.Payload.Function); | ||
| 9167 | new_func.* = .{ | 9180 | new_func.* = .{ |
| 9168 | .state = anal_state, | 9181 | .state = anal_state, |
| 9169 | .zir_body_inst = func_inst, | 9182 | .zir_body_inst = func_inst, |
| ... | @@ -9178,15 +9191,10 @@ fn funcCommon( | ... | @@ -9178,15 +9191,10 @@ fn funcCommon( |
| 9178 | .branch_quota = default_branch_quota, | 9191 | .branch_quota = default_branch_quota, |
| 9179 | .is_noinline = is_noinline, | 9192 | .is_noinline = is_noinline, |
| 9180 | }; | 9193 | }; |
| 9181 | if (maybe_inferred_error_set_node) |node| { | 9194 | return sema.addConstant(fn_ty, (try mod.intern(.{ .func = .{ |
| 9182 | new_func.inferred_error_sets.prepend(node); | 9195 | .ty = fn_ty.toIntern(), |
| 9183 | } | 9196 | .index = new_func_index, |
| 9184 | maybe_inferred_error_set_node = null; | 9197 | } })).toValue()); |
| 9185 | fn_payload.* = .{ | ||
| 9186 | .base = .{ .tag = .function }, | ||
| 9187 | .data = new_func, | ||
| 9188 | }; | ||
| 9189 | return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base)); | ||
| 9190 | } | 9198 | } |
| 9191 | 9199 | ||
| 9192 | fn analyzeParameter( | 9200 | fn analyzeParameter( |
| ... | @@ -9194,29 +9202,32 @@ fn analyzeParameter( | ... | @@ -9194,29 +9202,32 @@ fn analyzeParameter( |
| 9194 | block: *Block, | 9202 | block: *Block, |
| 9195 | param_src: LazySrcLoc, | 9203 | param_src: LazySrcLoc, |
| 9196 | param: Block.Param, | 9204 | param: Block.Param, |
| 9197 | comptime_params: []bool, | 9205 | comptime_bits: *u32, |
| 9198 | i: usize, | 9206 | i: usize, |
| 9199 | is_generic: *bool, | 9207 | is_generic: *bool, |
| 9200 | cc: std.builtin.CallingConvention, | 9208 | cc: std.builtin.CallingConvention, |
| 9201 | has_body: bool, | 9209 | has_body: bool, |
| 9202 | is_noalias: bool, | 9210 | is_noalias: bool, |
| 9203 | ) !void { | 9211 | ) !void { |
| 9212 | const mod = sema.mod; | ||
| 9204 | const requires_comptime = try sema.typeRequiresComptime(param.ty); | 9213 | const requires_comptime = try sema.typeRequiresComptime(param.ty); |
| 9205 | comptime_params[i] = param.is_comptime or requires_comptime; | 9214 | if (param.is_comptime or requires_comptime) { |
| 9206 | const this_generic = param.ty.tag() == .generic_poison; | 9215 | comptime_bits.* |= @as(u32, 1) << @intCast(u5, i); // TODO: handle cast error |
| 9216 | } | ||
| 9217 | const this_generic = param.ty.isGenericPoison(); | ||
| 9207 | is_generic.* = is_generic.* or this_generic; | 9218 | is_generic.* = is_generic.* or this_generic; |
| 9208 | const target = sema.mod.getTarget(); | 9219 | const target = mod.getTarget(); |
| 9209 | if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(target, cc)) { | 9220 | if (param.is_comptime and !target_util.fnCallConvAllowsZigTypes(target, cc)) { |
| 9210 | return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); | 9221 | return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); |
| 9211 | } | 9222 | } |
| 9212 | if (this_generic and !sema.no_partial_func_ty and !Type.fnCallingConventionAllowsZigTypes(target, cc)) { | 9223 | if (this_generic and !sema.no_partial_func_ty and !target_util.fnCallConvAllowsZigTypes(target, cc)) { |
| 9213 | return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); | 9224 | return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)}); |
| 9214 | } | 9225 | } |
| 9215 | if (!param.ty.isValidParamType()) { | 9226 | if (!param.ty.isValidParamType(mod)) { |
| 9216 | const opaque_str = if (param.ty.zigTypeTag() == .Opaque) "opaque " else ""; | 9227 | const opaque_str = if (param.ty.zigTypeTag(mod) == .Opaque) "opaque " else ""; |
| 9217 | const msg = msg: { | 9228 | const msg = msg: { |
| 9218 | const msg = try sema.errMsg(block, param_src, "parameter of {s}type '{}' not allowed", .{ | 9229 | const msg = try sema.errMsg(block, param_src, "parameter of {s}type '{}' not allowed", .{ |
| 9219 | opaque_str, param.ty.fmt(sema.mod), | 9230 | opaque_str, param.ty.fmt(mod), |
| 9220 | }); | 9231 | }); |
| 9221 | errdefer msg.destroy(sema.gpa); | 9232 | errdefer msg.destroy(sema.gpa); |
| 9222 | 9233 | ||
| ... | @@ -9225,15 +9236,15 @@ fn analyzeParameter( | ... | @@ -9225,15 +9236,15 @@ fn analyzeParameter( |
| 9225 | }; | 9236 | }; |
| 9226 | return sema.failWithOwnedErrorMsg(msg); | 9237 | return sema.failWithOwnedErrorMsg(msg); |
| 9227 | } | 9238 | } |
| 9228 | if (!this_generic and !Type.fnCallingConventionAllowsZigTypes(target, cc) and !try sema.validateExternType(param.ty, .param_ty)) { | 9239 | if (!this_generic and !target_util.fnCallConvAllowsZigTypes(target, cc) and !try sema.validateExternType(param.ty, .param_ty)) { |
| 9229 | const msg = msg: { | 9240 | const msg = msg: { |
| 9230 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ | 9241 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ |
| 9231 | param.ty.fmt(sema.mod), @tagName(cc), | 9242 | param.ty.fmt(mod), @tagName(cc), |
| 9232 | }); | 9243 | }); |
| 9233 | errdefer msg.destroy(sema.gpa); | 9244 | errdefer msg.destroy(sema.gpa); |
| 9234 | 9245 | ||
| 9235 | const src_decl = sema.mod.declPtr(block.src_decl); | 9246 | const src_decl = mod.declPtr(block.src_decl); |
| 9236 | try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl), param.ty, .param_ty); | 9247 | try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl, mod), param.ty, .param_ty); |
| 9237 | 9248 | ||
| 9238 | try sema.addDeclaredHereNote(msg, param.ty); | 9249 | try sema.addDeclaredHereNote(msg, param.ty); |
| 9239 | break :msg msg; | 9250 | break :msg msg; |
| ... | @@ -9243,12 +9254,12 @@ fn analyzeParameter( | ... | @@ -9243,12 +9254,12 @@ fn analyzeParameter( |
| 9243 | if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) { | 9254 | if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) { |
| 9244 | const msg = msg: { | 9255 | const msg = msg: { |
| 9245 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{ | 9256 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{ |
| 9246 | param.ty.fmt(sema.mod), | 9257 | param.ty.fmt(mod), |
| 9247 | }); | 9258 | }); |
| 9248 | errdefer msg.destroy(sema.gpa); | 9259 | errdefer msg.destroy(sema.gpa); |
| 9249 | 9260 | ||
| 9250 | const src_decl = sema.mod.declPtr(block.src_decl); | 9261 | const src_decl = mod.declPtr(block.src_decl); |
| 9251 | try sema.explainWhyTypeIsComptime(msg, param_src.toSrcLoc(src_decl), param.ty); | 9262 | try sema.explainWhyTypeIsComptime(msg, param_src.toSrcLoc(src_decl, mod), param.ty); |
| 9252 | 9263 | ||
| 9253 | try sema.addDeclaredHereNote(msg, param.ty); | 9264 | try sema.addDeclaredHereNote(msg, param.ty); |
| 9254 | break :msg msg; | 9265 | break :msg msg; |
| ... | @@ -9256,7 +9267,7 @@ fn analyzeParameter( | ... | @@ -9256,7 +9267,7 @@ fn analyzeParameter( |
| 9256 | return sema.failWithOwnedErrorMsg(msg); | 9267 | return sema.failWithOwnedErrorMsg(msg); |
| 9257 | } | 9268 | } |
| 9258 | if (!sema.is_generic_instantiation and !this_generic and is_noalias and | 9269 | if (!sema.is_generic_instantiation and !this_generic and is_noalias and |
| 9259 | !(param.ty.zigTypeTag() == .Pointer or param.ty.isPtrLikeOptional())) | 9270 | !(param.ty.zigTypeTag(mod) == .Pointer or param.ty.isPtrLikeOptional(mod))) |
| 9260 | { | 9271 | { |
| 9261 | return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{}); | 9272 | return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{}); |
| 9262 | } | 9273 | } |
| ... | @@ -9283,7 +9294,7 @@ fn zirParam( | ... | @@ -9283,7 +9294,7 @@ fn zirParam( |
| 9283 | const prev_preallocated_new_func = sema.preallocated_new_func; | 9294 | const prev_preallocated_new_func = sema.preallocated_new_func; |
| 9284 | const prev_no_partial_func_type = sema.no_partial_func_ty; | 9295 | const prev_no_partial_func_type = sema.no_partial_func_ty; |
| 9285 | block.params = .{}; | 9296 | block.params = .{}; |
| 9286 | sema.preallocated_new_func = null; | 9297 | sema.preallocated_new_func = .none; |
| 9287 | sema.no_partial_func_ty = true; | 9298 | sema.no_partial_func_ty = true; |
| 9288 | defer { | 9299 | defer { |
| 9289 | block.params.deinit(sema.gpa); | 9300 | block.params.deinit(sema.gpa); |
| ... | @@ -9309,7 +9320,7 @@ fn zirParam( | ... | @@ -9309,7 +9320,7 @@ fn zirParam( |
| 9309 | // We result the param instruction with a poison value and | 9320 | // We result the param instruction with a poison value and |
| 9310 | // insert an anytype parameter. | 9321 | // insert an anytype parameter. |
| 9311 | try block.params.append(sema.gpa, .{ | 9322 | try block.params.append(sema.gpa, .{ |
| 9312 | .ty = Type.initTag(.generic_poison), | 9323 | .ty = Type.generic_poison, |
| 9313 | .is_comptime = comptime_syntax, | 9324 | .is_comptime = comptime_syntax, |
| 9314 | .name = param_name, | 9325 | .name = param_name, |
| 9315 | }); | 9326 | }); |
| ... | @@ -9330,7 +9341,7 @@ fn zirParam( | ... | @@ -9330,7 +9341,7 @@ fn zirParam( |
| 9330 | // We result the param instruction with a poison value and | 9341 | // We result the param instruction with a poison value and |
| 9331 | // insert an anytype parameter. | 9342 | // insert an anytype parameter. |
| 9332 | try block.params.append(sema.gpa, .{ | 9343 | try block.params.append(sema.gpa, .{ |
| 9333 | .ty = Type.initTag(.generic_poison), | 9344 | .ty = Type.generic_poison, |
| 9334 | .is_comptime = comptime_syntax, | 9345 | .is_comptime = comptime_syntax, |
| 9335 | .name = param_name, | 9346 | .name = param_name, |
| 9336 | }); | 9347 | }); |
| ... | @@ -9340,7 +9351,7 @@ fn zirParam( | ... | @@ -9340,7 +9351,7 @@ fn zirParam( |
| 9340 | else => |e| return e, | 9351 | else => |e| return e, |
| 9341 | } or comptime_syntax; | 9352 | } or comptime_syntax; |
| 9342 | if (sema.inst_map.get(inst)) |arg| { | 9353 | if (sema.inst_map.get(inst)) |arg| { |
| 9343 | if (is_comptime and sema.preallocated_new_func != null) { | 9354 | if (is_comptime and sema.preallocated_new_func != .none) { |
| 9344 | // We have a comptime value for this parameter so it should be elided from the | 9355 | // We have a comptime value for this parameter so it should be elided from the |
| 9345 | // function type of the function instruction in this block. | 9356 | // function type of the function instruction in this block. |
| 9346 | const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) { | 9357 | const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) { |
| ... | @@ -9363,7 +9374,7 @@ fn zirParam( | ... | @@ -9363,7 +9374,7 @@ fn zirParam( |
| 9363 | assert(sema.inst_map.remove(inst)); | 9374 | assert(sema.inst_map.remove(inst)); |
| 9364 | } | 9375 | } |
| 9365 | 9376 | ||
| 9366 | if (sema.preallocated_new_func != null) { | 9377 | if (sema.preallocated_new_func != .none) { |
| 9367 | if (try sema.typeHasOnePossibleValue(param_ty)) |opv| { | 9378 | if (try sema.typeHasOnePossibleValue(param_ty)) |opv| { |
| 9368 | // In this case we are instantiating a generic function call with a non-comptime | 9379 | // In this case we are instantiating a generic function call with a non-comptime |
| 9369 | // non-anytype parameter that ended up being a one-possible-type. | 9380 | // non-anytype parameter that ended up being a one-possible-type. |
| ... | @@ -9383,7 +9394,7 @@ fn zirParam( | ... | @@ -9383,7 +9394,7 @@ fn zirParam( |
| 9383 | if (is_comptime) { | 9394 | if (is_comptime) { |
| 9384 | // If this is a comptime parameter we can add a constant generic_poison | 9395 | // If this is a comptime parameter we can add a constant generic_poison |
| 9385 | // since this is also a generic parameter. | 9396 | // since this is also a generic parameter. |
| 9386 | const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison)); | 9397 | const result = try sema.addConstant(Type.generic_poison, Value.generic_poison); |
| 9387 | sema.inst_map.putAssumeCapacityNoClobber(inst, result); | 9398 | sema.inst_map.putAssumeCapacityNoClobber(inst, result); |
| 9388 | } else { | 9399 | } else { |
| 9389 | // Otherwise we need a dummy runtime instruction. | 9400 | // Otherwise we need a dummy runtime instruction. |
| ... | @@ -9428,7 +9439,7 @@ fn zirParamAnytype( | ... | @@ -9428,7 +9439,7 @@ fn zirParamAnytype( |
| 9428 | // We are evaluating a generic function without any comptime args provided. | 9439 | // We are evaluating a generic function without any comptime args provided. |
| 9429 | 9440 | ||
| 9430 | try block.params.append(sema.gpa, .{ | 9441 | try block.params.append(sema.gpa, .{ |
| 9431 | .ty = Type.initTag(.generic_poison), | 9442 | .ty = Type.generic_poison, |
| 9432 | .is_comptime = comptime_syntax, | 9443 | .is_comptime = comptime_syntax, |
| 9433 | .name = param_name, | 9444 | .name = param_name, |
| 9434 | }); | 9445 | }); |
| ... | @@ -9472,13 +9483,14 @@ fn analyzeAs( | ... | @@ -9472,13 +9483,14 @@ fn analyzeAs( |
| 9472 | zir_operand: Zir.Inst.Ref, | 9483 | zir_operand: Zir.Inst.Ref, |
| 9473 | no_cast_to_comptime_int: bool, | 9484 | no_cast_to_comptime_int: bool, |
| 9474 | ) CompileError!Air.Inst.Ref { | 9485 | ) CompileError!Air.Inst.Ref { |
| 9486 | const mod = sema.mod; | ||
| 9475 | const operand = try sema.resolveInst(zir_operand); | 9487 | const operand = try sema.resolveInst(zir_operand); |
| 9476 | if (zir_dest_type == .var_args_param) return operand; | 9488 | if (zir_dest_type == .var_args_param_type) return operand; |
| 9477 | const dest_ty = sema.resolveType(block, src, zir_dest_type) catch |err| switch (err) { | 9489 | const dest_ty = sema.resolveType(block, src, zir_dest_type) catch |err| switch (err) { |
| 9478 | error.GenericPoison => return operand, | 9490 | error.GenericPoison => return operand, |
| 9479 | else => |e| return e, | 9491 | else => |e| return e, |
| 9480 | }; | 9492 | }; |
| 9481 | if (dest_ty.zigTypeTag() == .NoReturn) { | 9493 | if (dest_ty.zigTypeTag(mod) == .NoReturn) { |
| 9482 | return sema.fail(block, src, "cannot cast to noreturn", .{}); | 9494 | return sema.fail(block, src, "cannot cast to noreturn", .{}); |
| 9483 | } | 9495 | } |
| 9484 | const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index| | 9496 | const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index| |
| ... | @@ -9495,15 +9507,19 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -9495,15 +9507,19 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 9495 | const tracy = trace(@src()); | 9507 | const tracy = trace(@src()); |
| 9496 | defer tracy.end(); | 9508 | defer tracy.end(); |
| 9497 | 9509 | ||
| 9510 | const mod = sema.mod; | ||
| 9498 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 9511 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 9499 | const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 9512 | const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 9500 | const ptr = try sema.resolveInst(inst_data.operand); | 9513 | const ptr = try sema.resolveInst(inst_data.operand); |
| 9501 | const ptr_ty = sema.typeOf(ptr); | 9514 | const ptr_ty = sema.typeOf(ptr); |
| 9502 | if (!ptr_ty.isPtrAtRuntime()) { | 9515 | if (!ptr_ty.isPtrAtRuntime(mod)) { |
| 9503 | return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}); | 9516 | return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(mod)}); |
| 9504 | } | 9517 | } |
| 9505 | if (try sema.resolveMaybeUndefValIntable(ptr)) |ptr_val| { | 9518 | if (try sema.resolveMaybeUndefValIntable(ptr)) |ptr_val| { |
| 9506 | return sema.addConstant(Type.usize, ptr_val); | 9519 | return sema.addConstant( |
| 9520 | Type.usize, | ||
| 9521 | try mod.intValue(Type.usize, (try ptr_val.getUnsignedIntAdvanced(mod, sema)).?), | ||
| 9522 | ); | ||
| 9507 | } | 9523 | } |
| 9508 | try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); | 9524 | try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); |
| 9509 | return block.addUnOp(.ptrtoint, ptr); | 9525 | return block.addUnOp(.ptrtoint, ptr); |
| ... | @@ -9513,11 +9529,12 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -9513,11 +9529,12 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 9513 | const tracy = trace(@src()); | 9529 | const tracy = trace(@src()); |
| 9514 | defer tracy.end(); | 9530 | defer tracy.end(); |
| 9515 | 9531 | ||
| 9532 | const mod = sema.mod; | ||
| 9516 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 9533 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9517 | const src = inst_data.src(); | 9534 | const src = inst_data.src(); |
| 9518 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; | 9535 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 9519 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; | 9536 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 9520 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); | 9537 | const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start)); |
| 9521 | const object = try sema.resolveInst(extra.lhs); | 9538 | const object = try sema.resolveInst(extra.lhs); |
| 9522 | return sema.fieldVal(block, src, object, field_name, field_name_src); | 9539 | return sema.fieldVal(block, src, object, field_name, field_name_src); |
| 9523 | } | 9540 | } |
| ... | @@ -9526,11 +9543,12 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b | ... | @@ -9526,11 +9543,12 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b |
| 9526 | const tracy = trace(@src()); | 9543 | const tracy = trace(@src()); |
| 9527 | defer tracy.end(); | 9544 | defer tracy.end(); |
| 9528 | 9545 | ||
| 9546 | const mod = sema.mod; | ||
| 9529 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 9547 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9530 | const src = inst_data.src(); | 9548 | const src = inst_data.src(); |
| 9531 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; | 9549 | const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; |
| 9532 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; | 9550 | const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; |
| 9533 | const field_name = sema.code.nullTerminatedString(extra.field_name_start); | 9551 | const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start)); |
| 9534 | const object_ptr = try sema.resolveInst(extra.lhs); | 9552 | const object_ptr = try sema.resolveInst(extra.lhs); |
| 9535 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing); | 9553 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing); |
| 9536 | } | 9554 | } |
| ... | @@ -9544,7 +9562,7 @@ fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -9544,7 +9562,7 @@ fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 9544 | const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 9562 | const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 9545 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; | 9563 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; |
| 9546 | const object = try sema.resolveInst(extra.lhs); | 9564 | const object = try sema.resolveInst(extra.lhs); |
| 9547 | const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known"); | 9565 | const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, "field name must be comptime-known"); |
| 9548 | return sema.fieldVal(block, src, object, field_name, field_name_src); | 9566 | return sema.fieldVal(block, src, object, field_name, field_name_src); |
| 9549 | } | 9567 | } |
| 9550 | 9568 | ||
| ... | @@ -9557,7 +9575,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -9557,7 +9575,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 9557 | const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 9575 | const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 9558 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; | 9576 | const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; |
| 9559 | const object_ptr = try sema.resolveInst(extra.lhs); | 9577 | const object_ptr = try sema.resolveInst(extra.lhs); |
| 9560 | const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known"); | 9578 | const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, "field name must be comptime-known"); |
| 9561 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false); | 9579 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false); |
| 9562 | } | 9580 | } |
| 9563 | 9581 | ||
| ... | @@ -9586,31 +9604,31 @@ fn intCast( | ... | @@ -9586,31 +9604,31 @@ fn intCast( |
| 9586 | operand_src: LazySrcLoc, | 9604 | operand_src: LazySrcLoc, |
| 9587 | runtime_safety: bool, | 9605 | runtime_safety: bool, |
| 9588 | ) CompileError!Air.Inst.Ref { | 9606 | ) CompileError!Air.Inst.Ref { |
| 9607 | const mod = sema.mod; | ||
| 9589 | const operand_ty = sema.typeOf(operand); | 9608 | const operand_ty = sema.typeOf(operand); |
| 9590 | const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src); | 9609 | const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src); |
| 9591 | const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); | 9610 | const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); |
| 9592 | 9611 | ||
| 9593 | if (try sema.isComptimeKnown(operand)) { | 9612 | if (try sema.isComptimeKnown(operand)) { |
| 9594 | return sema.coerce(block, dest_ty, operand, operand_src); | 9613 | return sema.coerce(block, dest_ty, operand, operand_src); |
| 9595 | } else if (dest_scalar_ty.zigTypeTag() == .ComptimeInt) { | 9614 | } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) { |
| 9596 | return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{}); | 9615 | return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{}); |
| 9597 | } | 9616 | } |
| 9598 | 9617 | ||
| 9599 | try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src); | 9618 | try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src); |
| 9600 | const is_vector = dest_ty.zigTypeTag() == .Vector; | 9619 | const is_vector = dest_ty.zigTypeTag(mod) == .Vector; |
| 9601 | 9620 | ||
| 9602 | if ((try sema.typeHasOnePossibleValue(dest_ty))) |opv| { | 9621 | if ((try sema.typeHasOnePossibleValue(dest_ty))) |opv| { |
| 9603 | // requirement: intCast(u0, input) iff input == 0 | 9622 | // requirement: intCast(u0, input) iff input == 0 |
| 9604 | if (runtime_safety and block.wantSafety()) { | 9623 | if (runtime_safety and block.wantSafety()) { |
| 9605 | try sema.requireRuntimeBlock(block, src, operand_src); | 9624 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 9606 | const target = sema.mod.getTarget(); | 9625 | const wanted_info = dest_scalar_ty.intInfo(mod); |
| 9607 | const wanted_info = dest_scalar_ty.intInfo(target); | ||
| 9608 | const wanted_bits = wanted_info.bits; | 9626 | const wanted_bits = wanted_info.bits; |
| 9609 | 9627 | ||
| 9610 | if (wanted_bits == 0) { | 9628 | if (wanted_bits == 0) { |
| 9611 | const ok = if (is_vector) ok: { | 9629 | const ok = if (is_vector) ok: { |
| 9612 | const zeros = try Value.Tag.repeated.create(sema.arena, Value.zero); | 9630 | const zeros = try sema.splat(operand_ty, try mod.intValue(operand_scalar_ty, 0)); |
| 9613 | const zero_inst = try sema.addConstant(sema.typeOf(operand), zeros); | 9631 | const zero_inst = try sema.addConstant(operand_ty, zeros); |
| 9614 | const is_in_range = try block.addCmpVector(operand, zero_inst, .eq); | 9632 | const is_in_range = try block.addCmpVector(operand, zero_inst, .eq); |
| 9615 | const all_in_range = try block.addInst(.{ | 9633 | const all_in_range = try block.addInst(.{ |
| 9616 | .tag = .reduce, | 9634 | .tag = .reduce, |
| ... | @@ -9618,7 +9636,7 @@ fn intCast( | ... | @@ -9618,7 +9636,7 @@ fn intCast( |
| 9618 | }); | 9636 | }); |
| 9619 | break :ok all_in_range; | 9637 | break :ok all_in_range; |
| 9620 | } else ok: { | 9638 | } else ok: { |
| 9621 | const zero_inst = try sema.addConstant(sema.typeOf(operand), Value.zero); | 9639 | const zero_inst = try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0)); |
| 9622 | const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst); | 9640 | const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst); |
| 9623 | break :ok is_in_range; | 9641 | break :ok is_in_range; |
| 9624 | }; | 9642 | }; |
| ... | @@ -9631,9 +9649,8 @@ fn intCast( | ... | @@ -9631,9 +9649,8 @@ fn intCast( |
| 9631 | 9649 | ||
| 9632 | try sema.requireRuntimeBlock(block, src, operand_src); | 9650 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 9633 | if (runtime_safety and block.wantSafety()) { | 9651 | if (runtime_safety and block.wantSafety()) { |
| 9634 | const target = sema.mod.getTarget(); | 9652 | const actual_info = operand_scalar_ty.intInfo(mod); |
| 9635 | const actual_info = operand_scalar_ty.intInfo(target); | 9653 | const wanted_info = dest_scalar_ty.intInfo(mod); |
| 9636 | const wanted_info = dest_scalar_ty.intInfo(target); | ||
| 9637 | const actual_bits = actual_info.bits; | 9654 | const actual_bits = actual_info.bits; |
| 9638 | const wanted_bits = wanted_info.bits; | 9655 | const wanted_bits = wanted_info.bits; |
| 9639 | const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed); | 9656 | const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed); |
| ... | @@ -9642,26 +9659,24 @@ fn intCast( | ... | @@ -9642,26 +9659,24 @@ fn intCast( |
| 9642 | // range shrinkage | 9659 | // range shrinkage |
| 9643 | // requirement: int value fits into target type | 9660 | // requirement: int value fits into target type |
| 9644 | if (wanted_value_bits < actual_value_bits) { | 9661 | if (wanted_value_bits < actual_value_bits) { |
| 9645 | const dest_max_val_scalar = try dest_scalar_ty.maxInt(sema.arena, target); | 9662 | const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_scalar_ty); |
| 9646 | const dest_max_val = if (is_vector) | 9663 | const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar); |
| 9647 | try Value.Tag.repeated.create(sema.arena, dest_max_val_scalar) | ||
| 9648 | else | ||
| 9649 | dest_max_val_scalar; | ||
| 9650 | const dest_max = try sema.addConstant(operand_ty, dest_max_val); | 9664 | const dest_max = try sema.addConstant(operand_ty, dest_max_val); |
| 9651 | const diff = try block.addBinOp(.subwrap, dest_max, operand); | 9665 | const diff = try block.addBinOp(.subwrap, dest_max, operand); |
| 9652 | 9666 | ||
| 9653 | if (actual_info.signedness == .signed) { | 9667 | if (actual_info.signedness == .signed) { |
| 9654 | // Reinterpret the sign-bit as part of the value. This will make | 9668 | // Reinterpret the sign-bit as part of the value. This will make |
| 9655 | // negative differences (`operand` > `dest_max`) appear too big. | 9669 | // negative differences (`operand` > `dest_max`) appear too big. |
| 9656 | const unsigned_operand_ty = try Type.Tag.int_unsigned.create(sema.arena, actual_bits); | 9670 | const unsigned_operand_ty = try mod.intType(.unsigned, actual_bits); |
| 9657 | const diff_unsigned = try block.addBitCast(unsigned_operand_ty, diff); | 9671 | const diff_unsigned = try block.addBitCast(unsigned_operand_ty, diff); |
| 9658 | 9672 | ||
| 9659 | // If the destination type is signed, then we need to double its | 9673 | // If the destination type is signed, then we need to double its |
| 9660 | // range to account for negative values. | 9674 | // range to account for negative values. |
| 9661 | const dest_range_val = if (wanted_info.signedness == .signed) range_val: { | 9675 | const dest_range_val = if (wanted_info.signedness == .signed) range_val: { |
| 9662 | const range_minus_one = try dest_max_val.shl(Value.one, unsigned_operand_ty, sema.arena, sema.mod); | 9676 | const one = try mod.intValue(unsigned_operand_ty, 1); |
| 9663 | break :range_val try sema.intAdd(range_minus_one, Value.one, unsigned_operand_ty); | 9677 | const range_minus_one = try dest_max_val.shl(one, unsigned_operand_ty, sema.arena, mod); |
| 9664 | } else dest_max_val; | 9678 | break :range_val try sema.intAdd(range_minus_one, one, unsigned_operand_ty, undefined); |
| 9679 | } else try mod.getCoerced(dest_max_val, unsigned_operand_ty); | ||
| 9665 | const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val); | 9680 | const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val); |
| 9666 | 9681 | ||
| 9667 | const ok = if (is_vector) ok: { | 9682 | const ok = if (is_vector) ok: { |
| ... | @@ -9701,7 +9716,8 @@ fn intCast( | ... | @@ -9701,7 +9716,8 @@ fn intCast( |
| 9701 | // no shrinkage, yes sign loss | 9716 | // no shrinkage, yes sign loss |
| 9702 | // requirement: signed to unsigned >= 0 | 9717 | // requirement: signed to unsigned >= 0 |
| 9703 | const ok = if (is_vector) ok: { | 9718 | const ok = if (is_vector) ok: { |
| 9704 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); | 9719 | const scalar_zero = try mod.intValue(operand_scalar_ty, 0); |
| 9720 | const zero_val = try sema.splat(operand_ty, scalar_zero); | ||
| 9705 | const zero_inst = try sema.addConstant(operand_ty, zero_val); | 9721 | const zero_inst = try sema.addConstant(operand_ty, zero_val); |
| 9706 | const is_in_range = try block.addCmpVector(operand, zero_inst, .gte); | 9722 | const is_in_range = try block.addCmpVector(operand, zero_inst, .gte); |
| 9707 | const all_in_range = try block.addInst(.{ | 9723 | const all_in_range = try block.addInst(.{ |
| ... | @@ -9713,7 +9729,7 @@ fn intCast( | ... | @@ -9713,7 +9729,7 @@ fn intCast( |
| 9713 | }); | 9729 | }); |
| 9714 | break :ok all_in_range; | 9730 | break :ok all_in_range; |
| 9715 | } else ok: { | 9731 | } else ok: { |
| 9716 | const zero_inst = try sema.addConstant(operand_ty, Value.zero); | 9732 | const zero_inst = try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0)); |
| 9717 | const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); | 9733 | const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst); |
| 9718 | break :ok is_in_range; | 9734 | break :ok is_in_range; |
| 9719 | }; | 9735 | }; |
| ... | @@ -9727,6 +9743,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9727,6 +9743,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9727 | const tracy = trace(@src()); | 9743 | const tracy = trace(@src()); |
| 9728 | defer tracy.end(); | 9744 | defer tracy.end(); |
| 9729 | 9745 | ||
| 9746 | const mod = sema.mod; | ||
| 9730 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 9747 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9731 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 9748 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 9732 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 9749 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| ... | @@ -9735,7 +9752,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9735,7 +9752,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9735 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); | 9752 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 9736 | const operand = try sema.resolveInst(extra.rhs); | 9753 | const operand = try sema.resolveInst(extra.rhs); |
| 9737 | const operand_ty = sema.typeOf(operand); | 9754 | const operand_ty = sema.typeOf(operand); |
| 9738 | switch (dest_ty.zigTypeTag()) { | 9755 | switch (dest_ty.zigTypeTag(mod)) { |
| 9739 | .AnyFrame, | 9756 | .AnyFrame, |
| 9740 | .ComptimeFloat, | 9757 | .ComptimeFloat, |
| 9741 | .ComptimeInt, | 9758 | .ComptimeInt, |
| ... | @@ -9751,14 +9768,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9751,14 +9768,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9751 | .Type, | 9768 | .Type, |
| 9752 | .Undefined, | 9769 | .Undefined, |
| 9753 | .Void, | 9770 | .Void, |
| 9754 | => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}), | 9771 | => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)}), |
| 9755 | 9772 | ||
| 9756 | .Enum => { | 9773 | .Enum => { |
| 9757 | const msg = msg: { | 9774 | const msg = msg: { |
| 9758 | const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}); | 9775 | const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)}); |
| 9759 | errdefer msg.destroy(sema.gpa); | 9776 | errdefer msg.destroy(sema.gpa); |
| 9760 | switch (operand_ty.zigTypeTag()) { | 9777 | switch (operand_ty.zigTypeTag(mod)) { |
| 9761 | .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(sema.mod)}), | 9778 | .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(mod)}), |
| 9762 | else => {}, | 9779 | else => {}, |
| 9763 | } | 9780 | } |
| 9764 | 9781 | ||
| ... | @@ -9769,11 +9786,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9769,11 +9786,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9769 | 9786 | ||
| 9770 | .Pointer => { | 9787 | .Pointer => { |
| 9771 | const msg = msg: { | 9788 | const msg = msg: { |
| 9772 | const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}); | 9789 | const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)}); |
| 9773 | errdefer msg.destroy(sema.gpa); | 9790 | errdefer msg.destroy(sema.gpa); |
| 9774 | switch (operand_ty.zigTypeTag()) { | 9791 | switch (operand_ty.zigTypeTag(mod)) { |
| 9775 | .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(sema.mod)}), | 9792 | .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(mod)}), |
| 9776 | .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(sema.mod)}), | 9793 | .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(mod)}), |
| 9777 | else => {}, | 9794 | else => {}, |
| 9778 | } | 9795 | } |
| 9779 | 9796 | ||
| ... | @@ -9781,14 +9798,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9781,14 +9798,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9781 | }; | 9798 | }; |
| 9782 | return sema.failWithOwnedErrorMsg(msg); | 9799 | return sema.failWithOwnedErrorMsg(msg); |
| 9783 | }, | 9800 | }, |
| 9784 | .Struct, .Union => if (dest_ty.containerLayout() == .Auto) { | 9801 | .Struct, .Union => if (dest_ty.containerLayout(mod) == .Auto) { |
| 9785 | const container = switch (dest_ty.zigTypeTag()) { | 9802 | const container = switch (dest_ty.zigTypeTag(mod)) { |
| 9786 | .Struct => "struct", | 9803 | .Struct => "struct", |
| 9787 | .Union => "union", | 9804 | .Union => "union", |
| 9788 | else => unreachable, | 9805 | else => unreachable, |
| 9789 | }; | 9806 | }; |
| 9790 | return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{ | 9807 | return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{ |
| 9791 | dest_ty.fmt(sema.mod), container, | 9808 | dest_ty.fmt(mod), container, |
| 9792 | }); | 9809 | }); |
| 9793 | }, | 9810 | }, |
| 9794 | 9811 | ||
| ... | @@ -9799,7 +9816,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9799,7 +9816,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9799 | .Vector, | 9816 | .Vector, |
| 9800 | => {}, | 9817 | => {}, |
| 9801 | } | 9818 | } |
| 9802 | switch (operand_ty.zigTypeTag()) { | 9819 | switch (operand_ty.zigTypeTag(mod)) { |
| 9803 | .AnyFrame, | 9820 | .AnyFrame, |
| 9804 | .ComptimeFloat, | 9821 | .ComptimeFloat, |
| 9805 | .ComptimeInt, | 9822 | .ComptimeInt, |
| ... | @@ -9815,14 +9832,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9815,14 +9832,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9815 | .Type, | 9832 | .Type, |
| 9816 | .Undefined, | 9833 | .Undefined, |
| 9817 | .Void, | 9834 | .Void, |
| 9818 | => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}), | 9835 | => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(mod)}), |
| 9819 | 9836 | ||
| 9820 | .Enum => { | 9837 | .Enum => { |
| 9821 | const msg = msg: { | 9838 | const msg = msg: { |
| 9822 | const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}); | 9839 | const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(mod)}); |
| 9823 | errdefer msg.destroy(sema.gpa); | 9840 | errdefer msg.destroy(sema.gpa); |
| 9824 | switch (dest_ty.zigTypeTag()) { | 9841 | switch (dest_ty.zigTypeTag(mod)) { |
| 9825 | .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}), | 9842 | .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(mod)}), |
| 9826 | else => {}, | 9843 | else => {}, |
| 9827 | } | 9844 | } |
| 9828 | 9845 | ||
| ... | @@ -9832,11 +9849,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9832,11 +9849,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9832 | }, | 9849 | }, |
| 9833 | .Pointer => { | 9850 | .Pointer => { |
| 9834 | const msg = msg: { | 9851 | const msg = msg: { |
| 9835 | const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}); | 9852 | const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(mod)}); |
| 9836 | errdefer msg.destroy(sema.gpa); | 9853 | errdefer msg.destroy(sema.gpa); |
| 9837 | switch (dest_ty.zigTypeTag()) { | 9854 | switch (dest_ty.zigTypeTag(mod)) { |
| 9838 | .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}), | 9855 | .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(mod)}), |
| 9839 | .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(sema.mod)}), | 9856 | .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(mod)}), |
| 9840 | else => {}, | 9857 | else => {}, |
| 9841 | } | 9858 | } |
| 9842 | 9859 | ||
| ... | @@ -9844,14 +9861,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9844,14 +9861,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9844 | }; | 9861 | }; |
| 9845 | return sema.failWithOwnedErrorMsg(msg); | 9862 | return sema.failWithOwnedErrorMsg(msg); |
| 9846 | }, | 9863 | }, |
| 9847 | .Struct, .Union => if (operand_ty.containerLayout() == .Auto) { | 9864 | .Struct, .Union => if (operand_ty.containerLayout(mod) == .Auto) { |
| 9848 | const container = switch (operand_ty.zigTypeTag()) { | 9865 | const container = switch (operand_ty.zigTypeTag(mod)) { |
| 9849 | .Struct => "struct", | 9866 | .Struct => "struct", |
| 9850 | .Union => "union", | 9867 | .Union => "union", |
| 9851 | else => unreachable, | 9868 | else => unreachable, |
| 9852 | }; | 9869 | }; |
| 9853 | return sema.fail(block, operand_src, "cannot @bitCast from '{}'; {s} does not have a guaranteed in-memory layout", .{ | 9870 | return sema.fail(block, operand_src, "cannot @bitCast from '{}'; {s} does not have a guaranteed in-memory layout", .{ |
| 9854 | operand_ty.fmt(sema.mod), container, | 9871 | operand_ty.fmt(mod), container, |
| 9855 | }); | 9872 | }); |
| 9856 | }, | 9873 | }, |
| 9857 | 9874 | ||
| ... | @@ -9869,6 +9886,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -9869,6 +9886,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 9869 | const tracy = trace(@src()); | 9886 | const tracy = trace(@src()); |
| 9870 | defer tracy.end(); | 9887 | defer tracy.end(); |
| 9871 | 9888 | ||
| 9889 | const mod = sema.mod; | ||
| 9872 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 9890 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9873 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 9891 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 9874 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 9892 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| ... | @@ -9877,31 +9895,31 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -9877,31 +9895,31 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 9877 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); | 9895 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 9878 | const operand = try sema.resolveInst(extra.rhs); | 9896 | const operand = try sema.resolveInst(extra.rhs); |
| 9879 | 9897 | ||
| 9880 | const target = sema.mod.getTarget(); | 9898 | const target = mod.getTarget(); |
| 9881 | const dest_is_comptime_float = switch (dest_ty.zigTypeTag()) { | 9899 | const dest_is_comptime_float = switch (dest_ty.zigTypeTag(mod)) { |
| 9882 | .ComptimeFloat => true, | 9900 | .ComptimeFloat => true, |
| 9883 | .Float => false, | 9901 | .Float => false, |
| 9884 | else => return sema.fail( | 9902 | else => return sema.fail( |
| 9885 | block, | 9903 | block, |
| 9886 | dest_ty_src, | 9904 | dest_ty_src, |
| 9887 | "expected float type, found '{}'", | 9905 | "expected float type, found '{}'", |
| 9888 | .{dest_ty.fmt(sema.mod)}, | 9906 | .{dest_ty.fmt(mod)}, |
| 9889 | ), | 9907 | ), |
| 9890 | }; | 9908 | }; |
| 9891 | 9909 | ||
| 9892 | const operand_ty = sema.typeOf(operand); | 9910 | const operand_ty = sema.typeOf(operand); |
| 9893 | switch (operand_ty.zigTypeTag()) { | 9911 | switch (operand_ty.zigTypeTag(mod)) { |
| 9894 | .ComptimeFloat, .Float, .ComptimeInt => {}, | 9912 | .ComptimeFloat, .Float, .ComptimeInt => {}, |
| 9895 | else => return sema.fail( | 9913 | else => return sema.fail( |
| 9896 | block, | 9914 | block, |
| 9897 | operand_src, | 9915 | operand_src, |
| 9898 | "expected float type, found '{}'", | 9916 | "expected float type, found '{}'", |
| 9899 | .{operand_ty.fmt(sema.mod)}, | 9917 | .{operand_ty.fmt(mod)}, |
| 9900 | ), | 9918 | ), |
| 9901 | } | 9919 | } |
| 9902 | 9920 | ||
| 9903 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { | 9921 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { |
| 9904 | return sema.addConstant(dest_ty, try operand_val.floatCast(sema.arena, dest_ty, target)); | 9922 | return sema.addConstant(dest_ty, try operand_val.floatCast(dest_ty, mod)); |
| 9905 | } | 9923 | } |
| 9906 | if (dest_is_comptime_float) { | 9924 | if (dest_is_comptime_float) { |
| 9907 | return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_float'", .{}); | 9925 | return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_float'", .{}); |
| ... | @@ -9944,20 +9962,21 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9944,20 +9962,21 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9944 | const tracy = trace(@src()); | 9962 | const tracy = trace(@src()); |
| 9945 | defer tracy.end(); | 9963 | defer tracy.end(); |
| 9946 | 9964 | ||
| 9965 | const mod = sema.mod; | ||
| 9947 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 9966 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 9948 | const src = inst_data.src(); | 9967 | const src = inst_data.src(); |
| 9949 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 9968 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 9950 | const array_ptr = try sema.resolveInst(extra.lhs); | 9969 | const array_ptr = try sema.resolveInst(extra.lhs); |
| 9951 | const elem_index = try sema.resolveInst(extra.rhs); | 9970 | const elem_index = try sema.resolveInst(extra.rhs); |
| 9952 | const indexable_ty = sema.typeOf(array_ptr); | 9971 | const indexable_ty = sema.typeOf(array_ptr); |
| 9953 | if (indexable_ty.zigTypeTag() != .Pointer) { | 9972 | if (indexable_ty.zigTypeTag(mod) != .Pointer) { |
| 9954 | const capture_src: LazySrcLoc = .{ .for_capture_from_input = inst_data.src_node }; | 9973 | const capture_src: LazySrcLoc = .{ .for_capture_from_input = inst_data.src_node }; |
| 9955 | const msg = msg: { | 9974 | const msg = msg: { |
| 9956 | const msg = try sema.errMsg(block, capture_src, "pointer capture of non pointer type '{}'", .{ | 9975 | const msg = try sema.errMsg(block, capture_src, "pointer capture of non pointer type '{}'", .{ |
| 9957 | indexable_ty.fmt(sema.mod), | 9976 | indexable_ty.fmt(mod), |
| 9958 | }); | 9977 | }); |
| 9959 | errdefer msg.destroy(sema.gpa); | 9978 | errdefer msg.destroy(sema.gpa); |
| 9960 | if (indexable_ty.zigTypeTag() == .Array) { | 9979 | if (indexable_ty.zigTypeTag(mod) == .Array) { |
| 9961 | try sema.errNote(block, src, msg, "consider using '&' here", .{}); | 9980 | try sema.errNote(block, src, msg, "consider using '&' here", .{}); |
| 9962 | } | 9981 | } |
| 9963 | break :msg msg; | 9982 | break :msg msg; |
| ... | @@ -10054,7 +10073,7 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10054,7 +10073,7 @@ fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10054 | const array_ptr = try sema.resolveInst(extra.lhs); | 10073 | const array_ptr = try sema.resolveInst(extra.lhs); |
| 10055 | const start = try sema.resolveInst(extra.start); | 10074 | const start = try sema.resolveInst(extra.start); |
| 10056 | const len = try sema.resolveInst(extra.len); | 10075 | const len = try sema.resolveInst(extra.len); |
| 10057 | const sentinel = try sema.resolveInst(extra.sentinel); | 10076 | const sentinel = if (extra.sentinel == .none) .none else try sema.resolveInst(extra.sentinel); |
| 10058 | const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node }; | 10077 | const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node }; |
| 10059 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset }; | 10078 | const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset }; |
| 10060 | const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; | 10079 | const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node }; |
| ... | @@ -10076,6 +10095,8 @@ fn zirSwitchCapture( | ... | @@ -10076,6 +10095,8 @@ fn zirSwitchCapture( |
| 10076 | const tracy = trace(@src()); | 10095 | const tracy = trace(@src()); |
| 10077 | defer tracy.end(); | 10096 | defer tracy.end(); |
| 10078 | 10097 | ||
| 10098 | const mod = sema.mod; | ||
| 10099 | const gpa = sema.gpa; | ||
| 10079 | const zir_datas = sema.code.instructions.items(.data); | 10100 | const zir_datas = sema.code.instructions.items(.data); |
| 10080 | const capture_info = zir_datas[inst].switch_capture; | 10101 | const capture_info = zir_datas[inst].switch_capture; |
| 10081 | const switch_info = zir_datas[capture_info.switch_inst].pl_node; | 10102 | const switch_info = zir_datas[capture_info.switch_inst].pl_node; |
| ... | @@ -10087,47 +10108,49 @@ fn zirSwitchCapture( | ... | @@ -10087,47 +10108,49 @@ fn zirSwitchCapture( |
| 10087 | const operand_is_ref = cond_tag == .switch_cond_ref; | 10108 | const operand_is_ref = cond_tag == .switch_cond_ref; |
| 10088 | const operand_ptr = try sema.resolveInst(cond_info.operand); | 10109 | const operand_ptr = try sema.resolveInst(cond_info.operand); |
| 10089 | const operand_ptr_ty = sema.typeOf(operand_ptr); | 10110 | const operand_ptr_ty = sema.typeOf(operand_ptr); |
| 10090 | const operand_ty = if (operand_is_ref) operand_ptr_ty.childType() else operand_ptr_ty; | 10111 | const operand_ty = if (operand_is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty; |
| 10091 | 10112 | ||
| 10092 | if (block.inline_case_capture != .none) { | 10113 | if (block.inline_case_capture != .none) { |
| 10093 | const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable; | 10114 | const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable; |
| 10094 | if (operand_ty.zigTypeTag() == .Union) { | 10115 | const resolved_item_val = try sema.resolveLazyValue(item_val); |
| 10095 | const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?); | 10116 | if (operand_ty.zigTypeTag(mod) == .Union) { |
| 10096 | const union_obj = operand_ty.cast(Type.Payload.Union).?.data; | 10117 | const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(resolved_item_val, mod).?); |
| 10118 | const union_obj = mod.typeToUnion(operand_ty).?; | ||
| 10097 | const field_ty = union_obj.fields.values()[field_index].ty; | 10119 | const field_ty = union_obj.fields.values()[field_index].ty; |
| 10098 | if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| { | 10120 | if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| { |
| 10099 | if (is_ref) { | 10121 | if (is_ref) { |
| 10100 | const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{ | 10122 | const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ |
| 10101 | .pointee_type = field_ty, | 10123 | .pointee_type = field_ty, |
| 10102 | .mutable = operand_ptr_ty.ptrIsMutable(), | 10124 | .mutable = operand_ptr_ty.ptrIsMutable(mod), |
| 10103 | .@"volatile" = operand_ptr_ty.isVolatilePtr(), | 10125 | .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), |
| 10104 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(), | 10126 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), |
| 10105 | }); | 10127 | }); |
| 10106 | return sema.addConstant( | 10128 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ |
| 10107 | ptr_field_ty, | 10129 | .ty = ptr_field_ty.toIntern(), |
| 10108 | try Value.Tag.field_ptr.create(sema.arena, .{ | 10130 | .addr = .{ .field = .{ |
| 10109 | .container_ptr = union_val, | 10131 | .base = union_val.toIntern(), |
| 10110 | .container_ty = operand_ty, | 10132 | .index = field_index, |
| 10111 | .field_index = field_index, | 10133 | } }, |
| 10112 | }), | 10134 | } })).toValue()); |
| 10113 | ); | ||
| 10114 | } | 10135 | } |
| 10115 | const tag_and_val = union_val.castTag(.@"union").?.data; | 10136 | return sema.addConstant( |
| 10116 | return sema.addConstant(field_ty, tag_and_val.val); | 10137 | field_ty, |
| 10138 | mod.intern_pool.indexToKey(union_val.toIntern()).un.val.toValue(), | ||
| 10139 | ); | ||
| 10117 | } | 10140 | } |
| 10118 | if (is_ref) { | 10141 | if (is_ref) { |
| 10119 | const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{ | 10142 | const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ |
| 10120 | .pointee_type = field_ty, | 10143 | .pointee_type = field_ty, |
| 10121 | .mutable = operand_ptr_ty.ptrIsMutable(), | 10144 | .mutable = operand_ptr_ty.ptrIsMutable(mod), |
| 10122 | .@"volatile" = operand_ptr_ty.isVolatilePtr(), | 10145 | .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), |
| 10123 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(), | 10146 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), |
| 10124 | }); | 10147 | }); |
| 10125 | return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty); | 10148 | return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty); |
| 10126 | } else { | 10149 | } else { |
| 10127 | return block.addStructFieldVal(operand_ptr, field_index, field_ty); | 10150 | return block.addStructFieldVal(operand_ptr, field_index, field_ty); |
| 10128 | } | 10151 | } |
| 10129 | } else if (is_ref) { | 10152 | } else if (is_ref) { |
| 10130 | return sema.addConstantMaybeRef(block, operand_ty, item_val, true); | 10153 | return sema.addConstantMaybeRef(block, operand_ty, resolved_item_val, true); |
| 10131 | } else { | 10154 | } else { |
| 10132 | return block.inline_case_capture; | 10155 | return block.inline_case_capture; |
| 10133 | } | 10156 | } |
| ... | @@ -10144,7 +10167,7 @@ fn zirSwitchCapture( | ... | @@ -10144,7 +10167,7 @@ fn zirSwitchCapture( |
| 10144 | return operand_ptr; | 10167 | return operand_ptr; |
| 10145 | } | 10168 | } |
| 10146 | 10169 | ||
| 10147 | switch (operand_ty.zigTypeTag()) { | 10170 | switch (operand_ty.zigTypeTag(mod)) { |
| 10148 | .ErrorSet => if (block.switch_else_err_ty) |some| { | 10171 | .ErrorSet => if (block.switch_else_err_ty) |some| { |
| 10149 | return sema.bitCast(block, some, operand, operand_src, null); | 10172 | return sema.bitCast(block, some, operand, operand_src, null); |
| 10150 | } else { | 10173 | } else { |
| ... | @@ -10162,14 +10185,14 @@ fn zirSwitchCapture( | ... | @@ -10162,14 +10185,14 @@ fn zirSwitchCapture( |
| 10162 | switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item, | 10185 | switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item, |
| 10163 | }; | 10186 | }; |
| 10164 | 10187 | ||
| 10165 | switch (operand_ty.zigTypeTag()) { | 10188 | switch (operand_ty.zigTypeTag(mod)) { |
| 10166 | .Union => { | 10189 | .Union => { |
| 10167 | const union_obj = operand_ty.cast(Type.Payload.Union).?.data; | 10190 | const union_obj = mod.typeToUnion(operand_ty).?; |
| 10168 | const first_item = try sema.resolveInst(items[0]); | 10191 | const first_item = try sema.resolveInst(items[0]); |
| 10169 | // Previous switch validation ensured this will succeed | 10192 | // Previous switch validation ensured this will succeed |
| 10170 | const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable; | 10193 | const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable; |
| 10171 | 10194 | ||
| 10172 | const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, sema.mod).?); | 10195 | const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?); |
| 10173 | const first_field = union_obj.fields.values()[first_field_index]; | 10196 | const first_field = union_obj.fields.values()[first_field_index]; |
| 10174 | 10197 | ||
| 10175 | for (items[1..], 0..) |item, i| { | 10198 | for (items[1..], 0..) |item, i| { |
| ... | @@ -10177,22 +10200,22 @@ fn zirSwitchCapture( | ... | @@ -10177,22 +10200,22 @@ fn zirSwitchCapture( |
| 10177 | // Previous switch validation ensured this will succeed | 10200 | // Previous switch validation ensured this will succeed |
| 10178 | const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; | 10201 | const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; |
| 10179 | 10202 | ||
| 10180 | const field_index = operand_ty.unionTagFieldIndex(item_val, sema.mod).?; | 10203 | const field_index = operand_ty.unionTagFieldIndex(item_val, mod).?; |
| 10181 | const field = union_obj.fields.values()[field_index]; | 10204 | const field = union_obj.fields.values()[field_index]; |
| 10182 | if (!field.ty.eql(first_field.ty, sema.mod)) { | 10205 | if (!field.ty.eql(first_field.ty, mod)) { |
| 10183 | const msg = msg: { | 10206 | const msg = msg: { |
| 10184 | const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index }; | 10207 | const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index }; |
| 10185 | const capture_src = raw_capture_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); | 10208 | const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); |
| 10186 | 10209 | ||
| 10187 | const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{}); | 10210 | const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{}); |
| 10188 | errdefer msg.destroy(sema.gpa); | 10211 | errdefer msg.destroy(gpa); |
| 10189 | 10212 | ||
| 10190 | const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } }; | 10213 | const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } }; |
| 10191 | const first_item_src = raw_first_item_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); | 10214 | const first_item_src = raw_first_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); |
| 10192 | const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } }; | 10215 | const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } }; |
| 10193 | const item_src = raw_item_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first); | 10216 | const item_src = raw_item_src.resolve(mod, mod.declPtr(block.src_decl), switch_info.src_node, .first); |
| 10194 | try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(sema.mod)}); | 10217 | try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(mod)}); |
| 10195 | try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(sema.mod)}); | 10218 | try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(mod)}); |
| 10196 | break :msg msg; | 10219 | break :msg msg; |
| 10197 | }; | 10220 | }; |
| 10198 | return sema.failWithOwnedErrorMsg(msg); | 10221 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -10200,21 +10223,20 @@ fn zirSwitchCapture( | ... | @@ -10200,21 +10223,20 @@ fn zirSwitchCapture( |
| 10200 | } | 10223 | } |
| 10201 | 10224 | ||
| 10202 | if (is_ref) { | 10225 | if (is_ref) { |
| 10203 | const field_ty_ptr = try Type.ptr(sema.arena, sema.mod, .{ | 10226 | const field_ty_ptr = try Type.ptr(sema.arena, mod, .{ |
| 10204 | .pointee_type = first_field.ty, | 10227 | .pointee_type = first_field.ty, |
| 10205 | .@"addrspace" = .generic, | 10228 | .@"addrspace" = .generic, |
| 10206 | .mutable = operand_ptr_ty.ptrIsMutable(), | 10229 | .mutable = operand_ptr_ty.ptrIsMutable(mod), |
| 10207 | }); | 10230 | }); |
| 10208 | 10231 | ||
| 10209 | if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| { | 10232 | if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| { |
| 10210 | return sema.addConstant( | 10233 | return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{ |
| 10211 | field_ty_ptr, | 10234 | .ty = field_ty_ptr.toIntern(), |
| 10212 | try Value.Tag.field_ptr.create(sema.arena, .{ | 10235 | .addr = .{ .field = .{ |
| 10213 | .container_ptr = op_ptr_val, | 10236 | .base = op_ptr_val.toIntern(), |
| 10214 | .container_ty = operand_ty, | 10237 | .index = first_field_index, |
| 10215 | .field_index = first_field_index, | 10238 | } }, |
| 10216 | }), | 10239 | } })).toValue()); |
| 10217 | ); | ||
| 10218 | } | 10240 | } |
| 10219 | try sema.requireRuntimeBlock(block, operand_src, null); | 10241 | try sema.requireRuntimeBlock(block, operand_src, null); |
| 10220 | return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr); | 10242 | return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr); |
| ... | @@ -10223,7 +10245,7 @@ fn zirSwitchCapture( | ... | @@ -10223,7 +10245,7 @@ fn zirSwitchCapture( |
| 10223 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| { | 10245 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| { |
| 10224 | return sema.addConstant( | 10246 | return sema.addConstant( |
| 10225 | first_field.ty, | 10247 | first_field.ty, |
| 10226 | operand_val.castTag(.@"union").?.data.val, | 10248 | mod.intern_pool.indexToKey(operand_val.toIntern()).un.val.toValue(), |
| 10227 | ); | 10249 | ); |
| 10228 | } | 10250 | } |
| 10229 | try sema.requireRuntimeBlock(block, operand_src, null); | 10251 | try sema.requireRuntimeBlock(block, operand_src, null); |
| ... | @@ -10231,28 +10253,23 @@ fn zirSwitchCapture( | ... | @@ -10231,28 +10253,23 @@ fn zirSwitchCapture( |
| 10231 | }, | 10253 | }, |
| 10232 | .ErrorSet => { | 10254 | .ErrorSet => { |
| 10233 | if (is_multi) { | 10255 | if (is_multi) { |
| 10234 | var names: Module.ErrorSet.NameMap = .{}; | 10256 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; |
| 10235 | try names.ensureUnusedCapacity(sema.arena, items.len); | 10257 | try names.ensureUnusedCapacity(sema.arena, items.len); |
| 10236 | for (items) |item| { | 10258 | for (items) |item| { |
| 10237 | const item_ref = try sema.resolveInst(item); | 10259 | const item_ref = try sema.resolveInst(item); |
| 10238 | // Previous switch validation ensured this will succeed | 10260 | // Previous switch validation ensured this will succeed |
| 10239 | const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; | 10261 | const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable; |
| 10240 | names.putAssumeCapacityNoClobber( | 10262 | names.putAssumeCapacityNoClobber(item_val.getErrorName(mod).unwrap().?, {}); |
| 10241 | item_val.getError().?, | ||
| 10242 | {}, | ||
| 10243 | ); | ||
| 10244 | } | 10263 | } |
| 10245 | // names must be sorted | 10264 | const else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); |
| 10246 | Module.ErrorSet.sortNames(&names); | ||
| 10247 | const else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names); | ||
| 10248 | 10265 | ||
| 10249 | return sema.bitCast(block, else_error_ty, operand, operand_src, null); | 10266 | return sema.bitCast(block, else_error_ty, operand, operand_src, null); |
| 10250 | } else { | 10267 | } else { |
| 10251 | const item_ref = try sema.resolveInst(items[0]); | 10268 | const item_ref = try sema.resolveInst(items[0]); |
| 10252 | // Previous switch validation ensured this will succeed | 10269 | // Previous switch validation ensured this will succeed |
| 10253 | const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; | 10270 | const item_val = sema.resolveConstLazyValue(block, .unneeded, item_ref, "") catch unreachable; |
| 10254 | 10271 | ||
| 10255 | const item_ty = try Type.Tag.error_set_single.create(sema.arena, item_val.getError().?); | 10272 | const item_ty = try mod.singleErrorSetType(item_val.getErrorName(mod).unwrap().?); |
| 10256 | return sema.bitCast(block, item_ty, operand, operand_src, null); | 10273 | return sema.bitCast(block, item_ty, operand, operand_src, null); |
| 10257 | } | 10274 | } |
| 10258 | }, | 10275 | }, |
| ... | @@ -10269,6 +10286,7 @@ fn zirSwitchCapture( | ... | @@ -10269,6 +10286,7 @@ fn zirSwitchCapture( |
| 10269 | } | 10286 | } |
| 10270 | 10287 | ||
| 10271 | fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 10288 | fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 10289 | const mod = sema.mod; | ||
| 10272 | const zir_datas = sema.code.instructions.items(.data); | 10290 | const zir_datas = sema.code.instructions.items(.data); |
| 10273 | const inst_data = zir_datas[inst].un_tok; | 10291 | const inst_data = zir_datas[inst].un_tok; |
| 10274 | const src = inst_data.src(); | 10292 | const src = inst_data.src(); |
| ... | @@ -10278,12 +10296,12 @@ fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile | ... | @@ -10278,12 +10296,12 @@ fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile |
| 10278 | const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node; | 10296 | const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node; |
| 10279 | const operand_ptr = try sema.resolveInst(cond_data.operand); | 10297 | const operand_ptr = try sema.resolveInst(cond_data.operand); |
| 10280 | const operand_ptr_ty = sema.typeOf(operand_ptr); | 10298 | const operand_ptr_ty = sema.typeOf(operand_ptr); |
| 10281 | const operand_ty = if (is_ref) operand_ptr_ty.childType() else operand_ptr_ty; | 10299 | const operand_ty = if (is_ref) operand_ptr_ty.childType(mod) else operand_ptr_ty; |
| 10282 | 10300 | ||
| 10283 | if (operand_ty.zigTypeTag() != .Union) { | 10301 | if (operand_ty.zigTypeTag(mod) != .Union) { |
| 10284 | const msg = msg: { | 10302 | const msg = msg: { |
| 10285 | const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{ | 10303 | const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{ |
| 10286 | operand_ty.fmt(sema.mod), | 10304 | operand_ty.fmt(mod), |
| 10287 | }); | 10305 | }); |
| 10288 | errdefer msg.destroy(sema.gpa); | 10306 | errdefer msg.destroy(sema.gpa); |
| 10289 | try sema.addDeclaredHereNote(msg, operand_ty); | 10307 | try sema.addDeclaredHereNote(msg, operand_ty); |
| ... | @@ -10301,6 +10319,7 @@ fn zirSwitchCond( | ... | @@ -10301,6 +10319,7 @@ fn zirSwitchCond( |
| 10301 | inst: Zir.Inst.Index, | 10319 | inst: Zir.Inst.Index, |
| 10302 | is_ref: bool, | 10320 | is_ref: bool, |
| 10303 | ) CompileError!Air.Inst.Ref { | 10321 | ) CompileError!Air.Inst.Ref { |
| 10322 | const mod = sema.mod; | ||
| 10304 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 10323 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 10305 | const src = inst_data.src(); | 10324 | const src = inst_data.src(); |
| 10306 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; | 10325 | const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node }; |
| ... | @@ -10311,7 +10330,7 @@ fn zirSwitchCond( | ... | @@ -10311,7 +10330,7 @@ fn zirSwitchCond( |
| 10311 | operand_ptr; | 10330 | operand_ptr; |
| 10312 | const operand_ty = sema.typeOf(operand); | 10331 | const operand_ty = sema.typeOf(operand); |
| 10313 | 10332 | ||
| 10314 | switch (operand_ty.zigTypeTag()) { | 10333 | switch (operand_ty.zigTypeTag(mod)) { |
| 10315 | .Type, | 10334 | .Type, |
| 10316 | .Void, | 10335 | .Void, |
| 10317 | .Bool, | 10336 | .Bool, |
| ... | @@ -10325,8 +10344,8 @@ fn zirSwitchCond( | ... | @@ -10325,8 +10344,8 @@ fn zirSwitchCond( |
| 10325 | .ErrorSet, | 10344 | .ErrorSet, |
| 10326 | .Enum, | 10345 | .Enum, |
| 10327 | => { | 10346 | => { |
| 10328 | if (operand_ty.isSlice()) { | 10347 | if (operand_ty.isSlice(mod)) { |
| 10329 | return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}); | 10348 | return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(mod)}); |
| 10330 | } | 10349 | } |
| 10331 | if ((try sema.typeHasOnePossibleValue(operand_ty))) |opv| { | 10350 | if ((try sema.typeHasOnePossibleValue(operand_ty))) |opv| { |
| 10332 | return sema.addConstant(operand_ty, opv); | 10351 | return sema.addConstant(operand_ty, opv); |
| ... | @@ -10336,12 +10355,12 @@ fn zirSwitchCond( | ... | @@ -10336,12 +10355,12 @@ fn zirSwitchCond( |
| 10336 | 10355 | ||
| 10337 | .Union => { | 10356 | .Union => { |
| 10338 | const union_ty = try sema.resolveTypeFields(operand_ty); | 10357 | const union_ty = try sema.resolveTypeFields(operand_ty); |
| 10339 | const enum_ty = union_ty.unionTagType() orelse { | 10358 | const enum_ty = union_ty.unionTagType(mod) orelse { |
| 10340 | const msg = msg: { | 10359 | const msg = msg: { |
| 10341 | const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{}); | 10360 | const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{}); |
| 10342 | errdefer msg.destroy(sema.gpa); | 10361 | errdefer msg.destroy(sema.gpa); |
| 10343 | if (union_ty.declSrcLocOrNull(sema.mod)) |union_src| { | 10362 | if (union_ty.declSrcLocOrNull(mod)) |union_src| { |
| 10344 | try sema.mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{}); | 10363 | try mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{}); |
| 10345 | } | 10364 | } |
| 10346 | break :msg msg; | 10365 | break :msg msg; |
| 10347 | }; | 10366 | }; |
| ... | @@ -10361,17 +10380,19 @@ fn zirSwitchCond( | ... | @@ -10361,17 +10380,19 @@ fn zirSwitchCond( |
| 10361 | .Vector, | 10380 | .Vector, |
| 10362 | .Frame, | 10381 | .Frame, |
| 10363 | .AnyFrame, | 10382 | .AnyFrame, |
| 10364 | => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}), | 10383 | => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(mod)}), |
| 10365 | } | 10384 | } |
| 10366 | } | 10385 | } |
| 10367 | 10386 | ||
| 10368 | const SwitchErrorSet = std.StringHashMap(Module.SwitchProngSrc); | 10387 | const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc); |
| 10369 | 10388 | ||
| 10370 | fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 10389 | fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 10371 | const tracy = trace(@src()); | 10390 | const tracy = trace(@src()); |
| 10372 | defer tracy.end(); | 10391 | defer tracy.end(); |
| 10373 | 10392 | ||
| 10393 | const mod = sema.mod; | ||
| 10374 | const gpa = sema.gpa; | 10394 | const gpa = sema.gpa; |
| 10395 | const ip = &mod.intern_pool; | ||
| 10375 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 10396 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 10376 | const src = inst_data.src(); | 10397 | const src = inst_data.src(); |
| 10377 | const src_node_offset = inst_data.src_node; | 10398 | const src_node_offset = inst_data.src_node; |
| ... | @@ -10413,14 +10434,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10413,14 +10434,14 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10413 | const cond_index = Zir.refToIndex(extra.data.operand).?; | 10434 | const cond_index = Zir.refToIndex(extra.data.operand).?; |
| 10414 | const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable; | 10435 | const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable; |
| 10415 | const target_ty = sema.typeOf(raw_operand); | 10436 | const target_ty = sema.typeOf(raw_operand); |
| 10416 | break :blk if (zir_tags[cond_index] == .switch_cond_ref) target_ty.elemType() else target_ty; | 10437 | break :blk if (zir_tags[cond_index] == .switch_cond_ref) target_ty.childType(mod) else target_ty; |
| 10417 | }; | 10438 | }; |
| 10418 | const union_originally = maybe_union_ty.zigTypeTag() == .Union; | 10439 | const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union; |
| 10419 | 10440 | ||
| 10420 | // Duplicate checking variables later also used for `inline else`. | 10441 | // Duplicate checking variables later also used for `inline else`. |
| 10421 | var seen_enum_fields: []?Module.SwitchProngSrc = &.{}; | 10442 | var seen_enum_fields: []?Module.SwitchProngSrc = &.{}; |
| 10422 | var seen_errors = SwitchErrorSet.init(gpa); | 10443 | var seen_errors = SwitchErrorSet.init(gpa); |
| 10423 | var range_set = RangeSet.init(gpa, sema.mod); | 10444 | var range_set = RangeSet.init(gpa, mod); |
| 10424 | var true_count: u8 = 0; | 10445 | var true_count: u8 = 0; |
| 10425 | var false_count: u8 = 0; | 10446 | var false_count: u8 = 0; |
| 10426 | 10447 | ||
| ... | @@ -10433,12 +10454,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10433,12 +10454,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10433 | var empty_enum = false; | 10454 | var empty_enum = false; |
| 10434 | 10455 | ||
| 10435 | const operand_ty = sema.typeOf(operand); | 10456 | const operand_ty = sema.typeOf(operand); |
| 10436 | const err_set = operand_ty.zigTypeTag() == .ErrorSet; | 10457 | const err_set = operand_ty.zigTypeTag(mod) == .ErrorSet; |
| 10437 | 10458 | ||
| 10438 | var else_error_ty: ?Type = null; | 10459 | var else_error_ty: ?Type = null; |
| 10439 | 10460 | ||
| 10440 | // Validate usage of '_' prongs. | 10461 | // Validate usage of '_' prongs. |
| 10441 | if (special_prong == .under and (!operand_ty.isNonexhaustiveEnum() or union_originally)) { | 10462 | if (special_prong == .under and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) { |
| 10442 | const msg = msg: { | 10463 | const msg = msg: { |
| 10443 | const msg = try sema.errMsg( | 10464 | const msg = try sema.errMsg( |
| 10444 | block, | 10465 | block, |
| ... | @@ -10459,14 +10480,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10459,14 +10480,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10459 | return sema.failWithOwnedErrorMsg(msg); | 10480 | return sema.failWithOwnedErrorMsg(msg); |
| 10460 | } | 10481 | } |
| 10461 | 10482 | ||
| 10462 | const target = sema.mod.getTarget(); | ||
| 10463 | |||
| 10464 | // Validate for duplicate items, missing else prong, and invalid range. | 10483 | // Validate for duplicate items, missing else prong, and invalid range. |
| 10465 | switch (operand_ty.zigTypeTag()) { | 10484 | switch (operand_ty.zigTypeTag(mod)) { |
| 10466 | .Union => unreachable, // handled in zirSwitchCond | 10485 | .Union => unreachable, // handled in zirSwitchCond |
| 10467 | .Enum => { | 10486 | .Enum => { |
| 10468 | seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount()); | 10487 | seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount(mod)); |
| 10469 | empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(); | 10488 | empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(mod); |
| 10470 | @memset(seen_enum_fields, null); | 10489 | @memset(seen_enum_fields, null); |
| 10471 | // `range_set` is used for non-exhaustive enum values that do not correspond to any tags. | 10490 | // `range_set` is used for non-exhaustive enum values that do not correspond to any tags. |
| 10472 | 10491 | ||
| ... | @@ -10521,7 +10540,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10521,7 +10540,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10521 | } else true; | 10540 | } else true; |
| 10522 | 10541 | ||
| 10523 | if (special_prong == .@"else") { | 10542 | if (special_prong == .@"else") { |
| 10524 | if (all_tags_handled and !operand_ty.isNonexhaustiveEnum()) return sema.fail( | 10543 | if (all_tags_handled and !operand_ty.isNonexhaustiveEnum(mod)) return sema.fail( |
| 10525 | block, | 10544 | block, |
| 10526 | special_prong_src, | 10545 | special_prong_src, |
| 10527 | "unreachable else prong; all cases already handled", | 10546 | "unreachable else prong; all cases already handled", |
| ... | @@ -10539,25 +10558,25 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10539,25 +10558,25 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10539 | for (seen_enum_fields, 0..) |seen_src, i| { | 10558 | for (seen_enum_fields, 0..) |seen_src, i| { |
| 10540 | if (seen_src != null) continue; | 10559 | if (seen_src != null) continue; |
| 10541 | 10560 | ||
| 10542 | const field_name = operand_ty.enumFieldName(i); | 10561 | const field_name = operand_ty.enumFieldName(i, mod); |
| 10543 | try sema.addFieldErrNote( | 10562 | try sema.addFieldErrNote( |
| 10544 | operand_ty, | 10563 | operand_ty, |
| 10545 | i, | 10564 | i, |
| 10546 | msg, | 10565 | msg, |
| 10547 | "unhandled enumeration value: '{s}'", | 10566 | "unhandled enumeration value: '{}'", |
| 10548 | .{field_name}, | 10567 | .{field_name.fmt(&mod.intern_pool)}, |
| 10549 | ); | 10568 | ); |
| 10550 | } | 10569 | } |
| 10551 | try sema.mod.errNoteNonLazy( | 10570 | try mod.errNoteNonLazy( |
| 10552 | operand_ty.declSrcLoc(sema.mod), | 10571 | operand_ty.declSrcLoc(mod), |
| 10553 | msg, | 10572 | msg, |
| 10554 | "enum '{}' declared here", | 10573 | "enum '{}' declared here", |
| 10555 | .{operand_ty.fmt(sema.mod)}, | 10574 | .{operand_ty.fmt(mod)}, |
| 10556 | ); | 10575 | ); |
| 10557 | break :msg msg; | 10576 | break :msg msg; |
| 10558 | }; | 10577 | }; |
| 10559 | return sema.failWithOwnedErrorMsg(msg); | 10578 | return sema.failWithOwnedErrorMsg(msg); |
| 10560 | } else if (special_prong == .none and operand_ty.isNonexhaustiveEnum() and !union_originally) { | 10579 | } else if (special_prong == .none and operand_ty.isNonexhaustiveEnum(mod) and !union_originally) { |
| 10561 | return sema.fail( | 10580 | return sema.fail( |
| 10562 | block, | 10581 | block, |
| 10563 | src, | 10582 | src, |
| ... | @@ -10614,7 +10633,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10614,7 +10633,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10614 | 10633 | ||
| 10615 | try sema.resolveInferredErrorSetTy(block, src, operand_ty); | 10634 | try sema.resolveInferredErrorSetTy(block, src, operand_ty); |
| 10616 | 10635 | ||
| 10617 | if (operand_ty.isAnyError()) { | 10636 | if (operand_ty.isAnyError(mod)) { |
| 10618 | if (special_prong != .@"else") { | 10637 | if (special_prong != .@"else") { |
| 10619 | return sema.fail( | 10638 | return sema.fail( |
| 10620 | block, | 10639 | block, |
| ... | @@ -10628,7 +10647,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10628,7 +10647,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10628 | var maybe_msg: ?*Module.ErrorMsg = null; | 10647 | var maybe_msg: ?*Module.ErrorMsg = null; |
| 10629 | errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa); | 10648 | errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa); |
| 10630 | 10649 | ||
| 10631 | for (operand_ty.errorSetNames()) |error_name| { | 10650 | for (operand_ty.errorSetNames(mod)) |error_name| { |
| 10632 | if (!seen_errors.contains(error_name) and special_prong != .@"else") { | 10651 | if (!seen_errors.contains(error_name) and special_prong != .@"else") { |
| 10633 | const msg = maybe_msg orelse blk: { | 10652 | const msg = maybe_msg orelse blk: { |
| 10634 | maybe_msg = try sema.errMsg( | 10653 | maybe_msg = try sema.errMsg( |
| ... | @@ -10644,8 +10663,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10644,8 +10663,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10644 | block, | 10663 | block, |
| 10645 | src, | 10664 | src, |
| 10646 | msg, | 10665 | msg, |
| 10647 | "unhandled error value: 'error.{s}'", | 10666 | "unhandled error value: 'error.{}'", |
| 10648 | .{error_name}, | 10667 | .{error_name.fmt(ip)}, |
| 10649 | ); | 10668 | ); |
| 10650 | } | 10669 | } |
| 10651 | } | 10670 | } |
| ... | @@ -10656,7 +10675,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10656,7 +10675,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10656 | return sema.failWithOwnedErrorMsg(msg); | 10675 | return sema.failWithOwnedErrorMsg(msg); |
| 10657 | } | 10676 | } |
| 10658 | 10677 | ||
| 10659 | if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames().len) { | 10678 | if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames(mod).len) { |
| 10660 | // In order to enable common patterns for generic code allow simple else bodies | 10679 | // In order to enable common patterns for generic code allow simple else bodies |
| 10661 | // else => unreachable, | 10680 | // else => unreachable, |
| 10662 | // else => return, | 10681 | // else => return, |
| ... | @@ -10693,18 +10712,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10693,18 +10712,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10693 | ); | 10712 | ); |
| 10694 | } | 10713 | } |
| 10695 | 10714 | ||
| 10696 | const error_names = operand_ty.errorSetNames(); | 10715 | const error_names = operand_ty.errorSetNames(mod); |
| 10697 | var names: Module.ErrorSet.NameMap = .{}; | 10716 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; |
| 10698 | try names.ensureUnusedCapacity(sema.arena, error_names.len); | 10717 | try names.ensureUnusedCapacity(sema.arena, error_names.len); |
| 10699 | for (error_names) |error_name| { | 10718 | for (error_names) |error_name| { |
| 10700 | if (seen_errors.contains(error_name)) continue; | 10719 | if (seen_errors.contains(error_name)) continue; |
| 10701 | 10720 | ||
| 10702 | names.putAssumeCapacityNoClobber(error_name, {}); | 10721 | names.putAssumeCapacityNoClobber(error_name, {}); |
| 10703 | } | 10722 | } |
| 10704 | 10723 | // No need to keep the hash map metadata correct; here we | |
| 10705 | // names must be sorted | 10724 | // extract the (sorted) keys only. |
| 10706 | Module.ErrorSet.sortNames(&names); | 10725 | else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); |
| 10707 | else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names); | ||
| 10708 | } | 10726 | } |
| 10709 | }, | 10727 | }, |
| 10710 | .Int, .ComptimeInt => { | 10728 | .Int, .ComptimeInt => { |
| ... | @@ -10722,7 +10740,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10722,7 +10740,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10722 | block, | 10740 | block, |
| 10723 | &range_set, | 10741 | &range_set, |
| 10724 | item_ref, | 10742 | item_ref, |
| 10725 | operand_ty, | ||
| 10726 | src_node_offset, | 10743 | src_node_offset, |
| 10727 | .{ .scalar = scalar_i }, | 10744 | .{ .scalar = scalar_i }, |
| 10728 | ); | 10745 | ); |
| ... | @@ -10745,7 +10762,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10745,7 +10762,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10745 | block, | 10762 | block, |
| 10746 | &range_set, | 10763 | &range_set, |
| 10747 | item_ref, | 10764 | item_ref, |
| 10748 | operand_ty, | ||
| 10749 | src_node_offset, | 10765 | src_node_offset, |
| 10750 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, | 10766 | .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }, |
| 10751 | ); | 10767 | ); |
| ... | @@ -10763,7 +10779,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10763,7 +10779,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10763 | &range_set, | 10779 | &range_set, |
| 10764 | item_first, | 10780 | item_first, |
| 10765 | item_last, | 10781 | item_last, |
| 10766 | operand_ty, | ||
| 10767 | src_node_offset, | 10782 | src_node_offset, |
| 10768 | .{ .range = .{ .prong = multi_i, .item = range_i } }, | 10783 | .{ .range = .{ .prong = multi_i, .item = range_i } }, |
| 10769 | ); | 10784 | ); |
| ... | @@ -10774,13 +10789,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10774,13 +10789,10 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10774 | } | 10789 | } |
| 10775 | 10790 | ||
| 10776 | check_range: { | 10791 | check_range: { |
| 10777 | if (operand_ty.zigTypeTag() == .Int) { | 10792 | if (operand_ty.zigTypeTag(mod) == .Int) { |
| 10778 | var arena = std.heap.ArenaAllocator.init(gpa); | 10793 | const min_int = try operand_ty.minInt(mod, operand_ty); |
| 10779 | defer arena.deinit(); | 10794 | const max_int = try operand_ty.maxInt(mod, operand_ty); |
| 10780 | 10795 | if (try range_set.spans(min_int.toIntern(), max_int.toIntern())) { | |
| 10781 | const min_int = try operand_ty.minInt(arena.allocator(), target); | ||
| 10782 | const max_int = try operand_ty.maxInt(arena.allocator(), target); | ||
| 10783 | if (try range_set.spans(min_int, max_int, operand_ty)) { | ||
| 10784 | if (special_prong == .@"else") { | 10796 | if (special_prong == .@"else") { |
| 10785 | return sema.fail( | 10797 | return sema.fail( |
| 10786 | block, | 10798 | block, |
| ... | @@ -10878,15 +10890,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10878,15 +10890,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10878 | block, | 10890 | block, |
| 10879 | src, | 10891 | src, |
| 10880 | "else prong required when switching on type '{}'", | 10892 | "else prong required when switching on type '{}'", |
| 10881 | .{operand_ty.fmt(sema.mod)}, | 10893 | .{operand_ty.fmt(mod)}, |
| 10882 | ); | 10894 | ); |
| 10883 | } | 10895 | } |
| 10884 | 10896 | ||
| 10885 | var seen_values = ValueSrcMap.initContext(gpa, .{ | 10897 | var seen_values = ValueSrcMap{}; |
| 10886 | .ty = operand_ty, | 10898 | defer seen_values.deinit(gpa); |
| 10887 | .mod = sema.mod, | ||
| 10888 | }); | ||
| 10889 | defer seen_values.deinit(); | ||
| 10890 | 10899 | ||
| 10891 | var extra_index: usize = special.end; | 10900 | var extra_index: usize = special.end; |
| 10892 | { | 10901 | { |
| ... | @@ -10948,7 +10957,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10948,7 +10957,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10948 | .ComptimeFloat, | 10957 | .ComptimeFloat, |
| 10949 | .Float, | 10958 | .Float, |
| 10950 | => return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{ | 10959 | => return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{ |
| 10951 | operand_ty.fmt(sema.mod), | 10960 | operand_ty.fmt(mod), |
| 10952 | }), | 10961 | }), |
| 10953 | } | 10962 | } |
| 10954 | 10963 | ||
| ... | @@ -10991,6 +11000,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -10991,6 +11000,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10991 | defer merges.deinit(gpa); | 11000 | defer merges.deinit(gpa); |
| 10992 | 11001 | ||
| 10993 | if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| { | 11002 | if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| { |
| 11003 | const resolved_operand_val = try sema.resolveLazyValue(operand_val); | ||
| 10994 | var extra_index: usize = special.end; | 11004 | var extra_index: usize = special.end; |
| 10995 | { | 11005 | { |
| 10996 | var scalar_i: usize = 0; | 11006 | var scalar_i: usize = 0; |
| ... | @@ -11005,8 +11015,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11005,8 +11015,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11005 | 11015 | ||
| 11006 | const item = try sema.resolveInst(item_ref); | 11016 | const item = try sema.resolveInst(item_ref); |
| 11007 | // Validation above ensured these will succeed. | 11017 | // Validation above ensured these will succeed. |
| 11008 | const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable; | 11018 | const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11009 | if (operand_val.eql(item_val, operand_ty, sema.mod)) { | 11019 | if (resolved_operand_val.eql(item_val, operand_ty, mod)) { |
| 11010 | if (is_inline) child_block.inline_case_capture = operand; | 11020 | if (is_inline) child_block.inline_case_capture = operand; |
| 11011 | 11021 | ||
| 11012 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); | 11022 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| ... | @@ -11031,8 +11041,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11031,8 +11041,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11031 | for (items) |item_ref| { | 11041 | for (items) |item_ref| { |
| 11032 | const item = try sema.resolveInst(item_ref); | 11042 | const item = try sema.resolveInst(item_ref); |
| 11033 | // Validation above ensured these will succeed. | 11043 | // Validation above ensured these will succeed. |
| 11034 | const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable; | 11044 | const item_val = sema.resolveConstLazyValue(&child_block, .unneeded, item, "") catch unreachable; |
| 11035 | if (operand_val.eql(item_val, operand_ty, sema.mod)) { | 11045 | if (resolved_operand_val.eql(item_val, operand_ty, mod)) { |
| 11036 | if (is_inline) child_block.inline_case_capture = operand; | 11046 | if (is_inline) child_block.inline_case_capture = operand; |
| 11037 | 11047 | ||
| 11038 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); | 11048 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| ... | @@ -11050,8 +11060,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11050,8 +11060,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11050 | // Validation above ensured these will succeed. | 11060 | // Validation above ensured these will succeed. |
| 11051 | const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable; | 11061 | const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable; |
| 11052 | const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable; | 11062 | const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable; |
| 11053 | if ((try sema.compareAll(operand_val, .gte, first_tv.val, operand_ty)) and | 11063 | if ((try sema.compareAll(resolved_operand_val, .gte, first_tv.val, operand_ty)) and |
| 11054 | (try sema.compareAll(operand_val, .lte, last_tv.val, operand_ty))) | 11064 | (try sema.compareAll(resolved_operand_val, .lte, last_tv.val, operand_ty))) |
| 11055 | { | 11065 | { |
| 11056 | if (is_inline) child_block.inline_case_capture = operand; | 11066 | if (is_inline) child_block.inline_case_capture = operand; |
| 11057 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); | 11067 | if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand); |
| ... | @@ -11080,8 +11090,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11080,8 +11090,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11080 | if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { | 11090 | if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { |
| 11081 | return Air.Inst.Ref.unreachable_value; | 11091 | return Air.Inst.Ref.unreachable_value; |
| 11082 | } | 11092 | } |
| 11083 | if (sema.mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and | 11093 | if (mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag(mod) == .Enum and |
| 11084 | (!operand_ty.isNonexhaustiveEnum() or union_originally)) | 11094 | (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) |
| 11085 | { | 11095 | { |
| 11086 | try sema.zirDbgStmt(block, cond_dbg_node_index); | 11096 | try sema.zirDbgStmt(block, cond_dbg_node_index); |
| 11087 | const ok = try block.addUnOp(.is_named_enum_value, operand); | 11097 | const ok = try block.addUnOp(.is_named_enum_value, operand); |
| ... | @@ -11121,7 +11131,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11121,7 +11131,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11121 | const body = sema.code.extra[extra_index..][0..body_len]; | 11131 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 11122 | extra_index += body_len; | 11132 | extra_index += body_len; |
| 11123 | 11133 | ||
| 11124 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); | 11134 | var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope); |
| 11125 | defer wip_captures.deinit(); | 11135 | defer wip_captures.deinit(); |
| 11126 | 11136 | ||
| 11127 | case_block.instructions.shrinkRetainingCapacity(0); | 11137 | case_block.instructions.shrinkRetainingCapacity(0); |
| ... | @@ -11133,9 +11143,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11133,9 +11143,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11133 | // `item` is already guaranteed to be constant known. | 11143 | // `item` is already guaranteed to be constant known. |
| 11134 | 11144 | ||
| 11135 | const analyze_body = if (union_originally) blk: { | 11145 | const analyze_body = if (union_originally) blk: { |
| 11136 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; | 11146 | const item_val = sema.resolveConstLazyValue(block, .unneeded, item, "") catch unreachable; |
| 11137 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); | 11147 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); |
| 11138 | break :blk field_ty.zigTypeTag() != .NoReturn; | 11148 | break :blk field_ty.zigTypeTag(mod) != .NoReturn; |
| 11139 | } else true; | 11149 | } else true; |
| 11140 | 11150 | ||
| 11141 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { | 11151 | if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) { |
| ... | @@ -11197,9 +11207,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11197,9 +11207,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11197 | const item_last_ref = try sema.resolveInst(last_ref); | 11207 | const item_last_ref = try sema.resolveInst(last_ref); |
| 11198 | const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable; | 11208 | const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable; |
| 11199 | 11209 | ||
| 11200 | while (item.compareAll(.lte, item_last, operand_ty, sema.mod)) : ({ | 11210 | while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({ |
| 11201 | // Previous validation has resolved any possible lazy values. | 11211 | // Previous validation has resolved any possible lazy values. |
| 11202 | item = try sema.intAddScalar(item, Value.one); | 11212 | item = sema.intAddScalar(item, try mod.intValue(operand_ty, 1), operand_ty) catch |err| switch (err) { |
| 11213 | error.Overflow => unreachable, | ||
| 11214 | else => |e| return e, | ||
| 11215 | }; | ||
| 11203 | }) { | 11216 | }) { |
| 11204 | cases_len += 1; | 11217 | cases_len += 1; |
| 11205 | 11218 | ||
| ... | @@ -11212,8 +11225,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11212,8 +11225,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11212 | if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) { | 11225 | if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) { |
| 11213 | error.NeededSourceLocation => { | 11226 | error.NeededSourceLocation => { |
| 11214 | const case_src = Module.SwitchProngSrc{ .range = .{ .prong = multi_i, .item = range_i } }; | 11227 | const case_src = Module.SwitchProngSrc{ .range = .{ .prong = multi_i, .item = range_i } }; |
| 11215 | const decl = sema.mod.declPtr(case_block.src_decl); | 11228 | const decl = mod.declPtr(case_block.src_decl); |
| 11216 | try sema.emitBackwardBranch(block, case_src.resolve(sema.gpa, decl, src_node_offset, .none)); | 11229 | try sema.emitBackwardBranch(block, case_src.resolve(mod, decl, src_node_offset, .none)); |
| 11217 | unreachable; | 11230 | unreachable; |
| 11218 | }, | 11231 | }, |
| 11219 | else => return err, | 11232 | else => return err, |
| ... | @@ -11241,15 +11254,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11241,15 +11254,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11241 | 11254 | ||
| 11242 | const analyze_body = if (union_originally) blk: { | 11255 | const analyze_body = if (union_originally) blk: { |
| 11243 | const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; | 11256 | const item_val = sema.resolveConstValue(block, .unneeded, item, undefined) catch unreachable; |
| 11244 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); | 11257 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); |
| 11245 | break :blk field_ty.zigTypeTag() != .NoReturn; | 11258 | break :blk field_ty.zigTypeTag(mod) != .NoReturn; |
| 11246 | } else true; | 11259 | } else true; |
| 11247 | 11260 | ||
| 11248 | if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) { | 11261 | if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) { |
| 11249 | error.NeededSourceLocation => { | 11262 | error.NeededSourceLocation => { |
| 11250 | const case_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }; | 11263 | const case_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } }; |
| 11251 | const decl = sema.mod.declPtr(case_block.src_decl); | 11264 | const decl = mod.declPtr(case_block.src_decl); |
| 11252 | try sema.emitBackwardBranch(block, case_src.resolve(sema.gpa, decl, src_node_offset, .none)); | 11265 | try sema.emitBackwardBranch(block, case_src.resolve(mod, decl, src_node_offset, .none)); |
| 11253 | unreachable; | 11266 | unreachable; |
| 11254 | }, | 11267 | }, |
| 11255 | else => return err, | 11268 | else => return err, |
| ... | @@ -11285,8 +11298,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11285,8 +11298,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11285 | for (items) |item_ref| { | 11298 | for (items) |item_ref| { |
| 11286 | const item = try sema.resolveInst(item_ref); | 11299 | const item = try sema.resolveInst(item_ref); |
| 11287 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; | 11300 | const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable; |
| 11288 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); | 11301 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); |
| 11289 | if (field_ty.zigTypeTag() != .NoReturn) break true; | 11302 | if (field_ty.zigTypeTag(mod) != .NoReturn) break true; |
| 11290 | } else false | 11303 | } else false |
| 11291 | else | 11304 | else |
| 11292 | true; | 11305 | true; |
| ... | @@ -11366,7 +11379,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11366,7 +11379,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11366 | var cond_body = try case_block.instructions.toOwnedSlice(gpa); | 11379 | var cond_body = try case_block.instructions.toOwnedSlice(gpa); |
| 11367 | defer gpa.free(cond_body); | 11380 | defer gpa.free(cond_body); |
| 11368 | 11381 | ||
| 11369 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); | 11382 | var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope); |
| 11370 | defer wip_captures.deinit(); | 11383 | defer wip_captures.deinit(); |
| 11371 | 11384 | ||
| 11372 | case_block.instructions.shrinkRetainingCapacity(0); | 11385 | case_block.instructions.shrinkRetainingCapacity(0); |
| ... | @@ -11409,18 +11422,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11409,18 +11422,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11409 | var final_else_body: []const Air.Inst.Index = &.{}; | 11422 | var final_else_body: []const Air.Inst.Index = &.{}; |
| 11410 | if (special.body.len != 0 or !is_first or case_block.wantSafety()) { | 11423 | if (special.body.len != 0 or !is_first or case_block.wantSafety()) { |
| 11411 | var emit_bb = false; | 11424 | var emit_bb = false; |
| 11412 | if (special.is_inline) switch (operand_ty.zigTypeTag()) { | 11425 | if (special.is_inline) switch (operand_ty.zigTypeTag(mod)) { |
| 11413 | .Enum => { | 11426 | .Enum => { |
| 11414 | if (operand_ty.isNonexhaustiveEnum() and !union_originally) { | 11427 | if (operand_ty.isNonexhaustiveEnum(mod) and !union_originally) { |
| 11415 | return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ | 11428 | return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ |
| 11416 | operand_ty.fmt(sema.mod), | 11429 | operand_ty.fmt(mod), |
| 11417 | }); | 11430 | }); |
| 11418 | } | 11431 | } |
| 11419 | for (seen_enum_fields, 0..) |f, i| { | 11432 | for (seen_enum_fields, 0..) |f, i| { |
| 11420 | if (f != null) continue; | 11433 | if (f != null) continue; |
| 11421 | cases_len += 1; | 11434 | cases_len += 1; |
| 11422 | 11435 | ||
| 11423 | const item_val = try Value.Tag.enum_field_index.create(sema.arena, @intCast(u32, i)); | 11436 | const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i)); |
| 11424 | const item_ref = try sema.addConstant(operand_ty, item_val); | 11437 | const item_ref = try sema.addConstant(operand_ty, item_val); |
| 11425 | case_block.inline_case_capture = item_ref; | 11438 | case_block.inline_case_capture = item_ref; |
| 11426 | 11439 | ||
| ... | @@ -11428,8 +11441,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11428,8 +11441,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11428 | case_block.wip_capture_scope = child_block.wip_capture_scope; | 11441 | case_block.wip_capture_scope = child_block.wip_capture_scope; |
| 11429 | 11442 | ||
| 11430 | const analyze_body = if (union_originally) blk: { | 11443 | const analyze_body = if (union_originally) blk: { |
| 11431 | const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod); | 11444 | const field_ty = maybe_union_ty.unionFieldType(item_val, mod); |
| 11432 | break :blk field_ty.zigTypeTag() != .NoReturn; | 11445 | break :blk field_ty.zigTypeTag(mod) != .NoReturn; |
| 11433 | } else true; | 11446 | } else true; |
| 11434 | 11447 | ||
| 11435 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); | 11448 | if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src); |
| ... | @@ -11449,17 +11462,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11449,17 +11462,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11449 | } | 11462 | } |
| 11450 | }, | 11463 | }, |
| 11451 | .ErrorSet => { | 11464 | .ErrorSet => { |
| 11452 | if (operand_ty.isAnyError()) { | 11465 | if (operand_ty.isAnyError(mod)) { |
| 11453 | return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ | 11466 | return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ |
| 11454 | operand_ty.fmt(sema.mod), | 11467 | operand_ty.fmt(mod), |
| 11455 | }); | 11468 | }); |
| 11456 | } | 11469 | } |
| 11457 | for (operand_ty.errorSetNames()) |error_name| { | 11470 | for (0..operand_ty.errorSetNames(mod).len) |i| { |
| 11471 | const error_name = operand_ty.errorSetNames(mod)[i]; | ||
| 11458 | if (seen_errors.contains(error_name)) continue; | 11472 | if (seen_errors.contains(error_name)) continue; |
| 11459 | cases_len += 1; | 11473 | cases_len += 1; |
| 11460 | 11474 | ||
| 11461 | const item_val = try Value.Tag.@"error".create(sema.arena, .{ .name = error_name }); | 11475 | const item_val = try mod.intern(.{ .err = .{ |
| 11462 | const item_ref = try sema.addConstant(operand_ty, item_val); | 11476 | .ty = operand_ty.toIntern(), |
| 11477 | .name = error_name, | ||
| 11478 | } }); | ||
| 11479 | const item_ref = try sema.addConstant(operand_ty, item_val.toValue()); | ||
| 11463 | case_block.inline_case_capture = item_ref; | 11480 | case_block.inline_case_capture = item_ref; |
| 11464 | 11481 | ||
| 11465 | case_block.instructions.shrinkRetainingCapacity(0); | 11482 | case_block.instructions.shrinkRetainingCapacity(0); |
| ... | @@ -11482,7 +11499,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11482,7 +11499,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11482 | while (try it.next()) |cur| { | 11499 | while (try it.next()) |cur| { |
| 11483 | cases_len += 1; | 11500 | cases_len += 1; |
| 11484 | 11501 | ||
| 11485 | const item_ref = try sema.addConstant(operand_ty, cur); | 11502 | const item_ref = try sema.addConstant(operand_ty, cur.toValue()); |
| 11486 | case_block.inline_case_capture = item_ref; | 11503 | case_block.inline_case_capture = item_ref; |
| 11487 | 11504 | ||
| 11488 | case_block.instructions.shrinkRetainingCapacity(0); | 11505 | case_block.instructions.shrinkRetainingCapacity(0); |
| ... | @@ -11539,19 +11556,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11539,19 +11556,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11539 | } | 11556 | } |
| 11540 | }, | 11557 | }, |
| 11541 | else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ | 11558 | else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{ |
| 11542 | operand_ty.fmt(sema.mod), | 11559 | operand_ty.fmt(mod), |
| 11543 | }), | 11560 | }), |
| 11544 | }; | 11561 | }; |
| 11545 | 11562 | ||
| 11546 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); | 11563 | var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope); |
| 11547 | defer wip_captures.deinit(); | 11564 | defer wip_captures.deinit(); |
| 11548 | 11565 | ||
| 11549 | case_block.instructions.shrinkRetainingCapacity(0); | 11566 | case_block.instructions.shrinkRetainingCapacity(0); |
| 11550 | case_block.wip_capture_scope = wip_captures.scope; | 11567 | case_block.wip_capture_scope = wip_captures.scope; |
| 11551 | case_block.inline_case_capture = .none; | 11568 | case_block.inline_case_capture = .none; |
| 11552 | 11569 | ||
| 11553 | if (sema.mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and | 11570 | if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and |
| 11554 | operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally)) | 11571 | operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) |
| 11555 | { | 11572 | { |
| 11556 | try sema.zirDbgStmt(&case_block, cond_dbg_node_index); | 11573 | try sema.zirDbgStmt(&case_block, cond_dbg_node_index); |
| 11557 | const ok = try case_block.addUnOp(.is_named_enum_value, operand); | 11574 | const ok = try case_block.addUnOp(.is_named_enum_value, operand); |
| ... | @@ -11561,9 +11578,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11561,9 +11578,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11561 | const analyze_body = if (union_originally and !special.is_inline) | 11578 | const analyze_body = if (union_originally and !special.is_inline) |
| 11562 | for (seen_enum_fields, 0..) |seen_field, index| { | 11579 | for (seen_enum_fields, 0..) |seen_field, index| { |
| 11563 | if (seen_field != null) continue; | 11580 | if (seen_field != null) continue; |
| 11564 | const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data; | 11581 | const union_obj = mod.typeToUnion(maybe_union_ty).?; |
| 11565 | const field_ty = union_obj.fields.values()[index].ty; | 11582 | const field_ty = union_obj.fields.values()[index].ty; |
| 11566 | if (field_ty.zigTypeTag() != .NoReturn) break true; | 11583 | if (field_ty.zigTypeTag(mod) != .NoReturn) break true; |
| 11567 | } else false | 11584 | } else false |
| 11568 | else | 11585 | else |
| 11569 | true; | 11586 | true; |
| ... | @@ -11620,47 +11637,70 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -11620,47 +11637,70 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11620 | } | 11637 | } |
| 11621 | 11638 | ||
| 11622 | const RangeSetUnhandledIterator = struct { | 11639 | const RangeSetUnhandledIterator = struct { |
| 11623 | sema: *Sema, | 11640 | mod: *Module, |
| 11624 | ty: Type, | 11641 | cur: ?InternPool.Index, |
| 11625 | cur: Value, | 11642 | max: InternPool.Index, |
| 11626 | max: Value, | 11643 | range_i: usize, |
| 11627 | ranges: []const RangeSet.Range, | 11644 | ranges: []const RangeSet.Range, |
| 11628 | range_i: usize = 0, | 11645 | limbs: []math.big.Limb, |
| 11629 | first: bool = true, | ||
| 11630 | 11646 | ||
| 11631 | fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator { | 11647 | const preallocated_limbs = math.big.int.calcTwosCompLimbCount(128); |
| 11632 | const target = sema.mod.getTarget(); | ||
| 11633 | const min = try ty.minInt(sema.arena, target); | ||
| 11634 | const max = try ty.maxInt(sema.arena, target); | ||
| 11635 | 11648 | ||
| 11636 | return RangeSetUnhandledIterator{ | 11649 | fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator { |
| 11637 | .sema = sema, | 11650 | const mod = sema.mod; |
| 11638 | .ty = ty, | 11651 | const int_type = mod.intern_pool.indexToKey(ty.toIntern()).int_type; |
| 11639 | .cur = min, | 11652 | const needed_limbs = math.big.int.calcTwosCompLimbCount(int_type.bits); |
| 11640 | .max = max, | 11653 | return .{ |
| 11654 | .mod = mod, | ||
| 11655 | .cur = (try ty.minInt(mod, ty)).toIntern(), | ||
| 11656 | .max = (try ty.maxInt(mod, ty)).toIntern(), | ||
| 11657 | .range_i = 0, | ||
| 11641 | .ranges = range_set.ranges.items, | 11658 | .ranges = range_set.ranges.items, |
| 11659 | .limbs = if (needed_limbs > preallocated_limbs) | ||
| 11660 | try sema.arena.alloc(math.big.Limb, needed_limbs) | ||
| 11661 | else | ||
| 11662 | &.{}, | ||
| 11642 | }; | 11663 | }; |
| 11643 | } | 11664 | } |
| 11644 | 11665 | ||
| 11645 | fn next(it: *RangeSetUnhandledIterator) !?Value { | 11666 | fn addOne(it: *const RangeSetUnhandledIterator, val: InternPool.Index) !?InternPool.Index { |
| 11646 | while (it.range_i < it.ranges.len) : (it.range_i += 1) { | 11667 | if (val == it.max) return null; |
| 11647 | if (!it.first) { | 11668 | const int = it.mod.intern_pool.indexToKey(val).int; |
| 11648 | it.cur = try it.sema.intAdd(it.cur, Value.one, it.ty); | 11669 | |
| 11649 | } | 11670 | switch (int.storage) { |
| 11650 | it.first = false; | 11671 | inline .u64, .i64 => |val_int| { |
| 11651 | if (it.cur.compareAll(.lt, it.ranges[it.range_i].first, it.ty, it.sema.mod)) { | 11672 | const next_int = @addWithOverflow(val_int, 1); |
| 11652 | return it.cur; | 11673 | if (next_int[1] == 0) |
| 11653 | } | 11674 | return (try it.mod.intValue(int.ty.toType(), next_int[0])).toIntern(); |
| 11654 | it.cur = it.ranges[it.range_i].last; | 11675 | }, |
| 11655 | } | 11676 | .big_int => {}, |
| 11656 | if (!it.first) { | 11677 | .lazy_align, .lazy_size => unreachable, |
| 11657 | it.cur = try it.sema.intAdd(it.cur, Value.one, it.ty); | ||
| 11658 | } | 11678 | } |
| 11659 | it.first = false; | 11679 | |
| 11660 | if (it.cur.compareAll(.lte, it.max, it.ty, it.sema.mod)) { | 11680 | var val_space: InternPool.Key.Int.Storage.BigIntSpace = undefined; |
| 11661 | return it.cur; | 11681 | const val_bigint = int.storage.toBigInt(&val_space); |
| 11682 | |||
| 11683 | var result_limbs: [preallocated_limbs]math.big.Limb = undefined; | ||
| 11684 | var result_bigint = math.big.int.Mutable.init( | ||
| 11685 | if (it.limbs.len > 0) it.limbs else &result_limbs, | ||
| 11686 | 0, | ||
| 11687 | ); | ||
| 11688 | |||
| 11689 | result_bigint.addScalar(val_bigint, 1); | ||
| 11690 | return (try it.mod.intValue_big(int.ty.toType(), result_bigint.toConst())).toIntern(); | ||
| 11691 | } | ||
| 11692 | |||
| 11693 | fn next(it: *RangeSetUnhandledIterator) !?InternPool.Index { | ||
| 11694 | var cur = it.cur orelse return null; | ||
| 11695 | while (it.range_i < it.ranges.len and cur == it.ranges[it.range_i].first) { | ||
| 11696 | defer it.range_i += 1; | ||
| 11697 | cur = (try it.addOne(it.ranges[it.range_i].last)) orelse { | ||
| 11698 | it.cur = null; | ||
| 11699 | return null; | ||
| 11700 | }; | ||
| 11662 | } | 11701 | } |
| 11663 | return null; | 11702 | it.cur = try it.addOne(cur); |
| 11703 | return cur; | ||
| 11664 | } | 11704 | } |
| 11665 | }; | 11705 | }; |
| 11666 | 11706 | ||
| ... | @@ -11671,18 +11711,17 @@ fn resolveSwitchItemVal( | ... | @@ -11671,18 +11711,17 @@ fn resolveSwitchItemVal( |
| 11671 | switch_node_offset: i32, | 11711 | switch_node_offset: i32, |
| 11672 | switch_prong_src: Module.SwitchProngSrc, | 11712 | switch_prong_src: Module.SwitchProngSrc, |
| 11673 | range_expand: Module.SwitchProngSrc.RangeExpand, | 11713 | range_expand: Module.SwitchProngSrc.RangeExpand, |
| 11674 | ) CompileError!TypedValue { | 11714 | ) CompileError!InternPool.Index { |
| 11715 | const mod = sema.mod; | ||
| 11675 | const item = try sema.resolveInst(item_ref); | 11716 | const item = try sema.resolveInst(item_ref); |
| 11676 | const item_ty = sema.typeOf(item); | ||
| 11677 | // Constructing a LazySrcLoc is costly because we only have the switch AST node. | 11717 | // Constructing a LazySrcLoc is costly because we only have the switch AST node. |
| 11678 | // Only if we know for sure we need to report a compile error do we resolve the | 11718 | // Only if we know for sure we need to report a compile error do we resolve the |
| 11679 | // full source locations. | 11719 | // full source locations. |
| 11680 | if (sema.resolveConstValue(block, .unneeded, item, "")) |val| { | 11720 | if (sema.resolveConstLazyValue(block, .unneeded, item, "")) |val| { |
| 11681 | try sema.resolveLazyValue(val); | 11721 | return val.toIntern(); |
| 11682 | return TypedValue{ .ty = item_ty, .val = val }; | ||
| 11683 | } else |err| switch (err) { | 11722 | } else |err| switch (err) { |
| 11684 | error.NeededSourceLocation => { | 11723 | error.NeededSourceLocation => { |
| 11685 | const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_node_offset, range_expand); | 11724 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand); |
| 11686 | _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known"); | 11725 | _ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known"); |
| 11687 | unreachable; | 11726 | unreachable; |
| 11688 | }, | 11727 | }, |
| ... | @@ -11696,17 +11735,17 @@ fn validateSwitchRange( | ... | @@ -11696,17 +11735,17 @@ fn validateSwitchRange( |
| 11696 | range_set: *RangeSet, | 11735 | range_set: *RangeSet, |
| 11697 | first_ref: Zir.Inst.Ref, | 11736 | first_ref: Zir.Inst.Ref, |
| 11698 | last_ref: Zir.Inst.Ref, | 11737 | last_ref: Zir.Inst.Ref, |
| 11699 | operand_ty: Type, | ||
| 11700 | src_node_offset: i32, | 11738 | src_node_offset: i32, |
| 11701 | switch_prong_src: Module.SwitchProngSrc, | 11739 | switch_prong_src: Module.SwitchProngSrc, |
| 11702 | ) CompileError!void { | 11740 | ) CompileError!void { |
| 11703 | const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val; | 11741 | const mod = sema.mod; |
| 11704 | const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val; | 11742 | const first = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first); |
| 11705 | if (first_val.compareAll(.gt, last_val, operand_ty, sema.mod)) { | 11743 | const last = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last); |
| 11706 | const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .first); | 11744 | if (first.toValue().compareScalar(.gt, last.toValue(), mod.intern_pool.typeOf(first).toType(), mod)) { |
| 11745 | const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first); | ||
| 11707 | return sema.fail(block, src, "range start value is greater than the end value", .{}); | 11746 | return sema.fail(block, src, "range start value is greater than the end value", .{}); |
| 11708 | } | 11747 | } |
| 11709 | const maybe_prev_src = try range_set.add(first_val, last_val, operand_ty, switch_prong_src); | 11748 | const maybe_prev_src = try range_set.add(first, last, switch_prong_src); |
| 11710 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); | 11749 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 11711 | } | 11750 | } |
| 11712 | 11751 | ||
| ... | @@ -11715,12 +11754,11 @@ fn validateSwitchItem( | ... | @@ -11715,12 +11754,11 @@ fn validateSwitchItem( |
| 11715 | block: *Block, | 11754 | block: *Block, |
| 11716 | range_set: *RangeSet, | 11755 | range_set: *RangeSet, |
| 11717 | item_ref: Zir.Inst.Ref, | 11756 | item_ref: Zir.Inst.Ref, |
| 11718 | operand_ty: Type, | ||
| 11719 | src_node_offset: i32, | 11757 | src_node_offset: i32, |
| 11720 | switch_prong_src: Module.SwitchProngSrc, | 11758 | switch_prong_src: Module.SwitchProngSrc, |
| 11721 | ) CompileError!void { | 11759 | ) CompileError!void { |
| 11722 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; | 11760 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 11723 | const maybe_prev_src = try range_set.add(item_val, item_val, operand_ty, switch_prong_src); | 11761 | const maybe_prev_src = try range_set.add(item, item, switch_prong_src); |
| 11724 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); | 11762 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 11725 | } | 11763 | } |
| 11726 | 11764 | ||
| ... | @@ -11733,9 +11771,11 @@ fn validateSwitchItemEnum( | ... | @@ -11733,9 +11771,11 @@ fn validateSwitchItemEnum( |
| 11733 | src_node_offset: i32, | 11771 | src_node_offset: i32, |
| 11734 | switch_prong_src: Module.SwitchProngSrc, | 11772 | switch_prong_src: Module.SwitchProngSrc, |
| 11735 | ) CompileError!void { | 11773 | ) CompileError!void { |
| 11736 | const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 11774 | const ip = &sema.mod.intern_pool; |
| 11737 | const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, sema.mod) orelse { | 11775 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 11738 | const maybe_prev_src = try range_set.add(item_tv.val, item_tv.val, item_tv.ty, switch_prong_src); | 11776 | const int = ip.indexToKey(item).enum_tag.int; |
| 11777 | const field_index = ip.indexToKey(ip.typeOf(item)).enum_type.tagValueIndex(ip, int) orelse { | ||
| 11778 | const maybe_prev_src = try range_set.add(int, int, switch_prong_src); | ||
| 11739 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); | 11779 | return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset); |
| 11740 | }; | 11780 | }; |
| 11741 | const maybe_prev_src = seen_fields[field_index]; | 11781 | const maybe_prev_src = seen_fields[field_index]; |
| ... | @@ -11751,9 +11791,10 @@ fn validateSwitchItemError( | ... | @@ -11751,9 +11791,10 @@ fn validateSwitchItemError( |
| 11751 | src_node_offset: i32, | 11791 | src_node_offset: i32, |
| 11752 | switch_prong_src: Module.SwitchProngSrc, | 11792 | switch_prong_src: Module.SwitchProngSrc, |
| 11753 | ) CompileError!void { | 11793 | ) CompileError!void { |
| 11754 | const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | 11794 | const ip = &sema.mod.intern_pool; |
| 11795 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); | ||
| 11755 | // TODO: Do i need to typecheck here? | 11796 | // TODO: Do i need to typecheck here? |
| 11756 | const error_name = item_tv.val.castTag(.@"error").?.data.name; | 11797 | const error_name = ip.indexToKey(item).err.name; |
| 11757 | const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev| | 11798 | const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev| |
| 11758 | prev.value | 11799 | prev.value |
| 11759 | else | 11800 | else |
| ... | @@ -11769,10 +11810,10 @@ fn validateSwitchDupe( | ... | @@ -11769,10 +11810,10 @@ fn validateSwitchDupe( |
| 11769 | src_node_offset: i32, | 11810 | src_node_offset: i32, |
| 11770 | ) CompileError!void { | 11811 | ) CompileError!void { |
| 11771 | const prev_prong_src = maybe_prev_src orelse return; | 11812 | const prev_prong_src = maybe_prev_src orelse return; |
| 11772 | const gpa = sema.gpa; | 11813 | const mod = sema.mod; |
| 11773 | const block_src_decl = sema.mod.declPtr(block.src_decl); | 11814 | const block_src_decl = mod.declPtr(block.src_decl); |
| 11774 | const src = switch_prong_src.resolve(gpa, block_src_decl, src_node_offset, .none); | 11815 | const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); |
| 11775 | const prev_src = prev_prong_src.resolve(gpa, block_src_decl, src_node_offset, .none); | 11816 | const prev_src = prev_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); |
| 11776 | const msg = msg: { | 11817 | const msg = msg: { |
| 11777 | const msg = try sema.errMsg( | 11818 | const msg = try sema.errMsg( |
| 11778 | block, | 11819 | block, |
| ... | @@ -11802,20 +11843,21 @@ fn validateSwitchItemBool( | ... | @@ -11802,20 +11843,21 @@ fn validateSwitchItemBool( |
| 11802 | src_node_offset: i32, | 11843 | src_node_offset: i32, |
| 11803 | switch_prong_src: Module.SwitchProngSrc, | 11844 | switch_prong_src: Module.SwitchProngSrc, |
| 11804 | ) CompileError!void { | 11845 | ) CompileError!void { |
| 11805 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; | 11846 | const mod = sema.mod; |
| 11806 | if (item_val.toBool()) { | 11847 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 11848 | if (item.toValue().toBool()) { | ||
| 11807 | true_count.* += 1; | 11849 | true_count.* += 1; |
| 11808 | } else { | 11850 | } else { |
| 11809 | false_count.* += 1; | 11851 | false_count.* += 1; |
| 11810 | } | 11852 | } |
| 11811 | if (true_count.* + false_count.* > 2) { | 11853 | if (true_count.* + false_count.* > 2) { |
| 11812 | const block_src_decl = sema.mod.declPtr(block.src_decl); | 11854 | const block_src_decl = mod.declPtr(block.src_decl); |
| 11813 | const src = switch_prong_src.resolve(sema.gpa, block_src_decl, src_node_offset, .none); | 11855 | const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none); |
| 11814 | return sema.fail(block, src, "duplicate switch value", .{}); | 11856 | return sema.fail(block, src, "duplicate switch value", .{}); |
| 11815 | } | 11857 | } |
| 11816 | } | 11858 | } |
| 11817 | 11859 | ||
| 11818 | const ValueSrcMap = std.HashMap(Value, Module.SwitchProngSrc, Value.HashContext, std.hash_map.default_max_load_percentage); | 11860 | const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc); |
| 11819 | 11861 | ||
| 11820 | fn validateSwitchItemSparse( | 11862 | fn validateSwitchItemSparse( |
| 11821 | sema: *Sema, | 11863 | sema: *Sema, |
| ... | @@ -11825,8 +11867,8 @@ fn validateSwitchItemSparse( | ... | @@ -11825,8 +11867,8 @@ fn validateSwitchItemSparse( |
| 11825 | src_node_offset: i32, | 11867 | src_node_offset: i32, |
| 11826 | switch_prong_src: Module.SwitchProngSrc, | 11868 | switch_prong_src: Module.SwitchProngSrc, |
| 11827 | ) CompileError!void { | 11869 | ) CompileError!void { |
| 11828 | const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val; | 11870 | const item = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 11829 | const kv = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return; | 11871 | const kv = (try seen_values.fetchPut(sema.gpa, item, switch_prong_src)) orelse return; |
| 11830 | return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset); | 11872 | return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset); |
| 11831 | } | 11873 | } |
| 11832 | 11874 | ||
| ... | @@ -11864,7 +11906,8 @@ fn validateSwitchNoRange( | ... | @@ -11864,7 +11906,8 @@ fn validateSwitchNoRange( |
| 11864 | } | 11906 | } |
| 11865 | 11907 | ||
| 11866 | fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool { | 11908 | fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool { |
| 11867 | if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) return false; | 11909 | const mod = sema.mod; |
| 11910 | if (!mod.backendSupportsFeature(.panic_unwrap_error)) return false; | ||
| 11868 | 11911 | ||
| 11869 | const tags = sema.code.instructions.items(.tag); | 11912 | const tags = sema.code.instructions.items(.tag); |
| 11870 | for (body) |inst| { | 11913 | for (body) |inst| { |
| ... | @@ -11900,7 +11943,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op | ... | @@ -11900,7 +11943,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op |
| 11900 | .as_node => try sema.zirAsNode(block, inst), | 11943 | .as_node => try sema.zirAsNode(block, inst), |
| 11901 | .field_val => try sema.zirFieldVal(block, inst), | 11944 | .field_val => try sema.zirFieldVal(block, inst), |
| 11902 | .@"unreachable" => { | 11945 | .@"unreachable" => { |
| 11903 | if (!sema.mod.comp.formatted_panics) { | 11946 | if (!mod.comp.formatted_panics) { |
| 11904 | try sema.safetyPanic(block, .unwrap_error); | 11947 | try sema.safetyPanic(block, .unwrap_error); |
| 11905 | return true; | 11948 | return true; |
| 11906 | } | 11949 | } |
| ... | @@ -11923,7 +11966,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op | ... | @@ -11923,7 +11966,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op |
| 11923 | }, | 11966 | }, |
| 11924 | else => unreachable, | 11967 | else => unreachable, |
| 11925 | }; | 11968 | }; |
| 11926 | if (sema.typeOf(air_inst).isNoReturn()) | 11969 | if (sema.typeOf(air_inst).isNoReturn(mod)) |
| 11927 | return true; | 11970 | return true; |
| 11928 | sema.inst_map.putAssumeCapacity(inst, air_inst); | 11971 | sema.inst_map.putAssumeCapacity(inst, air_inst); |
| 11929 | } | 11972 | } |
| ... | @@ -11931,19 +11974,20 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op | ... | @@ -11931,19 +11974,20 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op |
| 11931 | } | 11974 | } |
| 11932 | 11975 | ||
| 11933 | fn maybeErrorUnwrapCondbr(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, cond: Zir.Inst.Ref, cond_src: LazySrcLoc) !void { | 11976 | fn maybeErrorUnwrapCondbr(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, cond: Zir.Inst.Ref, cond_src: LazySrcLoc) !void { |
| 11977 | const mod = sema.mod; | ||
| 11934 | const index = Zir.refToIndex(cond) orelse return; | 11978 | const index = Zir.refToIndex(cond) orelse return; |
| 11935 | if (sema.code.instructions.items(.tag)[index] != .is_non_err) return; | 11979 | if (sema.code.instructions.items(.tag)[index] != .is_non_err) return; |
| 11936 | 11980 | ||
| 11937 | const err_inst_data = sema.code.instructions.items(.data)[index].un_node; | 11981 | const err_inst_data = sema.code.instructions.items(.data)[index].un_node; |
| 11938 | const err_operand = try sema.resolveInst(err_inst_data.operand); | 11982 | const err_operand = try sema.resolveInst(err_inst_data.operand); |
| 11939 | const operand_ty = sema.typeOf(err_operand); | 11983 | const operand_ty = sema.typeOf(err_operand); |
| 11940 | if (operand_ty.zigTypeTag() == .ErrorSet) { | 11984 | if (operand_ty.zigTypeTag(mod) == .ErrorSet) { |
| 11941 | try sema.maybeErrorUnwrapComptime(block, body, err_operand); | 11985 | try sema.maybeErrorUnwrapComptime(block, body, err_operand); |
| 11942 | return; | 11986 | return; |
| 11943 | } | 11987 | } |
| 11944 | if (try sema.resolveDefinedValue(block, cond_src, err_operand)) |val| { | 11988 | if (try sema.resolveDefinedValue(block, cond_src, err_operand)) |val| { |
| 11945 | if (!operand_ty.isError()) return; | 11989 | if (!operand_ty.isError(mod)) return; |
| 11946 | if (val.getError() == null) return; | 11990 | if (val.getErrorName(mod) == .none) return; |
| 11947 | try sema.maybeErrorUnwrapComptime(block, body, err_operand); | 11991 | try sema.maybeErrorUnwrapComptime(block, body, err_operand); |
| 11948 | } | 11992 | } |
| 11949 | } | 11993 | } |
| ... | @@ -11965,45 +12009,60 @@ fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.I | ... | @@ -11965,45 +12009,60 @@ fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.I |
| 11965 | const src = inst_data.src(); | 12009 | const src = inst_data.src(); |
| 11966 | 12010 | ||
| 11967 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { | 12011 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { |
| 11968 | if (val.getError()) |name| { | 12012 | if (val.getErrorName(sema.mod).unwrap()) |name| { |
| 11969 | return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); | 12013 | return sema.fail(block, src, "caught unexpected error '{}'", .{name.fmt(&sema.mod.intern_pool)}); |
| 11970 | } | 12014 | } |
| 11971 | } | 12015 | } |
| 11972 | } | 12016 | } |
| 11973 | 12017 | ||
| 11974 | fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 12018 | fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 12019 | const mod = sema.mod; | ||
| 11975 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 12020 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 11976 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 12021 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 11977 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 12022 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 11978 | const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 12023 | const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 11979 | const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); | 12024 | const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); |
| 11980 | const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime-known"); | 12025 | const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, "field name must be comptime-known"); |
| 11981 | const ty = try sema.resolveTypeFields(unresolved_ty); | 12026 | const ty = try sema.resolveTypeFields(unresolved_ty); |
| 12027 | const ip = &mod.intern_pool; | ||
| 11982 | 12028 | ||
| 11983 | const has_field = hf: { | 12029 | const has_field = hf: { |
| 11984 | if (ty.isSlice()) { | 12030 | switch (ip.indexToKey(ty.toIntern())) { |
| 11985 | if (mem.eql(u8, field_name, "ptr")) break :hf true; | 12031 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 11986 | if (mem.eql(u8, field_name, "len")) break :hf true; | 12032 | .Slice => { |
| 11987 | break :hf false; | 12033 | if (ip.stringEqlSlice(field_name, "ptr")) break :hf true; |
| 11988 | } | 12034 | if (ip.stringEqlSlice(field_name, "len")) break :hf true; |
| 11989 | if (ty.castTag(.anon_struct)) |pl| { | 12035 | break :hf false; |
| 11990 | break :hf for (pl.data.names) |name| { | 12036 | }, |
| 11991 | if (mem.eql(u8, name, field_name)) break true; | 12037 | else => {}, |
| 11992 | } else false; | 12038 | }, |
| 11993 | } | 12039 | .anon_struct_type => |anon_struct| { |
| 11994 | if (ty.isTuple()) { | 12040 | if (anon_struct.names.len != 0) { |
| 11995 | const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false; | 12041 | break :hf mem.indexOfScalar(InternPool.NullTerminatedString, anon_struct.names, field_name) != null; |
| 11996 | break :hf field_index < ty.structFieldCount(); | 12042 | } else { |
| 11997 | } | 12043 | const field_index = field_name.toUnsigned(ip) orelse break :hf false; |
| 11998 | break :hf switch (ty.zigTypeTag()) { | 12044 | break :hf field_index < ty.structFieldCount(mod); |
| 11999 | .Struct => ty.structFields().contains(field_name), | 12045 | } |
| 12000 | .Union => ty.unionFields().contains(field_name), | 12046 | }, |
| 12001 | .Enum => ty.enumFields().contains(field_name), | 12047 | .struct_type => |struct_type| { |
| 12002 | .Array => mem.eql(u8, field_name, "len"), | 12048 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false; |
| 12003 | else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ | 12049 | assert(struct_obj.haveFieldTypes()); |
| 12004 | ty.fmt(sema.mod), | 12050 | break :hf struct_obj.fields.contains(field_name); |
| 12005 | }), | 12051 | }, |
| 12006 | }; | 12052 | .union_type => |union_type| { |
| 12053 | const union_obj = mod.unionPtr(union_type.index); | ||
| 12054 | assert(union_obj.haveFieldTypes()); | ||
| 12055 | break :hf union_obj.fields.contains(field_name); | ||
| 12056 | }, | ||
| 12057 | .enum_type => |enum_type| { | ||
| 12058 | break :hf enum_type.nameIndex(ip, field_name) != null; | ||
| 12059 | }, | ||
| 12060 | .array_type => break :hf ip.stringEqlSlice(field_name, "len"), | ||
| 12061 | else => {}, | ||
| 12062 | } | ||
| 12063 | return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ | ||
| 12064 | ty.fmt(mod), | ||
| 12065 | }); | ||
| 12007 | }; | 12066 | }; |
| 12008 | if (has_field) { | 12067 | if (has_field) { |
| 12009 | return Air.Inst.Ref.bool_true; | 12068 | return Air.Inst.Ref.bool_true; |
| ... | @@ -12013,20 +12072,22 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -12013,20 +12072,22 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12013 | } | 12072 | } |
| 12014 | 12073 | ||
| 12015 | fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 12074 | fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 12075 | const mod = sema.mod; | ||
| 12016 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 12076 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12017 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 12077 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 12018 | const src = inst_data.src(); | 12078 | const src = inst_data.src(); |
| 12019 | const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 12079 | const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 12020 | const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 12080 | const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| 12021 | const container_type = try sema.resolveType(block, lhs_src, extra.lhs); | 12081 | const container_type = try sema.resolveType(block, lhs_src, extra.lhs); |
| 12022 | const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "decl name must be comptime-known"); | 12082 | const decl_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, "decl name must be comptime-known"); |
| 12023 | 12083 | ||
| 12024 | try sema.checkNamespaceType(block, lhs_src, container_type); | 12084 | try sema.checkNamespaceType(block, lhs_src, container_type); |
| 12025 | 12085 | ||
| 12026 | const namespace = container_type.getNamespace() orelse return Air.Inst.Ref.bool_false; | 12086 | const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse |
| 12087 | return Air.Inst.Ref.bool_false; | ||
| 12027 | if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { | 12088 | if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { |
| 12028 | const decl = sema.mod.declPtr(decl_index); | 12089 | const decl = mod.declPtr(decl_index); |
| 12029 | if (decl.is_pub or decl.getFileScope() == block.getFileScope()) { | 12090 | if (decl.is_pub or decl.getFileScope(mod) == block.getFileScope(mod)) { |
| 12030 | return Air.Inst.Ref.bool_true; | 12091 | return Air.Inst.Ref.bool_true; |
| 12031 | } | 12092 | } |
| 12032 | } | 12093 | } |
| ... | @@ -12042,12 +12103,12 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -12042,12 +12103,12 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 12042 | const operand_src = inst_data.src(); | 12103 | const operand_src = inst_data.src(); |
| 12043 | const operand = inst_data.get(sema.code); | 12104 | const operand = inst_data.get(sema.code); |
| 12044 | 12105 | ||
| 12045 | const result = mod.importFile(block.getFileScope(), operand) catch |err| switch (err) { | 12106 | const result = mod.importFile(block.getFileScope(mod), operand) catch |err| switch (err) { |
| 12046 | error.ImportOutsidePkgPath => { | 12107 | error.ImportOutsidePkgPath => { |
| 12047 | return sema.fail(block, operand_src, "import of file outside package path: '{s}'", .{operand}); | 12108 | return sema.fail(block, operand_src, "import of file outside package path: '{s}'", .{operand}); |
| 12048 | }, | 12109 | }, |
| 12049 | error.PackageNotFound => { | 12110 | error.PackageNotFound => { |
| 12050 | const name = try block.getFileScope().pkg.getName(sema.gpa, mod.*); | 12111 | const name = try block.getFileScope(mod).pkg.getName(sema.gpa, mod.*); |
| 12051 | defer sema.gpa.free(name); | 12112 | defer sema.gpa.free(name); |
| 12052 | return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, name }); | 12113 | return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, name }); |
| 12053 | }, | 12114 | }, |
| ... | @@ -12073,7 +12134,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -12073,7 +12134,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 12073 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 12134 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 12074 | const name = try sema.resolveConstString(block, operand_src, inst_data.operand, "file path name must be comptime-known"); | 12135 | const name = try sema.resolveConstString(block, operand_src, inst_data.operand, "file path name must be comptime-known"); |
| 12075 | 12136 | ||
| 12076 | const embed_file = mod.embedFile(block.getFileScope(), name) catch |err| switch (err) { | 12137 | const embed_file = mod.embedFile(block.getFileScope(mod), name) catch |err| switch (err) { |
| 12077 | error.ImportOutsidePkgPath => { | 12138 | error.ImportOutsidePkgPath => { |
| 12078 | return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name}); | 12139 | return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name}); |
| 12079 | }, | 12140 | }, |
| ... | @@ -12087,17 +12148,23 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -12087,17 +12148,23 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 12087 | var anon_decl = try block.startAnonDecl(); | 12148 | var anon_decl = try block.startAnonDecl(); |
| 12088 | defer anon_decl.deinit(); | 12149 | defer anon_decl.deinit(); |
| 12089 | 12150 | ||
| 12090 | const bytes_including_null = embed_file.bytes[0 .. embed_file.bytes.len + 1]; | 12151 | // TODO instead of using `.bytes`, create a new value tag for pointing at |
| 12091 | |||
| 12092 | // TODO instead of using `Value.Tag.bytes`, create a new value tag for pointing at | ||
| 12093 | // a `*Module.EmbedFile`. The purpose of this would be: | 12152 | // a `*Module.EmbedFile`. The purpose of this would be: |
| 12094 | // - If only the length is read and the bytes are not inspected by comptime code, | 12153 | // - If only the length is read and the bytes are not inspected by comptime code, |
| 12095 | // there can be an optimization where the codegen backend does a copy_file_range | 12154 | // there can be an optimization where the codegen backend does a copy_file_range |
| 12096 | // into the final binary, and never loads the data into memory. | 12155 | // into the final binary, and never loads the data into memory. |
| 12097 | // - When a Decl is destroyed, it can free the `*Module.EmbedFile`. | 12156 | // - When a Decl is destroyed, it can free the `*Module.EmbedFile`. |
| 12157 | const ty = try mod.arrayType(.{ | ||
| 12158 | .len = embed_file.bytes.len, | ||
| 12159 | .child = .u8_type, | ||
| 12160 | .sentinel = .zero_u8, | ||
| 12161 | }); | ||
| 12098 | embed_file.owner_decl = try anon_decl.finish( | 12162 | embed_file.owner_decl = try anon_decl.finish( |
| 12099 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), embed_file.bytes.len), | 12163 | ty, |
| 12100 | try Value.Tag.bytes.create(anon_decl.arena(), bytes_including_null), | 12164 | (try mod.intern(.{ .aggregate = .{ |
| 12165 | .ty = ty.toIntern(), | ||
| 12166 | .storage = .{ .bytes = embed_file.bytes }, | ||
| 12167 | } })).toValue(), | ||
| 12101 | 0, // default alignment | 12168 | 0, // default alignment |
| 12102 | ); | 12169 | ); |
| 12103 | 12170 | ||
| ... | @@ -12105,16 +12172,15 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -12105,16 +12172,15 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 12105 | } | 12172 | } |
| 12106 | 12173 | ||
| 12107 | fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 12174 | fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 12175 | const mod = sema.mod; | ||
| 12108 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | 12176 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 12109 | const err_name = inst_data.get(sema.code); | 12177 | const name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); |
| 12110 | 12178 | _ = try mod.getErrorValue(name); | |
| 12111 | // Return the error code from the function. | 12179 | const error_set_type = try mod.singleErrorSetType(name); |
| 12112 | const kv = try sema.mod.getErrorValue(err_name); | 12180 | return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ |
| 12113 | const result_inst = try sema.addConstant( | 12181 | .ty = error_set_type.toIntern(), |
| 12114 | try Type.Tag.error_set_single.create(sema.arena, kv.key), | 12182 | .name = name, |
| 12115 | try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }), | 12183 | } })).toValue()); |
| 12116 | ); | ||
| 12117 | return result_inst; | ||
| 12118 | } | 12184 | } |
| 12119 | 12185 | ||
| 12120 | fn zirShl( | 12186 | fn zirShl( |
| ... | @@ -12126,6 +12192,7 @@ fn zirShl( | ... | @@ -12126,6 +12192,7 @@ fn zirShl( |
| 12126 | const tracy = trace(@src()); | 12192 | const tracy = trace(@src()); |
| 12127 | defer tracy.end(); | 12193 | defer tracy.end(); |
| 12128 | 12194 | ||
| 12195 | const mod = sema.mod; | ||
| 12129 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 12196 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12130 | const src = inst_data.src(); | 12197 | const src = inst_data.src(); |
| 12131 | sema.src = src; | 12198 | sema.src = src; |
| ... | @@ -12136,11 +12203,10 @@ fn zirShl( | ... | @@ -12136,11 +12203,10 @@ fn zirShl( |
| 12136 | const rhs = try sema.resolveInst(extra.rhs); | 12203 | const rhs = try sema.resolveInst(extra.rhs); |
| 12137 | const lhs_ty = sema.typeOf(lhs); | 12204 | const lhs_ty = sema.typeOf(lhs); |
| 12138 | const rhs_ty = sema.typeOf(rhs); | 12205 | const rhs_ty = sema.typeOf(rhs); |
| 12139 | const target = sema.mod.getTarget(); | ||
| 12140 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 12206 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 12141 | 12207 | ||
| 12142 | const scalar_ty = lhs_ty.scalarType(); | 12208 | const scalar_ty = lhs_ty.scalarType(mod); |
| 12143 | const scalar_rhs_ty = rhs_ty.scalarType(); | 12209 | const scalar_rhs_ty = rhs_ty.scalarType(mod); |
| 12144 | 12210 | ||
| 12145 | // TODO coerce rhs if air_tag is not shl_sat | 12211 | // TODO coerce rhs if air_tag is not shl_sat |
| 12146 | const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, scalar_rhs_ty); | 12212 | const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, scalar_rhs_ty); |
| ... | @@ -12149,62 +12215,56 @@ fn zirShl( | ... | @@ -12149,62 +12215,56 @@ fn zirShl( |
| 12149 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs); | 12215 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs); |
| 12150 | 12216 | ||
| 12151 | if (maybe_rhs_val) |rhs_val| { | 12217 | if (maybe_rhs_val) |rhs_val| { |
| 12152 | if (rhs_val.isUndef()) { | 12218 | if (rhs_val.isUndef(mod)) { |
| 12153 | return sema.addConstUndef(sema.typeOf(lhs)); | 12219 | return sema.addConstUndef(sema.typeOf(lhs)); |
| 12154 | } | 12220 | } |
| 12155 | // If rhs is 0, return lhs without doing any calculations. | 12221 | // If rhs is 0, return lhs without doing any calculations. |
| 12156 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 12222 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 12157 | return lhs; | 12223 | return lhs; |
| 12158 | } | 12224 | } |
| 12159 | if (scalar_ty.zigTypeTag() != .ComptimeInt and air_tag != .shl_sat) { | 12225 | if (scalar_ty.zigTypeTag(mod) != .ComptimeInt and air_tag != .shl_sat) { |
| 12160 | var bits_payload = Value.Payload.U64{ | 12226 | const bit_value = try mod.intValue(Type.comptime_int, scalar_ty.intInfo(mod).bits); |
| 12161 | .base = .{ .tag = .int_u64 }, | 12227 | if (rhs_ty.zigTypeTag(mod) == .Vector) { |
| 12162 | .data = scalar_ty.intInfo(target).bits, | ||
| 12163 | }; | ||
| 12164 | const bit_value = Value.initPayload(&bits_payload.base); | ||
| 12165 | if (rhs_ty.zigTypeTag() == .Vector) { | ||
| 12166 | var i: usize = 0; | 12228 | var i: usize = 0; |
| 12167 | while (i < rhs_ty.vectorLen()) : (i += 1) { | 12229 | while (i < rhs_ty.vectorLen(mod)) : (i += 1) { |
| 12168 | var elem_value_buf: Value.ElemValueBuffer = undefined; | 12230 | const rhs_elem = try rhs_val.elemValue(mod, i); |
| 12169 | const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf); | 12231 | if (rhs_elem.compareHetero(.gte, bit_value, mod)) { |
| 12170 | if (rhs_elem.compareHetero(.gte, bit_value, target)) { | ||
| 12171 | return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ | 12232 | return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ |
| 12172 | rhs_elem.fmtValue(scalar_ty, sema.mod), | 12233 | rhs_elem.fmtValue(scalar_ty, mod), |
| 12173 | i, | 12234 | i, |
| 12174 | scalar_ty.fmt(sema.mod), | 12235 | scalar_ty.fmt(mod), |
| 12175 | }); | 12236 | }); |
| 12176 | } | 12237 | } |
| 12177 | } | 12238 | } |
| 12178 | } else if (rhs_val.compareHetero(.gte, bit_value, target)) { | 12239 | } else if (rhs_val.compareHetero(.gte, bit_value, mod)) { |
| 12179 | return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ | 12240 | return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ |
| 12180 | rhs_val.fmtValue(scalar_ty, sema.mod), | 12241 | rhs_val.fmtValue(scalar_ty, mod), |
| 12181 | scalar_ty.fmt(sema.mod), | 12242 | scalar_ty.fmt(mod), |
| 12182 | }); | 12243 | }); |
| 12183 | } | 12244 | } |
| 12184 | } | 12245 | } |
| 12185 | if (rhs_ty.zigTypeTag() == .Vector) { | 12246 | if (rhs_ty.zigTypeTag(mod) == .Vector) { |
| 12186 | var i: usize = 0; | 12247 | var i: usize = 0; |
| 12187 | while (i < rhs_ty.vectorLen()) : (i += 1) { | 12248 | while (i < rhs_ty.vectorLen(mod)) : (i += 1) { |
| 12188 | var elem_value_buf: Value.ElemValueBuffer = undefined; | 12249 | const rhs_elem = try rhs_val.elemValue(mod, i); |
| 12189 | const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf); | 12250 | if (rhs_elem.compareHetero(.lt, try mod.intValue(scalar_rhs_ty, 0), mod)) { |
| 12190 | if (rhs_elem.compareHetero(.lt, Value.zero, target)) { | ||
| 12191 | return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ | 12251 | return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ |
| 12192 | rhs_elem.fmtValue(scalar_ty, sema.mod), | 12252 | rhs_elem.fmtValue(scalar_ty, mod), |
| 12193 | i, | 12253 | i, |
| 12194 | }); | 12254 | }); |
| 12195 | } | 12255 | } |
| 12196 | } | 12256 | } |
| 12197 | } else if (rhs_val.compareHetero(.lt, Value.zero, target)) { | 12257 | } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) { |
| 12198 | return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ | 12258 | return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ |
| 12199 | rhs_val.fmtValue(scalar_ty, sema.mod), | 12259 | rhs_val.fmtValue(scalar_ty, mod), |
| 12200 | }); | 12260 | }); |
| 12201 | } | 12261 | } |
| 12202 | } | 12262 | } |
| 12203 | 12263 | ||
| 12204 | const runtime_src = if (maybe_lhs_val) |lhs_val| rs: { | 12264 | const runtime_src = if (maybe_lhs_val) |lhs_val| rs: { |
| 12205 | if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty); | 12265 | if (lhs_val.isUndef(mod)) return sema.addConstUndef(lhs_ty); |
| 12206 | const rhs_val = maybe_rhs_val orelse { | 12266 | const rhs_val = maybe_rhs_val orelse { |
| 12207 | if (scalar_ty.zigTypeTag() == .ComptimeInt) { | 12267 | if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) { |
| 12208 | return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{}); | 12268 | return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{}); |
| 12209 | } | 12269 | } |
| 12210 | break :rs rhs_src; | 12270 | break :rs rhs_src; |
| ... | @@ -12212,25 +12272,25 @@ fn zirShl( | ... | @@ -12212,25 +12272,25 @@ fn zirShl( |
| 12212 | 12272 | ||
| 12213 | const val = switch (air_tag) { | 12273 | const val = switch (air_tag) { |
| 12214 | .shl_exact => val: { | 12274 | .shl_exact => val: { |
| 12215 | const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, sema.mod); | 12275 | const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, mod); |
| 12216 | if (scalar_ty.zigTypeTag() == .ComptimeInt) { | 12276 | if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) { |
| 12217 | break :val shifted.wrapped_result; | 12277 | break :val shifted.wrapped_result; |
| 12218 | } | 12278 | } |
| 12219 | if (shifted.overflow_bit.compareAllWithZero(.eq, sema.mod)) { | 12279 | if (shifted.overflow_bit.compareAllWithZero(.eq, mod)) { |
| 12220 | break :val shifted.wrapped_result; | 12280 | break :val shifted.wrapped_result; |
| 12221 | } | 12281 | } |
| 12222 | return sema.fail(block, src, "operation caused overflow", .{}); | 12282 | return sema.fail(block, src, "operation caused overflow", .{}); |
| 12223 | }, | 12283 | }, |
| 12224 | 12284 | ||
| 12225 | .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt) | 12285 | .shl_sat => if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) |
| 12226 | try lhs_val.shl(rhs_val, lhs_ty, sema.arena, sema.mod) | 12286 | try lhs_val.shl(rhs_val, lhs_ty, sema.arena, mod) |
| 12227 | else | 12287 | else |
| 12228 | try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, sema.mod), | 12288 | try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, mod), |
| 12229 | 12289 | ||
| 12230 | .shl => if (scalar_ty.zigTypeTag() == .ComptimeInt) | 12290 | .shl => if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) |
| 12231 | try lhs_val.shl(rhs_val, lhs_ty, sema.arena, sema.mod) | 12291 | try lhs_val.shl(rhs_val, lhs_ty, sema.arena, mod) |
| 12232 | else | 12292 | else |
| 12233 | try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, sema.mod), | 12293 | try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, mod), |
| 12234 | 12294 | ||
| 12235 | else => unreachable, | 12295 | else => unreachable, |
| 12236 | }; | 12296 | }; |
| ... | @@ -12241,11 +12301,11 @@ fn zirShl( | ... | @@ -12241,11 +12301,11 @@ fn zirShl( |
| 12241 | const new_rhs = if (air_tag == .shl_sat) rhs: { | 12301 | const new_rhs = if (air_tag == .shl_sat) rhs: { |
| 12242 | // Limit the RHS type for saturating shl to be an integer as small as the LHS. | 12302 | // Limit the RHS type for saturating shl to be an integer as small as the LHS. |
| 12243 | if (rhs_is_comptime_int or | 12303 | if (rhs_is_comptime_int or |
| 12244 | scalar_rhs_ty.intInfo(target).bits > scalar_ty.intInfo(target).bits) | 12304 | scalar_rhs_ty.intInfo(mod).bits > scalar_ty.intInfo(mod).bits) |
| 12245 | { | 12305 | { |
| 12246 | const max_int = try sema.addConstant( | 12306 | const max_int = try sema.addConstant( |
| 12247 | lhs_ty, | 12307 | lhs_ty, |
| 12248 | try lhs_ty.maxInt(sema.arena, target), | 12308 | try lhs_ty.maxInt(mod, lhs_ty), |
| 12249 | ); | 12309 | ); |
| 12250 | const rhs_limited = try sema.analyzeMinMax(block, rhs_src, .min, &.{ rhs, max_int }, &.{ rhs_src, rhs_src }); | 12310 | const rhs_limited = try sema.analyzeMinMax(block, rhs_src, .min, &.{ rhs, max_int }, &.{ rhs_src, rhs_src }); |
| 12251 | break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false); | 12311 | break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false); |
| ... | @@ -12256,12 +12316,11 @@ fn zirShl( | ... | @@ -12256,12 +12316,11 @@ fn zirShl( |
| 12256 | 12316 | ||
| 12257 | try sema.requireRuntimeBlock(block, src, runtime_src); | 12317 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 12258 | if (block.wantSafety()) { | 12318 | if (block.wantSafety()) { |
| 12259 | const bit_count = scalar_ty.intInfo(target).bits; | 12319 | const bit_count = scalar_ty.intInfo(mod).bits; |
| 12260 | if (!std.math.isPowerOfTwo(bit_count)) { | 12320 | if (!std.math.isPowerOfTwo(bit_count)) { |
| 12261 | const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count); | 12321 | const bit_count_val = try mod.intValue(scalar_rhs_ty, bit_count); |
| 12262 | 12322 | const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: { | |
| 12263 | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { | 12323 | const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val)); |
| 12264 | const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); | ||
| 12265 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt); | 12324 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt); |
| 12266 | break :ok try block.addInst(.{ | 12325 | break :ok try block.addInst(.{ |
| 12267 | .tag = .reduce, | 12326 | .tag = .reduce, |
| ... | @@ -12290,7 +12349,7 @@ fn zirShl( | ... | @@ -12290,7 +12349,7 @@ fn zirShl( |
| 12290 | } }, | 12349 | } }, |
| 12291 | }); | 12350 | }); |
| 12292 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); | 12351 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); |
| 12293 | const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector) | 12352 | const any_ov_bit = if (lhs_ty.zigTypeTag(mod) == .Vector) |
| 12294 | try block.addInst(.{ | 12353 | try block.addInst(.{ |
| 12295 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | 12354 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, |
| 12296 | .data = .{ .reduce = .{ | 12355 | .data = .{ .reduce = .{ |
| ... | @@ -12300,7 +12359,7 @@ fn zirShl( | ... | @@ -12300,7 +12359,7 @@ fn zirShl( |
| 12300 | }) | 12359 | }) |
| 12301 | else | 12360 | else |
| 12302 | ov_bit; | 12361 | ov_bit; |
| 12303 | const zero_ov = try sema.addConstant(Type.u1, Value.zero); | 12362 | const zero_ov = try sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0)); |
| 12304 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); | 12363 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); |
| 12305 | 12364 | ||
| 12306 | try sema.addSafetyCheck(block, no_ov, .shl_overflow); | 12365 | try sema.addSafetyCheck(block, no_ov, .shl_overflow); |
| ... | @@ -12319,6 +12378,7 @@ fn zirShr( | ... | @@ -12319,6 +12378,7 @@ fn zirShr( |
| 12319 | const tracy = trace(@src()); | 12378 | const tracy = trace(@src()); |
| 12320 | defer tracy.end(); | 12379 | defer tracy.end(); |
| 12321 | 12380 | ||
| 12381 | const mod = sema.mod; | ||
| 12322 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 12382 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12323 | const src = inst_data.src(); | 12383 | const src = inst_data.src(); |
| 12324 | sema.src = src; | 12384 | sema.src = src; |
| ... | @@ -12330,94 +12390,87 @@ fn zirShr( | ... | @@ -12330,94 +12390,87 @@ fn zirShr( |
| 12330 | const lhs_ty = sema.typeOf(lhs); | 12390 | const lhs_ty = sema.typeOf(lhs); |
| 12331 | const rhs_ty = sema.typeOf(rhs); | 12391 | const rhs_ty = sema.typeOf(rhs); |
| 12332 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 12392 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 12333 | const target = sema.mod.getTarget(); | 12393 | const scalar_ty = lhs_ty.scalarType(mod); |
| 12334 | const scalar_ty = lhs_ty.scalarType(); | ||
| 12335 | 12394 | ||
| 12336 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(lhs); | 12395 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(lhs); |
| 12337 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs); | 12396 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs); |
| 12338 | 12397 | ||
| 12339 | const runtime_src = if (maybe_rhs_val) |rhs_val| rs: { | 12398 | const runtime_src = if (maybe_rhs_val) |rhs_val| rs: { |
| 12340 | if (rhs_val.isUndef()) { | 12399 | if (rhs_val.isUndef(mod)) { |
| 12341 | return sema.addConstUndef(lhs_ty); | 12400 | return sema.addConstUndef(lhs_ty); |
| 12342 | } | 12401 | } |
| 12343 | // If rhs is 0, return lhs without doing any calculations. | 12402 | // If rhs is 0, return lhs without doing any calculations. |
| 12344 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 12403 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 12345 | return lhs; | 12404 | return lhs; |
| 12346 | } | 12405 | } |
| 12347 | if (scalar_ty.zigTypeTag() != .ComptimeInt) { | 12406 | if (scalar_ty.zigTypeTag(mod) != .ComptimeInt) { |
| 12348 | var bits_payload = Value.Payload.U64{ | 12407 | const bit_value = try mod.intValue(Type.comptime_int, scalar_ty.intInfo(mod).bits); |
| 12349 | .base = .{ .tag = .int_u64 }, | 12408 | if (rhs_ty.zigTypeTag(mod) == .Vector) { |
| 12350 | .data = scalar_ty.intInfo(target).bits, | ||
| 12351 | }; | ||
| 12352 | const bit_value = Value.initPayload(&bits_payload.base); | ||
| 12353 | if (rhs_ty.zigTypeTag() == .Vector) { | ||
| 12354 | var i: usize = 0; | 12409 | var i: usize = 0; |
| 12355 | while (i < rhs_ty.vectorLen()) : (i += 1) { | 12410 | while (i < rhs_ty.vectorLen(mod)) : (i += 1) { |
| 12356 | var elem_value_buf: Value.ElemValueBuffer = undefined; | 12411 | const rhs_elem = try rhs_val.elemValue(mod, i); |
| 12357 | const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf); | 12412 | if (rhs_elem.compareHetero(.gte, bit_value, mod)) { |
| 12358 | if (rhs_elem.compareHetero(.gte, bit_value, target)) { | ||
| 12359 | return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ | 12413 | return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{ |
| 12360 | rhs_elem.fmtValue(scalar_ty, sema.mod), | 12414 | rhs_elem.fmtValue(scalar_ty, mod), |
| 12361 | i, | 12415 | i, |
| 12362 | scalar_ty.fmt(sema.mod), | 12416 | scalar_ty.fmt(mod), |
| 12363 | }); | 12417 | }); |
| 12364 | } | 12418 | } |
| 12365 | } | 12419 | } |
| 12366 | } else if (rhs_val.compareHetero(.gte, bit_value, target)) { | 12420 | } else if (rhs_val.compareHetero(.gte, bit_value, mod)) { |
| 12367 | return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ | 12421 | return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{ |
| 12368 | rhs_val.fmtValue(scalar_ty, sema.mod), | 12422 | rhs_val.fmtValue(scalar_ty, mod), |
| 12369 | scalar_ty.fmt(sema.mod), | 12423 | scalar_ty.fmt(mod), |
| 12370 | }); | 12424 | }); |
| 12371 | } | 12425 | } |
| 12372 | } | 12426 | } |
| 12373 | if (rhs_ty.zigTypeTag() == .Vector) { | 12427 | if (rhs_ty.zigTypeTag(mod) == .Vector) { |
| 12374 | var i: usize = 0; | 12428 | var i: usize = 0; |
| 12375 | while (i < rhs_ty.vectorLen()) : (i += 1) { | 12429 | while (i < rhs_ty.vectorLen(mod)) : (i += 1) { |
| 12376 | var elem_value_buf: Value.ElemValueBuffer = undefined; | 12430 | const rhs_elem = try rhs_val.elemValue(mod, i); |
| 12377 | const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf); | 12431 | if (rhs_elem.compareHetero(.lt, try mod.intValue(rhs_ty.childType(mod), 0), mod)) { |
| 12378 | if (rhs_elem.compareHetero(.lt, Value.zero, target)) { | ||
| 12379 | return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ | 12432 | return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{ |
| 12380 | rhs_elem.fmtValue(scalar_ty, sema.mod), | 12433 | rhs_elem.fmtValue(scalar_ty, mod), |
| 12381 | i, | 12434 | i, |
| 12382 | }); | 12435 | }); |
| 12383 | } | 12436 | } |
| 12384 | } | 12437 | } |
| 12385 | } else if (rhs_val.compareHetero(.lt, Value.zero, target)) { | 12438 | } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) { |
| 12386 | return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ | 12439 | return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{ |
| 12387 | rhs_val.fmtValue(scalar_ty, sema.mod), | 12440 | rhs_val.fmtValue(scalar_ty, mod), |
| 12388 | }); | 12441 | }); |
| 12389 | } | 12442 | } |
| 12390 | if (maybe_lhs_val) |lhs_val| { | 12443 | if (maybe_lhs_val) |lhs_val| { |
| 12391 | if (lhs_val.isUndef()) { | 12444 | if (lhs_val.isUndef(mod)) { |
| 12392 | return sema.addConstUndef(lhs_ty); | 12445 | return sema.addConstUndef(lhs_ty); |
| 12393 | } | 12446 | } |
| 12394 | if (air_tag == .shr_exact) { | 12447 | if (air_tag == .shr_exact) { |
| 12395 | // Detect if any ones would be shifted out. | 12448 | // Detect if any ones would be shifted out. |
| 12396 | const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, sema.mod); | 12449 | const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, mod); |
| 12397 | if (!(try truncated.compareAllWithZeroAdvanced(.eq, sema))) { | 12450 | if (!(try truncated.compareAllWithZeroAdvanced(.eq, sema))) { |
| 12398 | return sema.fail(block, src, "exact shift shifted out 1 bits", .{}); | 12451 | return sema.fail(block, src, "exact shift shifted out 1 bits", .{}); |
| 12399 | } | 12452 | } |
| 12400 | } | 12453 | } |
| 12401 | const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, sema.mod); | 12454 | const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, mod); |
| 12402 | return sema.addConstant(lhs_ty, val); | 12455 | return sema.addConstant(lhs_ty, val); |
| 12403 | } else { | 12456 | } else { |
| 12404 | break :rs lhs_src; | 12457 | break :rs lhs_src; |
| 12405 | } | 12458 | } |
| 12406 | } else rhs_src; | 12459 | } else rhs_src; |
| 12407 | 12460 | ||
| 12408 | if (maybe_rhs_val == null and scalar_ty.zigTypeTag() == .ComptimeInt) { | 12461 | if (maybe_rhs_val == null and scalar_ty.zigTypeTag(mod) == .ComptimeInt) { |
| 12409 | return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{}); | 12462 | return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{}); |
| 12410 | } | 12463 | } |
| 12411 | 12464 | ||
| 12412 | try sema.requireRuntimeBlock(block, src, runtime_src); | 12465 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 12413 | const result = try block.addBinOp(air_tag, lhs, rhs); | 12466 | const result = try block.addBinOp(air_tag, lhs, rhs); |
| 12414 | if (block.wantSafety()) { | 12467 | if (block.wantSafety()) { |
| 12415 | const bit_count = scalar_ty.intInfo(target).bits; | 12468 | const bit_count = scalar_ty.intInfo(mod).bits; |
| 12416 | if (!std.math.isPowerOfTwo(bit_count)) { | 12469 | if (!std.math.isPowerOfTwo(bit_count)) { |
| 12417 | const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count); | 12470 | const bit_count_val = try mod.intValue(rhs_ty.scalarType(mod), bit_count); |
| 12418 | 12471 | ||
| 12419 | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { | 12472 | const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: { |
| 12420 | const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); | 12473 | const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val)); |
| 12421 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt); | 12474 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt); |
| 12422 | break :ok try block.addInst(.{ | 12475 | break :ok try block.addInst(.{ |
| 12423 | .tag = .reduce, | 12476 | .tag = .reduce, |
| ... | @@ -12436,7 +12489,7 @@ fn zirShr( | ... | @@ -12436,7 +12489,7 @@ fn zirShr( |
| 12436 | if (air_tag == .shr_exact) { | 12489 | if (air_tag == .shr_exact) { |
| 12437 | const back = try block.addBinOp(.shl, result, rhs); | 12490 | const back = try block.addBinOp(.shl, result, rhs); |
| 12438 | 12491 | ||
| 12439 | const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { | 12492 | const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: { |
| 12440 | const eql = try block.addCmpVector(lhs, back, .eq); | 12493 | const eql = try block.addCmpVector(lhs, back, .eq); |
| 12441 | break :ok try block.addInst(.{ | 12494 | break :ok try block.addInst(.{ |
| 12442 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | 12495 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, |
| ... | @@ -12461,6 +12514,7 @@ fn zirBitwise( | ... | @@ -12461,6 +12514,7 @@ fn zirBitwise( |
| 12461 | const tracy = trace(@src()); | 12514 | const tracy = trace(@src()); |
| 12462 | defer tracy.end(); | 12515 | defer tracy.end(); |
| 12463 | 12516 | ||
| 12517 | const mod = sema.mod; | ||
| 12464 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 12518 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12465 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 12519 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 12466 | sema.src = src; | 12520 | sema.src = src; |
| ... | @@ -12475,8 +12529,8 @@ fn zirBitwise( | ... | @@ -12475,8 +12529,8 @@ fn zirBitwise( |
| 12475 | 12529 | ||
| 12476 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | 12530 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 12477 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } }); | 12531 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } }); |
| 12478 | const scalar_type = resolved_type.scalarType(); | 12532 | const scalar_type = resolved_type.scalarType(mod); |
| 12479 | const scalar_tag = scalar_type.zigTypeTag(); | 12533 | const scalar_tag = scalar_type.zigTypeTag(mod); |
| 12480 | 12534 | ||
| 12481 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 12535 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 12482 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 12536 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| ... | @@ -12484,7 +12538,7 @@ fn zirBitwise( | ... | @@ -12484,7 +12538,7 @@ fn zirBitwise( |
| 12484 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | 12538 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 12485 | 12539 | ||
| 12486 | if (!is_int) { | 12540 | if (!is_int) { |
| 12487 | return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) }); | 12541 | return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag(mod)), @tagName(rhs_ty.zigTypeTag(mod)) }); |
| 12488 | } | 12542 | } |
| 12489 | 12543 | ||
| 12490 | const runtime_src = runtime: { | 12544 | const runtime_src = runtime: { |
| ... | @@ -12493,9 +12547,9 @@ fn zirBitwise( | ... | @@ -12493,9 +12547,9 @@ fn zirBitwise( |
| 12493 | if (try sema.resolveMaybeUndefValIntable(casted_lhs)) |lhs_val| { | 12547 | if (try sema.resolveMaybeUndefValIntable(casted_lhs)) |lhs_val| { |
| 12494 | if (try sema.resolveMaybeUndefValIntable(casted_rhs)) |rhs_val| { | 12548 | if (try sema.resolveMaybeUndefValIntable(casted_rhs)) |rhs_val| { |
| 12495 | const result_val = switch (air_tag) { | 12549 | const result_val = switch (air_tag) { |
| 12496 | .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, sema.mod), | 12550 | .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, mod), |
| 12497 | .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, sema.mod), | 12551 | .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, mod), |
| 12498 | .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, sema.mod), | 12552 | .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, mod), |
| 12499 | else => unreachable, | 12553 | else => unreachable, |
| 12500 | }; | 12554 | }; |
| 12501 | return sema.addConstant(resolved_type, result_val); | 12555 | return sema.addConstant(resolved_type, result_val); |
| ... | @@ -12515,37 +12569,37 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -12515,37 +12569,37 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 12515 | const tracy = trace(@src()); | 12569 | const tracy = trace(@src()); |
| 12516 | defer tracy.end(); | 12570 | defer tracy.end(); |
| 12517 | 12571 | ||
| 12572 | const mod = sema.mod; | ||
| 12518 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 12573 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 12519 | const src = inst_data.src(); | 12574 | const src = inst_data.src(); |
| 12520 | const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; | 12575 | const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; |
| 12521 | 12576 | ||
| 12522 | const operand = try sema.resolveInst(inst_data.operand); | 12577 | const operand = try sema.resolveInst(inst_data.operand); |
| 12523 | const operand_type = sema.typeOf(operand); | 12578 | const operand_type = sema.typeOf(operand); |
| 12524 | const scalar_type = operand_type.scalarType(); | 12579 | const scalar_type = operand_type.scalarType(mod); |
| 12525 | 12580 | ||
| 12526 | if (scalar_type.zigTypeTag() != .Int) { | 12581 | if (scalar_type.zigTypeTag(mod) != .Int) { |
| 12527 | return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{ | 12582 | return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{ |
| 12528 | operand_type.fmt(sema.mod), | 12583 | operand_type.fmt(mod), |
| 12529 | }); | 12584 | }); |
| 12530 | } | 12585 | } |
| 12531 | 12586 | ||
| 12532 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 12587 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 12533 | if (val.isUndef()) { | 12588 | if (val.isUndef(mod)) { |
| 12534 | return sema.addConstUndef(operand_type); | 12589 | return sema.addConstUndef(operand_type); |
| 12535 | } else if (operand_type.zigTypeTag() == .Vector) { | 12590 | } else if (operand_type.zigTypeTag(mod) == .Vector) { |
| 12536 | const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen()); | 12591 | const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen(mod)); |
| 12537 | var elem_val_buf: Value.ElemValueBuffer = undefined; | 12592 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); |
| 12538 | const elems = try sema.arena.alloc(Value, vec_len); | ||
| 12539 | for (elems, 0..) |*elem, i| { | 12593 | for (elems, 0..) |*elem, i| { |
| 12540 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_val_buf); | 12594 | const elem_val = try val.elemValue(mod, i); |
| 12541 | elem.* = try elem_val.bitwiseNot(scalar_type, sema.arena, sema.mod); | 12595 | elem.* = try (try elem_val.bitwiseNot(scalar_type, sema.arena, mod)).intern(scalar_type, mod); |
| 12542 | } | 12596 | } |
| 12543 | return sema.addConstant( | 12597 | return sema.addConstant(operand_type, (try mod.intern(.{ .aggregate = .{ |
| 12544 | operand_type, | 12598 | .ty = operand_type.toIntern(), |
| 12545 | try Value.Tag.aggregate.create(sema.arena, elems), | 12599 | .storage = .{ .elems = elems }, |
| 12546 | ); | 12600 | } })).toValue()); |
| 12547 | } else { | 12601 | } else { |
| 12548 | const result_val = try val.bitwiseNot(operand_type, sema.arena, sema.mod); | 12602 | const result_val = try val.bitwiseNot(operand_type, sema.arena, mod); |
| 12549 | return sema.addConstant(operand_type, result_val); | 12603 | return sema.addConstant(operand_type, result_val); |
| 12550 | } | 12604 | } |
| 12551 | } | 12605 | } |
| ... | @@ -12561,18 +12615,19 @@ fn analyzeTupleCat( | ... | @@ -12561,18 +12615,19 @@ fn analyzeTupleCat( |
| 12561 | lhs: Air.Inst.Ref, | 12615 | lhs: Air.Inst.Ref, |
| 12562 | rhs: Air.Inst.Ref, | 12616 | rhs: Air.Inst.Ref, |
| 12563 | ) CompileError!Air.Inst.Ref { | 12617 | ) CompileError!Air.Inst.Ref { |
| 12618 | const mod = sema.mod; | ||
| 12564 | const lhs_ty = sema.typeOf(lhs); | 12619 | const lhs_ty = sema.typeOf(lhs); |
| 12565 | const rhs_ty = sema.typeOf(rhs); | 12620 | const rhs_ty = sema.typeOf(rhs); |
| 12566 | const src = LazySrcLoc.nodeOffset(src_node); | 12621 | const src = LazySrcLoc.nodeOffset(src_node); |
| 12567 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; | 12622 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; |
| 12568 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; | 12623 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; |
| 12569 | 12624 | ||
| 12570 | const lhs_len = lhs_ty.structFieldCount(); | 12625 | const lhs_len = lhs_ty.structFieldCount(mod); |
| 12571 | const rhs_len = rhs_ty.structFieldCount(); | 12626 | const rhs_len = rhs_ty.structFieldCount(mod); |
| 12572 | const dest_fields = lhs_len + rhs_len; | 12627 | const dest_fields = lhs_len + rhs_len; |
| 12573 | 12628 | ||
| 12574 | if (dest_fields == 0) { | 12629 | if (dest_fields == 0) { |
| 12575 | return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value)); | 12630 | return sema.addConstant(Type.empty_struct_literal, Value.empty_struct); |
| 12576 | } | 12631 | } |
| 12577 | if (lhs_len == 0) { | 12632 | if (lhs_len == 0) { |
| 12578 | return rhs; | 12633 | return rhs; |
| ... | @@ -12582,42 +12637,48 @@ fn analyzeTupleCat( | ... | @@ -12582,42 +12637,48 @@ fn analyzeTupleCat( |
| 12582 | } | 12637 | } |
| 12583 | const final_len = try sema.usizeCast(block, rhs_src, dest_fields); | 12638 | const final_len = try sema.usizeCast(block, rhs_src, dest_fields); |
| 12584 | 12639 | ||
| 12585 | const types = try sema.arena.alloc(Type, final_len); | 12640 | const types = try sema.arena.alloc(InternPool.Index, final_len); |
| 12586 | const values = try sema.arena.alloc(Value, final_len); | 12641 | const values = try sema.arena.alloc(InternPool.Index, final_len); |
| 12587 | 12642 | ||
| 12588 | const opt_runtime_src = rs: { | 12643 | const opt_runtime_src = rs: { |
| 12589 | var runtime_src: ?LazySrcLoc = null; | 12644 | var runtime_src: ?LazySrcLoc = null; |
| 12590 | var i: u32 = 0; | 12645 | var i: u32 = 0; |
| 12591 | while (i < lhs_len) : (i += 1) { | 12646 | while (i < lhs_len) : (i += 1) { |
| 12592 | types[i] = lhs_ty.structFieldType(i); | 12647 | types[i] = lhs_ty.structFieldType(i, mod).toIntern(); |
| 12593 | const default_val = lhs_ty.structFieldDefaultValue(i); | 12648 | const default_val = lhs_ty.structFieldDefaultValue(i, mod); |
| 12594 | values[i] = default_val; | 12649 | values[i] = default_val.toIntern(); |
| 12595 | const operand_src = lhs_src; // TODO better source location | 12650 | const operand_src = lhs_src; // TODO better source location |
| 12596 | if (default_val.tag() == .unreachable_value) { | 12651 | if (default_val.toIntern() == .unreachable_value) { |
| 12597 | runtime_src = operand_src; | 12652 | runtime_src = operand_src; |
| 12653 | values[i] = .none; | ||
| 12598 | } | 12654 | } |
| 12599 | } | 12655 | } |
| 12600 | i = 0; | 12656 | i = 0; |
| 12601 | while (i < rhs_len) : (i += 1) { | 12657 | while (i < rhs_len) : (i += 1) { |
| 12602 | types[i + lhs_len] = rhs_ty.structFieldType(i); | 12658 | types[i + lhs_len] = rhs_ty.structFieldType(i, mod).toIntern(); |
| 12603 | const default_val = rhs_ty.structFieldDefaultValue(i); | 12659 | const default_val = rhs_ty.structFieldDefaultValue(i, mod); |
| 12604 | values[i + lhs_len] = default_val; | 12660 | values[i + lhs_len] = default_val.toIntern(); |
| 12605 | const operand_src = rhs_src; // TODO better source location | 12661 | const operand_src = rhs_src; // TODO better source location |
| 12606 | if (default_val.tag() == .unreachable_value) { | 12662 | if (default_val.toIntern() == .unreachable_value) { |
| 12607 | runtime_src = operand_src; | 12663 | runtime_src = operand_src; |
| 12664 | values[i + lhs_len] = .none; | ||
| 12608 | } | 12665 | } |
| 12609 | } | 12666 | } |
| 12610 | break :rs runtime_src; | 12667 | break :rs runtime_src; |
| 12611 | }; | 12668 | }; |
| 12612 | 12669 | ||
| 12613 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ | 12670 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ |
| 12614 | .types = types, | 12671 | .types = types, |
| 12615 | .values = values, | 12672 | .values = values, |
| 12616 | }); | 12673 | .names = &.{}, |
| 12674 | } }); | ||
| 12617 | 12675 | ||
| 12618 | const runtime_src = opt_runtime_src orelse { | 12676 | const runtime_src = opt_runtime_src orelse { |
| 12619 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | 12677 | const tuple_val = try mod.intern(.{ .aggregate = .{ |
| 12620 | return sema.addConstant(tuple_ty, tuple_val); | 12678 | .ty = tuple_ty, |
| 12679 | .storage = .{ .elems = values }, | ||
| 12680 | } }); | ||
| 12681 | return sema.addConstant(tuple_ty.toType(), tuple_val.toValue()); | ||
| 12621 | }; | 12682 | }; |
| 12622 | 12683 | ||
| 12623 | try sema.requireRuntimeBlock(block, src, runtime_src); | 12684 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | @@ -12635,13 +12696,14 @@ fn analyzeTupleCat( | ... | @@ -12635,13 +12696,14 @@ fn analyzeTupleCat( |
| 12635 | try sema.tupleFieldValByIndex(block, operand_src, rhs, i, rhs_ty); | 12696 | try sema.tupleFieldValByIndex(block, operand_src, rhs, i, rhs_ty); |
| 12636 | } | 12697 | } |
| 12637 | 12698 | ||
| 12638 | return block.addAggregateInit(tuple_ty, element_refs); | 12699 | return block.addAggregateInit(tuple_ty.toType(), element_refs); |
| 12639 | } | 12700 | } |
| 12640 | 12701 | ||
| 12641 | fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 12702 | fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 12642 | const tracy = trace(@src()); | 12703 | const tracy = trace(@src()); |
| 12643 | defer tracy.end(); | 12704 | defer tracy.end(); |
| 12644 | 12705 | ||
| 12706 | const mod = sema.mod; | ||
| 12645 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 12707 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12646 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 12708 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 12647 | const lhs = try sema.resolveInst(extra.lhs); | 12709 | const lhs = try sema.resolveInst(extra.lhs); |
| ... | @@ -12650,8 +12712,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -12650,8 +12712,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12650 | const rhs_ty = sema.typeOf(rhs); | 12712 | const rhs_ty = sema.typeOf(rhs); |
| 12651 | const src = inst_data.src(); | 12713 | const src = inst_data.src(); |
| 12652 | 12714 | ||
| 12653 | const lhs_is_tuple = lhs_ty.isTuple(); | 12715 | const lhs_is_tuple = lhs_ty.isTuple(mod); |
| 12654 | const rhs_is_tuple = rhs_ty.isTuple(); | 12716 | const rhs_is_tuple = rhs_ty.isTuple(mod); |
| 12655 | if (lhs_is_tuple and rhs_is_tuple) { | 12717 | if (lhs_is_tuple and rhs_is_tuple) { |
| 12656 | return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs); | 12718 | return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs); |
| 12657 | } | 12719 | } |
| ... | @@ -12661,11 +12723,11 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -12661,11 +12723,11 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12661 | 12723 | ||
| 12662 | const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, rhs_ty) orelse lhs_info: { | 12724 | const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, rhs_ty) orelse lhs_info: { |
| 12663 | if (lhs_is_tuple) break :lhs_info @as(Type.ArrayInfo, undefined); | 12725 | if (lhs_is_tuple) break :lhs_info @as(Type.ArrayInfo, undefined); |
| 12664 | return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(sema.mod)}); | 12726 | return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(mod)}); |
| 12665 | }; | 12727 | }; |
| 12666 | const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs, lhs_ty) orelse { | 12728 | const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs, lhs_ty) orelse { |
| 12667 | assert(!rhs_is_tuple); | 12729 | assert(!rhs_is_tuple); |
| 12668 | return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(sema.mod)}); | 12730 | return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(mod)}); |
| 12669 | }; | 12731 | }; |
| 12670 | 12732 | ||
| 12671 | const resolved_elem_ty = t: { | 12733 | const resolved_elem_ty = t: { |
| ... | @@ -12727,73 +12789,71 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -12727,73 +12789,71 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12727 | ), | 12789 | ), |
| 12728 | }; | 12790 | }; |
| 12729 | 12791 | ||
| 12730 | const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, sema.mod); | 12792 | const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, mod); |
| 12731 | const ptr_addrspace = p: { | 12793 | const ptr_addrspace = p: { |
| 12732 | if (lhs_ty.zigTypeTag() == .Pointer) break :p lhs_ty.ptrAddressSpace(); | 12794 | if (lhs_ty.zigTypeTag(mod) == .Pointer) break :p lhs_ty.ptrAddressSpace(mod); |
| 12733 | if (rhs_ty.zigTypeTag() == .Pointer) break :p rhs_ty.ptrAddressSpace(); | 12795 | if (rhs_ty.zigTypeTag(mod) == .Pointer) break :p rhs_ty.ptrAddressSpace(mod); |
| 12734 | break :p null; | 12796 | break :p null; |
| 12735 | }; | 12797 | }; |
| 12736 | 12798 | ||
| 12737 | const runtime_src = if (switch (lhs_ty.zigTypeTag()) { | 12799 | const runtime_src = if (switch (lhs_ty.zigTypeTag(mod)) { |
| 12738 | .Array, .Struct => try sema.resolveMaybeUndefVal(lhs), | 12800 | .Array, .Struct => try sema.resolveMaybeUndefVal(lhs), |
| 12739 | .Pointer => try sema.resolveDefinedValue(block, lhs_src, lhs), | 12801 | .Pointer => try sema.resolveDefinedValue(block, lhs_src, lhs), |
| 12740 | else => unreachable, | 12802 | else => unreachable, |
| 12741 | }) |lhs_val| rs: { | 12803 | }) |lhs_val| rs: { |
| 12742 | if (switch (rhs_ty.zigTypeTag()) { | 12804 | if (switch (rhs_ty.zigTypeTag(mod)) { |
| 12743 | .Array, .Struct => try sema.resolveMaybeUndefVal(rhs), | 12805 | .Array, .Struct => try sema.resolveMaybeUndefVal(rhs), |
| 12744 | .Pointer => try sema.resolveDefinedValue(block, rhs_src, rhs), | 12806 | .Pointer => try sema.resolveDefinedValue(block, rhs_src, rhs), |
| 12745 | else => unreachable, | 12807 | else => unreachable, |
| 12746 | }) |rhs_val| { | 12808 | }) |rhs_val| { |
| 12747 | const lhs_sub_val = if (lhs_ty.isSinglePointer()) | 12809 | const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) |
| 12748 | (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? | 12810 | (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? |
| 12749 | else | 12811 | else |
| 12750 | lhs_val; | 12812 | lhs_val; |
| 12751 | 12813 | ||
| 12752 | const rhs_sub_val = if (rhs_ty.isSinglePointer()) | 12814 | const rhs_sub_val = if (rhs_ty.isSinglePointer(mod)) |
| 12753 | (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? | 12815 | (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? |
| 12754 | else | 12816 | else |
| 12755 | rhs_val; | 12817 | rhs_val; |
| 12756 | 12818 | ||
| 12757 | const final_len_including_sent = result_len + @boolToInt(res_sent_val != null); | 12819 | const element_vals = try sema.arena.alloc(InternPool.Index, result_len); |
| 12758 | const element_vals = try sema.arena.alloc(Value, final_len_including_sent); | ||
| 12759 | var elem_i: usize = 0; | 12820 | var elem_i: usize = 0; |
| 12760 | while (elem_i < lhs_len) : (elem_i += 1) { | 12821 | while (elem_i < lhs_len) : (elem_i += 1) { |
| 12761 | const lhs_elem_i = elem_i; | 12822 | const lhs_elem_i = elem_i; |
| 12762 | const elem_ty = if (lhs_is_tuple) lhs_ty.structFieldType(lhs_elem_i) else lhs_info.elem_type; | 12823 | const elem_ty = if (lhs_is_tuple) lhs_ty.structFieldType(lhs_elem_i, mod) else lhs_info.elem_type; |
| 12763 | const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i) else Value.initTag(.unreachable_value); | 12824 | const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, mod) else Value.@"unreachable"; |
| 12764 | const elem_val = if (elem_default_val.tag() == .unreachable_value) try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_elem_i) else elem_default_val; | 12825 | const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try lhs_sub_val.elemValue(mod, lhs_elem_i) else elem_default_val; |
| 12765 | const elem_val_inst = try sema.addConstant(elem_ty, elem_val); | 12826 | const elem_val_inst = try sema.addConstant(elem_ty, elem_val); |
| 12766 | const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); | 12827 | const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); |
| 12767 | const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, ""); | 12828 | const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, ""); |
| 12768 | element_vals[elem_i] = coerced_elem_val; | 12829 | element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod); |
| 12769 | } | 12830 | } |
| 12770 | while (elem_i < result_len) : (elem_i += 1) { | 12831 | while (elem_i < result_len) : (elem_i += 1) { |
| 12771 | const rhs_elem_i = elem_i - lhs_len; | 12832 | const rhs_elem_i = elem_i - lhs_len; |
| 12772 | const elem_ty = if (rhs_is_tuple) rhs_ty.structFieldType(rhs_elem_i) else rhs_info.elem_type; | 12833 | const elem_ty = if (rhs_is_tuple) rhs_ty.structFieldType(rhs_elem_i, mod) else rhs_info.elem_type; |
| 12773 | const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i) else Value.initTag(.unreachable_value); | 12834 | const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, mod) else Value.@"unreachable"; |
| 12774 | const elem_val = if (elem_default_val.tag() == .unreachable_value) try rhs_sub_val.elemValue(sema.mod, sema.arena, rhs_elem_i) else elem_default_val; | 12835 | const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try rhs_sub_val.elemValue(mod, rhs_elem_i) else elem_default_val; |
| 12775 | const elem_val_inst = try sema.addConstant(elem_ty, elem_val); | 12836 | const elem_val_inst = try sema.addConstant(elem_ty, elem_val); |
| 12776 | const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); | 12837 | const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded); |
| 12777 | const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, ""); | 12838 | const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, ""); |
| 12778 | element_vals[elem_i] = coerced_elem_val; | 12839 | element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod); |
| 12779 | } | 12840 | } |
| 12780 | if (res_sent_val) |sent_val| { | 12841 | return sema.addConstantMaybeRef(block, result_ty, (try mod.intern(.{ .aggregate = .{ |
| 12781 | element_vals[result_len] = sent_val; | 12842 | .ty = result_ty.toIntern(), |
| 12782 | } | 12843 | .storage = .{ .elems = element_vals }, |
| 12783 | const val = try Value.Tag.aggregate.create(sema.arena, element_vals); | 12844 | } })).toValue(), ptr_addrspace != null); |
| 12784 | return sema.addConstantMaybeRef(block, result_ty, val, ptr_addrspace != null); | ||
| 12785 | } else break :rs rhs_src; | 12845 | } else break :rs rhs_src; |
| 12786 | } else lhs_src; | 12846 | } else lhs_src; |
| 12787 | 12847 | ||
| 12788 | try sema.requireRuntimeBlock(block, src, runtime_src); | 12848 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 12789 | 12849 | ||
| 12790 | if (ptr_addrspace) |ptr_as| { | 12850 | if (ptr_addrspace) |ptr_as| { |
| 12791 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | 12851 | const alloc_ty = try Type.ptr(sema.arena, mod, .{ |
| 12792 | .pointee_type = result_ty, | 12852 | .pointee_type = result_ty, |
| 12793 | .@"addrspace" = ptr_as, | 12853 | .@"addrspace" = ptr_as, |
| 12794 | }); | 12854 | }); |
| 12795 | const alloc = try block.addTy(.alloc, alloc_ty); | 12855 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 12796 | const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 12856 | const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{ |
| 12797 | .pointee_type = resolved_elem_ty, | 12857 | .pointee_type = resolved_elem_ty, |
| 12798 | .@"addrspace" = ptr_as, | 12858 | .@"addrspace" = ptr_as, |
| 12799 | }); | 12859 | }); |
| ... | @@ -12815,7 +12875,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -12815,7 +12875,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12815 | if (res_sent_val) |sent_val| { | 12875 | if (res_sent_val) |sent_val| { |
| 12816 | const elem_index = try sema.addIntUnsigned(Type.usize, result_len); | 12876 | const elem_index = try sema.addIntUnsigned(Type.usize, result_len); |
| 12817 | const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); | 12877 | const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); |
| 12818 | const init = try sema.addConstant(lhs_info.elem_type, sent_val); | 12878 | const init = try sema.addConstant(lhs_info.elem_type, try mod.getCoerced(sent_val, lhs_info.elem_type)); |
| 12819 | try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); | 12879 | try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); |
| 12820 | } | 12880 | } |
| 12821 | 12881 | ||
| ... | @@ -12841,11 +12901,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -12841,11 +12901,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12841 | } | 12901 | } |
| 12842 | 12902 | ||
| 12843 | fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref, peer_ty: Type) !?Type.ArrayInfo { | 12903 | fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref, peer_ty: Type) !?Type.ArrayInfo { |
| 12904 | const mod = sema.mod; | ||
| 12844 | const operand_ty = sema.typeOf(operand); | 12905 | const operand_ty = sema.typeOf(operand); |
| 12845 | switch (operand_ty.zigTypeTag()) { | 12906 | switch (operand_ty.zigTypeTag(mod)) { |
| 12846 | .Array => return operand_ty.arrayInfo(), | 12907 | .Array => return operand_ty.arrayInfo(mod), |
| 12847 | .Pointer => { | 12908 | .Pointer => { |
| 12848 | const ptr_info = operand_ty.ptrInfo().data; | 12909 | const ptr_info = operand_ty.ptrInfo(mod); |
| 12849 | switch (ptr_info.size) { | 12910 | switch (ptr_info.size) { |
| 12850 | // TODO: in the Many case here this should only work if the type | 12911 | // TODO: in the Many case here this should only work if the type |
| 12851 | // has a sentinel, and this code should compute the length based | 12912 | // has a sentinel, and this code should compute the length based |
| ... | @@ -12855,24 +12916,24 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins | ... | @@ -12855,24 +12916,24 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins |
| 12855 | return Type.ArrayInfo{ | 12916 | return Type.ArrayInfo{ |
| 12856 | .elem_type = ptr_info.pointee_type, | 12917 | .elem_type = ptr_info.pointee_type, |
| 12857 | .sentinel = ptr_info.sentinel, | 12918 | .sentinel = ptr_info.sentinel, |
| 12858 | .len = val.sliceLen(sema.mod), | 12919 | .len = val.sliceLen(mod), |
| 12859 | }; | 12920 | }; |
| 12860 | }, | 12921 | }, |
| 12861 | .One => { | 12922 | .One => { |
| 12862 | if (ptr_info.pointee_type.zigTypeTag() == .Array) { | 12923 | if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) { |
| 12863 | return ptr_info.pointee_type.arrayInfo(); | 12924 | return ptr_info.pointee_type.arrayInfo(mod); |
| 12864 | } | 12925 | } |
| 12865 | }, | 12926 | }, |
| 12866 | .C => {}, | 12927 | .C => {}, |
| 12867 | } | 12928 | } |
| 12868 | }, | 12929 | }, |
| 12869 | .Struct => { | 12930 | .Struct => { |
| 12870 | if (operand_ty.isTuple() and peer_ty.isIndexable()) { | 12931 | if (operand_ty.isTuple(mod) and peer_ty.isIndexable(mod)) { |
| 12871 | assert(!peer_ty.isTuple()); | 12932 | assert(!peer_ty.isTuple(mod)); |
| 12872 | return .{ | 12933 | return .{ |
| 12873 | .elem_type = peer_ty.elemType2(), | 12934 | .elem_type = peer_ty.elemType2(mod), |
| 12874 | .sentinel = null, | 12935 | .sentinel = null, |
| 12875 | .len = operand_ty.arrayLen(), | 12936 | .len = operand_ty.arrayLen(mod), |
| 12876 | }; | 12937 | }; |
| 12877 | } | 12938 | } |
| 12878 | }, | 12939 | }, |
| ... | @@ -12886,52 +12947,54 @@ fn analyzeTupleMul( | ... | @@ -12886,52 +12947,54 @@ fn analyzeTupleMul( |
| 12886 | block: *Block, | 12947 | block: *Block, |
| 12887 | src_node: i32, | 12948 | src_node: i32, |
| 12888 | operand: Air.Inst.Ref, | 12949 | operand: Air.Inst.Ref, |
| 12889 | factor: u64, | 12950 | factor: usize, |
| 12890 | ) CompileError!Air.Inst.Ref { | 12951 | ) CompileError!Air.Inst.Ref { |
| 12952 | const mod = sema.mod; | ||
| 12891 | const operand_ty = sema.typeOf(operand); | 12953 | const operand_ty = sema.typeOf(operand); |
| 12892 | const src = LazySrcLoc.nodeOffset(src_node); | 12954 | const src = LazySrcLoc.nodeOffset(src_node); |
| 12893 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; | 12955 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; |
| 12894 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; | 12956 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; |
| 12895 | 12957 | ||
| 12896 | const tuple_len = operand_ty.structFieldCount(); | 12958 | const tuple_len = operand_ty.structFieldCount(mod); |
| 12897 | const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch | 12959 | const final_len = std.math.mul(usize, tuple_len, factor) catch |
| 12898 | return sema.fail(block, rhs_src, "operation results in overflow", .{}); | 12960 | return sema.fail(block, rhs_src, "operation results in overflow", .{}); |
| 12899 | 12961 | ||
| 12900 | if (final_len_u64 == 0) { | 12962 | if (final_len == 0) { |
| 12901 | return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value)); | 12963 | return sema.addConstant(Type.empty_struct_literal, Value.empty_struct); |
| 12902 | } | 12964 | } |
| 12903 | const final_len = try sema.usizeCast(block, rhs_src, final_len_u64); | 12965 | const types = try sema.arena.alloc(InternPool.Index, final_len); |
| 12904 | 12966 | const values = try sema.arena.alloc(InternPool.Index, final_len); | |
| 12905 | const types = try sema.arena.alloc(Type, final_len); | ||
| 12906 | const values = try sema.arena.alloc(Value, final_len); | ||
| 12907 | 12967 | ||
| 12908 | const opt_runtime_src = rs: { | 12968 | const opt_runtime_src = rs: { |
| 12909 | var runtime_src: ?LazySrcLoc = null; | 12969 | var runtime_src: ?LazySrcLoc = null; |
| 12910 | var i: u32 = 0; | 12970 | for (0..tuple_len) |i| { |
| 12911 | while (i < tuple_len) : (i += 1) { | 12971 | types[i] = operand_ty.structFieldType(i, mod).toIntern(); |
| 12912 | types[i] = operand_ty.structFieldType(i); | 12972 | values[i] = operand_ty.structFieldDefaultValue(i, mod).toIntern(); |
| 12913 | values[i] = operand_ty.structFieldDefaultValue(i); | ||
| 12914 | const operand_src = lhs_src; // TODO better source location | 12973 | const operand_src = lhs_src; // TODO better source location |
| 12915 | if (values[i].tag() == .unreachable_value) { | 12974 | if (values[i] == .unreachable_value) { |
| 12916 | runtime_src = operand_src; | 12975 | runtime_src = operand_src; |
| 12976 | values[i] = .none; // TODO don't treat unreachable_value as special | ||
| 12917 | } | 12977 | } |
| 12918 | } | 12978 | } |
| 12919 | i = 0; | 12979 | for (0..factor) |i| { |
| 12920 | while (i < factor) : (i += 1) { | 12980 | mem.copyForwards(InternPool.Index, types[tuple_len * i ..], types[0..tuple_len]); |
| 12921 | mem.copyForwards(Type, types[tuple_len * i ..], types[0..tuple_len]); | 12981 | mem.copyForwards(InternPool.Index, values[tuple_len * i ..], values[0..tuple_len]); |
| 12922 | mem.copyForwards(Value, values[tuple_len * i ..], values[0..tuple_len]); | ||
| 12923 | } | 12982 | } |
| 12924 | break :rs runtime_src; | 12983 | break :rs runtime_src; |
| 12925 | }; | 12984 | }; |
| 12926 | 12985 | ||
| 12927 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ | 12986 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ |
| 12928 | .types = types, | 12987 | .types = types, |
| 12929 | .values = values, | 12988 | .values = values, |
| 12930 | }); | 12989 | .names = &.{}, |
| 12990 | } }); | ||
| 12931 | 12991 | ||
| 12932 | const runtime_src = opt_runtime_src orelse { | 12992 | const runtime_src = opt_runtime_src orelse { |
| 12933 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | 12993 | const tuple_val = try mod.intern(.{ .aggregate = .{ |
| 12934 | return sema.addConstant(tuple_ty, tuple_val); | 12994 | .ty = tuple_ty, |
| 12995 | .storage = .{ .elems = values }, | ||
| 12996 | } }); | ||
| 12997 | return sema.addConstant(tuple_ty.toType(), tuple_val.toValue()); | ||
| 12935 | }; | 12998 | }; |
| 12936 | 12999 | ||
| 12937 | try sema.requireRuntimeBlock(block, src, runtime_src); | 13000 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | @@ -12947,13 +13010,14 @@ fn analyzeTupleMul( | ... | @@ -12947,13 +13010,14 @@ fn analyzeTupleMul( |
| 12947 | @memcpy(element_refs[tuple_len * i ..][0..tuple_len], element_refs[0..tuple_len]); | 13010 | @memcpy(element_refs[tuple_len * i ..][0..tuple_len], element_refs[0..tuple_len]); |
| 12948 | } | 13011 | } |
| 12949 | 13012 | ||
| 12950 | return block.addAggregateInit(tuple_ty, element_refs); | 13013 | return block.addAggregateInit(tuple_ty.toType(), element_refs); |
| 12951 | } | 13014 | } |
| 12952 | 13015 | ||
| 12953 | fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13016 | fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 12954 | const tracy = trace(@src()); | 13017 | const tracy = trace(@src()); |
| 12955 | defer tracy.end(); | 13018 | defer tracy.end(); |
| 12956 | 13019 | ||
| 13020 | const mod = sema.mod; | ||
| 12957 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 13021 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 12958 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 13022 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 12959 | const lhs = try sema.resolveInst(extra.lhs); | 13023 | const lhs = try sema.resolveInst(extra.lhs); |
| ... | @@ -12963,18 +13027,19 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -12963,18 +13027,19 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12963 | const operator_src: LazySrcLoc = .{ .node_offset_main_token = inst_data.src_node }; | 13027 | const operator_src: LazySrcLoc = .{ .node_offset_main_token = inst_data.src_node }; |
| 12964 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | 13028 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| 12965 | 13029 | ||
| 12966 | if (lhs_ty.isTuple()) { | 13030 | if (lhs_ty.isTuple(mod)) { |
| 12967 | // In `**` rhs must be comptime-known, but lhs can be runtime-known | 13031 | // In `**` rhs must be comptime-known, but lhs can be runtime-known |
| 12968 | const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime-known"); | 13032 | const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime-known"); |
| 12969 | return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor); | 13033 | const factor_casted = try sema.usizeCast(block, rhs_src, factor); |
| 13034 | return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor_casted); | ||
| 12970 | } | 13035 | } |
| 12971 | 13036 | ||
| 12972 | // Analyze the lhs first, to catch the case that someone tried to do exponentiation | 13037 | // Analyze the lhs first, to catch the case that someone tried to do exponentiation |
| 12973 | const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse { | 13038 | const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse { |
| 12974 | const msg = msg: { | 13039 | const msg = msg: { |
| 12975 | const msg = try sema.errMsg(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(sema.mod)}); | 13040 | const msg = try sema.errMsg(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(mod)}); |
| 12976 | errdefer msg.destroy(sema.gpa); | 13041 | errdefer msg.destroy(sema.gpa); |
| 12977 | switch (lhs_ty.zigTypeTag()) { | 13042 | switch (lhs_ty.zigTypeTag(mod)) { |
| 12978 | .Int, .Float, .ComptimeFloat, .ComptimeInt, .Vector => { | 13043 | .Int, .Float, .ComptimeFloat, .ComptimeInt, .Vector => { |
| 12979 | try sema.errNote(block, operator_src, msg, "this operator multiplies arrays; use std.math.pow for exponentiation", .{}); | 13044 | try sema.errNote(block, operator_src, msg, "this operator multiplies arrays; use std.math.pow for exponentiation", .{}); |
| 12980 | }, | 13045 | }, |
| ... | @@ -12992,15 +13057,13 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -12992,15 +13057,13 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 12992 | return sema.fail(block, rhs_src, "operation results in overflow", .{}); | 13057 | return sema.fail(block, rhs_src, "operation results in overflow", .{}); |
| 12993 | const result_len = try sema.usizeCast(block, src, result_len_u64); | 13058 | const result_len = try sema.usizeCast(block, src, result_len_u64); |
| 12994 | 13059 | ||
| 12995 | const result_ty = try Type.array(sema.arena, result_len, lhs_info.sentinel, lhs_info.elem_type, sema.mod); | 13060 | const result_ty = try Type.array(sema.arena, result_len, lhs_info.sentinel, lhs_info.elem_type, mod); |
| 12996 | 13061 | ||
| 12997 | const ptr_addrspace = if (lhs_ty.zigTypeTag() == .Pointer) lhs_ty.ptrAddressSpace() else null; | 13062 | const ptr_addrspace = if (lhs_ty.zigTypeTag(mod) == .Pointer) lhs_ty.ptrAddressSpace(mod) else null; |
| 12998 | const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); | 13063 | const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len); |
| 12999 | 13064 | ||
| 13000 | if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| { | 13065 | if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| { |
| 13001 | const final_len_including_sent = result_len + @boolToInt(lhs_info.sentinel != null); | 13066 | const lhs_sub_val = if (lhs_ty.isSinglePointer(mod)) |
| 13002 | |||
| 13003 | const lhs_sub_val = if (lhs_ty.isSinglePointer()) | ||
| 13004 | (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? | 13067 | (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? |
| 13005 | else | 13068 | else |
| 13006 | lhs_val; | 13069 | lhs_val; |
| ... | @@ -13008,38 +13071,41 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13008,38 +13071,41 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13008 | const val = v: { | 13071 | const val = v: { |
| 13009 | // Optimization for the common pattern of a single element repeated N times, such | 13072 | // Optimization for the common pattern of a single element repeated N times, such |
| 13010 | // as zero-filling a byte array. | 13073 | // as zero-filling a byte array. |
| 13011 | if (lhs_len == 1) { | 13074 | if (lhs_len == 1 and lhs_info.sentinel == null) { |
| 13012 | const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, 0); | 13075 | const elem_val = try lhs_sub_val.elemValue(mod, 0); |
| 13013 | break :v try Value.Tag.repeated.create(sema.arena, elem_val); | 13076 | break :v try mod.intern(.{ .aggregate = .{ |
| 13077 | .ty = result_ty.toIntern(), | ||
| 13078 | .storage = .{ .repeated_elem = elem_val.toIntern() }, | ||
| 13079 | } }); | ||
| 13014 | } | 13080 | } |
| 13015 | 13081 | ||
| 13016 | const element_vals = try sema.arena.alloc(Value, final_len_including_sent); | 13082 | const element_vals = try sema.arena.alloc(InternPool.Index, result_len); |
| 13017 | var elem_i: usize = 0; | 13083 | var elem_i: usize = 0; |
| 13018 | while (elem_i < result_len) { | 13084 | while (elem_i < result_len) { |
| 13019 | var lhs_i: usize = 0; | 13085 | var lhs_i: usize = 0; |
| 13020 | while (lhs_i < lhs_len) : (lhs_i += 1) { | 13086 | while (lhs_i < lhs_len) : (lhs_i += 1) { |
| 13021 | const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_i); | 13087 | const elem_val = try lhs_sub_val.elemValue(mod, lhs_i); |
| 13022 | element_vals[elem_i] = elem_val; | 13088 | element_vals[elem_i] = elem_val.toIntern(); |
| 13023 | elem_i += 1; | 13089 | elem_i += 1; |
| 13024 | } | 13090 | } |
| 13025 | } | 13091 | } |
| 13026 | if (lhs_info.sentinel) |sent_val| { | 13092 | break :v try mod.intern(.{ .aggregate = .{ |
| 13027 | element_vals[result_len] = sent_val; | 13093 | .ty = result_ty.toIntern(), |
| 13028 | } | 13094 | .storage = .{ .elems = element_vals }, |
| 13029 | break :v try Value.Tag.aggregate.create(sema.arena, element_vals); | 13095 | } }); |
| 13030 | }; | 13096 | }; |
| 13031 | return sema.addConstantMaybeRef(block, result_ty, val, ptr_addrspace != null); | 13097 | return sema.addConstantMaybeRef(block, result_ty, val.toValue(), ptr_addrspace != null); |
| 13032 | } | 13098 | } |
| 13033 | 13099 | ||
| 13034 | try sema.requireRuntimeBlock(block, src, lhs_src); | 13100 | try sema.requireRuntimeBlock(block, src, lhs_src); |
| 13035 | 13101 | ||
| 13036 | if (ptr_addrspace) |ptr_as| { | 13102 | if (ptr_addrspace) |ptr_as| { |
| 13037 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | 13103 | const alloc_ty = try Type.ptr(sema.arena, mod, .{ |
| 13038 | .pointee_type = result_ty, | 13104 | .pointee_type = result_ty, |
| 13039 | .@"addrspace" = ptr_as, | 13105 | .@"addrspace" = ptr_as, |
| 13040 | }); | 13106 | }); |
| 13041 | const alloc = try block.addTy(.alloc, alloc_ty); | 13107 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 13042 | const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 13108 | const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{ |
| 13043 | .pointee_type = lhs_info.elem_type, | 13109 | .pointee_type = lhs_info.elem_type, |
| 13044 | .@"addrspace" = ptr_as, | 13110 | .@"addrspace" = ptr_as, |
| 13045 | }); | 13111 | }); |
| ... | @@ -13082,6 +13148,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13082,6 +13148,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13082 | } | 13148 | } |
| 13083 | 13149 | ||
| 13084 | fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13150 | fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13151 | const mod = sema.mod; | ||
| 13085 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 13152 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 13086 | const src = inst_data.src(); | 13153 | const src = inst_data.src(); |
| 13087 | const lhs_src = src; | 13154 | const lhs_src = src; |
| ... | @@ -13089,34 +13156,31 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -13089,34 +13156,31 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13089 | 13156 | ||
| 13090 | const rhs = try sema.resolveInst(inst_data.operand); | 13157 | const rhs = try sema.resolveInst(inst_data.operand); |
| 13091 | const rhs_ty = sema.typeOf(rhs); | 13158 | const rhs_ty = sema.typeOf(rhs); |
| 13092 | const rhs_scalar_ty = rhs_ty.scalarType(); | 13159 | const rhs_scalar_ty = rhs_ty.scalarType(mod); |
| 13093 | 13160 | ||
| 13094 | if (rhs_scalar_ty.isUnsignedInt() or switch (rhs_scalar_ty.zigTypeTag()) { | 13161 | if (rhs_scalar_ty.isUnsignedInt(mod) or switch (rhs_scalar_ty.zigTypeTag(mod)) { |
| 13095 | .Int, .ComptimeInt, .Float, .ComptimeFloat => false, | 13162 | .Int, .ComptimeInt, .Float, .ComptimeFloat => false, |
| 13096 | else => true, | 13163 | else => true, |
| 13097 | }) { | 13164 | }) { |
| 13098 | return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}); | 13165 | return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(mod)}); |
| 13099 | } | 13166 | } |
| 13100 | 13167 | ||
| 13101 | if (rhs_scalar_ty.isAnyFloat()) { | 13168 | if (rhs_scalar_ty.isAnyFloat()) { |
| 13102 | // We handle float negation here to ensure negative zero is represented in the bits. | 13169 | // We handle float negation here to ensure negative zero is represented in the bits. |
| 13103 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { | 13170 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { |
| 13104 | if (rhs_val.isUndef()) return sema.addConstUndef(rhs_ty); | 13171 | if (rhs_val.isUndef(mod)) return sema.addConstUndef(rhs_ty); |
| 13105 | return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, sema.mod)); | 13172 | return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, mod)); |
| 13106 | } | 13173 | } |
| 13107 | try sema.requireRuntimeBlock(block, src, null); | 13174 | try sema.requireRuntimeBlock(block, src, null); |
| 13108 | return block.addUnOp(if (block.float_mode == .Optimized) .neg_optimized else .neg, rhs); | 13175 | return block.addUnOp(if (block.float_mode == .Optimized) .neg_optimized else .neg, rhs); |
| 13109 | } | 13176 | } |
| 13110 | 13177 | ||
| 13111 | const lhs = if (rhs_ty.zigTypeTag() == .Vector) | 13178 | const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0))); |
| 13112 | try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero)) | ||
| 13113 | else | ||
| 13114 | try sema.resolveInst(.zero); | ||
| 13115 | |||
| 13116 | return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src, true); | 13179 | return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src, true); |
| 13117 | } | 13180 | } |
| 13118 | 13181 | ||
| 13119 | fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13182 | fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13183 | const mod = sema.mod; | ||
| 13120 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 13184 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 13121 | const src = inst_data.src(); | 13185 | const src = inst_data.src(); |
| 13122 | const lhs_src = src; | 13186 | const lhs_src = src; |
| ... | @@ -13124,18 +13188,14 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -13124,18 +13188,14 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 13124 | 13188 | ||
| 13125 | const rhs = try sema.resolveInst(inst_data.operand); | 13189 | const rhs = try sema.resolveInst(inst_data.operand); |
| 13126 | const rhs_ty = sema.typeOf(rhs); | 13190 | const rhs_ty = sema.typeOf(rhs); |
| 13127 | const rhs_scalar_ty = rhs_ty.scalarType(); | 13191 | const rhs_scalar_ty = rhs_ty.scalarType(mod); |
| 13128 | 13192 | ||
| 13129 | switch (rhs_scalar_ty.zigTypeTag()) { | 13193 | switch (rhs_scalar_ty.zigTypeTag(mod)) { |
| 13130 | .Int, .ComptimeInt, .Float, .ComptimeFloat => {}, | 13194 | .Int, .ComptimeInt, .Float, .ComptimeFloat => {}, |
| 13131 | else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}), | 13195 | else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(mod)}), |
| 13132 | } | 13196 | } |
| 13133 | 13197 | ||
| 13134 | const lhs = if (rhs_ty.zigTypeTag() == .Vector) | 13198 | const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0))); |
| 13135 | try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero)) | ||
| 13136 | else | ||
| 13137 | try sema.resolveInst(.zero); | ||
| 13138 | |||
| 13139 | return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src, true); | 13199 | return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src, true); |
| 13140 | } | 13200 | } |
| 13141 | 13201 | ||
| ... | @@ -13161,6 +13221,7 @@ fn zirArithmetic( | ... | @@ -13161,6 +13221,7 @@ fn zirArithmetic( |
| 13161 | } | 13221 | } |
| 13162 | 13222 | ||
| 13163 | fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13223 | fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13224 | const mod = sema.mod; | ||
| 13164 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 13225 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 13165 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 13226 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 13166 | sema.src = src; | 13227 | sema.src = src; |
| ... | @@ -13171,8 +13232,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -13171,8 +13232,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13171 | const rhs = try sema.resolveInst(extra.rhs); | 13232 | const rhs = try sema.resolveInst(extra.rhs); |
| 13172 | const lhs_ty = sema.typeOf(lhs); | 13233 | const lhs_ty = sema.typeOf(lhs); |
| 13173 | const rhs_ty = sema.typeOf(rhs); | 13234 | const rhs_ty = sema.typeOf(rhs); |
| 13174 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | 13235 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 13175 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | 13236 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 13176 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 13237 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13177 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 13238 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); |
| 13178 | 13239 | ||
| ... | @@ -13181,25 +13242,22 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -13181,25 +13242,22 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13181 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, | 13242 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13182 | }); | 13243 | }); |
| 13183 | 13244 | ||
| 13184 | const is_vector = resolved_type.zigTypeTag() == .Vector; | ||
| 13185 | |||
| 13186 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 13245 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13187 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 13246 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13188 | 13247 | ||
| 13189 | const lhs_scalar_ty = lhs_ty.scalarType(); | 13248 | const lhs_scalar_ty = lhs_ty.scalarType(mod); |
| 13190 | const rhs_scalar_ty = rhs_ty.scalarType(); | 13249 | const rhs_scalar_ty = rhs_ty.scalarType(mod); |
| 13191 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | 13250 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); |
| 13192 | 13251 | ||
| 13193 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | 13252 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 13194 | 13253 | ||
| 13195 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div); | 13254 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div); |
| 13196 | 13255 | ||
| 13197 | const mod = sema.mod; | ||
| 13198 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); | 13256 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 13199 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); | 13257 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); |
| 13200 | 13258 | ||
| 13201 | if ((lhs_ty.zigTypeTag() == .ComptimeFloat and rhs_ty.zigTypeTag() == .ComptimeInt) or | 13259 | if ((lhs_ty.zigTypeTag(mod) == .ComptimeFloat and rhs_ty.zigTypeTag(mod) == .ComptimeInt) or |
| 13202 | (lhs_ty.zigTypeTag() == .ComptimeInt and rhs_ty.zigTypeTag() == .ComptimeFloat)) | 13260 | (lhs_ty.zigTypeTag(mod) == .ComptimeInt and rhs_ty.zigTypeTag(mod) == .ComptimeFloat)) |
| 13203 | { | 13261 | { |
| 13204 | // If it makes a difference whether we coerce to ints or floats before doing the division, error. | 13262 | // If it makes a difference whether we coerce to ints or floats before doing the division, error. |
| 13205 | // If lhs % rhs is 0, it doesn't matter. | 13263 | // If lhs % rhs is 0, it doesn't matter. |
| ... | @@ -13207,9 +13265,12 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -13207,9 +13265,12 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13207 | const rhs_val = maybe_rhs_val orelse unreachable; | 13265 | const rhs_val = maybe_rhs_val orelse unreachable; |
| 13208 | const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod) catch unreachable; | 13266 | const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod) catch unreachable; |
| 13209 | if (!rem.compareAllWithZero(.eq, mod)) { | 13267 | if (!rem.compareAllWithZero(.eq, mod)) { |
| 13210 | return sema.fail(block, src, "ambiguous coercion of division operands '{s}' and '{s}'; non-zero remainder '{}'", .{ | 13268 | return sema.fail( |
| 13211 | @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), rem.fmtValue(resolved_type, sema.mod), | 13269 | block, |
| 13212 | }); | 13270 | src, |
| 13271 | "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'", | ||
| 13272 | .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod), rem.fmtValue(resolved_type, mod) }, | ||
| 13273 | ); | ||
| 13213 | } | 13274 | } |
| 13214 | } | 13275 | } |
| 13215 | 13276 | ||
| ... | @@ -13243,17 +13304,20 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -13243,17 +13304,20 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13243 | switch (scalar_tag) { | 13304 | switch (scalar_tag) { |
| 13244 | .Int, .ComptimeInt, .ComptimeFloat => { | 13305 | .Int, .ComptimeInt, .ComptimeFloat => { |
| 13245 | if (maybe_lhs_val) |lhs_val| { | 13306 | if (maybe_lhs_val) |lhs_val| { |
| 13246 | if (!lhs_val.isUndef()) { | 13307 | if (!lhs_val.isUndef(mod)) { |
| 13247 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 13308 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 13248 | const zero_val = if (is_vector) b: { | 13309 | const scalar_zero = switch (scalar_tag) { |
| 13249 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | 13310 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), |
| 13250 | } else Value.zero; | 13311 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), |
| 13312 | else => unreachable, | ||
| 13313 | }; | ||
| 13314 | const zero_val = try sema.splat(resolved_type, scalar_zero); | ||
| 13251 | return sema.addConstant(resolved_type, zero_val); | 13315 | return sema.addConstant(resolved_type, zero_val); |
| 13252 | } | 13316 | } |
| 13253 | } | 13317 | } |
| 13254 | } | 13318 | } |
| 13255 | if (maybe_rhs_val) |rhs_val| { | 13319 | if (maybe_rhs_val) |rhs_val| { |
| 13256 | if (rhs_val.isUndef()) { | 13320 | if (rhs_val.isUndef(mod)) { |
| 13257 | return sema.failWithUseOfUndef(block, rhs_src); | 13321 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13258 | } | 13322 | } |
| 13259 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { | 13323 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { |
| ... | @@ -13267,10 +13331,10 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -13267,10 +13331,10 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13267 | 13331 | ||
| 13268 | const runtime_src = rs: { | 13332 | const runtime_src = rs: { |
| 13269 | if (maybe_lhs_val) |lhs_val| { | 13333 | if (maybe_lhs_val) |lhs_val| { |
| 13270 | if (lhs_val.isUndef()) { | 13334 | if (lhs_val.isUndef(mod)) { |
| 13271 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | 13335 | if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) { |
| 13272 | if (maybe_rhs_val) |rhs_val| { | 13336 | if (maybe_rhs_val) |rhs_val| { |
| 13273 | if (try sema.compareAll(rhs_val, .neq, Value.negative_one, resolved_type)) { | 13337 | if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) { |
| 13274 | return sema.addConstUndef(resolved_type); | 13338 | return sema.addConstUndef(resolved_type); |
| 13275 | } | 13339 | } |
| 13276 | } | 13340 | } |
| ... | @@ -13281,10 +13345,10 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -13281,10 +13345,10 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13281 | 13345 | ||
| 13282 | if (maybe_rhs_val) |rhs_val| { | 13346 | if (maybe_rhs_val) |rhs_val| { |
| 13283 | if (is_int) { | 13347 | if (is_int) { |
| 13284 | const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod); | 13348 | var overflow_idx: ?usize = null; |
| 13285 | var vector_index: usize = undefined; | 13349 | const res = try lhs_val.intDiv(rhs_val, resolved_type, &overflow_idx, sema.arena, mod); |
| 13286 | if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) { | 13350 | if (overflow_idx) |vec_idx| { |
| 13287 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); | 13351 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vec_idx); |
| 13288 | } | 13352 | } |
| 13289 | return sema.addConstant(resolved_type, res); | 13353 | return sema.addConstant(resolved_type, res); |
| 13290 | } else { | 13354 | } else { |
| ... | @@ -13309,8 +13373,13 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -13309,8 +13373,13 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13309 | } | 13373 | } |
| 13310 | 13374 | ||
| 13311 | const air_tag = if (is_int) blk: { | 13375 | const air_tag = if (is_int) blk: { |
| 13312 | if (lhs_ty.isSignedInt() or rhs_ty.isSignedInt()) { | 13376 | if (lhs_ty.isSignedInt(mod) or rhs_ty.isSignedInt(mod)) { |
| 13313 | return sema.fail(block, src, "division with '{s}' and '{s}': signed integers must use @divTrunc, @divFloor, or @divExact", .{ @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()) }); | 13377 | return sema.fail( |
| 13378 | block, | ||
| 13379 | src, | ||
| 13380 | "division with '{}' and '{}': signed integers must use @divTrunc, @divFloor, or @divExact", | ||
| 13381 | .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod) }, | ||
| 13382 | ); | ||
| 13314 | } | 13383 | } |
| 13315 | break :blk Air.Inst.Tag.div_trunc; | 13384 | break :blk Air.Inst.Tag.div_trunc; |
| 13316 | } else switch (block.float_mode) { | 13385 | } else switch (block.float_mode) { |
| ... | @@ -13321,6 +13390,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -13321,6 +13390,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13321 | } | 13390 | } |
| 13322 | 13391 | ||
| 13323 | fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13392 | fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13393 | const mod = sema.mod; | ||
| 13324 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 13394 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 13325 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 13395 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 13326 | sema.src = src; | 13396 | sema.src = src; |
| ... | @@ -13331,8 +13401,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13331,8 +13401,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13331 | const rhs = try sema.resolveInst(extra.rhs); | 13401 | const rhs = try sema.resolveInst(extra.rhs); |
| 13332 | const lhs_ty = sema.typeOf(lhs); | 13402 | const lhs_ty = sema.typeOf(lhs); |
| 13333 | const rhs_ty = sema.typeOf(rhs); | 13403 | const rhs_ty = sema.typeOf(rhs); |
| 13334 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | 13404 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 13335 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | 13405 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 13336 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 13406 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13337 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 13407 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); |
| 13338 | 13408 | ||
| ... | @@ -13341,19 +13411,16 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13341,19 +13411,16 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13341 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, | 13411 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13342 | }); | 13412 | }); |
| 13343 | 13413 | ||
| 13344 | const is_vector = resolved_type.zigTypeTag() == .Vector; | ||
| 13345 | |||
| 13346 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 13414 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13347 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 13415 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13348 | 13416 | ||
| 13349 | const lhs_scalar_ty = lhs_ty.scalarType(); | 13417 | const lhs_scalar_ty = lhs_ty.scalarType(mod); |
| 13350 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | 13418 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); |
| 13351 | 13419 | ||
| 13352 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | 13420 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 13353 | 13421 | ||
| 13354 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact); | 13422 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact); |
| 13355 | 13423 | ||
| 13356 | const mod = sema.mod; | ||
| 13357 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); | 13424 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 13358 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); | 13425 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); |
| 13359 | 13426 | ||
| ... | @@ -13375,19 +13442,22 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13375,19 +13442,22 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13375 | // If the lhs is undefined, compile error because there is a possible | 13442 | // If the lhs is undefined, compile error because there is a possible |
| 13376 | // value for which the division would result in a remainder. | 13443 | // value for which the division would result in a remainder. |
| 13377 | if (maybe_lhs_val) |lhs_val| { | 13444 | if (maybe_lhs_val) |lhs_val| { |
| 13378 | if (lhs_val.isUndef()) { | 13445 | if (lhs_val.isUndef(mod)) { |
| 13379 | return sema.failWithUseOfUndef(block, rhs_src); | 13446 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13380 | } else { | 13447 | } else { |
| 13381 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 13448 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 13382 | const zero_val = if (is_vector) b: { | 13449 | const scalar_zero = switch (scalar_tag) { |
| 13383 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | 13450 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), |
| 13384 | } else Value.zero; | 13451 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), |
| 13452 | else => unreachable, | ||
| 13453 | }; | ||
| 13454 | const zero_val = try sema.splat(resolved_type, scalar_zero); | ||
| 13385 | return sema.addConstant(resolved_type, zero_val); | 13455 | return sema.addConstant(resolved_type, zero_val); |
| 13386 | } | 13456 | } |
| 13387 | } | 13457 | } |
| 13388 | } | 13458 | } |
| 13389 | if (maybe_rhs_val) |rhs_val| { | 13459 | if (maybe_rhs_val) |rhs_val| { |
| 13390 | if (rhs_val.isUndef()) { | 13460 | if (rhs_val.isUndef(mod)) { |
| 13391 | return sema.failWithUseOfUndef(block, rhs_src); | 13461 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13392 | } | 13462 | } |
| 13393 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { | 13463 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { |
| ... | @@ -13402,10 +13472,10 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13402,10 +13472,10 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13402 | if (!(modulus_val.compareAllWithZero(.eq, mod))) { | 13472 | if (!(modulus_val.compareAllWithZero(.eq, mod))) { |
| 13403 | return sema.fail(block, src, "exact division produced remainder", .{}); | 13473 | return sema.fail(block, src, "exact division produced remainder", .{}); |
| 13404 | } | 13474 | } |
| 13405 | const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod); | 13475 | var overflow_idx: ?usize = null; |
| 13406 | var vector_index: usize = undefined; | 13476 | const res = try lhs_val.intDiv(rhs_val, resolved_type, &overflow_idx, sema.arena, mod); |
| 13407 | if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) { | 13477 | if (overflow_idx) |vec_idx| { |
| 13408 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); | 13478 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vec_idx); |
| 13409 | } | 13479 | } |
| 13410 | return sema.addConstant(resolved_type, res); | 13480 | return sema.addConstant(resolved_type, res); |
| 13411 | } else { | 13481 | } else { |
| ... | @@ -13437,7 +13507,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13437,7 +13507,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13437 | const ok = if (!is_int) ok: { | 13507 | const ok = if (!is_int) ok: { |
| 13438 | const floored = try block.addUnOp(.floor, result); | 13508 | const floored = try block.addUnOp(.floor, result); |
| 13439 | 13509 | ||
| 13440 | if (resolved_type.zigTypeTag() == .Vector) { | 13510 | if (resolved_type.zigTypeTag(mod) == .Vector) { |
| 13441 | const eql = try block.addCmpVector(result, floored, .eq); | 13511 | const eql = try block.addCmpVector(result, floored, .eq); |
| 13442 | break :ok try block.addInst(.{ | 13512 | break :ok try block.addInst(.{ |
| 13443 | .tag = switch (block.float_mode) { | 13513 | .tag = switch (block.float_mode) { |
| ... | @@ -13459,8 +13529,13 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13459,8 +13529,13 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13459 | } else ok: { | 13529 | } else ok: { |
| 13460 | const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs); | 13530 | const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs); |
| 13461 | 13531 | ||
| 13462 | if (resolved_type.zigTypeTag() == .Vector) { | 13532 | const scalar_zero = switch (scalar_tag) { |
| 13463 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); | 13533 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), |
| 13534 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), | ||
| 13535 | else => unreachable, | ||
| 13536 | }; | ||
| 13537 | if (resolved_type.zigTypeTag(mod) == .Vector) { | ||
| 13538 | const zero_val = try sema.splat(resolved_type, scalar_zero); | ||
| 13464 | const zero = try sema.addConstant(resolved_type, zero_val); | 13539 | const zero = try sema.addConstant(resolved_type, zero_val); |
| 13465 | const eql = try block.addCmpVector(remainder, zero, .eq); | 13540 | const eql = try block.addCmpVector(remainder, zero, .eq); |
| 13466 | break :ok try block.addInst(.{ | 13541 | break :ok try block.addInst(.{ |
| ... | @@ -13471,7 +13546,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13471,7 +13546,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13471 | } }, | 13546 | } }, |
| 13472 | }); | 13547 | }); |
| 13473 | } else { | 13548 | } else { |
| 13474 | const zero = try sema.addConstant(resolved_type, Value.zero); | 13549 | const zero = try sema.addConstant(resolved_type, scalar_zero); |
| 13475 | const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero); | 13550 | const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero); |
| 13476 | break :ok is_in_range; | 13551 | break :ok is_in_range; |
| 13477 | } | 13552 | } |
| ... | @@ -13484,6 +13559,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13484,6 +13559,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13484 | } | 13559 | } |
| 13485 | 13560 | ||
| 13486 | fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13561 | fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13562 | const mod = sema.mod; | ||
| 13487 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 13563 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 13488 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 13564 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 13489 | sema.src = src; | 13565 | sema.src = src; |
| ... | @@ -13494,8 +13570,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13494,8 +13570,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13494 | const rhs = try sema.resolveInst(extra.rhs); | 13570 | const rhs = try sema.resolveInst(extra.rhs); |
| 13495 | const lhs_ty = sema.typeOf(lhs); | 13571 | const lhs_ty = sema.typeOf(lhs); |
| 13496 | const rhs_ty = sema.typeOf(rhs); | 13572 | const rhs_ty = sema.typeOf(rhs); |
| 13497 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | 13573 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 13498 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | 13574 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 13499 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 13575 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13500 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 13576 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); |
| 13501 | 13577 | ||
| ... | @@ -13504,20 +13580,17 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13504,20 +13580,17 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13504 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, | 13580 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13505 | }); | 13581 | }); |
| 13506 | 13582 | ||
| 13507 | const is_vector = resolved_type.zigTypeTag() == .Vector; | ||
| 13508 | |||
| 13509 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 13583 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13510 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 13584 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13511 | 13585 | ||
| 13512 | const lhs_scalar_ty = lhs_ty.scalarType(); | 13586 | const lhs_scalar_ty = lhs_ty.scalarType(mod); |
| 13513 | const rhs_scalar_ty = rhs_ty.scalarType(); | 13587 | const rhs_scalar_ty = rhs_ty.scalarType(mod); |
| 13514 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | 13588 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); |
| 13515 | 13589 | ||
| 13516 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | 13590 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 13517 | 13591 | ||
| 13518 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor); | 13592 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor); |
| 13519 | 13593 | ||
| 13520 | const mod = sema.mod; | ||
| 13521 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); | 13594 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 13522 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); | 13595 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); |
| 13523 | 13596 | ||
| ... | @@ -13542,17 +13615,20 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13542,17 +13615,20 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13542 | // value (zero) for which the division would be illegal behavior. | 13615 | // value (zero) for which the division would be illegal behavior. |
| 13543 | // If the lhs is undefined, result is undefined. | 13616 | // If the lhs is undefined, result is undefined. |
| 13544 | if (maybe_lhs_val) |lhs_val| { | 13617 | if (maybe_lhs_val) |lhs_val| { |
| 13545 | if (!lhs_val.isUndef()) { | 13618 | if (!lhs_val.isUndef(mod)) { |
| 13546 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 13619 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 13547 | const zero_val = if (is_vector) b: { | 13620 | const scalar_zero = switch (scalar_tag) { |
| 13548 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | 13621 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), |
| 13549 | } else Value.zero; | 13622 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), |
| 13623 | else => unreachable, | ||
| 13624 | }; | ||
| 13625 | const zero_val = try sema.splat(resolved_type, scalar_zero); | ||
| 13550 | return sema.addConstant(resolved_type, zero_val); | 13626 | return sema.addConstant(resolved_type, zero_val); |
| 13551 | } | 13627 | } |
| 13552 | } | 13628 | } |
| 13553 | } | 13629 | } |
| 13554 | if (maybe_rhs_val) |rhs_val| { | 13630 | if (maybe_rhs_val) |rhs_val| { |
| 13555 | if (rhs_val.isUndef()) { | 13631 | if (rhs_val.isUndef(mod)) { |
| 13556 | return sema.failWithUseOfUndef(block, rhs_src); | 13632 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13557 | } | 13633 | } |
| 13558 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { | 13634 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { |
| ... | @@ -13561,10 +13637,10 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13561,10 +13637,10 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13561 | // TODO: if the RHS is one, return the LHS directly | 13637 | // TODO: if the RHS is one, return the LHS directly |
| 13562 | } | 13638 | } |
| 13563 | if (maybe_lhs_val) |lhs_val| { | 13639 | if (maybe_lhs_val) |lhs_val| { |
| 13564 | if (lhs_val.isUndef()) { | 13640 | if (lhs_val.isUndef(mod)) { |
| 13565 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | 13641 | if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) { |
| 13566 | if (maybe_rhs_val) |rhs_val| { | 13642 | if (maybe_rhs_val) |rhs_val| { |
| 13567 | if (try sema.compareAll(rhs_val, .neq, Value.negative_one, resolved_type)) { | 13643 | if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) { |
| 13568 | return sema.addConstUndef(resolved_type); | 13644 | return sema.addConstUndef(resolved_type); |
| 13569 | } | 13645 | } |
| 13570 | } | 13646 | } |
| ... | @@ -13600,6 +13676,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13600,6 +13676,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13600 | } | 13676 | } |
| 13601 | 13677 | ||
| 13602 | fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13678 | fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13679 | const mod = sema.mod; | ||
| 13603 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 13680 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 13604 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 13681 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 13605 | sema.src = src; | 13682 | sema.src = src; |
| ... | @@ -13610,8 +13687,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13610,8 +13687,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13610 | const rhs = try sema.resolveInst(extra.rhs); | 13687 | const rhs = try sema.resolveInst(extra.rhs); |
| 13611 | const lhs_ty = sema.typeOf(lhs); | 13688 | const lhs_ty = sema.typeOf(lhs); |
| 13612 | const rhs_ty = sema.typeOf(rhs); | 13689 | const rhs_ty = sema.typeOf(rhs); |
| 13613 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | 13690 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 13614 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | 13691 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 13615 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 13692 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13616 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 13693 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); |
| 13617 | 13694 | ||
| ... | @@ -13620,20 +13697,17 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13620,20 +13697,17 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13620 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, | 13697 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13621 | }); | 13698 | }); |
| 13622 | 13699 | ||
| 13623 | const is_vector = resolved_type.zigTypeTag() == .Vector; | ||
| 13624 | |||
| 13625 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 13700 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13626 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 13701 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13627 | 13702 | ||
| 13628 | const lhs_scalar_ty = lhs_ty.scalarType(); | 13703 | const lhs_scalar_ty = lhs_ty.scalarType(mod); |
| 13629 | const rhs_scalar_ty = rhs_ty.scalarType(); | 13704 | const rhs_scalar_ty = rhs_ty.scalarType(mod); |
| 13630 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | 13705 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); |
| 13631 | 13706 | ||
| 13632 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | 13707 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 13633 | 13708 | ||
| 13634 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc); | 13709 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc); |
| 13635 | 13710 | ||
| 13636 | const mod = sema.mod; | ||
| 13637 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); | 13711 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 13638 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); | 13712 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); |
| 13639 | 13713 | ||
| ... | @@ -13658,17 +13732,20 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13658,17 +13732,20 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13658 | // value (zero) for which the division would be illegal behavior. | 13732 | // value (zero) for which the division would be illegal behavior. |
| 13659 | // If the lhs is undefined, result is undefined. | 13733 | // If the lhs is undefined, result is undefined. |
| 13660 | if (maybe_lhs_val) |lhs_val| { | 13734 | if (maybe_lhs_val) |lhs_val| { |
| 13661 | if (!lhs_val.isUndef()) { | 13735 | if (!lhs_val.isUndef(mod)) { |
| 13662 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 13736 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 13663 | const zero_val = if (is_vector) b: { | 13737 | const scalar_zero = switch (scalar_tag) { |
| 13664 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | 13738 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), |
| 13665 | } else Value.zero; | 13739 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), |
| 13740 | else => unreachable, | ||
| 13741 | }; | ||
| 13742 | const zero_val = try sema.splat(resolved_type, scalar_zero); | ||
| 13666 | return sema.addConstant(resolved_type, zero_val); | 13743 | return sema.addConstant(resolved_type, zero_val); |
| 13667 | } | 13744 | } |
| 13668 | } | 13745 | } |
| 13669 | } | 13746 | } |
| 13670 | if (maybe_rhs_val) |rhs_val| { | 13747 | if (maybe_rhs_val) |rhs_val| { |
| 13671 | if (rhs_val.isUndef()) { | 13748 | if (rhs_val.isUndef(mod)) { |
| 13672 | return sema.failWithUseOfUndef(block, rhs_src); | 13749 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13673 | } | 13750 | } |
| 13674 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { | 13751 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { |
| ... | @@ -13676,10 +13753,10 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13676,10 +13753,10 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13676 | } | 13753 | } |
| 13677 | } | 13754 | } |
| 13678 | if (maybe_lhs_val) |lhs_val| { | 13755 | if (maybe_lhs_val) |lhs_val| { |
| 13679 | if (lhs_val.isUndef()) { | 13756 | if (lhs_val.isUndef(mod)) { |
| 13680 | if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { | 13757 | if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) { |
| 13681 | if (maybe_rhs_val) |rhs_val| { | 13758 | if (maybe_rhs_val) |rhs_val| { |
| 13682 | if (try sema.compareAll(rhs_val, .neq, Value.negative_one, resolved_type)) { | 13759 | if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) { |
| 13683 | return sema.addConstUndef(resolved_type); | 13760 | return sema.addConstUndef(resolved_type); |
| 13684 | } | 13761 | } |
| 13685 | } | 13762 | } |
| ... | @@ -13690,10 +13767,10 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -13690,10 +13767,10 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13690 | 13767 | ||
| 13691 | if (maybe_rhs_val) |rhs_val| { | 13768 | if (maybe_rhs_val) |rhs_val| { |
| 13692 | if (is_int) { | 13769 | if (is_int) { |
| 13693 | const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod); | 13770 | var overflow_idx: ?usize = null; |
| 13694 | var vector_index: usize = undefined; | 13771 | const res = try lhs_val.intDiv(rhs_val, resolved_type, &overflow_idx, sema.arena, mod); |
| 13695 | if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) { | 13772 | if (overflow_idx) |vec_idx| { |
| 13696 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index); | 13773 | return sema.failWithIntegerOverflow(block, src, resolved_type, res, vec_idx); |
| 13697 | } | 13774 | } |
| 13698 | return sema.addConstant(resolved_type, res); | 13775 | return sema.addConstant(resolved_type, res); |
| 13699 | } else { | 13776 | } else { |
| ... | @@ -13727,39 +13804,34 @@ fn addDivIntOverflowSafety( | ... | @@ -13727,39 +13804,34 @@ fn addDivIntOverflowSafety( |
| 13727 | casted_rhs: Air.Inst.Ref, | 13804 | casted_rhs: Air.Inst.Ref, |
| 13728 | is_int: bool, | 13805 | is_int: bool, |
| 13729 | ) CompileError!void { | 13806 | ) CompileError!void { |
| 13807 | const mod = sema.mod; | ||
| 13730 | if (!is_int) return; | 13808 | if (!is_int) return; |
| 13731 | 13809 | ||
| 13732 | // If the LHS is unsigned, it cannot cause overflow. | 13810 | // If the LHS is unsigned, it cannot cause overflow. |
| 13733 | if (!lhs_scalar_ty.isSignedInt()) return; | 13811 | if (!lhs_scalar_ty.isSignedInt(mod)) return; |
| 13734 | |||
| 13735 | const mod = sema.mod; | ||
| 13736 | const target = mod.getTarget(); | ||
| 13737 | 13812 | ||
| 13738 | // If the LHS is widened to a larger integer type, no overflow is possible. | 13813 | // If the LHS is widened to a larger integer type, no overflow is possible. |
| 13739 | if (lhs_scalar_ty.intInfo(target).bits < resolved_type.intInfo(target).bits) { | 13814 | if (lhs_scalar_ty.intInfo(mod).bits < resolved_type.intInfo(mod).bits) { |
| 13740 | return; | 13815 | return; |
| 13741 | } | 13816 | } |
| 13742 | 13817 | ||
| 13743 | const min_int = try resolved_type.minInt(sema.arena, target); | 13818 | const min_int = try resolved_type.minInt(mod, resolved_type); |
| 13744 | const neg_one_scalar = try Value.Tag.int_i64.create(sema.arena, -1); | 13819 | const neg_one_scalar = try mod.intValue(lhs_scalar_ty, -1); |
| 13745 | const neg_one = if (resolved_type.zigTypeTag() == .Vector) | 13820 | const neg_one = try sema.splat(resolved_type, neg_one_scalar); |
| 13746 | try Value.Tag.repeated.create(sema.arena, neg_one_scalar) | ||
| 13747 | else | ||
| 13748 | neg_one_scalar; | ||
| 13749 | 13821 | ||
| 13750 | // If the LHS is comptime-known to be not equal to the min int, | 13822 | // If the LHS is comptime-known to be not equal to the min int, |
| 13751 | // no overflow is possible. | 13823 | // no overflow is possible. |
| 13752 | if (maybe_lhs_val) |lhs_val| { | 13824 | if (maybe_lhs_val) |lhs_val| { |
| 13753 | if (lhs_val.compareAll(.neq, min_int, resolved_type, mod)) return; | 13825 | if (try lhs_val.compareAll(.neq, min_int, resolved_type, mod)) return; |
| 13754 | } | 13826 | } |
| 13755 | 13827 | ||
| 13756 | // If the RHS is comptime-known to not be equal to -1, no overflow is possible. | 13828 | // If the RHS is comptime-known to not be equal to -1, no overflow is possible. |
| 13757 | if (maybe_rhs_val) |rhs_val| { | 13829 | if (maybe_rhs_val) |rhs_val| { |
| 13758 | if (rhs_val.compareAll(.neq, neg_one, resolved_type, mod)) return; | 13830 | if (try rhs_val.compareAll(.neq, neg_one, resolved_type, mod)) return; |
| 13759 | } | 13831 | } |
| 13760 | 13832 | ||
| 13761 | var ok: Air.Inst.Ref = .none; | 13833 | var ok: Air.Inst.Ref = .none; |
| 13762 | if (resolved_type.zigTypeTag() == .Vector) { | 13834 | if (resolved_type.zigTypeTag(mod) == .Vector) { |
| 13763 | if (maybe_lhs_val == null) { | 13835 | if (maybe_lhs_val == null) { |
| 13764 | const min_int_ref = try sema.addConstant(resolved_type, min_int); | 13836 | const min_int_ref = try sema.addConstant(resolved_type, min_int); |
| 13765 | ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq); | 13837 | ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq); |
| ... | @@ -13815,8 +13887,13 @@ fn addDivByZeroSafety( | ... | @@ -13815,8 +13887,13 @@ fn addDivByZeroSafety( |
| 13815 | // emitted above. | 13887 | // emitted above. |
| 13816 | if (maybe_rhs_val != null) return; | 13888 | if (maybe_rhs_val != null) return; |
| 13817 | 13889 | ||
| 13818 | const ok = if (resolved_type.zigTypeTag() == .Vector) ok: { | 13890 | const mod = sema.mod; |
| 13819 | const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); | 13891 | const scalar_zero = if (is_int) |
| 13892 | try mod.intValue(resolved_type.scalarType(mod), 0) | ||
| 13893 | else | ||
| 13894 | try mod.floatValue(resolved_type.scalarType(mod), 0.0); | ||
| 13895 | const ok = if (resolved_type.zigTypeTag(mod) == .Vector) ok: { | ||
| 13896 | const zero_val = try sema.splat(resolved_type, scalar_zero); | ||
| 13820 | const zero = try sema.addConstant(resolved_type, zero_val); | 13897 | const zero = try sema.addConstant(resolved_type, zero_val); |
| 13821 | const ok = try block.addCmpVector(casted_rhs, zero, .neq); | 13898 | const ok = try block.addCmpVector(casted_rhs, zero, .neq); |
| 13822 | break :ok try block.addInst(.{ | 13899 | break :ok try block.addInst(.{ |
| ... | @@ -13827,7 +13904,7 @@ fn addDivByZeroSafety( | ... | @@ -13827,7 +13904,7 @@ fn addDivByZeroSafety( |
| 13827 | } }, | 13904 | } }, |
| 13828 | }); | 13905 | }); |
| 13829 | } else ok: { | 13906 | } else ok: { |
| 13830 | const zero = try sema.addConstant(resolved_type, Value.zero); | 13907 | const zero = try sema.addConstant(resolved_type, scalar_zero); |
| 13831 | break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero); | 13908 | break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero); |
| 13832 | }; | 13909 | }; |
| 13833 | try sema.addSafetyCheck(block, ok, .divide_by_zero); | 13910 | try sema.addSafetyCheck(block, ok, .divide_by_zero); |
| ... | @@ -13842,6 +13919,7 @@ fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst | ... | @@ -13842,6 +13919,7 @@ fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst |
| 13842 | } | 13919 | } |
| 13843 | 13920 | ||
| 13844 | fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 13921 | fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 13922 | const mod = sema.mod; | ||
| 13845 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 13923 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 13846 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 13924 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 13847 | sema.src = src; | 13925 | sema.src = src; |
| ... | @@ -13852,8 +13930,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -13852,8 +13930,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13852 | const rhs = try sema.resolveInst(extra.rhs); | 13930 | const rhs = try sema.resolveInst(extra.rhs); |
| 13853 | const lhs_ty = sema.typeOf(lhs); | 13931 | const lhs_ty = sema.typeOf(lhs); |
| 13854 | const rhs_ty = sema.typeOf(rhs); | 13932 | const rhs_ty = sema.typeOf(rhs); |
| 13855 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | 13933 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 13856 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | 13934 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 13857 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 13935 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13858 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 13936 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); |
| 13859 | 13937 | ||
| ... | @@ -13862,20 +13940,19 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -13862,20 +13940,19 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13862 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, | 13940 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13863 | }); | 13941 | }); |
| 13864 | 13942 | ||
| 13865 | const is_vector = resolved_type.zigTypeTag() == .Vector; | 13943 | const is_vector = resolved_type.zigTypeTag(mod) == .Vector; |
| 13866 | 13944 | ||
| 13867 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 13945 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13868 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 13946 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13869 | 13947 | ||
| 13870 | const lhs_scalar_ty = lhs_ty.scalarType(); | 13948 | const lhs_scalar_ty = lhs_ty.scalarType(mod); |
| 13871 | const rhs_scalar_ty = rhs_ty.scalarType(); | 13949 | const rhs_scalar_ty = rhs_ty.scalarType(mod); |
| 13872 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | 13950 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); |
| 13873 | 13951 | ||
| 13874 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | 13952 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 13875 | 13953 | ||
| 13876 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem); | 13954 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem); |
| 13877 | 13955 | ||
| 13878 | const mod = sema.mod; | ||
| 13879 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); | 13956 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 13880 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); | 13957 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); |
| 13881 | 13958 | ||
| ... | @@ -13895,20 +13972,26 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -13895,20 +13972,26 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13895 | // then emit a compile error saying you have to pick one. | 13972 | // then emit a compile error saying you have to pick one. |
| 13896 | if (is_int) { | 13973 | if (is_int) { |
| 13897 | if (maybe_lhs_val) |lhs_val| { | 13974 | if (maybe_lhs_val) |lhs_val| { |
| 13898 | if (lhs_val.isUndef()) { | 13975 | if (lhs_val.isUndef(mod)) { |
| 13899 | return sema.failWithUseOfUndef(block, lhs_src); | 13976 | return sema.failWithUseOfUndef(block, lhs_src); |
| 13900 | } | 13977 | } |
| 13901 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 13978 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 13902 | const zero_val = if (is_vector) b: { | 13979 | const scalar_zero = switch (scalar_tag) { |
| 13903 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | 13980 | .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0), |
| 13904 | } else Value.zero; | 13981 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), |
| 13982 | else => unreachable, | ||
| 13983 | }; | ||
| 13984 | const zero_val = if (is_vector) (try mod.intern(.{ .aggregate = .{ | ||
| 13985 | .ty = resolved_type.toIntern(), | ||
| 13986 | .storage = .{ .repeated_elem = scalar_zero.toIntern() }, | ||
| 13987 | } })).toValue() else scalar_zero; | ||
| 13905 | return sema.addConstant(resolved_type, zero_val); | 13988 | return sema.addConstant(resolved_type, zero_val); |
| 13906 | } | 13989 | } |
| 13907 | } else if (lhs_scalar_ty.isSignedInt()) { | 13990 | } else if (lhs_scalar_ty.isSignedInt(mod)) { |
| 13908 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); | 13991 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); |
| 13909 | } | 13992 | } |
| 13910 | if (maybe_rhs_val) |rhs_val| { | 13993 | if (maybe_rhs_val) |rhs_val| { |
| 13911 | if (rhs_val.isUndef()) { | 13994 | if (rhs_val.isUndef(mod)) { |
| 13912 | return sema.failWithUseOfUndef(block, rhs_src); | 13995 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13913 | } | 13996 | } |
| 13914 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { | 13997 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { |
| ... | @@ -13929,7 +14012,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -13929,7 +14012,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13929 | return sema.addConstant(resolved_type, rem_result); | 14012 | return sema.addConstant(resolved_type, rem_result); |
| 13930 | } | 14013 | } |
| 13931 | break :rs lhs_src; | 14014 | break :rs lhs_src; |
| 13932 | } else if (rhs_scalar_ty.isSignedInt()) { | 14015 | } else if (rhs_scalar_ty.isSignedInt(mod)) { |
| 13933 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); | 14016 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); |
| 13934 | } else { | 14017 | } else { |
| 13935 | break :rs rhs_src; | 14018 | break :rs rhs_src; |
| ... | @@ -13937,7 +14020,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -13937,7 +14020,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13937 | } | 14020 | } |
| 13938 | // float operands | 14021 | // float operands |
| 13939 | if (maybe_rhs_val) |rhs_val| { | 14022 | if (maybe_rhs_val) |rhs_val| { |
| 13940 | if (rhs_val.isUndef()) { | 14023 | if (rhs_val.isUndef(mod)) { |
| 13941 | return sema.failWithUseOfUndef(block, rhs_src); | 14024 | return sema.failWithUseOfUndef(block, rhs_src); |
| 13942 | } | 14025 | } |
| 13943 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { | 14026 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { |
| ... | @@ -13947,7 +14030,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -13947,7 +14030,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13947 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); | 14030 | return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty); |
| 13948 | } | 14031 | } |
| 13949 | if (maybe_lhs_val) |lhs_val| { | 14032 | if (maybe_lhs_val) |lhs_val| { |
| 13950 | if (lhs_val.isUndef() or !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))) { | 14033 | if (lhs_val.isUndef(mod) or !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))) { |
| 13951 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); | 14034 | return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty); |
| 13952 | } | 14035 | } |
| 13953 | return sema.addConstant( | 14036 | return sema.addConstant( |
| ... | @@ -13978,32 +14061,31 @@ fn intRem( | ... | @@ -13978,32 +14061,31 @@ fn intRem( |
| 13978 | lhs: Value, | 14061 | lhs: Value, |
| 13979 | rhs: Value, | 14062 | rhs: Value, |
| 13980 | ) CompileError!Value { | 14063 | ) CompileError!Value { |
| 13981 | if (ty.zigTypeTag() == .Vector) { | 14064 | const mod = sema.mod; |
| 13982 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | 14065 | if (ty.zigTypeTag(mod) == .Vector) { |
| 14066 | const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod)); | ||
| 14067 | const scalar_ty = ty.scalarType(mod); | ||
| 13983 | for (result_data, 0..) |*scalar, i| { | 14068 | for (result_data, 0..) |*scalar, i| { |
| 13984 | var lhs_buf: Value.ElemValueBuffer = undefined; | 14069 | const lhs_elem = try lhs.elemValue(mod, i); |
| 13985 | var rhs_buf: Value.ElemValueBuffer = undefined; | 14070 | const rhs_elem = try rhs.elemValue(mod, i); |
| 13986 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | 14071 | scalar.* = try (try sema.intRemScalar(lhs_elem, rhs_elem, scalar_ty)).intern(scalar_ty, mod); |
| 13987 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | ||
| 13988 | scalar.* = try sema.intRemScalar(lhs_elem, rhs_elem); | ||
| 13989 | } | 14072 | } |
| 13990 | return Value.Tag.aggregate.create(sema.arena, result_data); | 14073 | return (try mod.intern(.{ .aggregate = .{ |
| 14074 | .ty = ty.toIntern(), | ||
| 14075 | .storage = .{ .elems = result_data }, | ||
| 14076 | } })).toValue(); | ||
| 13991 | } | 14077 | } |
| 13992 | return sema.intRemScalar(lhs, rhs); | 14078 | return sema.intRemScalar(lhs, rhs, ty); |
| 13993 | } | 14079 | } |
| 13994 | 14080 | ||
| 13995 | fn intRemScalar( | 14081 | fn intRemScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) CompileError!Value { |
| 13996 | sema: *Sema, | 14082 | const mod = sema.mod; |
| 13997 | lhs: Value, | ||
| 13998 | rhs: Value, | ||
| 13999 | ) CompileError!Value { | ||
| 14000 | const target = sema.mod.getTarget(); | ||
| 14001 | // TODO is this a performance issue? maybe we should try the operation without | 14083 | // TODO is this a performance issue? maybe we should try the operation without |
| 14002 | // resorting to BigInt first. | 14084 | // resorting to BigInt first. |
| 14003 | var lhs_space: Value.BigIntSpace = undefined; | 14085 | var lhs_space: Value.BigIntSpace = undefined; |
| 14004 | var rhs_space: Value.BigIntSpace = undefined; | 14086 | var rhs_space: Value.BigIntSpace = undefined; |
| 14005 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema); | 14087 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); |
| 14006 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema); | 14088 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); |
| 14007 | const limbs_q = try sema.arena.alloc( | 14089 | const limbs_q = try sema.arena.alloc( |
| 14008 | math.big.Limb, | 14090 | math.big.Limb, |
| 14009 | lhs_bigint.limbs.len, | 14091 | lhs_bigint.limbs.len, |
| ... | @@ -14021,10 +14103,11 @@ fn intRemScalar( | ... | @@ -14021,10 +14103,11 @@ fn intRemScalar( |
| 14021 | var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; | 14103 | var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; |
| 14022 | var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; | 14104 | var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; |
| 14023 | result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); | 14105 | result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); |
| 14024 | return Value.fromBigInt(sema.arena, result_r.toConst()); | 14106 | return mod.intValue_big(scalar_ty, result_r.toConst()); |
| 14025 | } | 14107 | } |
| 14026 | 14108 | ||
| 14027 | fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 14109 | fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 14110 | const mod = sema.mod; | ||
| 14028 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 14111 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 14029 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 14112 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 14030 | sema.src = src; | 14113 | sema.src = src; |
| ... | @@ -14035,8 +14118,8 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14035,8 +14118,8 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14035 | const rhs = try sema.resolveInst(extra.rhs); | 14118 | const rhs = try sema.resolveInst(extra.rhs); |
| 14036 | const lhs_ty = sema.typeOf(lhs); | 14119 | const lhs_ty = sema.typeOf(lhs); |
| 14037 | const rhs_ty = sema.typeOf(rhs); | 14120 | const rhs_ty = sema.typeOf(rhs); |
| 14038 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | 14121 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 14039 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | 14122 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 14040 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 14123 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 14041 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 14124 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); |
| 14042 | 14125 | ||
| ... | @@ -14048,13 +14131,12 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14048,13 +14131,12 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14048 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 14131 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 14049 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 14132 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 14050 | 14133 | ||
| 14051 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | 14134 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); |
| 14052 | 14135 | ||
| 14053 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | 14136 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 14054 | 14137 | ||
| 14055 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod); | 14138 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod); |
| 14056 | 14139 | ||
| 14057 | const mod = sema.mod; | ||
| 14058 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); | 14140 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 14059 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); | 14141 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); |
| 14060 | 14142 | ||
| ... | @@ -14072,12 +14154,12 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14072,12 +14154,12 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14072 | // If the lhs is undefined, result is undefined. | 14154 | // If the lhs is undefined, result is undefined. |
| 14073 | if (is_int) { | 14155 | if (is_int) { |
| 14074 | if (maybe_lhs_val) |lhs_val| { | 14156 | if (maybe_lhs_val) |lhs_val| { |
| 14075 | if (lhs_val.isUndef()) { | 14157 | if (lhs_val.isUndef(mod)) { |
| 14076 | return sema.failWithUseOfUndef(block, lhs_src); | 14158 | return sema.failWithUseOfUndef(block, lhs_src); |
| 14077 | } | 14159 | } |
| 14078 | } | 14160 | } |
| 14079 | if (maybe_rhs_val) |rhs_val| { | 14161 | if (maybe_rhs_val) |rhs_val| { |
| 14080 | if (rhs_val.isUndef()) { | 14162 | if (rhs_val.isUndef(mod)) { |
| 14081 | return sema.failWithUseOfUndef(block, rhs_src); | 14163 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14082 | } | 14164 | } |
| 14083 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { | 14165 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { |
| ... | @@ -14096,7 +14178,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14096,7 +14178,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14096 | } | 14178 | } |
| 14097 | // float operands | 14179 | // float operands |
| 14098 | if (maybe_rhs_val) |rhs_val| { | 14180 | if (maybe_rhs_val) |rhs_val| { |
| 14099 | if (rhs_val.isUndef()) { | 14181 | if (rhs_val.isUndef(mod)) { |
| 14100 | return sema.failWithUseOfUndef(block, rhs_src); | 14182 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14101 | } | 14183 | } |
| 14102 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { | 14184 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { |
| ... | @@ -14104,7 +14186,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14104,7 +14186,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14104 | } | 14186 | } |
| 14105 | } | 14187 | } |
| 14106 | if (maybe_lhs_val) |lhs_val| { | 14188 | if (maybe_lhs_val) |lhs_val| { |
| 14107 | if (lhs_val.isUndef()) { | 14189 | if (lhs_val.isUndef(mod)) { |
| 14108 | return sema.addConstUndef(resolved_type); | 14190 | return sema.addConstUndef(resolved_type); |
| 14109 | } | 14191 | } |
| 14110 | if (maybe_rhs_val) |rhs_val| { | 14192 | if (maybe_rhs_val) |rhs_val| { |
| ... | @@ -14127,6 +14209,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14127,6 +14209,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14127 | } | 14209 | } |
| 14128 | 14210 | ||
| 14129 | fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 14211 | fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 14212 | const mod = sema.mod; | ||
| 14130 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 14213 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 14131 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; | 14214 | const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node }; |
| 14132 | sema.src = src; | 14215 | sema.src = src; |
| ... | @@ -14137,8 +14220,8 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14137,8 +14220,8 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14137 | const rhs = try sema.resolveInst(extra.rhs); | 14220 | const rhs = try sema.resolveInst(extra.rhs); |
| 14138 | const lhs_ty = sema.typeOf(lhs); | 14221 | const lhs_ty = sema.typeOf(lhs); |
| 14139 | const rhs_ty = sema.typeOf(rhs); | 14222 | const rhs_ty = sema.typeOf(rhs); |
| 14140 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | 14223 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 14141 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | 14224 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 14142 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 14225 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 14143 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); | 14226 | try sema.checkInvalidPtrArithmetic(block, src, lhs_ty); |
| 14144 | 14227 | ||
| ... | @@ -14150,13 +14233,12 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14150,13 +14233,12 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14150 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 14233 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 14151 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 14234 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 14152 | 14235 | ||
| 14153 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | 14236 | const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod); |
| 14154 | 14237 | ||
| 14155 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | 14238 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 14156 | 14239 | ||
| 14157 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem); | 14240 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem); |
| 14158 | 14241 | ||
| 14159 | const mod = sema.mod; | ||
| 14160 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); | 14242 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 14161 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); | 14243 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); |
| 14162 | 14244 | ||
| ... | @@ -14174,12 +14256,12 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14174,12 +14256,12 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14174 | // If the lhs is undefined, result is undefined. | 14256 | // If the lhs is undefined, result is undefined. |
| 14175 | if (is_int) { | 14257 | if (is_int) { |
| 14176 | if (maybe_lhs_val) |lhs_val| { | 14258 | if (maybe_lhs_val) |lhs_val| { |
| 14177 | if (lhs_val.isUndef()) { | 14259 | if (lhs_val.isUndef(mod)) { |
| 14178 | return sema.failWithUseOfUndef(block, lhs_src); | 14260 | return sema.failWithUseOfUndef(block, lhs_src); |
| 14179 | } | 14261 | } |
| 14180 | } | 14262 | } |
| 14181 | if (maybe_rhs_val) |rhs_val| { | 14263 | if (maybe_rhs_val) |rhs_val| { |
| 14182 | if (rhs_val.isUndef()) { | 14264 | if (rhs_val.isUndef(mod)) { |
| 14183 | return sema.failWithUseOfUndef(block, rhs_src); | 14265 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14184 | } | 14266 | } |
| 14185 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { | 14267 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { |
| ... | @@ -14198,7 +14280,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14198,7 +14280,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14198 | } | 14280 | } |
| 14199 | // float operands | 14281 | // float operands |
| 14200 | if (maybe_rhs_val) |rhs_val| { | 14282 | if (maybe_rhs_val) |rhs_val| { |
| 14201 | if (rhs_val.isUndef()) { | 14283 | if (rhs_val.isUndef(mod)) { |
| 14202 | return sema.failWithUseOfUndef(block, rhs_src); | 14284 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14203 | } | 14285 | } |
| 14204 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { | 14286 | if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) { |
| ... | @@ -14206,7 +14288,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -14206,7 +14288,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14206 | } | 14288 | } |
| 14207 | } | 14289 | } |
| 14208 | if (maybe_lhs_val) |lhs_val| { | 14290 | if (maybe_lhs_val) |lhs_val| { |
| 14209 | if (lhs_val.isUndef()) { | 14291 | if (lhs_val.isUndef(mod)) { |
| 14210 | return sema.addConstUndef(resolved_type); | 14292 | return sema.addConstUndef(resolved_type); |
| 14211 | } | 14293 | } |
| 14212 | if (maybe_rhs_val) |rhs_val| { | 14294 | if (maybe_rhs_val) |rhs_val| { |
| ... | @@ -14268,7 +14350,7 @@ fn zirOverflowArithmetic( | ... | @@ -14268,7 +14350,7 @@ fn zirOverflowArithmetic( |
| 14268 | const lhs = try sema.coerce(block, dest_ty, uncasted_lhs, lhs_src); | 14350 | const lhs = try sema.coerce(block, dest_ty, uncasted_lhs, lhs_src); |
| 14269 | const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src); | 14351 | const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src); |
| 14270 | 14352 | ||
| 14271 | if (dest_ty.scalarType().zigTypeTag() != .Int) { | 14353 | if (dest_ty.scalarType(mod).zigTypeTag(mod) != .Int) { |
| 14272 | return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)}); | 14354 | return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)}); |
| 14273 | } | 14355 | } |
| 14274 | 14356 | ||
| ... | @@ -14276,30 +14358,32 @@ fn zirOverflowArithmetic( | ... | @@ -14276,30 +14358,32 @@ fn zirOverflowArithmetic( |
| 14276 | const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs); | 14358 | const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs); |
| 14277 | 14359 | ||
| 14278 | const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty); | 14360 | const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty); |
| 14361 | const overflow_ty = mod.intern_pool.indexToKey(tuple_ty.toIntern()).anon_struct_type.types[1].toType(); | ||
| 14279 | 14362 | ||
| 14280 | var result: struct { | 14363 | var result: struct { |
| 14281 | inst: Air.Inst.Ref = .none, | 14364 | inst: Air.Inst.Ref = .none, |
| 14282 | wrapped: Value = Value.initTag(.unreachable_value), | 14365 | wrapped: Value = Value.@"unreachable", |
| 14283 | overflow_bit: Value, | 14366 | overflow_bit: Value, |
| 14284 | } = result: { | 14367 | } = result: { |
| 14368 | const zero_bit = try mod.intValue(Type.u1, 0); | ||
| 14285 | switch (zir_tag) { | 14369 | switch (zir_tag) { |
| 14286 | .add_with_overflow => { | 14370 | .add_with_overflow => { |
| 14287 | // If either of the arguments is zero, `false` is returned and the other is stored | 14371 | // If either of the arguments is zero, `false` is returned and the other is stored |
| 14288 | // to the result, even if it is undefined.. | 14372 | // to the result, even if it is undefined.. |
| 14289 | // Otherwise, if either of the argument is undefined, undefined is returned. | 14373 | // Otherwise, if either of the argument is undefined, undefined is returned. |
| 14290 | if (maybe_lhs_val) |lhs_val| { | 14374 | if (maybe_lhs_val) |lhs_val| { |
| 14291 | if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | 14375 | if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14292 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs }; | 14376 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; |
| 14293 | } | 14377 | } |
| 14294 | } | 14378 | } |
| 14295 | if (maybe_rhs_val) |rhs_val| { | 14379 | if (maybe_rhs_val) |rhs_val| { |
| 14296 | if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | 14380 | if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14297 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | 14381 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; |
| 14298 | } | 14382 | } |
| 14299 | } | 14383 | } |
| 14300 | if (maybe_lhs_val) |lhs_val| { | 14384 | if (maybe_lhs_val) |lhs_val| { |
| 14301 | if (maybe_rhs_val) |rhs_val| { | 14385 | if (maybe_rhs_val) |rhs_val| { |
| 14302 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | 14386 | if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) { |
| 14303 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; | 14387 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| 14304 | } | 14388 | } |
| 14305 | 14389 | ||
| ... | @@ -14312,12 +14396,12 @@ fn zirOverflowArithmetic( | ... | @@ -14312,12 +14396,12 @@ fn zirOverflowArithmetic( |
| 14312 | // If the rhs is zero, then the result is lhs and no overflow occured. | 14396 | // If the rhs is zero, then the result is lhs and no overflow occured. |
| 14313 | // Otherwise, if either result is undefined, both results are undefined. | 14397 | // Otherwise, if either result is undefined, both results are undefined. |
| 14314 | if (maybe_rhs_val) |rhs_val| { | 14398 | if (maybe_rhs_val) |rhs_val| { |
| 14315 | if (rhs_val.isUndef()) { | 14399 | if (rhs_val.isUndef(mod)) { |
| 14316 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; | 14400 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| 14317 | } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14401 | } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14318 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | 14402 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; |
| 14319 | } else if (maybe_lhs_val) |lhs_val| { | 14403 | } else if (maybe_lhs_val) |lhs_val| { |
| 14320 | if (lhs_val.isUndef()) { | 14404 | if (lhs_val.isUndef(mod)) { |
| 14321 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; | 14405 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| 14322 | } | 14406 | } |
| 14323 | 14407 | ||
| ... | @@ -14330,29 +14414,30 @@ fn zirOverflowArithmetic( | ... | @@ -14330,29 +14414,30 @@ fn zirOverflowArithmetic( |
| 14330 | // If either of the arguments is zero, the result is zero and no overflow occured. | 14414 | // If either of the arguments is zero, the result is zero and no overflow occured. |
| 14331 | // If either of the arguments is one, the result is the other and no overflow occured. | 14415 | // If either of the arguments is one, the result is the other and no overflow occured. |
| 14332 | // Otherwise, if either of the arguments is undefined, both results are undefined. | 14416 | // Otherwise, if either of the arguments is undefined, both results are undefined. |
| 14417 | const scalar_one = try mod.intValue(dest_ty.scalarType(mod), 1); | ||
| 14333 | if (maybe_lhs_val) |lhs_val| { | 14418 | if (maybe_lhs_val) |lhs_val| { |
| 14334 | if (!lhs_val.isUndef()) { | 14419 | if (!lhs_val.isUndef(mod)) { |
| 14335 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14420 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14336 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | 14421 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; |
| 14337 | } else if (try sema.compareAll(lhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) { | 14422 | } else if (try sema.compareAll(lhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) { |
| 14338 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs }; | 14423 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; |
| 14339 | } | 14424 | } |
| 14340 | } | 14425 | } |
| 14341 | } | 14426 | } |
| 14342 | 14427 | ||
| 14343 | if (maybe_rhs_val) |rhs_val| { | 14428 | if (maybe_rhs_val) |rhs_val| { |
| 14344 | if (!rhs_val.isUndef()) { | 14429 | if (!rhs_val.isUndef(mod)) { |
| 14345 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14430 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14346 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs }; | 14431 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs }; |
| 14347 | } else if (try sema.compareAll(rhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) { | 14432 | } else if (try sema.compareAll(rhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) { |
| 14348 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | 14433 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; |
| 14349 | } | 14434 | } |
| 14350 | } | 14435 | } |
| 14351 | } | 14436 | } |
| 14352 | 14437 | ||
| 14353 | if (maybe_lhs_val) |lhs_val| { | 14438 | if (maybe_lhs_val) |lhs_val| { |
| 14354 | if (maybe_rhs_val) |rhs_val| { | 14439 | if (maybe_rhs_val) |rhs_val| { |
| 14355 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | 14440 | if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) { |
| 14356 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; | 14441 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| 14357 | } | 14442 | } |
| 14358 | 14443 | ||
| ... | @@ -14366,22 +14451,22 @@ fn zirOverflowArithmetic( | ... | @@ -14366,22 +14451,22 @@ fn zirOverflowArithmetic( |
| 14366 | // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred. | 14451 | // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred. |
| 14367 | // Oterhwise if either of the arguments is undefined, both results are undefined. | 14452 | // Oterhwise if either of the arguments is undefined, both results are undefined. |
| 14368 | if (maybe_lhs_val) |lhs_val| { | 14453 | if (maybe_lhs_val) |lhs_val| { |
| 14369 | if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | 14454 | if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14370 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | 14455 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; |
| 14371 | } | 14456 | } |
| 14372 | } | 14457 | } |
| 14373 | if (maybe_rhs_val) |rhs_val| { | 14458 | if (maybe_rhs_val) |rhs_val| { |
| 14374 | if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | 14459 | if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14375 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs }; | 14460 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs }; |
| 14376 | } | 14461 | } |
| 14377 | } | 14462 | } |
| 14378 | if (maybe_lhs_val) |lhs_val| { | 14463 | if (maybe_lhs_val) |lhs_val| { |
| 14379 | if (maybe_rhs_val) |rhs_val| { | 14464 | if (maybe_rhs_val) |rhs_val| { |
| 14380 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | 14465 | if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) { |
| 14381 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; | 14466 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| 14382 | } | 14467 | } |
| 14383 | 14468 | ||
| 14384 | const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, sema.mod); | 14469 | const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, mod); |
| 14385 | break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; | 14470 | break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result }; |
| 14386 | } | 14471 | } |
| 14387 | } | 14472 | } |
| ... | @@ -14420,40 +14505,46 @@ fn zirOverflowArithmetic( | ... | @@ -14420,40 +14505,46 @@ fn zirOverflowArithmetic( |
| 14420 | } | 14505 | } |
| 14421 | 14506 | ||
| 14422 | if (result.inst == .none) { | 14507 | if (result.inst == .none) { |
| 14423 | const values = try sema.arena.alloc(Value, 2); | 14508 | return sema.addConstant(tuple_ty, (try mod.intern(.{ .aggregate = .{ |
| 14424 | values[0] = result.wrapped; | 14509 | .ty = tuple_ty.toIntern(), |
| 14425 | values[1] = result.overflow_bit; | 14510 | .storage = .{ .elems = &.{ |
| 14426 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | 14511 | result.wrapped.toIntern(), |
| 14427 | return sema.addConstant(tuple_ty, tuple_val); | 14512 | result.overflow_bit.toIntern(), |
| 14513 | } }, | ||
| 14514 | } })).toValue()); | ||
| 14428 | } | 14515 | } |
| 14429 | 14516 | ||
| 14430 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, 2); | 14517 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, 2); |
| 14431 | element_refs[0] = result.inst; | 14518 | element_refs[0] = result.inst; |
| 14432 | element_refs[1] = try sema.addConstant(tuple_ty.structFieldType(1), result.overflow_bit); | 14519 | element_refs[1] = try sema.addConstant(tuple_ty.structFieldType(1, mod), result.overflow_bit); |
| 14433 | return block.addAggregateInit(tuple_ty, element_refs); | 14520 | return block.addAggregateInit(tuple_ty, element_refs); |
| 14434 | } | 14521 | } |
| 14435 | 14522 | ||
| 14436 | fn maybeRepeated(sema: *Sema, ty: Type, val: Value) !Value { | 14523 | fn splat(sema: *Sema, ty: Type, val: Value) !Value { |
| 14437 | if (ty.zigTypeTag() != .Vector) return val; | 14524 | const mod = sema.mod; |
| 14438 | return Value.Tag.repeated.create(sema.arena, val); | 14525 | if (ty.zigTypeTag(mod) != .Vector) return val; |
| 14526 | const repeated = try mod.intern(.{ .aggregate = .{ | ||
| 14527 | .ty = ty.toIntern(), | ||
| 14528 | .storage = .{ .repeated_elem = val.toIntern() }, | ||
| 14529 | } }); | ||
| 14530 | return repeated.toValue(); | ||
| 14439 | } | 14531 | } |
| 14440 | 14532 | ||
| 14441 | fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type { | 14533 | fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type { |
| 14442 | const ov_ty = if (ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, ty.vectorLen(), Type.u1) else Type.u1; | 14534 | const mod = sema.mod; |
| 14443 | 14535 | const ov_ty = if (ty.zigTypeTag(mod) == .Vector) try mod.vectorType(.{ | |
| 14444 | const types = try sema.arena.alloc(Type, 2); | 14536 | .len = ty.vectorLen(mod), |
| 14445 | const values = try sema.arena.alloc(Value, 2); | 14537 | .child = .u1_type, |
| 14446 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ | 14538 | }) else Type.u1; |
| 14447 | .types = types, | ||
| 14448 | .values = values, | ||
| 14449 | }); | ||
| 14450 | |||
| 14451 | types[0] = ty; | ||
| 14452 | types[1] = ov_ty; | ||
| 14453 | values[0] = Value.initTag(.unreachable_value); | ||
| 14454 | values[1] = Value.initTag(.unreachable_value); | ||
| 14455 | 14539 | ||
| 14456 | return tuple_ty; | 14540 | const types = [2]InternPool.Index{ ty.toIntern(), ov_ty.toIntern() }; |
| 14541 | const values = [2]InternPool.Index{ .none, .none }; | ||
| 14542 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ | ||
| 14543 | .types = &types, | ||
| 14544 | .values = &values, | ||
| 14545 | .names = &.{}, | ||
| 14546 | } }); | ||
| 14547 | return tuple_ty.toType(); | ||
| 14457 | } | 14548 | } |
| 14458 | 14549 | ||
| 14459 | fn analyzeArithmetic( | 14550 | fn analyzeArithmetic( |
| ... | @@ -14468,13 +14559,14 @@ fn analyzeArithmetic( | ... | @@ -14468,13 +14559,14 @@ fn analyzeArithmetic( |
| 14468 | rhs_src: LazySrcLoc, | 14559 | rhs_src: LazySrcLoc, |
| 14469 | want_safety: bool, | 14560 | want_safety: bool, |
| 14470 | ) CompileError!Air.Inst.Ref { | 14561 | ) CompileError!Air.Inst.Ref { |
| 14562 | const mod = sema.mod; | ||
| 14471 | const lhs_ty = sema.typeOf(lhs); | 14563 | const lhs_ty = sema.typeOf(lhs); |
| 14472 | const rhs_ty = sema.typeOf(rhs); | 14564 | const rhs_ty = sema.typeOf(rhs); |
| 14473 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | 14565 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 14474 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | 14566 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); |
| 14475 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 14567 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 14476 | 14568 | ||
| 14477 | if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize()) { | 14569 | if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize(mod)) { |
| 14478 | .One, .Slice => {}, | 14570 | .One, .Slice => {}, |
| 14479 | .Many, .C => { | 14571 | .Many, .C => { |
| 14480 | const air_tag: Air.Inst.Tag = switch (zir_tag) { | 14572 | const air_tag: Air.Inst.Tag = switch (zir_tag) { |
| ... | @@ -14491,18 +14583,16 @@ fn analyzeArithmetic( | ... | @@ -14491,18 +14583,16 @@ fn analyzeArithmetic( |
| 14491 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, | 14583 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 14492 | }); | 14584 | }); |
| 14493 | 14585 | ||
| 14494 | const is_vector = resolved_type.zigTypeTag() == .Vector; | ||
| 14495 | |||
| 14496 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 14586 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 14497 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | 14587 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 14498 | 14588 | ||
| 14499 | const scalar_tag = resolved_type.scalarType().zigTypeTag(); | 14589 | const scalar_type = resolved_type.scalarType(mod); |
| 14590 | const scalar_tag = scalar_type.zigTypeTag(mod); | ||
| 14500 | 14591 | ||
| 14501 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; | 14592 | const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt; |
| 14502 | 14593 | ||
| 14503 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, zir_tag); | 14594 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, zir_tag); |
| 14504 | 14595 | ||
| 14505 | const mod = sema.mod; | ||
| 14506 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); | 14596 | const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs); |
| 14507 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); | 14597 | const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); |
| 14508 | const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: { | 14598 | const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: { |
| ... | @@ -14516,12 +14606,12 @@ fn analyzeArithmetic( | ... | @@ -14516,12 +14606,12 @@ fn analyzeArithmetic( |
| 14516 | // overflow (max_int), causing illegal behavior. | 14606 | // overflow (max_int), causing illegal behavior. |
| 14517 | // For floats: either operand being undef makes the result undef. | 14607 | // For floats: either operand being undef makes the result undef. |
| 14518 | if (maybe_lhs_val) |lhs_val| { | 14608 | if (maybe_lhs_val) |lhs_val| { |
| 14519 | if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | 14609 | if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14520 | return casted_rhs; | 14610 | return casted_rhs; |
| 14521 | } | 14611 | } |
| 14522 | } | 14612 | } |
| 14523 | if (maybe_rhs_val) |rhs_val| { | 14613 | if (maybe_rhs_val) |rhs_val| { |
| 14524 | if (rhs_val.isUndef()) { | 14614 | if (rhs_val.isUndef(mod)) { |
| 14525 | if (is_int) { | 14615 | if (is_int) { |
| 14526 | return sema.failWithUseOfUndef(block, rhs_src); | 14616 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14527 | } else { | 14617 | } else { |
| ... | @@ -14534,7 +14624,7 @@ fn analyzeArithmetic( | ... | @@ -14534,7 +14624,7 @@ fn analyzeArithmetic( |
| 14534 | } | 14624 | } |
| 14535 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add; | 14625 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add; |
| 14536 | if (maybe_lhs_val) |lhs_val| { | 14626 | if (maybe_lhs_val) |lhs_val| { |
| 14537 | if (lhs_val.isUndef()) { | 14627 | if (lhs_val.isUndef(mod)) { |
| 14538 | if (is_int) { | 14628 | if (is_int) { |
| 14539 | return sema.failWithUseOfUndef(block, lhs_src); | 14629 | return sema.failWithUseOfUndef(block, lhs_src); |
| 14540 | } else { | 14630 | } else { |
| ... | @@ -14543,16 +14633,16 @@ fn analyzeArithmetic( | ... | @@ -14543,16 +14633,16 @@ fn analyzeArithmetic( |
| 14543 | } | 14633 | } |
| 14544 | if (maybe_rhs_val) |rhs_val| { | 14634 | if (maybe_rhs_val) |rhs_val| { |
| 14545 | if (is_int) { | 14635 | if (is_int) { |
| 14546 | const sum = try sema.intAdd(lhs_val, rhs_val, resolved_type); | 14636 | var overflow_idx: ?usize = null; |
| 14547 | var vector_index: usize = undefined; | 14637 | const sum = try sema.intAdd(lhs_val, rhs_val, resolved_type, &overflow_idx); |
| 14548 | if (!(try sema.intFitsInType(sum, resolved_type, &vector_index))) { | 14638 | if (overflow_idx) |vec_idx| { |
| 14549 | return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vector_index); | 14639 | return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vec_idx); |
| 14550 | } | 14640 | } |
| 14551 | return sema.addConstant(resolved_type, sum); | 14641 | return sema.addConstant(resolved_type, sum); |
| 14552 | } else { | 14642 | } else { |
| 14553 | return sema.addConstant( | 14643 | return sema.addConstant( |
| 14554 | resolved_type, | 14644 | resolved_type, |
| 14555 | try sema.floatAdd(lhs_val, rhs_val, resolved_type), | 14645 | try Value.floatAdd(lhs_val, rhs_val, resolved_type, sema.arena, mod), |
| 14556 | ); | 14646 | ); |
| 14557 | } | 14647 | } |
| 14558 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | 14648 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; |
| ... | @@ -14563,13 +14653,13 @@ fn analyzeArithmetic( | ... | @@ -14563,13 +14653,13 @@ fn analyzeArithmetic( |
| 14563 | // If either of the operands are zero, the other operand is returned. | 14653 | // If either of the operands are zero, the other operand is returned. |
| 14564 | // If either of the operands are undefined, the result is undefined. | 14654 | // If either of the operands are undefined, the result is undefined. |
| 14565 | if (maybe_lhs_val) |lhs_val| { | 14655 | if (maybe_lhs_val) |lhs_val| { |
| 14566 | if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | 14656 | if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14567 | return casted_rhs; | 14657 | return casted_rhs; |
| 14568 | } | 14658 | } |
| 14569 | } | 14659 | } |
| 14570 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap; | 14660 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap; |
| 14571 | if (maybe_rhs_val) |rhs_val| { | 14661 | if (maybe_rhs_val) |rhs_val| { |
| 14572 | if (rhs_val.isUndef()) { | 14662 | if (rhs_val.isUndef(mod)) { |
| 14573 | return sema.addConstUndef(resolved_type); | 14663 | return sema.addConstUndef(resolved_type); |
| 14574 | } | 14664 | } |
| 14575 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14665 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| ... | @@ -14588,12 +14678,12 @@ fn analyzeArithmetic( | ... | @@ -14588,12 +14678,12 @@ fn analyzeArithmetic( |
| 14588 | // If either of the operands are zero, then the other operand is returned. | 14678 | // If either of the operands are zero, then the other operand is returned. |
| 14589 | // If either of the operands are undefined, the result is undefined. | 14679 | // If either of the operands are undefined, the result is undefined. |
| 14590 | if (maybe_lhs_val) |lhs_val| { | 14680 | if (maybe_lhs_val) |lhs_val| { |
| 14591 | if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { | 14681 | if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14592 | return casted_rhs; | 14682 | return casted_rhs; |
| 14593 | } | 14683 | } |
| 14594 | } | 14684 | } |
| 14595 | if (maybe_rhs_val) |rhs_val| { | 14685 | if (maybe_rhs_val) |rhs_val| { |
| 14596 | if (rhs_val.isUndef()) { | 14686 | if (rhs_val.isUndef(mod)) { |
| 14597 | return sema.addConstUndef(resolved_type); | 14687 | return sema.addConstUndef(resolved_type); |
| 14598 | } | 14688 | } |
| 14599 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14689 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| ... | @@ -14601,7 +14691,7 @@ fn analyzeArithmetic( | ... | @@ -14601,7 +14691,7 @@ fn analyzeArithmetic( |
| 14601 | } | 14691 | } |
| 14602 | if (maybe_lhs_val) |lhs_val| { | 14692 | if (maybe_lhs_val) |lhs_val| { |
| 14603 | const val = if (scalar_tag == .ComptimeInt) | 14693 | const val = if (scalar_tag == .ComptimeInt) |
| 14604 | try sema.intAdd(lhs_val, rhs_val, resolved_type) | 14694 | try sema.intAdd(lhs_val, rhs_val, resolved_type, undefined) |
| 14605 | else | 14695 | else |
| 14606 | try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, mod); | 14696 | try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, mod); |
| 14607 | 14697 | ||
| ... | @@ -14618,7 +14708,7 @@ fn analyzeArithmetic( | ... | @@ -14618,7 +14708,7 @@ fn analyzeArithmetic( |
| 14618 | // overflow, causing illegal behavior. | 14708 | // overflow, causing illegal behavior. |
| 14619 | // For floats: either operand being undef makes the result undef. | 14709 | // For floats: either operand being undef makes the result undef. |
| 14620 | if (maybe_rhs_val) |rhs_val| { | 14710 | if (maybe_rhs_val) |rhs_val| { |
| 14621 | if (rhs_val.isUndef()) { | 14711 | if (rhs_val.isUndef(mod)) { |
| 14622 | if (is_int) { | 14712 | if (is_int) { |
| 14623 | return sema.failWithUseOfUndef(block, rhs_src); | 14713 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14624 | } else { | 14714 | } else { |
| ... | @@ -14631,7 +14721,7 @@ fn analyzeArithmetic( | ... | @@ -14631,7 +14721,7 @@ fn analyzeArithmetic( |
| 14631 | } | 14721 | } |
| 14632 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub; | 14722 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub; |
| 14633 | if (maybe_lhs_val) |lhs_val| { | 14723 | if (maybe_lhs_val) |lhs_val| { |
| 14634 | if (lhs_val.isUndef()) { | 14724 | if (lhs_val.isUndef(mod)) { |
| 14635 | if (is_int) { | 14725 | if (is_int) { |
| 14636 | return sema.failWithUseOfUndef(block, lhs_src); | 14726 | return sema.failWithUseOfUndef(block, lhs_src); |
| 14637 | } else { | 14727 | } else { |
| ... | @@ -14640,16 +14730,16 @@ fn analyzeArithmetic( | ... | @@ -14640,16 +14730,16 @@ fn analyzeArithmetic( |
| 14640 | } | 14730 | } |
| 14641 | if (maybe_rhs_val) |rhs_val| { | 14731 | if (maybe_rhs_val) |rhs_val| { |
| 14642 | if (is_int) { | 14732 | if (is_int) { |
| 14643 | const diff = try sema.intSub(lhs_val, rhs_val, resolved_type); | 14733 | var overflow_idx: ?usize = null; |
| 14644 | var vector_index: usize = undefined; | 14734 | const diff = try sema.intSub(lhs_val, rhs_val, resolved_type, &overflow_idx); |
| 14645 | if (!(try sema.intFitsInType(diff, resolved_type, &vector_index))) { | 14735 | if (overflow_idx) |vec_idx| { |
| 14646 | return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vector_index); | 14736 | return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vec_idx); |
| 14647 | } | 14737 | } |
| 14648 | return sema.addConstant(resolved_type, diff); | 14738 | return sema.addConstant(resolved_type, diff); |
| 14649 | } else { | 14739 | } else { |
| 14650 | return sema.addConstant( | 14740 | return sema.addConstant( |
| 14651 | resolved_type, | 14741 | resolved_type, |
| 14652 | try sema.floatSub(lhs_val, rhs_val, resolved_type), | 14742 | try Value.floatSub(lhs_val, rhs_val, resolved_type, sema.arena, mod), |
| 14653 | ); | 14743 | ); |
| 14654 | } | 14744 | } |
| 14655 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | 14745 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; |
| ... | @@ -14660,7 +14750,7 @@ fn analyzeArithmetic( | ... | @@ -14660,7 +14750,7 @@ fn analyzeArithmetic( |
| 14660 | // If the RHS is zero, then the other operand is returned, even if it is undefined. | 14750 | // If the RHS is zero, then the other operand is returned, even if it is undefined. |
| 14661 | // If either of the operands are undefined, the result is undefined. | 14751 | // If either of the operands are undefined, the result is undefined. |
| 14662 | if (maybe_rhs_val) |rhs_val| { | 14752 | if (maybe_rhs_val) |rhs_val| { |
| 14663 | if (rhs_val.isUndef()) { | 14753 | if (rhs_val.isUndef(mod)) { |
| 14664 | return sema.addConstUndef(resolved_type); | 14754 | return sema.addConstUndef(resolved_type); |
| 14665 | } | 14755 | } |
| 14666 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14756 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| ... | @@ -14669,7 +14759,7 @@ fn analyzeArithmetic( | ... | @@ -14669,7 +14759,7 @@ fn analyzeArithmetic( |
| 14669 | } | 14759 | } |
| 14670 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap; | 14760 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap; |
| 14671 | if (maybe_lhs_val) |lhs_val| { | 14761 | if (maybe_lhs_val) |lhs_val| { |
| 14672 | if (lhs_val.isUndef()) { | 14762 | if (lhs_val.isUndef(mod)) { |
| 14673 | return sema.addConstUndef(resolved_type); | 14763 | return sema.addConstUndef(resolved_type); |
| 14674 | } | 14764 | } |
| 14675 | if (maybe_rhs_val) |rhs_val| { | 14765 | if (maybe_rhs_val) |rhs_val| { |
| ... | @@ -14685,7 +14775,7 @@ fn analyzeArithmetic( | ... | @@ -14685,7 +14775,7 @@ fn analyzeArithmetic( |
| 14685 | // If the RHS is zero, result is LHS. | 14775 | // If the RHS is zero, result is LHS. |
| 14686 | // If either of the operands are undefined, result is undefined. | 14776 | // If either of the operands are undefined, result is undefined. |
| 14687 | if (maybe_rhs_val) |rhs_val| { | 14777 | if (maybe_rhs_val) |rhs_val| { |
| 14688 | if (rhs_val.isUndef()) { | 14778 | if (rhs_val.isUndef(mod)) { |
| 14689 | return sema.addConstUndef(resolved_type); | 14779 | return sema.addConstUndef(resolved_type); |
| 14690 | } | 14780 | } |
| 14691 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14781 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| ... | @@ -14693,12 +14783,12 @@ fn analyzeArithmetic( | ... | @@ -14693,12 +14783,12 @@ fn analyzeArithmetic( |
| 14693 | } | 14783 | } |
| 14694 | } | 14784 | } |
| 14695 | if (maybe_lhs_val) |lhs_val| { | 14785 | if (maybe_lhs_val) |lhs_val| { |
| 14696 | if (lhs_val.isUndef()) { | 14786 | if (lhs_val.isUndef(mod)) { |
| 14697 | return sema.addConstUndef(resolved_type); | 14787 | return sema.addConstUndef(resolved_type); |
| 14698 | } | 14788 | } |
| 14699 | if (maybe_rhs_val) |rhs_val| { | 14789 | if (maybe_rhs_val) |rhs_val| { |
| 14700 | const val = if (scalar_tag == .ComptimeInt) | 14790 | const val = if (scalar_tag == .ComptimeInt) |
| 14701 | try sema.intSub(lhs_val, rhs_val, resolved_type) | 14791 | try sema.intSub(lhs_val, rhs_val, resolved_type, undefined) |
| 14702 | else | 14792 | else |
| 14703 | try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, mod); | 14793 | try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, mod); |
| 14704 | 14794 | ||
| ... | @@ -14718,62 +14808,74 @@ fn analyzeArithmetic( | ... | @@ -14718,62 +14808,74 @@ fn analyzeArithmetic( |
| 14718 | // If either of the operands are inf, and the other operand is zero, | 14808 | // If either of the operands are inf, and the other operand is zero, |
| 14719 | // the result is nan. | 14809 | // the result is nan. |
| 14720 | // If either of the operands are nan, the result is nan. | 14810 | // If either of the operands are nan, the result is nan. |
| 14811 | const scalar_zero = switch (scalar_tag) { | ||
| 14812 | .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0), | ||
| 14813 | .ComptimeInt, .Int => try mod.intValue(scalar_type, 0), | ||
| 14814 | else => unreachable, | ||
| 14815 | }; | ||
| 14816 | const scalar_one = switch (scalar_tag) { | ||
| 14817 | .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0), | ||
| 14818 | .ComptimeInt, .Int => try mod.intValue(scalar_type, 1), | ||
| 14819 | else => unreachable, | ||
| 14820 | }; | ||
| 14721 | if (maybe_lhs_val) |lhs_val| { | 14821 | if (maybe_lhs_val) |lhs_val| { |
| 14722 | if (!lhs_val.isUndef()) { | 14822 | if (!lhs_val.isUndef(mod)) { |
| 14723 | if (lhs_val.isNan()) { | 14823 | if (lhs_val.isNan(mod)) { |
| 14724 | return sema.addConstant(resolved_type, lhs_val); | 14824 | return sema.addConstant(resolved_type, lhs_val); |
| 14725 | } | 14825 | } |
| 14726 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) lz: { | 14826 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) lz: { |
| 14727 | if (maybe_rhs_val) |rhs_val| { | 14827 | if (maybe_rhs_val) |rhs_val| { |
| 14728 | if (rhs_val.isNan()) { | 14828 | if (rhs_val.isNan(mod)) { |
| 14729 | return sema.addConstant(resolved_type, rhs_val); | 14829 | return sema.addConstant(resolved_type, rhs_val); |
| 14730 | } | 14830 | } |
| 14731 | if (rhs_val.isInf()) { | 14831 | if (rhs_val.isInf(mod)) { |
| 14732 | return sema.addConstant(resolved_type, try Value.Tag.float_32.create(sema.arena, std.math.nan_f32)); | 14832 | return sema.addConstant( |
| 14833 | resolved_type, | ||
| 14834 | try mod.floatValue(resolved_type, std.math.nan_f128), | ||
| 14835 | ); | ||
| 14733 | } | 14836 | } |
| 14734 | } else if (resolved_type.isAnyFloat()) { | 14837 | } else if (resolved_type.isAnyFloat()) { |
| 14735 | break :lz; | 14838 | break :lz; |
| 14736 | } | 14839 | } |
| 14737 | const zero_val = if (is_vector) b: { | 14840 | const zero_val = try sema.splat(resolved_type, scalar_zero); |
| 14738 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | ||
| 14739 | } else Value.zero; | ||
| 14740 | return sema.addConstant(resolved_type, zero_val); | 14841 | return sema.addConstant(resolved_type, zero_val); |
| 14741 | } | 14842 | } |
| 14742 | if (try sema.compareAll(lhs_val, .eq, Value.one, resolved_type)) { | 14843 | if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { |
| 14743 | return casted_rhs; | 14844 | return casted_rhs; |
| 14744 | } | 14845 | } |
| 14745 | } | 14846 | } |
| 14746 | } | 14847 | } |
| 14747 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul; | 14848 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul; |
| 14748 | if (maybe_rhs_val) |rhs_val| { | 14849 | if (maybe_rhs_val) |rhs_val| { |
| 14749 | if (rhs_val.isUndef()) { | 14850 | if (rhs_val.isUndef(mod)) { |
| 14750 | if (is_int) { | 14851 | if (is_int) { |
| 14751 | return sema.failWithUseOfUndef(block, rhs_src); | 14852 | return sema.failWithUseOfUndef(block, rhs_src); |
| 14752 | } else { | 14853 | } else { |
| 14753 | return sema.addConstUndef(resolved_type); | 14854 | return sema.addConstUndef(resolved_type); |
| 14754 | } | 14855 | } |
| 14755 | } | 14856 | } |
| 14756 | if (rhs_val.isNan()) { | 14857 | if (rhs_val.isNan(mod)) { |
| 14757 | return sema.addConstant(resolved_type, rhs_val); | 14858 | return sema.addConstant(resolved_type, rhs_val); |
| 14758 | } | 14859 | } |
| 14759 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) rz: { | 14860 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) rz: { |
| 14760 | if (maybe_lhs_val) |lhs_val| { | 14861 | if (maybe_lhs_val) |lhs_val| { |
| 14761 | if (lhs_val.isInf()) { | 14862 | if (lhs_val.isInf(mod)) { |
| 14762 | return sema.addConstant(resolved_type, try Value.Tag.float_32.create(sema.arena, std.math.nan_f32)); | 14863 | return sema.addConstant( |
| 14864 | resolved_type, | ||
| 14865 | try mod.floatValue(resolved_type, std.math.nan_f128), | ||
| 14866 | ); | ||
| 14763 | } | 14867 | } |
| 14764 | } else if (resolved_type.isAnyFloat()) { | 14868 | } else if (resolved_type.isAnyFloat()) { |
| 14765 | break :rz; | 14869 | break :rz; |
| 14766 | } | 14870 | } |
| 14767 | const zero_val = if (is_vector) b: { | 14871 | const zero_val = try sema.splat(resolved_type, scalar_zero); |
| 14768 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | ||
| 14769 | } else Value.zero; | ||
| 14770 | return sema.addConstant(resolved_type, zero_val); | 14872 | return sema.addConstant(resolved_type, zero_val); |
| 14771 | } | 14873 | } |
| 14772 | if (try sema.compareAll(rhs_val, .eq, Value.one, resolved_type)) { | 14874 | if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { |
| 14773 | return casted_lhs; | 14875 | return casted_lhs; |
| 14774 | } | 14876 | } |
| 14775 | if (maybe_lhs_val) |lhs_val| { | 14877 | if (maybe_lhs_val) |lhs_val| { |
| 14776 | if (lhs_val.isUndef()) { | 14878 | if (lhs_val.isUndef(mod)) { |
| 14777 | if (is_int) { | 14879 | if (is_int) { |
| 14778 | return sema.failWithUseOfUndef(block, lhs_src); | 14880 | return sema.failWithUseOfUndef(block, lhs_src); |
| 14779 | } else { | 14881 | } else { |
| ... | @@ -14781,16 +14883,16 @@ fn analyzeArithmetic( | ... | @@ -14781,16 +14883,16 @@ fn analyzeArithmetic( |
| 14781 | } | 14883 | } |
| 14782 | } | 14884 | } |
| 14783 | if (is_int) { | 14885 | if (is_int) { |
| 14784 | const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, sema.mod); | 14886 | var overflow_idx: ?usize = null; |
| 14785 | var vector_index: usize = undefined; | 14887 | const product = try lhs_val.intMul(rhs_val, resolved_type, &overflow_idx, sema.arena, mod); |
| 14786 | if (!(try sema.intFitsInType(product, resolved_type, &vector_index))) { | 14888 | if (overflow_idx) |vec_idx| { |
| 14787 | return sema.failWithIntegerOverflow(block, src, resolved_type, product, vector_index); | 14889 | return sema.failWithIntegerOverflow(block, src, resolved_type, product, vec_idx); |
| 14788 | } | 14890 | } |
| 14789 | return sema.addConstant(resolved_type, product); | 14891 | return sema.addConstant(resolved_type, product); |
| 14790 | } else { | 14892 | } else { |
| 14791 | return sema.addConstant( | 14893 | return sema.addConstant( |
| 14792 | resolved_type, | 14894 | resolved_type, |
| 14793 | try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, sema.mod), | 14895 | try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, mod), |
| 14794 | ); | 14896 | ); |
| 14795 | } | 14897 | } |
| 14796 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | 14898 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; |
| ... | @@ -14801,40 +14903,46 @@ fn analyzeArithmetic( | ... | @@ -14801,40 +14903,46 @@ fn analyzeArithmetic( |
| 14801 | // If either of the operands are zero, result is zero. | 14903 | // If either of the operands are zero, result is zero. |
| 14802 | // If either of the operands are one, result is the other operand. | 14904 | // If either of the operands are one, result is the other operand. |
| 14803 | // If either of the operands are undefined, result is undefined. | 14905 | // If either of the operands are undefined, result is undefined. |
| 14906 | const scalar_zero = switch (scalar_tag) { | ||
| 14907 | .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0), | ||
| 14908 | .ComptimeInt, .Int => try mod.intValue(scalar_type, 0), | ||
| 14909 | else => unreachable, | ||
| 14910 | }; | ||
| 14911 | const scalar_one = switch (scalar_tag) { | ||
| 14912 | .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0), | ||
| 14913 | .ComptimeInt, .Int => try mod.intValue(scalar_type, 1), | ||
| 14914 | else => unreachable, | ||
| 14915 | }; | ||
| 14804 | if (maybe_lhs_val) |lhs_val| { | 14916 | if (maybe_lhs_val) |lhs_val| { |
| 14805 | if (!lhs_val.isUndef()) { | 14917 | if (!lhs_val.isUndef(mod)) { |
| 14806 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14918 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14807 | const zero_val = if (is_vector) b: { | 14919 | const zero_val = try sema.splat(resolved_type, scalar_zero); |
| 14808 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | ||
| 14809 | } else Value.zero; | ||
| 14810 | return sema.addConstant(resolved_type, zero_val); | 14920 | return sema.addConstant(resolved_type, zero_val); |
| 14811 | } | 14921 | } |
| 14812 | if (try sema.compareAll(lhs_val, .eq, Value.one, resolved_type)) { | 14922 | if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { |
| 14813 | return casted_rhs; | 14923 | return casted_rhs; |
| 14814 | } | 14924 | } |
| 14815 | } | 14925 | } |
| 14816 | } | 14926 | } |
| 14817 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap; | 14927 | const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap; |
| 14818 | if (maybe_rhs_val) |rhs_val| { | 14928 | if (maybe_rhs_val) |rhs_val| { |
| 14819 | if (rhs_val.isUndef()) { | 14929 | if (rhs_val.isUndef(mod)) { |
| 14820 | return sema.addConstUndef(resolved_type); | 14930 | return sema.addConstUndef(resolved_type); |
| 14821 | } | 14931 | } |
| 14822 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14932 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14823 | const zero_val = if (is_vector) b: { | 14933 | const zero_val = try sema.splat(resolved_type, scalar_zero); |
| 14824 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | ||
| 14825 | } else Value.zero; | ||
| 14826 | return sema.addConstant(resolved_type, zero_val); | 14934 | return sema.addConstant(resolved_type, zero_val); |
| 14827 | } | 14935 | } |
| 14828 | if (try sema.compareAll(rhs_val, .eq, Value.one, resolved_type)) { | 14936 | if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { |
| 14829 | return casted_lhs; | 14937 | return casted_lhs; |
| 14830 | } | 14938 | } |
| 14831 | if (maybe_lhs_val) |lhs_val| { | 14939 | if (maybe_lhs_val) |lhs_val| { |
| 14832 | if (lhs_val.isUndef()) { | 14940 | if (lhs_val.isUndef(mod)) { |
| 14833 | return sema.addConstUndef(resolved_type); | 14941 | return sema.addConstUndef(resolved_type); |
| 14834 | } | 14942 | } |
| 14835 | return sema.addConstant( | 14943 | return sema.addConstant( |
| 14836 | resolved_type, | 14944 | resolved_type, |
| 14837 | try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, sema.mod), | 14945 | try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, mod), |
| 14838 | ); | 14946 | ); |
| 14839 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; | 14947 | } else break :rs .{ .src = lhs_src, .air_tag = air_tag }; |
| 14840 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; | 14948 | } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; |
| ... | @@ -14844,41 +14952,47 @@ fn analyzeArithmetic( | ... | @@ -14844,41 +14952,47 @@ fn analyzeArithmetic( |
| 14844 | // If either of the operands are zero, result is zero. | 14952 | // If either of the operands are zero, result is zero. |
| 14845 | // If either of the operands are one, result is the other operand. | 14953 | // If either of the operands are one, result is the other operand. |
| 14846 | // If either of the operands are undefined, result is undefined. | 14954 | // If either of the operands are undefined, result is undefined. |
| 14955 | const scalar_zero = switch (scalar_tag) { | ||
| 14956 | .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0), | ||
| 14957 | .ComptimeInt, .Int => try mod.intValue(scalar_type, 0), | ||
| 14958 | else => unreachable, | ||
| 14959 | }; | ||
| 14960 | const scalar_one = switch (scalar_tag) { | ||
| 14961 | .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0), | ||
| 14962 | .ComptimeInt, .Int => try mod.intValue(scalar_type, 1), | ||
| 14963 | else => unreachable, | ||
| 14964 | }; | ||
| 14847 | if (maybe_lhs_val) |lhs_val| { | 14965 | if (maybe_lhs_val) |lhs_val| { |
| 14848 | if (!lhs_val.isUndef()) { | 14966 | if (!lhs_val.isUndef(mod)) { |
| 14849 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14967 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14850 | const zero_val = if (is_vector) b: { | 14968 | const zero_val = try sema.splat(resolved_type, scalar_zero); |
| 14851 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | ||
| 14852 | } else Value.zero; | ||
| 14853 | return sema.addConstant(resolved_type, zero_val); | 14969 | return sema.addConstant(resolved_type, zero_val); |
| 14854 | } | 14970 | } |
| 14855 | if (try sema.compareAll(lhs_val, .eq, Value.one, resolved_type)) { | 14971 | if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { |
| 14856 | return casted_rhs; | 14972 | return casted_rhs; |
| 14857 | } | 14973 | } |
| 14858 | } | 14974 | } |
| 14859 | } | 14975 | } |
| 14860 | if (maybe_rhs_val) |rhs_val| { | 14976 | if (maybe_rhs_val) |rhs_val| { |
| 14861 | if (rhs_val.isUndef()) { | 14977 | if (rhs_val.isUndef(mod)) { |
| 14862 | return sema.addConstUndef(resolved_type); | 14978 | return sema.addConstUndef(resolved_type); |
| 14863 | } | 14979 | } |
| 14864 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { | 14980 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14865 | const zero_val = if (is_vector) b: { | 14981 | const zero_val = try sema.splat(resolved_type, scalar_zero); |
| 14866 | break :b try Value.Tag.repeated.create(sema.arena, Value.zero); | ||
| 14867 | } else Value.zero; | ||
| 14868 | return sema.addConstant(resolved_type, zero_val); | 14982 | return sema.addConstant(resolved_type, zero_val); |
| 14869 | } | 14983 | } |
| 14870 | if (try sema.compareAll(rhs_val, .eq, Value.one, resolved_type)) { | 14984 | if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) { |
| 14871 | return casted_lhs; | 14985 | return casted_lhs; |
| 14872 | } | 14986 | } |
| 14873 | if (maybe_lhs_val) |lhs_val| { | 14987 | if (maybe_lhs_val) |lhs_val| { |
| 14874 | if (lhs_val.isUndef()) { | 14988 | if (lhs_val.isUndef(mod)) { |
| 14875 | return sema.addConstUndef(resolved_type); | 14989 | return sema.addConstUndef(resolved_type); |
| 14876 | } | 14990 | } |
| 14877 | 14991 | ||
| 14878 | const val = if (scalar_tag == .ComptimeInt) | 14992 | const val = if (scalar_tag == .ComptimeInt) |
| 14879 | try lhs_val.intMul(rhs_val, resolved_type, sema.arena, sema.mod) | 14993 | try lhs_val.intMul(rhs_val, resolved_type, undefined, sema.arena, mod) |
| 14880 | else | 14994 | else |
| 14881 | try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, sema.mod); | 14995 | try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, mod); |
| 14882 | 14996 | ||
| 14883 | return sema.addConstant(resolved_type, val); | 14997 | return sema.addConstant(resolved_type, val); |
| 14884 | } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat }; | 14998 | } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat }; |
| ... | @@ -14910,7 +15024,7 @@ fn analyzeArithmetic( | ... | @@ -14910,7 +15024,7 @@ fn analyzeArithmetic( |
| 14910 | } }, | 15024 | } }, |
| 14911 | }); | 15025 | }); |
| 14912 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); | 15026 | const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); |
| 14913 | const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector) | 15027 | const any_ov_bit = if (resolved_type.zigTypeTag(mod) == .Vector) |
| 14914 | try block.addInst(.{ | 15028 | try block.addInst(.{ |
| 14915 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, | 15029 | .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce, |
| 14916 | .data = .{ .reduce = .{ | 15030 | .data = .{ .reduce = .{ |
| ... | @@ -14920,7 +15034,7 @@ fn analyzeArithmetic( | ... | @@ -14920,7 +15034,7 @@ fn analyzeArithmetic( |
| 14920 | }) | 15034 | }) |
| 14921 | else | 15035 | else |
| 14922 | ov_bit; | 15036 | ov_bit; |
| 14923 | const zero_ov = try sema.addConstant(Type.u1, Value.zero); | 15037 | const zero_ov = try sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0)); |
| 14924 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); | 15038 | const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov); |
| 14925 | 15039 | ||
| 14926 | try sema.addSafetyCheck(block, no_ov, .integer_overflow); | 15040 | try sema.addSafetyCheck(block, no_ov, .integer_overflow); |
| ... | @@ -14944,15 +15058,12 @@ fn analyzePtrArithmetic( | ... | @@ -14944,15 +15058,12 @@ fn analyzePtrArithmetic( |
| 14944 | // TODO if the operand is comptime-known to be negative, or is a negative int, | 15058 | // TODO if the operand is comptime-known to be negative, or is a negative int, |
| 14945 | // coerce to isize instead of usize. | 15059 | // coerce to isize instead of usize. |
| 14946 | const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src); | 15060 | const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src); |
| 14947 | const target = sema.mod.getTarget(); | 15061 | const mod = sema.mod; |
| 14948 | const opt_ptr_val = try sema.resolveMaybeUndefVal(ptr); | 15062 | const opt_ptr_val = try sema.resolveMaybeUndefVal(ptr); |
| 14949 | const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset); | 15063 | const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset); |
| 14950 | const ptr_ty = sema.typeOf(ptr); | 15064 | const ptr_ty = sema.typeOf(ptr); |
| 14951 | const ptr_info = ptr_ty.ptrInfo().data; | 15065 | const ptr_info = ptr_ty.ptrInfo(mod); |
| 14952 | const elem_ty = if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Array) | 15066 | assert(ptr_info.size == .Many or ptr_info.size == .C); |
| 14953 | ptr_info.pointee_type.childType() | ||
| 14954 | else | ||
| 14955 | ptr_info.pointee_type; | ||
| 14956 | 15067 | ||
| 14957 | const new_ptr_ty = t: { | 15068 | const new_ptr_ty = t: { |
| 14958 | // Calculate the new pointer alignment. | 15069 | // Calculate the new pointer alignment. |
| ... | @@ -14963,9 +15074,9 @@ fn analyzePtrArithmetic( | ... | @@ -14963,9 +15074,9 @@ fn analyzePtrArithmetic( |
| 14963 | } | 15074 | } |
| 14964 | // If the addend is not a comptime-known value we can still count on | 15075 | // If the addend is not a comptime-known value we can still count on |
| 14965 | // it being a multiple of the type size. | 15076 | // it being a multiple of the type size. |
| 14966 | const elem_size = elem_ty.abiSize(target); | 15077 | const elem_size = ptr_info.pointee_type.abiSize(mod); |
| 14967 | const addend = if (opt_off_val) |off_val| a: { | 15078 | const addend = if (opt_off_val) |off_val| a: { |
| 14968 | const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(target)); | 15079 | const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(mod)); |
| 14969 | break :a elem_size * off_int; | 15080 | break :a elem_size * off_int; |
| 14970 | } else elem_size; | 15081 | } else elem_size; |
| 14971 | 15082 | ||
| ... | @@ -14974,7 +15085,7 @@ fn analyzePtrArithmetic( | ... | @@ -14974,7 +15085,7 @@ fn analyzePtrArithmetic( |
| 14974 | // non zero). | 15085 | // non zero). |
| 14975 | const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align")); | 15086 | const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align")); |
| 14976 | 15087 | ||
| 14977 | break :t try Type.ptr(sema.arena, sema.mod, .{ | 15088 | break :t try Type.ptr(sema.arena, mod, .{ |
| 14978 | .pointee_type = ptr_info.pointee_type, | 15089 | .pointee_type = ptr_info.pointee_type, |
| 14979 | .sentinel = ptr_info.sentinel, | 15090 | .sentinel = ptr_info.sentinel, |
| 14980 | .@"align" = new_align, | 15091 | .@"align" = new_align, |
| ... | @@ -14989,24 +15100,24 @@ fn analyzePtrArithmetic( | ... | @@ -14989,24 +15100,24 @@ fn analyzePtrArithmetic( |
| 14989 | const runtime_src = rs: { | 15100 | const runtime_src = rs: { |
| 14990 | if (opt_ptr_val) |ptr_val| { | 15101 | if (opt_ptr_val) |ptr_val| { |
| 14991 | if (opt_off_val) |offset_val| { | 15102 | if (opt_off_val) |offset_val| { |
| 14992 | if (ptr_val.isUndef()) return sema.addConstUndef(new_ptr_ty); | 15103 | if (ptr_val.isUndef(mod)) return sema.addConstUndef(new_ptr_ty); |
| 14993 | 15104 | ||
| 14994 | const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target)); | 15105 | const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(mod)); |
| 14995 | if (offset_int == 0) return ptr; | 15106 | if (offset_int == 0) return ptr; |
| 14996 | if (try ptr_val.getUnsignedIntAdvanced(target, sema)) |addr| { | 15107 | if (try ptr_val.getUnsignedIntAdvanced(mod, sema)) |addr| { |
| 14997 | const elem_size = elem_ty.abiSize(target); | 15108 | const elem_size = ptr_info.pointee_type.abiSize(mod); |
| 14998 | const new_addr = switch (air_tag) { | 15109 | const new_addr = switch (air_tag) { |
| 14999 | .ptr_add => addr + elem_size * offset_int, | 15110 | .ptr_add => addr + elem_size * offset_int, |
| 15000 | .ptr_sub => addr - elem_size * offset_int, | 15111 | .ptr_sub => addr - elem_size * offset_int, |
| 15001 | else => unreachable, | 15112 | else => unreachable, |
| 15002 | }; | 15113 | }; |
| 15003 | const new_ptr_val = try Value.Tag.int_u64.create(sema.arena, new_addr); | 15114 | const new_ptr_val = try mod.ptrIntValue(new_ptr_ty, new_addr); |
| 15004 | return sema.addConstant(new_ptr_ty, new_ptr_val); | 15115 | return sema.addConstant(new_ptr_ty, new_ptr_val); |
| 15005 | } | 15116 | } |
| 15006 | if (air_tag == .ptr_sub) { | 15117 | if (air_tag == .ptr_sub) { |
| 15007 | return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{}); | 15118 | return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{}); |
| 15008 | } | 15119 | } |
| 15009 | const new_ptr_val = try ptr_val.elemPtr(ptr_ty, sema.arena, offset_int, sema.mod); | 15120 | const new_ptr_val = try ptr_val.elemPtr(new_ptr_ty, offset_int, mod); |
| 15010 | return sema.addConstant(new_ptr_ty, new_ptr_val); | 15121 | return sema.addConstant(new_ptr_ty, new_ptr_val); |
| 15011 | } else break :rs offset_src; | 15122 | } else break :rs offset_src; |
| 15012 | } else break :rs ptr_src; | 15123 | } else break :rs ptr_src; |
| ... | @@ -15052,7 +15163,7 @@ fn zirAsm( | ... | @@ -15052,7 +15163,7 @@ fn zirAsm( |
| 15052 | const inputs_len = @truncate(u5, extended.small >> 5); | 15163 | const inputs_len = @truncate(u5, extended.small >> 5); |
| 15053 | const clobbers_len = @truncate(u5, extended.small >> 10); | 15164 | const clobbers_len = @truncate(u5, extended.small >> 10); |
| 15054 | const is_volatile = @truncate(u1, extended.small >> 15) != 0; | 15165 | const is_volatile = @truncate(u1, extended.small >> 15) != 0; |
| 15055 | const is_global_assembly = sema.func == null; | 15166 | const is_global_assembly = sema.func_index == .none; |
| 15056 | 15167 | ||
| 15057 | const asm_source: []const u8 = if (tmpl_is_expr) blk: { | 15168 | const asm_source: []const u8 = if (tmpl_is_expr) blk: { |
| 15058 | const tmpl = @intToEnum(Zir.Inst.Ref, extra.data.asm_source); | 15169 | const tmpl = @intToEnum(Zir.Inst.Ref, extra.data.asm_source); |
| ... | @@ -15116,6 +15227,7 @@ fn zirAsm( | ... | @@ -15116,6 +15227,7 @@ fn zirAsm( |
| 15116 | 15227 | ||
| 15117 | const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len); | 15228 | const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len); |
| 15118 | const inputs = try sema.arena.alloc(ConstraintName, inputs_len); | 15229 | const inputs = try sema.arena.alloc(ConstraintName, inputs_len); |
| 15230 | const mod = sema.mod; | ||
| 15119 | 15231 | ||
| 15120 | for (args, 0..) |*arg, arg_i| { | 15232 | for (args, 0..) |*arg, arg_i| { |
| 15121 | const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i); | 15233 | const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i); |
| ... | @@ -15123,9 +15235,9 @@ fn zirAsm( | ... | @@ -15123,9 +15235,9 @@ fn zirAsm( |
| 15123 | 15235 | ||
| 15124 | const uncasted_arg = try sema.resolveInst(input.data.operand); | 15236 | const uncasted_arg = try sema.resolveInst(input.data.operand); |
| 15125 | const uncasted_arg_ty = sema.typeOf(uncasted_arg); | 15237 | const uncasted_arg_ty = sema.typeOf(uncasted_arg); |
| 15126 | switch (uncasted_arg_ty.zigTypeTag()) { | 15238 | switch (uncasted_arg_ty.zigTypeTag(mod)) { |
| 15127 | .ComptimeInt => arg.* = try sema.coerce(block, Type.initTag(.usize), uncasted_arg, src), | 15239 | .ComptimeInt => arg.* = try sema.coerce(block, Type.usize, uncasted_arg, src), |
| 15128 | .ComptimeFloat => arg.* = try sema.coerce(block, Type.initTag(.f64), uncasted_arg, src), | 15240 | .ComptimeFloat => arg.* = try sema.coerce(block, Type.f64, uncasted_arg, src), |
| 15129 | else => { | 15241 | else => { |
| 15130 | arg.* = uncasted_arg; | 15242 | arg.* = uncasted_arg; |
| 15131 | try sema.queueFullTypeResolution(uncasted_arg_ty); | 15243 | try sema.queueFullTypeResolution(uncasted_arg_ty); |
| ... | @@ -15205,6 +15317,7 @@ fn zirCmpEq( | ... | @@ -15205,6 +15317,7 @@ fn zirCmpEq( |
| 15205 | const tracy = trace(@src()); | 15317 | const tracy = trace(@src()); |
| 15206 | defer tracy.end(); | 15318 | defer tracy.end(); |
| 15207 | 15319 | ||
| 15320 | const mod = sema.mod; | ||
| 15208 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 15321 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 15209 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 15322 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 15210 | const src: LazySrcLoc = inst_data.src(); | 15323 | const src: LazySrcLoc = inst_data.src(); |
| ... | @@ -15215,8 +15328,8 @@ fn zirCmpEq( | ... | @@ -15215,8 +15328,8 @@ fn zirCmpEq( |
| 15215 | 15328 | ||
| 15216 | const lhs_ty = sema.typeOf(lhs); | 15329 | const lhs_ty = sema.typeOf(lhs); |
| 15217 | const rhs_ty = sema.typeOf(rhs); | 15330 | const rhs_ty = sema.typeOf(rhs); |
| 15218 | const lhs_ty_tag = lhs_ty.zigTypeTag(); | 15331 | const lhs_ty_tag = lhs_ty.zigTypeTag(mod); |
| 15219 | const rhs_ty_tag = rhs_ty.zigTypeTag(); | 15332 | const rhs_ty_tag = rhs_ty.zigTypeTag(mod); |
| 15220 | if (lhs_ty_tag == .Null and rhs_ty_tag == .Null) { | 15333 | if (lhs_ty_tag == .Null and rhs_ty_tag == .Null) { |
| 15221 | // null == null, null != null | 15334 | // null == null, null != null |
| 15222 | if (op == .eq) { | 15335 | if (op == .eq) { |
| ... | @@ -15227,16 +15340,16 @@ fn zirCmpEq( | ... | @@ -15227,16 +15340,16 @@ fn zirCmpEq( |
| 15227 | } | 15340 | } |
| 15228 | 15341 | ||
| 15229 | // comparing null with optionals | 15342 | // comparing null with optionals |
| 15230 | if (lhs_ty_tag == .Null and (rhs_ty_tag == .Optional or rhs_ty.isCPtr())) { | 15343 | if (lhs_ty_tag == .Null and (rhs_ty_tag == .Optional or rhs_ty.isCPtr(mod))) { |
| 15231 | return sema.analyzeIsNull(block, src, rhs, op == .neq); | 15344 | return sema.analyzeIsNull(block, src, rhs, op == .neq); |
| 15232 | } | 15345 | } |
| 15233 | if (rhs_ty_tag == .Null and (lhs_ty_tag == .Optional or lhs_ty.isCPtr())) { | 15346 | if (rhs_ty_tag == .Null and (lhs_ty_tag == .Optional or lhs_ty.isCPtr(mod))) { |
| 15234 | return sema.analyzeIsNull(block, src, lhs, op == .neq); | 15347 | return sema.analyzeIsNull(block, src, lhs, op == .neq); |
| 15235 | } | 15348 | } |
| 15236 | 15349 | ||
| 15237 | if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) { | 15350 | if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) { |
| 15238 | const non_null_type = if (lhs_ty_tag == .Null) rhs_ty else lhs_ty; | 15351 | const non_null_type = if (lhs_ty_tag == .Null) rhs_ty else lhs_ty; |
| 15239 | return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(sema.mod)}); | 15352 | return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(mod)}); |
| 15240 | } | 15353 | } |
| 15241 | 15354 | ||
| 15242 | if (lhs_ty_tag == .Union and (rhs_ty_tag == .EnumLiteral or rhs_ty_tag == .Enum)) { | 15355 | if (lhs_ty_tag == .Union and (rhs_ty_tag == .EnumLiteral or rhs_ty_tag == .Enum)) { |
| ... | @@ -15250,15 +15363,12 @@ fn zirCmpEq( | ... | @@ -15250,15 +15363,12 @@ fn zirCmpEq( |
| 15250 | const runtime_src: LazySrcLoc = src: { | 15363 | const runtime_src: LazySrcLoc = src: { |
| 15251 | if (try sema.resolveMaybeUndefVal(lhs)) |lval| { | 15364 | if (try sema.resolveMaybeUndefVal(lhs)) |lval| { |
| 15252 | if (try sema.resolveMaybeUndefVal(rhs)) |rval| { | 15365 | if (try sema.resolveMaybeUndefVal(rhs)) |rval| { |
| 15253 | if (lval.isUndef() or rval.isUndef()) { | 15366 | if (lval.isUndef(mod) or rval.isUndef(mod)) { |
| 15254 | return sema.addConstUndef(Type.bool); | 15367 | return sema.addConstUndef(Type.bool); |
| 15255 | } | 15368 | } |
| 15256 | // TODO optimisation opportunity: evaluate if mem.eql is faster with the names, | 15369 | const lkey = mod.intern_pool.indexToKey(lval.toIntern()); |
| 15257 | // or calling to Module.getErrorValue to get the values and then compare them is | 15370 | const rkey = mod.intern_pool.indexToKey(rval.toIntern()); |
| 15258 | // faster. | 15371 | if ((lkey.err.name == rkey.err.name) == (op == .eq)) { |
| 15259 | const lhs_name = lval.castTag(.@"error").?.data.name; | ||
| 15260 | const rhs_name = rval.castTag(.@"error").?.data.name; | ||
| 15261 | if (mem.eql(u8, lhs_name, rhs_name) == (op == .eq)) { | ||
| 15262 | return Air.Inst.Ref.bool_true; | 15372 | return Air.Inst.Ref.bool_true; |
| 15263 | } else { | 15373 | } else { |
| 15264 | return Air.Inst.Ref.bool_false; | 15374 | return Air.Inst.Ref.bool_false; |
| ... | @@ -15276,7 +15386,7 @@ fn zirCmpEq( | ... | @@ -15276,7 +15386,7 @@ fn zirCmpEq( |
| 15276 | if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) { | 15386 | if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) { |
| 15277 | const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs); | 15387 | const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs); |
| 15278 | const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs); | 15388 | const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs); |
| 15279 | if (lhs_as_type.eql(rhs_as_type, sema.mod) == (op == .eq)) { | 15389 | if (lhs_as_type.eql(rhs_as_type, mod) == (op == .eq)) { |
| 15280 | return Air.Inst.Ref.bool_true; | 15390 | return Air.Inst.Ref.bool_true; |
| 15281 | } else { | 15391 | } else { |
| 15282 | return Air.Inst.Ref.bool_false; | 15392 | return Air.Inst.Ref.bool_false; |
| ... | @@ -15295,12 +15405,13 @@ fn analyzeCmpUnionTag( | ... | @@ -15295,12 +15405,13 @@ fn analyzeCmpUnionTag( |
| 15295 | tag_src: LazySrcLoc, | 15405 | tag_src: LazySrcLoc, |
| 15296 | op: std.math.CompareOperator, | 15406 | op: std.math.CompareOperator, |
| 15297 | ) CompileError!Air.Inst.Ref { | 15407 | ) CompileError!Air.Inst.Ref { |
| 15408 | const mod = sema.mod; | ||
| 15298 | const union_ty = try sema.resolveTypeFields(sema.typeOf(un)); | 15409 | const union_ty = try sema.resolveTypeFields(sema.typeOf(un)); |
| 15299 | const union_tag_ty = union_ty.unionTagType() orelse { | 15410 | const union_tag_ty = union_ty.unionTagType(mod) orelse { |
| 15300 | const msg = msg: { | 15411 | const msg = msg: { |
| 15301 | const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); | 15412 | const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); |
| 15302 | errdefer msg.destroy(sema.gpa); | 15413 | errdefer msg.destroy(sema.gpa); |
| 15303 | try sema.mod.errNoteNonLazy(union_ty.declSrcLoc(sema.mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(sema.mod)}); | 15414 | try mod.errNoteNonLazy(union_ty.declSrcLoc(mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(mod)}); |
| 15304 | break :msg msg; | 15415 | break :msg msg; |
| 15305 | }; | 15416 | }; |
| 15306 | return sema.failWithOwnedErrorMsg(msg); | 15417 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -15311,9 +15422,9 @@ fn analyzeCmpUnionTag( | ... | @@ -15311,9 +15422,9 @@ fn analyzeCmpUnionTag( |
| 15311 | const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src); | 15422 | const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src); |
| 15312 | 15423 | ||
| 15313 | if (try sema.resolveMaybeUndefVal(coerced_tag)) |enum_val| { | 15424 | if (try sema.resolveMaybeUndefVal(coerced_tag)) |enum_val| { |
| 15314 | if (enum_val.isUndef()) return sema.addConstUndef(Type.bool); | 15425 | if (enum_val.isUndef(mod)) return sema.addConstUndef(Type.bool); |
| 15315 | const field_ty = union_ty.unionFieldType(enum_val, sema.mod); | 15426 | const field_ty = union_ty.unionFieldType(enum_val, mod); |
| 15316 | if (field_ty.zigTypeTag() == .NoReturn) { | 15427 | if (field_ty.zigTypeTag(mod) == .NoReturn) { |
| 15317 | return Air.Inst.Ref.bool_false; | 15428 | return Air.Inst.Ref.bool_false; |
| 15318 | } | 15429 | } |
| 15319 | } | 15430 | } |
| ... | @@ -15352,34 +15463,35 @@ fn analyzeCmp( | ... | @@ -15352,34 +15463,35 @@ fn analyzeCmp( |
| 15352 | rhs_src: LazySrcLoc, | 15463 | rhs_src: LazySrcLoc, |
| 15353 | is_equality_cmp: bool, | 15464 | is_equality_cmp: bool, |
| 15354 | ) CompileError!Air.Inst.Ref { | 15465 | ) CompileError!Air.Inst.Ref { |
| 15466 | const mod = sema.mod; | ||
| 15355 | const lhs_ty = sema.typeOf(lhs); | 15467 | const lhs_ty = sema.typeOf(lhs); |
| 15356 | const rhs_ty = sema.typeOf(rhs); | 15468 | const rhs_ty = sema.typeOf(rhs); |
| 15357 | if (lhs_ty.zigTypeTag() != .Optional and rhs_ty.zigTypeTag() != .Optional) { | 15469 | if (lhs_ty.zigTypeTag(mod) != .Optional and rhs_ty.zigTypeTag(mod) != .Optional) { |
| 15358 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 15470 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 15359 | } | 15471 | } |
| 15360 | 15472 | ||
| 15361 | if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) { | 15473 | if (lhs_ty.zigTypeTag(mod) == .Vector and rhs_ty.zigTypeTag(mod) == .Vector) { |
| 15362 | return sema.cmpVector(block, src, lhs, rhs, op, lhs_src, rhs_src); | 15474 | return sema.cmpVector(block, src, lhs, rhs, op, lhs_src, rhs_src); |
| 15363 | } | 15475 | } |
| 15364 | if (lhs_ty.isNumeric() and rhs_ty.isNumeric()) { | 15476 | if (lhs_ty.isNumeric(mod) and rhs_ty.isNumeric(mod)) { |
| 15365 | // This operation allows any combination of integer and float types, regardless of the | 15477 | // This operation allows any combination of integer and float types, regardless of the |
| 15366 | // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for | 15478 | // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for |
| 15367 | // numeric types. | 15479 | // numeric types. |
| 15368 | return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src); | 15480 | return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src); |
| 15369 | } | 15481 | } |
| 15370 | if (is_equality_cmp and lhs_ty.zigTypeTag() == .ErrorUnion and rhs_ty.zigTypeTag() == .ErrorSet) { | 15482 | if (is_equality_cmp and lhs_ty.zigTypeTag(mod) == .ErrorUnion and rhs_ty.zigTypeTag(mod) == .ErrorSet) { |
| 15371 | const casted_lhs = try sema.analyzeErrUnionCode(block, lhs_src, lhs); | 15483 | const casted_lhs = try sema.analyzeErrUnionCode(block, lhs_src, lhs); |
| 15372 | return sema.cmpSelf(block, src, casted_lhs, rhs, op, lhs_src, rhs_src); | 15484 | return sema.cmpSelf(block, src, casted_lhs, rhs, op, lhs_src, rhs_src); |
| 15373 | } | 15485 | } |
| 15374 | if (is_equality_cmp and lhs_ty.zigTypeTag() == .ErrorSet and rhs_ty.zigTypeTag() == .ErrorUnion) { | 15486 | if (is_equality_cmp and lhs_ty.zigTypeTag(mod) == .ErrorSet and rhs_ty.zigTypeTag(mod) == .ErrorUnion) { |
| 15375 | const casted_rhs = try sema.analyzeErrUnionCode(block, rhs_src, rhs); | 15487 | const casted_rhs = try sema.analyzeErrUnionCode(block, rhs_src, rhs); |
| 15376 | return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src); | 15488 | return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src); |
| 15377 | } | 15489 | } |
| 15378 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; | 15490 | const instructions = &[_]Air.Inst.Ref{ lhs, rhs }; |
| 15379 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } }); | 15491 | const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } }); |
| 15380 | if (!resolved_type.isSelfComparable(is_equality_cmp)) { | 15492 | if (!resolved_type.isSelfComparable(mod, is_equality_cmp)) { |
| 15381 | return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{ | 15493 | return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{ |
| 15382 | compareOperatorName(op), resolved_type.fmt(sema.mod), | 15494 | compareOperatorName(op), resolved_type.fmt(mod), |
| 15383 | }); | 15495 | }); |
| 15384 | } | 15496 | } |
| 15385 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | 15497 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| ... | @@ -15408,15 +15520,19 @@ fn cmpSelf( | ... | @@ -15408,15 +15520,19 @@ fn cmpSelf( |
| 15408 | lhs_src: LazySrcLoc, | 15520 | lhs_src: LazySrcLoc, |
| 15409 | rhs_src: LazySrcLoc, | 15521 | rhs_src: LazySrcLoc, |
| 15410 | ) CompileError!Air.Inst.Ref { | 15522 | ) CompileError!Air.Inst.Ref { |
| 15523 | const mod = sema.mod; | ||
| 15411 | const resolved_type = sema.typeOf(casted_lhs); | 15524 | const resolved_type = sema.typeOf(casted_lhs); |
| 15412 | const runtime_src: LazySrcLoc = src: { | 15525 | const runtime_src: LazySrcLoc = src: { |
| 15413 | if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| { | 15526 | if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| { |
| 15414 | if (lhs_val.isUndef()) return sema.addConstUndef(Type.bool); | 15527 | if (lhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool); |
| 15415 | if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| { | 15528 | if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| { |
| 15416 | if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool); | 15529 | if (rhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool); |
| 15417 | 15530 | ||
| 15418 | if (resolved_type.zigTypeTag() == .Vector) { | 15531 | if (resolved_type.zigTypeTag(mod) == .Vector) { |
| 15419 | const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.bool); | 15532 | const result_ty = try mod.vectorType(.{ |
| 15533 | .len = resolved_type.vectorLen(mod), | ||
| 15534 | .child = .bool_type, | ||
| 15535 | }); | ||
| 15420 | const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_type); | 15536 | const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_type); |
| 15421 | return sema.addConstant(result_ty, cmp_val); | 15537 | return sema.addConstant(result_ty, cmp_val); |
| 15422 | } | 15538 | } |
| ... | @@ -15427,7 +15543,7 @@ fn cmpSelf( | ... | @@ -15427,7 +15543,7 @@ fn cmpSelf( |
| 15427 | return Air.Inst.Ref.bool_false; | 15543 | return Air.Inst.Ref.bool_false; |
| 15428 | } | 15544 | } |
| 15429 | } else { | 15545 | } else { |
| 15430 | if (resolved_type.zigTypeTag() == .Bool) { | 15546 | if (resolved_type.zigTypeTag(mod) == .Bool) { |
| 15431 | // We can lower bool eq/neq more efficiently. | 15547 | // We can lower bool eq/neq more efficiently. |
| 15432 | return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src); | 15548 | return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src); |
| 15433 | } | 15549 | } |
| ... | @@ -15436,9 +15552,9 @@ fn cmpSelf( | ... | @@ -15436,9 +15552,9 @@ fn cmpSelf( |
| 15436 | } else { | 15552 | } else { |
| 15437 | // For bools, we still check the other operand, because we can lower | 15553 | // For bools, we still check the other operand, because we can lower |
| 15438 | // bool eq/neq more efficiently. | 15554 | // bool eq/neq more efficiently. |
| 15439 | if (resolved_type.zigTypeTag() == .Bool) { | 15555 | if (resolved_type.zigTypeTag(mod) == .Bool) { |
| 15440 | if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| { | 15556 | if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| { |
| 15441 | if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool); | 15557 | if (rhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool); |
| 15442 | return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src); | 15558 | return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src); |
| 15443 | } | 15559 | } |
| 15444 | } | 15560 | } |
| ... | @@ -15446,7 +15562,7 @@ fn cmpSelf( | ... | @@ -15446,7 +15562,7 @@ fn cmpSelf( |
| 15446 | } | 15562 | } |
| 15447 | }; | 15563 | }; |
| 15448 | try sema.requireRuntimeBlock(block, src, runtime_src); | 15564 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 15449 | if (resolved_type.zigTypeTag() == .Vector) { | 15565 | if (resolved_type.zigTypeTag(mod) == .Vector) { |
| 15450 | return block.addCmpVector(casted_lhs, casted_rhs, op); | 15566 | return block.addCmpVector(casted_lhs, casted_rhs, op); |
| 15451 | } | 15567 | } |
| 15452 | const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized); | 15568 | const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized); |
| ... | @@ -15475,16 +15591,17 @@ fn runtimeBoolCmp( | ... | @@ -15475,16 +15591,17 @@ fn runtimeBoolCmp( |
| 15475 | } | 15591 | } |
| 15476 | 15592 | ||
| 15477 | fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 15593 | fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 15594 | const mod = sema.mod; | ||
| 15478 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 15595 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 15479 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 15596 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 15480 | const ty = try sema.resolveType(block, operand_src, inst_data.operand); | 15597 | const ty = try sema.resolveType(block, operand_src, inst_data.operand); |
| 15481 | switch (ty.zigTypeTag()) { | 15598 | switch (ty.zigTypeTag(mod)) { |
| 15482 | .Fn, | 15599 | .Fn, |
| 15483 | .NoReturn, | 15600 | .NoReturn, |
| 15484 | .Undefined, | 15601 | .Undefined, |
| 15485 | .Null, | 15602 | .Null, |
| 15486 | .Opaque, | 15603 | .Opaque, |
| 15487 | => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(sema.mod)}), | 15604 | => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(mod)}), |
| 15488 | 15605 | ||
| 15489 | .Type, | 15606 | .Type, |
| 15490 | .EnumLiteral, | 15607 | .EnumLiteral, |
| ... | @@ -15509,25 +15626,25 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -15509,25 +15626,25 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 15509 | .AnyFrame, | 15626 | .AnyFrame, |
| 15510 | => {}, | 15627 | => {}, |
| 15511 | } | 15628 | } |
| 15512 | const target = sema.mod.getTarget(); | 15629 | const val = try ty.lazyAbiSize(mod); |
| 15513 | const val = try ty.lazyAbiSize(target, sema.arena); | 15630 | if (val.isLazySize(mod)) { |
| 15514 | if (val.tag() == .lazy_size) { | ||
| 15515 | try sema.queueFullTypeResolution(ty); | 15631 | try sema.queueFullTypeResolution(ty); |
| 15516 | } | 15632 | } |
| 15517 | return sema.addConstant(Type.comptime_int, val); | 15633 | return sema.addConstant(Type.comptime_int, val); |
| 15518 | } | 15634 | } |
| 15519 | 15635 | ||
| 15520 | fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 15636 | fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 15637 | const mod = sema.mod; | ||
| 15521 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 15638 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 15522 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 15639 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 15523 | const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand); | 15640 | const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand); |
| 15524 | switch (operand_ty.zigTypeTag()) { | 15641 | switch (operand_ty.zigTypeTag(mod)) { |
| 15525 | .Fn, | 15642 | .Fn, |
| 15526 | .NoReturn, | 15643 | .NoReturn, |
| 15527 | .Undefined, | 15644 | .Undefined, |
| 15528 | .Null, | 15645 | .Null, |
| 15529 | .Opaque, | 15646 | .Opaque, |
| 15530 | => return sema.fail(block, operand_src, "no size available for type '{}'", .{operand_ty.fmt(sema.mod)}), | 15647 | => return sema.fail(block, operand_src, "no size available for type '{}'", .{operand_ty.fmt(mod)}), |
| 15531 | 15648 | ||
| 15532 | .Type, | 15649 | .Type, |
| 15533 | .EnumLiteral, | 15650 | .EnumLiteral, |
| ... | @@ -15552,8 +15669,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -15552,8 +15669,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 15552 | .AnyFrame, | 15669 | .AnyFrame, |
| 15553 | => {}, | 15670 | => {}, |
| 15554 | } | 15671 | } |
| 15555 | const target = sema.mod.getTarget(); | 15672 | const bit_size = try operand_ty.bitSizeAdvanced(mod, sema); |
| 15556 | const bit_size = try operand_ty.bitSizeAdvanced(target, sema); | ||
| 15557 | return sema.addIntUnsigned(Type.comptime_int, bit_size); | 15673 | return sema.addIntUnsigned(Type.comptime_int, bit_size); |
| 15558 | } | 15674 | } |
| 15559 | 15675 | ||
| ... | @@ -15562,17 +15678,13 @@ fn zirThis( | ... | @@ -15562,17 +15678,13 @@ fn zirThis( |
| 15562 | block: *Block, | 15678 | block: *Block, |
| 15563 | extended: Zir.Inst.Extended.InstData, | 15679 | extended: Zir.Inst.Extended.InstData, |
| 15564 | ) CompileError!Air.Inst.Ref { | 15680 | ) CompileError!Air.Inst.Ref { |
| 15565 | const this_decl_index = block.namespace.getDeclIndex(); | 15681 | const mod = sema.mod; |
| 15682 | const this_decl_index = mod.namespaceDeclIndex(block.namespace); | ||
| 15566 | const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); | 15683 | const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand)); |
| 15567 | return sema.analyzeDeclVal(block, src, this_decl_index); | 15684 | return sema.analyzeDeclVal(block, src, this_decl_index); |
| 15568 | } | 15685 | } |
| 15569 | 15686 | ||
| 15570 | fn zirClosureCapture( | 15687 | fn zirClosureCapture(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 15571 | sema: *Sema, | ||
| 15572 | block: *Block, | ||
| 15573 | inst: Zir.Inst.Index, | ||
| 15574 | ) CompileError!void { | ||
| 15575 | // TODO: Compile error when closed over values are modified | ||
| 15576 | const inst_data = sema.code.instructions.items(.data)[inst].un_tok; | 15688 | const inst_data = sema.code.instructions.items(.data)[inst].un_tok; |
| 15577 | // Closures are not necessarily constant values. For example, the | 15689 | // Closures are not necessarily constant values. For example, the |
| 15578 | // code might do something like this: | 15690 | // code might do something like this: |
| ... | @@ -15580,26 +15692,24 @@ fn zirClosureCapture( | ... | @@ -15580,26 +15692,24 @@ fn zirClosureCapture( |
| 15580 | // ...in which case the closure_capture instruction has access to a runtime | 15692 | // ...in which case the closure_capture instruction has access to a runtime |
| 15581 | // value only. In such case we preserve the type and use a dummy runtime value. | 15693 | // value only. In such case we preserve the type and use a dummy runtime value. |
| 15582 | const operand = try sema.resolveInst(inst_data.operand); | 15694 | const operand = try sema.resolveInst(inst_data.operand); |
| 15583 | const val = (try sema.resolveMaybeUndefValAllowVariables(operand)) orelse | 15695 | const ty = sema.typeOf(operand); |
| 15584 | Value.initTag(.unreachable_value); | 15696 | const capture: CaptureScope.Capture = blk: { |
| 15585 | 15697 | if (try sema.resolveMaybeUndefValAllowVariables(operand)) |val| { | |
| 15586 | try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, .{ | 15698 | const ip_index = try val.intern(ty, sema.mod); |
| 15587 | .ty = try sema.typeOf(operand).copy(sema.perm_arena), | 15699 | break :blk .{ .comptime_val = ip_index }; |
| 15588 | .val = try val.copy(sema.perm_arena), | 15700 | } |
| 15589 | }); | 15701 | break :blk .{ .runtime_val = ty.toIntern() }; |
| 15702 | }; | ||
| 15703 | try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, capture); | ||
| 15590 | } | 15704 | } |
| 15591 | 15705 | ||
| 15592 | fn zirClosureGet( | 15706 | fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 15593 | sema: *Sema, | 15707 | const mod = sema.mod; |
| 15594 | block: *Block, | ||
| 15595 | inst: Zir.Inst.Index, | ||
| 15596 | ) CompileError!Air.Inst.Ref { | ||
| 15597 | // TODO CLOSURE: Test this with inline functions | ||
| 15598 | const inst_data = sema.code.instructions.items(.data)[inst].inst_node; | 15708 | const inst_data = sema.code.instructions.items(.data)[inst].inst_node; |
| 15599 | var scope: *CaptureScope = sema.mod.declPtr(block.src_decl).src_scope.?; | 15709 | var scope: *CaptureScope = mod.declPtr(block.src_decl).src_scope.?; |
| 15600 | // Note: The target closure must be in this scope list. | 15710 | // Note: The target closure must be in this scope list. |
| 15601 | // If it's not here, the zir is invalid, or the list is broken. | 15711 | // If it's not here, the zir is invalid, or the list is broken. |
| 15602 | const tv = while (true) { | 15712 | const capture = while (true) { |
| 15603 | // Note: We don't need to add a dependency here, because | 15713 | // Note: We don't need to add a dependency here, because |
| 15604 | // decls always depend on their lexical parents. | 15714 | // decls always depend on their lexical parents. |
| 15605 | 15715 | ||
| ... | @@ -15612,17 +15722,17 @@ fn zirClosureGet( | ... | @@ -15612,17 +15722,17 @@ fn zirClosureGet( |
| 15612 | } | 15722 | } |
| 15613 | return error.AnalysisFail; | 15723 | return error.AnalysisFail; |
| 15614 | } | 15724 | } |
| 15615 | if (scope.captures.getPtr(inst_data.inst)) |tv| { | 15725 | if (scope.captures.get(inst_data.inst)) |capture| { |
| 15616 | break tv; | 15726 | break capture; |
| 15617 | } | 15727 | } |
| 15618 | scope = scope.parent.?; | 15728 | scope = scope.parent.?; |
| 15619 | }; | 15729 | }; |
| 15620 | 15730 | ||
| 15621 | if (tv.val.tag() == .unreachable_value and !block.is_typeof and sema.func == null) { | 15731 | if (capture == .runtime_val and !block.is_typeof and sema.func_index == .none) { |
| 15622 | const msg = msg: { | 15732 | const msg = msg: { |
| 15623 | const name = name: { | 15733 | const name = name: { |
| 15624 | const file = sema.owner_decl.getFileScope(); | 15734 | const file = sema.owner_decl.getFileScope(mod); |
| 15625 | const tree = file.getTree(sema.mod.gpa) catch |err| { | 15735 | const tree = file.getTree(sema.gpa) catch |err| { |
| 15626 | // In this case we emit a warning + a less precise source location. | 15736 | // In this case we emit a warning + a less precise source location. |
| 15627 | log.warn("unable to load {s}: {s}", .{ | 15737 | log.warn("unable to load {s}: {s}", .{ |
| 15628 | file.sub_file_path, @errorName(err), | 15738 | file.sub_file_path, @errorName(err), |
| ... | @@ -15646,11 +15756,11 @@ fn zirClosureGet( | ... | @@ -15646,11 +15756,11 @@ fn zirClosureGet( |
| 15646 | return sema.failWithOwnedErrorMsg(msg); | 15756 | return sema.failWithOwnedErrorMsg(msg); |
| 15647 | } | 15757 | } |
| 15648 | 15758 | ||
| 15649 | if (tv.val.tag() == .unreachable_value and !block.is_typeof and !block.is_comptime and sema.func != null) { | 15759 | if (capture == .runtime_val and !block.is_typeof and !block.is_comptime and sema.func_index != .none) { |
| 15650 | const msg = msg: { | 15760 | const msg = msg: { |
| 15651 | const name = name: { | 15761 | const name = name: { |
| 15652 | const file = sema.owner_decl.getFileScope(); | 15762 | const file = sema.owner_decl.getFileScope(mod); |
| 15653 | const tree = file.getTree(sema.mod.gpa) catch |err| { | 15763 | const tree = file.getTree(sema.gpa) catch |err| { |
| 15654 | // In this case we emit a warning + a less precise source location. | 15764 | // In this case we emit a warning + a less precise source location. |
| 15655 | log.warn("unable to load {s}: {s}", .{ | 15765 | log.warn("unable to load {s}: {s}", .{ |
| 15656 | file.sub_file_path, @errorName(err), | 15766 | file.sub_file_path, @errorName(err), |
| ... | @@ -15676,13 +15786,17 @@ fn zirClosureGet( | ... | @@ -15676,13 +15786,17 @@ fn zirClosureGet( |
| 15676 | return sema.failWithOwnedErrorMsg(msg); | 15786 | return sema.failWithOwnedErrorMsg(msg); |
| 15677 | } | 15787 | } |
| 15678 | 15788 | ||
| 15679 | if (tv.val.tag() == .unreachable_value) { | 15789 | switch (capture) { |
| 15680 | assert(block.is_typeof); | 15790 | .runtime_val => |ty_ip_index| { |
| 15681 | // We need a dummy runtime instruction with the correct type. | 15791 | assert(block.is_typeof); |
| 15682 | return block.addTy(.alloc, tv.ty); | 15792 | // We need a dummy runtime instruction with the correct type. |
| 15793 | return block.addTy(.alloc, ty_ip_index.toType()); | ||
| 15794 | }, | ||
| 15795 | .comptime_val => |val_ip_index| { | ||
| 15796 | const ty = mod.intern_pool.typeOf(val_ip_index).toType(); | ||
| 15797 | return sema.addConstant(ty, val_ip_index.toValue()); | ||
| 15798 | }, | ||
| 15683 | } | 15799 | } |
| 15684 | |||
| 15685 | return sema.addConstant(tv.ty, tv.val); | ||
| 15686 | } | 15800 | } |
| 15687 | 15801 | ||
| 15688 | fn zirRetAddr( | 15802 | fn zirRetAddr( |
| ... | @@ -15717,345 +15831,422 @@ fn zirBuiltinSrc( | ... | @@ -15717,345 +15831,422 @@ fn zirBuiltinSrc( |
| 15717 | const tracy = trace(@src()); | 15831 | const tracy = trace(@src()); |
| 15718 | defer tracy.end(); | 15832 | defer tracy.end(); |
| 15719 | 15833 | ||
| 15834 | const mod = sema.mod; | ||
| 15720 | const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data; | 15835 | const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data; |
| 15721 | const src = LazySrcLoc.nodeOffset(extra.node); | 15836 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 15722 | const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{}); | 15837 | const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{}); |
| 15723 | const fn_owner_decl = sema.mod.declPtr(func.owner_decl); | 15838 | const fn_owner_decl = mod.declPtr(func.owner_decl); |
| 15724 | 15839 | ||
| 15725 | const func_name_val = blk: { | 15840 | const func_name_val = blk: { |
| 15726 | var anon_decl = try block.startAnonDecl(); | 15841 | var anon_decl = try block.startAnonDecl(); |
| 15727 | defer anon_decl.deinit(); | 15842 | defer anon_decl.deinit(); |
| 15728 | const name = std.mem.span(fn_owner_decl.name); | 15843 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 15729 | const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]); | 15844 | const name = try sema.arena.dupe(u8, mod.intern_pool.stringToSlice(fn_owner_decl.name)); |
| 15845 | const new_decl_ty = try mod.arrayType(.{ | ||
| 15846 | .len = name.len, | ||
| 15847 | .child = .u8_type, | ||
| 15848 | .sentinel = .zero_u8, | ||
| 15849 | }); | ||
| 15730 | const new_decl = try anon_decl.finish( | 15850 | const new_decl = try anon_decl.finish( |
| 15731 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len - 1), | 15851 | new_decl_ty, |
| 15732 | try Value.Tag.bytes.create(anon_decl.arena(), bytes), | 15852 | (try mod.intern(.{ .aggregate = .{ |
| 15853 | .ty = new_decl_ty.toIntern(), | ||
| 15854 | .storage = .{ .bytes = name }, | ||
| 15855 | } })).toValue(), | ||
| 15733 | 0, // default alignment | 15856 | 0, // default alignment |
| 15734 | ); | 15857 | ); |
| 15735 | break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl); | 15858 | break :blk try mod.intern(.{ .ptr = .{ |
| 15859 | .ty = .slice_const_u8_sentinel_0_type, | ||
| 15860 | .addr = .{ .decl = new_decl }, | ||
| 15861 | .len = (try mod.intValue(Type.usize, name.len)).toIntern(), | ||
| 15862 | } }); | ||
| 15736 | }; | 15863 | }; |
| 15737 | 15864 | ||
| 15738 | const file_name_val = blk: { | 15865 | const file_name_val = blk: { |
| 15739 | var anon_decl = try block.startAnonDecl(); | 15866 | var anon_decl = try block.startAnonDecl(); |
| 15740 | defer anon_decl.deinit(); | 15867 | defer anon_decl.deinit(); |
| 15741 | // The compiler must not call realpath anywhere. | 15868 | // The compiler must not call realpath anywhere. |
| 15742 | const name = try fn_owner_decl.getFileScope().fullPathZ(anon_decl.arena()); | 15869 | const name = try fn_owner_decl.getFileScope(mod).fullPathZ(sema.arena); |
| 15870 | const new_decl_ty = try mod.arrayType(.{ | ||
| 15871 | .len = name.len, | ||
| 15872 | .child = .u8_type, | ||
| 15873 | .sentinel = .zero_u8, | ||
| 15874 | }); | ||
| 15743 | const new_decl = try anon_decl.finish( | 15875 | const new_decl = try anon_decl.finish( |
| 15744 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), name.len), | 15876 | new_decl_ty, |
| 15745 | try Value.Tag.bytes.create(anon_decl.arena(), name[0 .. name.len + 1]), | 15877 | (try mod.intern(.{ .aggregate = .{ |
| 15878 | .ty = new_decl_ty.toIntern(), | ||
| 15879 | .storage = .{ .bytes = name }, | ||
| 15880 | } })).toValue(), | ||
| 15746 | 0, // default alignment | 15881 | 0, // default alignment |
| 15747 | ); | 15882 | ); |
| 15748 | break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl); | 15883 | break :blk try mod.intern(.{ .ptr = .{ |
| 15884 | .ty = .slice_const_u8_sentinel_0_type, | ||
| 15885 | .addr = .{ .decl = new_decl }, | ||
| 15886 | .len = (try mod.intValue(Type.usize, name.len)).toIntern(), | ||
| 15887 | } }); | ||
| 15749 | }; | 15888 | }; |
| 15750 | 15889 | ||
| 15751 | const field_values = try sema.arena.alloc(Value, 4); | 15890 | const src_loc_ty = try sema.getBuiltinType("SourceLocation"); |
| 15752 | // file: [:0]const u8, | 15891 | const fields = .{ |
| 15753 | field_values[0] = file_name_val; | 15892 | // file: [:0]const u8, |
| 15754 | // fn_name: [:0]const u8, | 15893 | file_name_val, |
| 15755 | field_values[1] = func_name_val; | 15894 | // fn_name: [:0]const u8, |
| 15756 | // line: u32 | 15895 | func_name_val, |
| 15757 | field_values[2] = try Value.Tag.runtime_value.create(sema.arena, try Value.Tag.int_u64.create(sema.arena, extra.line + 1)); | 15896 | // line: u32, |
| 15758 | // column: u32, | 15897 | try mod.intern(.{ .runtime_value = .{ |
| 15759 | field_values[3] = try Value.Tag.int_u64.create(sema.arena, extra.column + 1); | 15898 | .ty = .u32_type, |
| 15760 | 15899 | .val = (try mod.intValue(Type.u32, extra.line + 1)).toIntern(), | |
| 15761 | return sema.addConstant( | 15900 | } }), |
| 15762 | try sema.getBuiltinType("SourceLocation"), | 15901 | // column: u32, |
| 15763 | try Value.Tag.aggregate.create(sema.arena, field_values), | 15902 | (try mod.intValue(Type.u32, extra.column + 1)).toIntern(), |
| 15764 | ); | 15903 | }; |
| 15904 | return sema.addConstant(src_loc_ty, (try mod.intern(.{ .aggregate = .{ | ||
| 15905 | .ty = src_loc_ty.toIntern(), | ||
| 15906 | .storage = .{ .elems = &fields }, | ||
| 15907 | } })).toValue()); | ||
| 15765 | } | 15908 | } |
| 15766 | 15909 | ||
| 15767 | fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 15910 | fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 15911 | const mod = sema.mod; | ||
| 15912 | const gpa = sema.gpa; | ||
| 15913 | const ip = &mod.intern_pool; | ||
| 15768 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 15914 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 15769 | const src = inst_data.src(); | 15915 | const src = inst_data.src(); |
| 15770 | const ty = try sema.resolveType(block, src, inst_data.operand); | 15916 | const ty = try sema.resolveType(block, src, inst_data.operand); |
| 15771 | const type_info_ty = try sema.getBuiltinType("Type"); | 15917 | const type_info_ty = try sema.getBuiltinType("Type"); |
| 15772 | const target = sema.mod.getTarget(); | 15918 | const type_info_tag_ty = type_info_ty.unionTagType(mod).?; |
| 15773 | 15919 | ||
| 15774 | switch (ty.zigTypeTag()) { | 15920 | switch (ty.zigTypeTag(mod)) { |
| 15775 | .Type => return sema.addConstant( | 15921 | .Type, |
| 15776 | type_info_ty, | 15922 | .Void, |
| 15777 | try Value.Tag.@"union".create(sema.arena, .{ | 15923 | .Bool, |
| 15778 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Type)), | 15924 | .NoReturn, |
| 15779 | .val = Value.void, | 15925 | .ComptimeFloat, |
| 15780 | }), | 15926 | .ComptimeInt, |
| 15781 | ), | 15927 | .Undefined, |
| 15782 | .Void => return sema.addConstant( | 15928 | .Null, |
| 15783 | type_info_ty, | 15929 | .EnumLiteral, |
| 15784 | try Value.Tag.@"union".create(sema.arena, .{ | 15930 | => |type_info_tag| return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ |
| 15785 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Void)), | 15931 | .ty = type_info_ty.toIntern(), |
| 15786 | .val = Value.void, | 15932 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(type_info_tag))).toIntern(), |
| 15787 | }), | 15933 | .val = .void_value, |
| 15788 | ), | 15934 | } })).toValue()), |
| 15789 | .Bool => return sema.addConstant( | ||
| 15790 | type_info_ty, | ||
| 15791 | try Value.Tag.@"union".create(sema.arena, .{ | ||
| 15792 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Bool)), | ||
| 15793 | .val = Value.void, | ||
| 15794 | }), | ||
| 15795 | ), | ||
| 15796 | .NoReturn => return sema.addConstant( | ||
| 15797 | type_info_ty, | ||
| 15798 | try Value.Tag.@"union".create(sema.arena, .{ | ||
| 15799 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.NoReturn)), | ||
| 15800 | .val = Value.void, | ||
| 15801 | }), | ||
| 15802 | ), | ||
| 15803 | .ComptimeFloat => return sema.addConstant( | ||
| 15804 | type_info_ty, | ||
| 15805 | try Value.Tag.@"union".create(sema.arena, .{ | ||
| 15806 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeFloat)), | ||
| 15807 | .val = Value.void, | ||
| 15808 | }), | ||
| 15809 | ), | ||
| 15810 | .ComptimeInt => return sema.addConstant( | ||
| 15811 | type_info_ty, | ||
| 15812 | try Value.Tag.@"union".create(sema.arena, .{ | ||
| 15813 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeInt)), | ||
| 15814 | .val = Value.void, | ||
| 15815 | }), | ||
| 15816 | ), | ||
| 15817 | .Undefined => return sema.addConstant( | ||
| 15818 | type_info_ty, | ||
| 15819 | try Value.Tag.@"union".create(sema.arena, .{ | ||
| 15820 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Undefined)), | ||
| 15821 | .val = Value.void, | ||
| 15822 | }), | ||
| 15823 | ), | ||
| 15824 | .Null => return sema.addConstant( | ||
| 15825 | type_info_ty, | ||
| 15826 | try Value.Tag.@"union".create(sema.arena, .{ | ||
| 15827 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Null)), | ||
| 15828 | .val = Value.void, | ||
| 15829 | }), | ||
| 15830 | ), | ||
| 15831 | .EnumLiteral => return sema.addConstant( | ||
| 15832 | type_info_ty, | ||
| 15833 | try Value.Tag.@"union".create(sema.arena, .{ | ||
| 15834 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.EnumLiteral)), | ||
| 15835 | .val = Value.void, | ||
| 15836 | }), | ||
| 15837 | ), | ||
| 15838 | .Fn => { | 15935 | .Fn => { |
| 15839 | // TODO: look into memoizing this result. | 15936 | // TODO: look into memoizing this result. |
| 15840 | const info = ty.fnInfo(); | ||
| 15841 | |||
| 15842 | var params_anon_decl = try block.startAnonDecl(); | 15937 | var params_anon_decl = try block.startAnonDecl(); |
| 15843 | defer params_anon_decl.deinit(); | 15938 | defer params_anon_decl.deinit(); |
| 15844 | 15939 | ||
| 15845 | const param_vals = try params_anon_decl.arena().alloc(Value, info.param_types.len); | 15940 | const fn_info_decl_index = (try sema.namespaceLookup( |
| 15941 | block, | ||
| 15942 | src, | ||
| 15943 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | ||
| 15944 | try ip.getOrPutString(gpa, "Fn"), | ||
| 15945 | )).?; | ||
| 15946 | try mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index); | ||
| 15947 | try sema.ensureDeclAnalyzed(fn_info_decl_index); | ||
| 15948 | const fn_info_decl = mod.declPtr(fn_info_decl_index); | ||
| 15949 | const fn_info_ty = fn_info_decl.val.toType(); | ||
| 15950 | |||
| 15951 | const param_info_decl_index = (try sema.namespaceLookup( | ||
| 15952 | block, | ||
| 15953 | src, | ||
| 15954 | fn_info_ty.getNamespaceIndex(mod).unwrap().?, | ||
| 15955 | try ip.getOrPutString(gpa, "Param"), | ||
| 15956 | )).?; | ||
| 15957 | try mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index); | ||
| 15958 | try sema.ensureDeclAnalyzed(param_info_decl_index); | ||
| 15959 | const param_info_decl = mod.declPtr(param_info_decl_index); | ||
| 15960 | const param_info_ty = param_info_decl.val.toType(); | ||
| 15961 | |||
| 15962 | const param_vals = try sema.arena.alloc(InternPool.Index, mod.typeToFunc(ty).?.param_types.len); | ||
| 15846 | for (param_vals, 0..) |*param_val, i| { | 15963 | for (param_vals, 0..) |*param_val, i| { |
| 15964 | const info = mod.typeToFunc(ty).?; | ||
| 15847 | const param_ty = info.param_types[i]; | 15965 | const param_ty = info.param_types[i]; |
| 15848 | const is_generic = param_ty.tag() == .generic_poison; | 15966 | const is_generic = param_ty == .generic_poison_type; |
| 15849 | const param_ty_val = if (is_generic) | 15967 | const param_ty_val = try ip.get(gpa, .{ .opt = .{ |
| 15850 | Value.null | 15968 | .ty = try ip.get(gpa, .{ .opt_type = .type_type }), |
| 15851 | else | 15969 | .val = if (is_generic) .none else param_ty, |
| 15852 | try Value.Tag.opt_payload.create( | 15970 | } }); |
| 15853 | params_anon_decl.arena(), | ||
| 15854 | try Value.Tag.ty.create(params_anon_decl.arena(), try param_ty.copy(params_anon_decl.arena())), | ||
| 15855 | ); | ||
| 15856 | 15971 | ||
| 15857 | const is_noalias = blk: { | 15972 | const is_noalias = blk: { |
| 15858 | const index = std.math.cast(u5, i) orelse break :blk false; | 15973 | const index = std.math.cast(u5, i) orelse break :blk false; |
| 15859 | break :blk @truncate(u1, info.noalias_bits >> index) != 0; | 15974 | break :blk @truncate(u1, info.noalias_bits >> index) != 0; |
| 15860 | }; | 15975 | }; |
| 15861 | 15976 | ||
| 15862 | const param_fields = try params_anon_decl.arena().create([3]Value); | 15977 | const param_fields = .{ |
| 15863 | param_fields.* = .{ | ||
| 15864 | // is_generic: bool, | 15978 | // is_generic: bool, |
| 15865 | Value.makeBool(is_generic), | 15979 | Value.makeBool(is_generic).toIntern(), |
| 15866 | // is_noalias: bool, | 15980 | // is_noalias: bool, |
| 15867 | Value.makeBool(is_noalias), | 15981 | Value.makeBool(is_noalias).toIntern(), |
| 15868 | // type: ?type, | 15982 | // type: ?type, |
| 15869 | param_ty_val, | 15983 | param_ty_val, |
| 15870 | }; | 15984 | }; |
| 15871 | param_val.* = try Value.Tag.aggregate.create(params_anon_decl.arena(), param_fields); | 15985 | param_val.* = try mod.intern(.{ .aggregate = .{ |
| 15986 | .ty = param_info_ty.toIntern(), | ||
| 15987 | .storage = .{ .elems = &param_fields }, | ||
| 15988 | } }); | ||
| 15872 | } | 15989 | } |
| 15873 | 15990 | ||
| 15874 | const args_val = v: { | 15991 | const args_val = v: { |
| 15875 | const fn_info_decl_index = (try sema.namespaceLookup( | 15992 | const new_decl_ty = try mod.arrayType(.{ |
| 15876 | block, | 15993 | .len = param_vals.len, |
| 15877 | src, | 15994 | .child = param_info_ty.toIntern(), |
| 15878 | type_info_ty.getNamespace().?, | 15995 | }); |
| 15879 | "Fn", | ||
| 15880 | )).?; | ||
| 15881 | try sema.mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index); | ||
| 15882 | try sema.ensureDeclAnalyzed(fn_info_decl_index); | ||
| 15883 | const fn_info_decl = sema.mod.declPtr(fn_info_decl_index); | ||
| 15884 | var fn_ty_buffer: Value.ToTypeBuffer = undefined; | ||
| 15885 | const fn_ty = fn_info_decl.val.toType(&fn_ty_buffer); | ||
| 15886 | const param_info_decl_index = (try sema.namespaceLookup( | ||
| 15887 | block, | ||
| 15888 | src, | ||
| 15889 | fn_ty.getNamespace().?, | ||
| 15890 | "Param", | ||
| 15891 | )).?; | ||
| 15892 | try sema.mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index); | ||
| 15893 | try sema.ensureDeclAnalyzed(param_info_decl_index); | ||
| 15894 | const param_info_decl = sema.mod.declPtr(param_info_decl_index); | ||
| 15895 | var param_buffer: Value.ToTypeBuffer = undefined; | ||
| 15896 | const param_ty = param_info_decl.val.toType(&param_buffer); | ||
| 15897 | const new_decl = try params_anon_decl.finish( | 15996 | const new_decl = try params_anon_decl.finish( |
| 15898 | try Type.Tag.array.create(params_anon_decl.arena(), .{ | 15997 | new_decl_ty, |
| 15899 | .len = param_vals.len, | 15998 | (try mod.intern(.{ .aggregate = .{ |
| 15900 | .elem_type = try param_ty.copy(params_anon_decl.arena()), | 15999 | .ty = new_decl_ty.toIntern(), |
| 15901 | }), | 16000 | .storage = .{ .elems = param_vals }, |
| 15902 | try Value.Tag.aggregate.create( | 16001 | } })).toValue(), |
| 15903 | params_anon_decl.arena(), | ||
| 15904 | param_vals, | ||
| 15905 | ), | ||
| 15906 | 0, // default alignment | 16002 | 0, // default alignment |
| 15907 | ); | 16003 | ); |
| 15908 | break :v try Value.Tag.slice.create(sema.arena, .{ | 16004 | break :v try mod.intern(.{ .ptr = .{ |
| 15909 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | 16005 | .ty = (try mod.ptrType(.{ |
| 15910 | .len = try Value.Tag.int_u64.create(sema.arena, param_vals.len), | 16006 | .child = param_info_ty.toIntern(), |
| 15911 | }); | 16007 | .flags = .{ |
| 16008 | .size = .Slice, | ||
| 16009 | .is_const = true, | ||
| 16010 | }, | ||
| 16011 | })).toIntern(), | ||
| 16012 | .addr = .{ .decl = new_decl }, | ||
| 16013 | .len = (try mod.intValue(Type.usize, param_vals.len)).toIntern(), | ||
| 16014 | } }); | ||
| 15912 | }; | 16015 | }; |
| 15913 | 16016 | ||
| 15914 | const ret_ty_opt = if (info.return_type.tag() != .generic_poison) | 16017 | const info = mod.typeToFunc(ty).?; |
| 15915 | try Value.Tag.opt_payload.create( | 16018 | const ret_ty_opt = try mod.intern(.{ .opt = .{ |
| 15916 | sema.arena, | 16019 | .ty = try ip.get(gpa, .{ .opt_type = .type_type }), |
| 15917 | try Value.Tag.ty.create(sema.arena, info.return_type), | 16020 | .val = if (info.return_type == .generic_poison_type) .none else info.return_type, |
| 15918 | ) | 16021 | } }); |
| 15919 | else | 16022 | |
| 15920 | Value.null; | 16023 | const callconv_ty = try sema.getBuiltinType("CallingConvention"); |
| 15921 | 16024 | ||
| 15922 | const field_values = try sema.arena.create([6]Value); | 16025 | const field_values = .{ |
| 15923 | field_values.* = .{ | ||
| 15924 | // calling_convention: CallingConvention, | 16026 | // calling_convention: CallingConvention, |
| 15925 | try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.cc)), | 16027 | (try mod.enumValueFieldIndex(callconv_ty, @enumToInt(info.cc))).toIntern(), |
| 15926 | // alignment: comptime_int, | 16028 | // alignment: comptime_int, |
| 15927 | try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target)), | 16029 | (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod))).toIntern(), |
| 15928 | // is_generic: bool, | 16030 | // is_generic: bool, |
| 15929 | Value.makeBool(info.is_generic), | 16031 | Value.makeBool(info.is_generic).toIntern(), |
| 15930 | // is_var_args: bool, | 16032 | // is_var_args: bool, |
| 15931 | Value.makeBool(info.is_var_args), | 16033 | Value.makeBool(info.is_var_args).toIntern(), |
| 15932 | // return_type: ?type, | 16034 | // return_type: ?type, |
| 15933 | ret_ty_opt, | 16035 | ret_ty_opt, |
| 15934 | // args: []const Fn.Param, | 16036 | // args: []const Fn.Param, |
| 15935 | args_val, | 16037 | args_val, |
| 15936 | }; | 16038 | }; |
| 15937 | 16039 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 15938 | return sema.addConstant( | 16040 | .ty = type_info_ty.toIntern(), |
| 15939 | type_info_ty, | 16041 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Fn))).toIntern(), |
| 15940 | try Value.Tag.@"union".create(sema.arena, .{ | 16042 | .val = try mod.intern(.{ .aggregate = .{ |
| 15941 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Fn)), | 16043 | .ty = fn_info_ty.toIntern(), |
| 15942 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16044 | .storage = .{ .elems = &field_values }, |
| 15943 | }), | 16045 | } }), |
| 15944 | ); | 16046 | } })).toValue()); |
| 15945 | }, | 16047 | }, |
| 15946 | .Int => { | 16048 | .Int => { |
| 15947 | const info = ty.intInfo(target); | 16049 | const int_info_decl_index = (try sema.namespaceLookup( |
| 15948 | const field_values = try sema.arena.alloc(Value, 2); | 16050 | block, |
| 15949 | // signedness: Signedness, | 16051 | src, |
| 15950 | field_values[0] = try Value.Tag.enum_field_index.create( | 16052 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 15951 | sema.arena, | 16053 | try ip.getOrPutString(gpa, "Int"), |
| 15952 | @enumToInt(info.signedness), | 16054 | )).?; |
| 15953 | ); | 16055 | try mod.declareDeclDependency(sema.owner_decl_index, int_info_decl_index); |
| 15954 | // bits: comptime_int, | 16056 | try sema.ensureDeclAnalyzed(int_info_decl_index); |
| 15955 | field_values[1] = try Value.Tag.int_u64.create(sema.arena, info.bits); | 16057 | const int_info_decl = mod.declPtr(int_info_decl_index); |
| 15956 | 16058 | const int_info_ty = int_info_decl.val.toType(); | |
| 15957 | return sema.addConstant( | 16059 | |
| 15958 | type_info_ty, | 16060 | const signedness_ty = try sema.getBuiltinType("Signedness"); |
| 15959 | try Value.Tag.@"union".create(sema.arena, .{ | 16061 | const info = ty.intInfo(mod); |
| 15960 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Int)), | 16062 | const field_values = .{ |
| 15961 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16063 | // signedness: Signedness, |
| 15962 | }), | 16064 | try (try mod.enumValueFieldIndex(signedness_ty, @enumToInt(info.signedness))).intern(signedness_ty, mod), |
| 15963 | ); | 16065 | // bits: u16, |
| 16066 | (try mod.intValue(Type.u16, info.bits)).toIntern(), | ||
| 16067 | }; | ||
| 16068 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | ||
| 16069 | .ty = type_info_ty.toIntern(), | ||
| 16070 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Int))).toIntern(), | ||
| 16071 | .val = try mod.intern(.{ .aggregate = .{ | ||
| 16072 | .ty = int_info_ty.toIntern(), | ||
| 16073 | .storage = .{ .elems = &field_values }, | ||
| 16074 | } }), | ||
| 16075 | } })).toValue()); | ||
| 15964 | }, | 16076 | }, |
| 15965 | .Float => { | 16077 | .Float => { |
| 15966 | const field_values = try sema.arena.alloc(Value, 1); | 16078 | const float_info_decl_index = (try sema.namespaceLookup( |
| 15967 | // bits: comptime_int, | 16079 | block, |
| 15968 | field_values[0] = try Value.Tag.int_u64.create(sema.arena, ty.bitSize(target)); | 16080 | src, |
| 15969 | 16081 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 15970 | return sema.addConstant( | 16082 | try ip.getOrPutString(gpa, "Float"), |
| 15971 | type_info_ty, | 16083 | )).?; |
| 15972 | try Value.Tag.@"union".create(sema.arena, .{ | 16084 | try mod.declareDeclDependency(sema.owner_decl_index, float_info_decl_index); |
| 15973 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Float)), | 16085 | try sema.ensureDeclAnalyzed(float_info_decl_index); |
| 15974 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16086 | const float_info_decl = mod.declPtr(float_info_decl_index); |
| 15975 | }), | 16087 | const float_info_ty = float_info_decl.val.toType(); |
| 15976 | ); | 16088 | |
| 16089 | const field_vals = .{ | ||
| 16090 | // bits: u16, | ||
| 16091 | (try mod.intValue(Type.u16, ty.bitSize(mod))).toIntern(), | ||
| 16092 | }; | ||
| 16093 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | ||
| 16094 | .ty = type_info_ty.toIntern(), | ||
| 16095 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Float))).toIntern(), | ||
| 16096 | .val = try mod.intern(.{ .aggregate = .{ | ||
| 16097 | .ty = float_info_ty.toIntern(), | ||
| 16098 | .storage = .{ .elems = &field_vals }, | ||
| 16099 | } }), | ||
| 16100 | } })).toValue()); | ||
| 15977 | }, | 16101 | }, |
| 15978 | .Pointer => { | 16102 | .Pointer => { |
| 15979 | const info = ty.ptrInfo().data; | 16103 | const info = ty.ptrInfo(mod); |
| 15980 | const alignment = if (info.@"align" != 0) | 16104 | const alignment = if (info.@"align" != 0) |
| 15981 | try Value.Tag.int_u64.create(sema.arena, info.@"align") | 16105 | try mod.intValue(Type.comptime_int, info.@"align") |
| 15982 | else | 16106 | else |
| 15983 | try info.pointee_type.lazyAbiAlignment(target, sema.arena); | 16107 | try info.pointee_type.lazyAbiAlignment(mod); |
| 15984 | 16108 | ||
| 15985 | const field_values = try sema.arena.create([8]Value); | 16109 | const addrspace_ty = try sema.getBuiltinType("AddressSpace"); |
| 15986 | field_values.* = .{ | 16110 | const pointer_ty = t: { |
| 16111 | const decl_index = (try sema.namespaceLookup( | ||
| 16112 | block, | ||
| 16113 | src, | ||
| 16114 | (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?, | ||
| 16115 | try ip.getOrPutString(gpa, "Pointer"), | ||
| 16116 | )).?; | ||
| 16117 | try mod.declareDeclDependency(sema.owner_decl_index, decl_index); | ||
| 16118 | try sema.ensureDeclAnalyzed(decl_index); | ||
| 16119 | const decl = mod.declPtr(decl_index); | ||
| 16120 | break :t decl.val.toType(); | ||
| 16121 | }; | ||
| 16122 | const ptr_size_ty = t: { | ||
| 16123 | const decl_index = (try sema.namespaceLookup( | ||
| 16124 | block, | ||
| 16125 | src, | ||
| 16126 | pointer_ty.getNamespaceIndex(mod).unwrap().?, | ||
| 16127 | try ip.getOrPutString(gpa, "Size"), | ||
| 16128 | )).?; | ||
| 16129 | try mod.declareDeclDependency(sema.owner_decl_index, decl_index); | ||
| 16130 | try sema.ensureDeclAnalyzed(decl_index); | ||
| 16131 | const decl = mod.declPtr(decl_index); | ||
| 16132 | break :t decl.val.toType(); | ||
| 16133 | }; | ||
| 16134 | |||
| 16135 | const field_values = .{ | ||
| 15987 | // size: Size, | 16136 | // size: Size, |
| 15988 | try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.size)), | 16137 | try (try mod.enumValueFieldIndex(ptr_size_ty, @enumToInt(info.size))).intern(ptr_size_ty, mod), |
| 15989 | // is_const: bool, | 16138 | // is_const: bool, |
| 15990 | Value.makeBool(!info.mutable), | 16139 | Value.makeBool(!info.mutable).toIntern(), |
| 15991 | // is_volatile: bool, | 16140 | // is_volatile: bool, |
| 15992 | Value.makeBool(info.@"volatile"), | 16141 | Value.makeBool(info.@"volatile").toIntern(), |
| 15993 | // alignment: comptime_int, | 16142 | // alignment: comptime_int, |
| 15994 | alignment, | 16143 | alignment.toIntern(), |
| 15995 | // address_space: AddressSpace | 16144 | // address_space: AddressSpace |
| 15996 | try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.@"addrspace")), | 16145 | try (try mod.enumValueFieldIndex(addrspace_ty, @enumToInt(info.@"addrspace"))).intern(addrspace_ty, mod), |
| 15997 | // child: type, | 16146 | // child: type, |
| 15998 | try Value.Tag.ty.create(sema.arena, info.pointee_type), | 16147 | info.pointee_type.toIntern(), |
| 15999 | // is_allowzero: bool, | 16148 | // is_allowzero: bool, |
| 16000 | Value.makeBool(info.@"allowzero"), | 16149 | Value.makeBool(info.@"allowzero").toIntern(), |
| 16001 | // sentinel: ?*const anyopaque, | 16150 | // sentinel: ?*const anyopaque, |
| 16002 | try sema.optRefValue(block, info.pointee_type, info.sentinel), | 16151 | (try sema.optRefValue(block, info.pointee_type, info.sentinel)).toIntern(), |
| 16003 | }; | 16152 | }; |
| 16004 | 16153 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16005 | return sema.addConstant( | 16154 | .ty = type_info_ty.toIntern(), |
| 16006 | type_info_ty, | 16155 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Pointer))).toIntern(), |
| 16007 | try Value.Tag.@"union".create(sema.arena, .{ | 16156 | .val = try mod.intern(.{ .aggregate = .{ |
| 16008 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Pointer)), | 16157 | .ty = pointer_ty.toIntern(), |
| 16009 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16158 | .storage = .{ .elems = &field_values }, |
| 16010 | }), | 16159 | } }), |
| 16011 | ); | 16160 | } })).toValue()); |
| 16012 | }, | 16161 | }, |
| 16013 | .Array => { | 16162 | .Array => { |
| 16014 | const info = ty.arrayInfo(); | 16163 | const array_field_ty = t: { |
| 16015 | const field_values = try sema.arena.alloc(Value, 3); | 16164 | const array_field_ty_decl_index = (try sema.namespaceLookup( |
| 16016 | // len: comptime_int, | 16165 | block, |
| 16017 | field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len); | 16166 | src, |
| 16018 | // child: type, | 16167 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 16019 | field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type); | 16168 | try ip.getOrPutString(gpa, "Array"), |
| 16020 | // sentinel: ?*const anyopaque, | 16169 | )).?; |
| 16021 | field_values[2] = try sema.optRefValue(block, info.elem_type, info.sentinel); | 16170 | try mod.declareDeclDependency(sema.owner_decl_index, array_field_ty_decl_index); |
| 16022 | 16171 | try sema.ensureDeclAnalyzed(array_field_ty_decl_index); | |
| 16023 | return sema.addConstant( | 16172 | const array_field_ty_decl = mod.declPtr(array_field_ty_decl_index); |
| 16024 | type_info_ty, | 16173 | break :t array_field_ty_decl.val.toType(); |
| 16025 | try Value.Tag.@"union".create(sema.arena, .{ | 16174 | }; |
| 16026 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Array)), | 16175 | |
| 16027 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16176 | const info = ty.arrayInfo(mod); |
| 16028 | }), | 16177 | const field_values = .{ |
| 16029 | ); | 16178 | // len: comptime_int, |
| 16179 | (try mod.intValue(Type.comptime_int, info.len)).toIntern(), | ||
| 16180 | // child: type, | ||
| 16181 | info.elem_type.toIntern(), | ||
| 16182 | // sentinel: ?*const anyopaque, | ||
| 16183 | (try sema.optRefValue(block, info.elem_type, info.sentinel)).toIntern(), | ||
| 16184 | }; | ||
| 16185 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | ||
| 16186 | .ty = type_info_ty.toIntern(), | ||
| 16187 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Array))).toIntern(), | ||
| 16188 | .val = try mod.intern(.{ .aggregate = .{ | ||
| 16189 | .ty = array_field_ty.toIntern(), | ||
| 16190 | .storage = .{ .elems = &field_values }, | ||
| 16191 | } }), | ||
| 16192 | } })).toValue()); | ||
| 16030 | }, | 16193 | }, |
| 16031 | .Vector => { | 16194 | .Vector => { |
| 16032 | const info = ty.arrayInfo(); | 16195 | const vector_field_ty = t: { |
| 16033 | const field_values = try sema.arena.alloc(Value, 2); | 16196 | const vector_field_ty_decl_index = (try sema.namespaceLookup( |
| 16034 | // len: comptime_int, | 16197 | block, |
| 16035 | field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len); | 16198 | src, |
| 16036 | // child: type, | 16199 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 16037 | field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type); | 16200 | try ip.getOrPutString(gpa, "Vector"), |
| 16038 | 16201 | )).?; | |
| 16039 | return sema.addConstant( | 16202 | try mod.declareDeclDependency(sema.owner_decl_index, vector_field_ty_decl_index); |
| 16040 | type_info_ty, | 16203 | try sema.ensureDeclAnalyzed(vector_field_ty_decl_index); |
| 16041 | try Value.Tag.@"union".create(sema.arena, .{ | 16204 | const vector_field_ty_decl = mod.declPtr(vector_field_ty_decl_index); |
| 16042 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Vector)), | 16205 | break :t vector_field_ty_decl.val.toType(); |
| 16043 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16206 | }; |
| 16044 | }), | 16207 | |
| 16045 | ); | 16208 | const info = ty.arrayInfo(mod); |
| 16209 | const field_values = .{ | ||
| 16210 | // len: comptime_int, | ||
| 16211 | (try mod.intValue(Type.comptime_int, info.len)).toIntern(), | ||
| 16212 | // child: type, | ||
| 16213 | info.elem_type.toIntern(), | ||
| 16214 | }; | ||
| 16215 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | ||
| 16216 | .ty = type_info_ty.toIntern(), | ||
| 16217 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Vector))).toIntern(), | ||
| 16218 | .val = try mod.intern(.{ .aggregate = .{ | ||
| 16219 | .ty = vector_field_ty.toIntern(), | ||
| 16220 | .storage = .{ .elems = &field_values }, | ||
| 16221 | } }), | ||
| 16222 | } })).toValue()); | ||
| 16046 | }, | 16223 | }, |
| 16047 | .Optional => { | 16224 | .Optional => { |
| 16048 | const field_values = try sema.arena.alloc(Value, 1); | 16225 | const optional_field_ty = t: { |
| 16049 | // child: type, | 16226 | const optional_field_ty_decl_index = (try sema.namespaceLookup( |
| 16050 | field_values[0] = try Value.Tag.ty.create(sema.arena, try ty.optionalChildAlloc(sema.arena)); | 16227 | block, |
| 16051 | 16228 | src, | |
| 16052 | return sema.addConstant( | 16229 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 16053 | type_info_ty, | 16230 | try ip.getOrPutString(gpa, "Optional"), |
| 16054 | try Value.Tag.@"union".create(sema.arena, .{ | 16231 | )).?; |
| 16055 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Optional)), | 16232 | try mod.declareDeclDependency(sema.owner_decl_index, optional_field_ty_decl_index); |
| 16056 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16233 | try sema.ensureDeclAnalyzed(optional_field_ty_decl_index); |
| 16057 | }), | 16234 | const optional_field_ty_decl = mod.declPtr(optional_field_ty_decl_index); |
| 16058 | ); | 16235 | break :t optional_field_ty_decl.val.toType(); |
| 16236 | }; | ||
| 16237 | |||
| 16238 | const field_values = .{ | ||
| 16239 | // child: type, | ||
| 16240 | ty.optionalChild(mod).toIntern(), | ||
| 16241 | }; | ||
| 16242 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | ||
| 16243 | .ty = type_info_ty.toIntern(), | ||
| 16244 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Optional))).toIntern(), | ||
| 16245 | .val = try mod.intern(.{ .aggregate = .{ | ||
| 16246 | .ty = optional_field_ty.toIntern(), | ||
| 16247 | .storage = .{ .elems = &field_values }, | ||
| 16248 | } }), | ||
| 16249 | } })).toValue()); | ||
| 16059 | }, | 16250 | }, |
| 16060 | .ErrorSet => { | 16251 | .ErrorSet => { |
| 16061 | var fields_anon_decl = try block.startAnonDecl(); | 16252 | var fields_anon_decl = try block.startAnonDecl(); |
| ... | @@ -16066,17 +16257,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16066,17 +16257,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16066 | const set_field_ty_decl_index = (try sema.namespaceLookup( | 16257 | const set_field_ty_decl_index = (try sema.namespaceLookup( |
| 16067 | block, | 16258 | block, |
| 16068 | src, | 16259 | src, |
| 16069 | type_info_ty.getNamespace().?, | 16260 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 16070 | "Error", | 16261 | try ip.getOrPutString(gpa, "Error"), |
| 16071 | )).?; | 16262 | )).?; |
| 16072 | try sema.mod.declareDeclDependency(sema.owner_decl_index, set_field_ty_decl_index); | 16263 | try mod.declareDeclDependency(sema.owner_decl_index, set_field_ty_decl_index); |
| 16073 | try sema.ensureDeclAnalyzed(set_field_ty_decl_index); | 16264 | try sema.ensureDeclAnalyzed(set_field_ty_decl_index); |
| 16074 | const set_field_ty_decl = sema.mod.declPtr(set_field_ty_decl_index); | 16265 | const set_field_ty_decl = mod.declPtr(set_field_ty_decl_index); |
| 16075 | var buffer: Value.ToTypeBuffer = undefined; | 16266 | break :t set_field_ty_decl.val.toType(); |
| 16076 | break :t try set_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); | ||
| 16077 | }; | 16267 | }; |
| 16078 | 16268 | ||
| 16079 | try sema.queueFullTypeResolution(try error_field_ty.copy(sema.arena)); | 16269 | try sema.queueFullTypeResolution(error_field_ty); |
| 16080 | 16270 | ||
| 16081 | // If the error set is inferred it must be resolved at this point | 16271 | // If the error set is inferred it must be resolved at this point |
| 16082 | try sema.resolveInferredErrorSetTy(block, src, ty); | 16272 | try sema.resolveInferredErrorSetTy(block, src, ty); |
| ... | @@ -16084,90 +16274,119 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16084,90 +16274,119 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16084 | // Build our list of Error values | 16274 | // Build our list of Error values |
| 16085 | // Optional value is only null if anyerror | 16275 | // Optional value is only null if anyerror |
| 16086 | // Value can be zero-length slice otherwise | 16276 | // Value can be zero-length slice otherwise |
| 16087 | const error_field_vals: ?[]Value = if (ty.isAnyError()) null else blk: { | 16277 | const error_field_vals = if (ty.isAnyError(mod)) null else blk: { |
| 16088 | const names = ty.errorSetNames(); | 16278 | const vals = try sema.arena.alloc(InternPool.Index, ty.errorSetNames(mod).len); |
| 16089 | const vals = try fields_anon_decl.arena().alloc(Value, names.len); | ||
| 16090 | for (vals, 0..) |*field_val, i| { | 16279 | for (vals, 0..) |*field_val, i| { |
| 16091 | const name = names[i]; | 16280 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 16281 | const name = try sema.arena.dupe(u8, ip.stringToSlice(ty.errorSetNames(mod)[i])); | ||
| 16092 | const name_val = v: { | 16282 | const name_val = v: { |
| 16093 | var anon_decl = try block.startAnonDecl(); | 16283 | var anon_decl = try block.startAnonDecl(); |
| 16094 | defer anon_decl.deinit(); | 16284 | defer anon_decl.deinit(); |
| 16095 | const bytes = try anon_decl.arena().dupeZ(u8, name); | 16285 | const new_decl_ty = try mod.arrayType(.{ |
| 16286 | .len = name.len, | ||
| 16287 | .child = .u8_type, | ||
| 16288 | }); | ||
| 16096 | const new_decl = try anon_decl.finish( | 16289 | const new_decl = try anon_decl.finish( |
| 16097 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | 16290 | new_decl_ty, |
| 16098 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | 16291 | (try mod.intern(.{ .aggregate = .{ |
| 16292 | .ty = new_decl_ty.toIntern(), | ||
| 16293 | .storage = .{ .bytes = name }, | ||
| 16294 | } })).toValue(), | ||
| 16099 | 0, // default alignment | 16295 | 0, // default alignment |
| 16100 | ); | 16296 | ); |
| 16101 | break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl); | 16297 | break :v try mod.intern(.{ .ptr = .{ |
| 16298 | .ty = .slice_const_u8_type, | ||
| 16299 | .addr = .{ .decl = new_decl }, | ||
| 16300 | .len = (try mod.intValue(Type.usize, name.len)).toIntern(), | ||
| 16301 | } }); | ||
| 16102 | }; | 16302 | }; |
| 16103 | 16303 | ||
| 16104 | const error_field_fields = try fields_anon_decl.arena().create([1]Value); | 16304 | const error_field_fields = .{ |
| 16105 | error_field_fields.* = .{ | ||
| 16106 | // name: []const u8, | 16305 | // name: []const u8, |
| 16107 | name_val, | 16306 | name_val, |
| 16108 | }; | 16307 | }; |
| 16109 | 16308 | field_val.* = try mod.intern(.{ .aggregate = .{ | |
| 16110 | field_val.* = try Value.Tag.aggregate.create( | 16309 | .ty = error_field_ty.toIntern(), |
| 16111 | fields_anon_decl.arena(), | 16310 | .storage = .{ .elems = &error_field_fields }, |
| 16112 | error_field_fields, | 16311 | } }); |
| 16113 | ); | ||
| 16114 | } | 16312 | } |
| 16115 | 16313 | ||
| 16116 | break :blk vals; | 16314 | break :blk vals; |
| 16117 | }; | 16315 | }; |
| 16118 | 16316 | ||
| 16119 | // Build our ?[]const Error value | 16317 | // Build our ?[]const Error value |
| 16120 | const errors_val = if (error_field_vals) |vals| v: { | 16318 | const slice_errors_ty = try mod.ptrType(.{ |
| 16319 | .child = error_field_ty.toIntern(), | ||
| 16320 | .flags = .{ | ||
| 16321 | .size = .Slice, | ||
| 16322 | .is_const = true, | ||
| 16323 | }, | ||
| 16324 | }); | ||
| 16325 | const opt_slice_errors_ty = try mod.optionalType(slice_errors_ty.toIntern()); | ||
| 16326 | const errors_payload_val: InternPool.Index = if (error_field_vals) |vals| v: { | ||
| 16327 | const array_errors_ty = try mod.arrayType(.{ | ||
| 16328 | .len = vals.len, | ||
| 16329 | .child = error_field_ty.toIntern(), | ||
| 16330 | .sentinel = .none, | ||
| 16331 | }); | ||
| 16121 | const new_decl = try fields_anon_decl.finish( | 16332 | const new_decl = try fields_anon_decl.finish( |
| 16122 | try Type.Tag.array.create(fields_anon_decl.arena(), .{ | 16333 | array_errors_ty, |
| 16123 | .len = vals.len, | 16334 | (try mod.intern(.{ .aggregate = .{ |
| 16124 | .elem_type = error_field_ty, | 16335 | .ty = array_errors_ty.toIntern(), |
| 16125 | }), | 16336 | .storage = .{ .elems = vals }, |
| 16126 | try Value.Tag.aggregate.create( | 16337 | } })).toValue(), |
| 16127 | fields_anon_decl.arena(), | ||
| 16128 | vals, | ||
| 16129 | ), | ||
| 16130 | 0, // default alignment | 16338 | 0, // default alignment |
| 16131 | ); | 16339 | ); |
| 16132 | 16340 | break :v try mod.intern(.{ .ptr = .{ | |
| 16133 | const new_decl_val = try Value.Tag.decl_ref.create(sema.arena, new_decl); | 16341 | .ty = slice_errors_ty.toIntern(), |
| 16134 | const slice_val = try Value.Tag.slice.create(sema.arena, .{ | 16342 | .addr = .{ .decl = new_decl }, |
| 16135 | .ptr = new_decl_val, | 16343 | .len = (try mod.intValue(Type.usize, vals.len)).toIntern(), |
| 16136 | .len = try Value.Tag.int_u64.create(sema.arena, vals.len), | 16344 | } }); |
| 16137 | }); | 16345 | } else .none; |
| 16138 | break :v try Value.Tag.opt_payload.create(sema.arena, slice_val); | 16346 | const errors_val = try mod.intern(.{ .opt = .{ |
| 16139 | } else Value.null; | 16347 | .ty = opt_slice_errors_ty.toIntern(), |
| 16348 | .val = errors_payload_val, | ||
| 16349 | } }); | ||
| 16140 | 16350 | ||
| 16141 | // Construct Type{ .ErrorSet = errors_val } | 16351 | // Construct Type{ .ErrorSet = errors_val } |
| 16142 | return sema.addConstant( | 16352 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ |
| 16143 | type_info_ty, | 16353 | .ty = type_info_ty.toIntern(), |
| 16144 | try Value.Tag.@"union".create(sema.arena, .{ | 16354 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorSet))).toIntern(), |
| 16145 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorSet)), | 16355 | .val = errors_val, |
| 16146 | .val = errors_val, | 16356 | } })).toValue()); |
| 16147 | }), | ||
| 16148 | ); | ||
| 16149 | }, | 16357 | }, |
| 16150 | .ErrorUnion => { | 16358 | .ErrorUnion => { |
| 16151 | const field_values = try sema.arena.alloc(Value, 2); | 16359 | const error_union_field_ty = t: { |
| 16152 | // error_set: type, | 16360 | const error_union_field_ty_decl_index = (try sema.namespaceLookup( |
| 16153 | field_values[0] = try Value.Tag.ty.create(sema.arena, ty.errorUnionSet()); | 16361 | block, |
| 16154 | // payload: type, | 16362 | src, |
| 16155 | field_values[1] = try Value.Tag.ty.create(sema.arena, ty.errorUnionPayload()); | 16363 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 16156 | 16364 | try ip.getOrPutString(gpa, "ErrorUnion"), | |
| 16157 | return sema.addConstant( | 16365 | )).?; |
| 16158 | type_info_ty, | 16366 | try mod.declareDeclDependency(sema.owner_decl_index, error_union_field_ty_decl_index); |
| 16159 | try Value.Tag.@"union".create(sema.arena, .{ | 16367 | try sema.ensureDeclAnalyzed(error_union_field_ty_decl_index); |
| 16160 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorUnion)), | 16368 | const error_union_field_ty_decl = mod.declPtr(error_union_field_ty_decl_index); |
| 16161 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16369 | break :t error_union_field_ty_decl.val.toType(); |
| 16162 | }), | 16370 | }; |
| 16163 | ); | 16371 | |
| 16372 | const field_values = .{ | ||
| 16373 | // error_set: type, | ||
| 16374 | ty.errorUnionSet(mod).toIntern(), | ||
| 16375 | // payload: type, | ||
| 16376 | ty.errorUnionPayload(mod).toIntern(), | ||
| 16377 | }; | ||
| 16378 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | ||
| 16379 | .ty = type_info_ty.toIntern(), | ||
| 16380 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorUnion))).toIntern(), | ||
| 16381 | .val = try mod.intern(.{ .aggregate = .{ | ||
| 16382 | .ty = error_union_field_ty.toIntern(), | ||
| 16383 | .storage = .{ .elems = &field_values }, | ||
| 16384 | } }), | ||
| 16385 | } })).toValue()); | ||
| 16164 | }, | 16386 | }, |
| 16165 | .Enum => { | 16387 | .Enum => { |
| 16166 | // TODO: look into memoizing this result. | 16388 | // TODO: look into memoizing this result. |
| 16167 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | 16389 | const is_exhaustive = Value.makeBool(ip.indexToKey(ty.toIntern()).enum_type.tag_mode != .nonexhaustive); |
| 16168 | const int_tag_ty = try ty.intTagType(&int_tag_type_buffer).copy(sema.arena); | ||
| 16169 | |||
| 16170 | const is_exhaustive = Value.makeBool(!ty.isNonexhaustiveEnum()); | ||
| 16171 | 16390 | ||
| 16172 | var fields_anon_decl = try block.startAnonDecl(); | 16391 | var fields_anon_decl = try block.startAnonDecl(); |
| 16173 | defer fields_anon_decl.deinit(); | 16392 | defer fields_anon_decl.deinit(); |
| ... | @@ -16176,88 +16395,121 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16176,88 +16395,121 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16176 | const enum_field_ty_decl_index = (try sema.namespaceLookup( | 16395 | const enum_field_ty_decl_index = (try sema.namespaceLookup( |
| 16177 | block, | 16396 | block, |
| 16178 | src, | 16397 | src, |
| 16179 | type_info_ty.getNamespace().?, | 16398 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 16180 | "EnumField", | 16399 | try ip.getOrPutString(gpa, "EnumField"), |
| 16181 | )).?; | 16400 | )).?; |
| 16182 | try sema.mod.declareDeclDependency(sema.owner_decl_index, enum_field_ty_decl_index); | 16401 | try mod.declareDeclDependency(sema.owner_decl_index, enum_field_ty_decl_index); |
| 16183 | try sema.ensureDeclAnalyzed(enum_field_ty_decl_index); | 16402 | try sema.ensureDeclAnalyzed(enum_field_ty_decl_index); |
| 16184 | const enum_field_ty_decl = sema.mod.declPtr(enum_field_ty_decl_index); | 16403 | const enum_field_ty_decl = mod.declPtr(enum_field_ty_decl_index); |
| 16185 | var buffer: Value.ToTypeBuffer = undefined; | 16404 | break :t enum_field_ty_decl.val.toType(); |
| 16186 | break :t try enum_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); | ||
| 16187 | }; | 16405 | }; |
| 16188 | 16406 | ||
| 16189 | const enum_fields = ty.enumFields(); | 16407 | const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.indexToKey(ty.toIntern()).enum_type.names.len); |
| 16190 | const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_fields.count()); | ||
| 16191 | |||
| 16192 | for (enum_field_vals, 0..) |*field_val, i| { | 16408 | for (enum_field_vals, 0..) |*field_val, i| { |
| 16193 | var tag_val_payload: Value.Payload.U32 = .{ | 16409 | const enum_type = ip.indexToKey(ty.toIntern()).enum_type; |
| 16194 | .base = .{ .tag = .enum_field_index }, | 16410 | const value_val = if (enum_type.values.len > 0) |
| 16195 | .data = @intCast(u32, i), | 16411 | try mod.intern_pool.getCoerced(gpa, enum_type.values[i], .comptime_int_type) |
| 16196 | }; | 16412 | else |
| 16197 | const tag_val = Value.initPayload(&tag_val_payload.base); | 16413 | try mod.intern(.{ .int = .{ |
| 16198 | 16414 | .ty = .comptime_int_type, | |
| 16199 | var buffer: Value.Payload.U64 = undefined; | 16415 | .storage = .{ .u64 = @intCast(u64, i) }, |
| 16200 | const int_val = try tag_val.enumToInt(ty, &buffer).copy(fields_anon_decl.arena()); | 16416 | } }); |
| 16201 | 16417 | // TODO: write something like getCoercedInts to avoid needing to dupe | |
| 16202 | const name = enum_fields.keys()[i]; | 16418 | const name = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names[i])); |
| 16203 | const name_val = v: { | 16419 | const name_val = v: { |
| 16204 | var anon_decl = try block.startAnonDecl(); | 16420 | var anon_decl = try block.startAnonDecl(); |
| 16205 | defer anon_decl.deinit(); | 16421 | defer anon_decl.deinit(); |
| 16206 | const bytes = try anon_decl.arena().dupeZ(u8, name); | 16422 | const new_decl_ty = try mod.arrayType(.{ |
| 16423 | .len = name.len, | ||
| 16424 | .child = .u8_type, | ||
| 16425 | }); | ||
| 16207 | const new_decl = try anon_decl.finish( | 16426 | const new_decl = try anon_decl.finish( |
| 16208 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | 16427 | new_decl_ty, |
| 16209 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | 16428 | (try mod.intern(.{ .aggregate = .{ |
| 16429 | .ty = new_decl_ty.toIntern(), | ||
| 16430 | .storage = .{ .bytes = name }, | ||
| 16431 | } })).toValue(), | ||
| 16210 | 0, // default alignment | 16432 | 0, // default alignment |
| 16211 | ); | 16433 | ); |
| 16212 | break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl); | 16434 | break :v try mod.intern(.{ .ptr = .{ |
| 16435 | .ty = .slice_const_u8_type, | ||
| 16436 | .addr = .{ .decl = new_decl }, | ||
| 16437 | .len = (try mod.intValue(Type.usize, name.len)).toIntern(), | ||
| 16438 | } }); | ||
| 16213 | }; | 16439 | }; |
| 16214 | 16440 | ||
| 16215 | const enum_field_fields = try fields_anon_decl.arena().create([2]Value); | 16441 | const enum_field_fields = .{ |
| 16216 | enum_field_fields.* = .{ | ||
| 16217 | // name: []const u8, | 16442 | // name: []const u8, |
| 16218 | name_val, | 16443 | name_val, |
| 16219 | // value: comptime_int, | 16444 | // value: comptime_int, |
| 16220 | int_val, | 16445 | value_val, |
| 16221 | }; | 16446 | }; |
| 16222 | field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), enum_field_fields); | 16447 | field_val.* = try mod.intern(.{ .aggregate = .{ |
| 16448 | .ty = enum_field_ty.toIntern(), | ||
| 16449 | .storage = .{ .elems = &enum_field_fields }, | ||
| 16450 | } }); | ||
| 16223 | } | 16451 | } |
| 16224 | 16452 | ||
| 16225 | const fields_val = v: { | 16453 | const fields_val = v: { |
| 16454 | const fields_array_ty = try mod.arrayType(.{ | ||
| 16455 | .len = enum_field_vals.len, | ||
| 16456 | .child = enum_field_ty.toIntern(), | ||
| 16457 | .sentinel = .none, | ||
| 16458 | }); | ||
| 16226 | const new_decl = try fields_anon_decl.finish( | 16459 | const new_decl = try fields_anon_decl.finish( |
| 16227 | try Type.Tag.array.create(fields_anon_decl.arena(), .{ | 16460 | fields_array_ty, |
| 16228 | .len = enum_field_vals.len, | 16461 | (try mod.intern(.{ .aggregate = .{ |
| 16229 | .elem_type = enum_field_ty, | 16462 | .ty = fields_array_ty.toIntern(), |
| 16230 | }), | 16463 | .storage = .{ .elems = enum_field_vals }, |
| 16231 | try Value.Tag.aggregate.create( | 16464 | } })).toValue(), |
| 16232 | fields_anon_decl.arena(), | ||
| 16233 | enum_field_vals, | ||
| 16234 | ), | ||
| 16235 | 0, // default alignment | 16465 | 0, // default alignment |
| 16236 | ); | 16466 | ); |
| 16237 | break :v try Value.Tag.decl_ref.create(sema.arena, new_decl); | 16467 | break :v try mod.intern(.{ .ptr = .{ |
| 16468 | .ty = (try mod.ptrType(.{ | ||
| 16469 | .child = enum_field_ty.toIntern(), | ||
| 16470 | .flags = .{ | ||
| 16471 | .size = .Slice, | ||
| 16472 | .is_const = true, | ||
| 16473 | }, | ||
| 16474 | })).toIntern(), | ||
| 16475 | .addr = .{ .decl = new_decl }, | ||
| 16476 | .len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(), | ||
| 16477 | } }); | ||
| 16238 | }; | 16478 | }; |
| 16239 | 16479 | ||
| 16240 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace()); | 16480 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ip.indexToKey(ty.toIntern()).enum_type.namespace); |
| 16481 | |||
| 16482 | const type_enum_ty = t: { | ||
| 16483 | const type_enum_ty_decl_index = (try sema.namespaceLookup( | ||
| 16484 | block, | ||
| 16485 | src, | ||
| 16486 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | ||
| 16487 | try ip.getOrPutString(gpa, "Enum"), | ||
| 16488 | )).?; | ||
| 16489 | try mod.declareDeclDependency(sema.owner_decl_index, type_enum_ty_decl_index); | ||
| 16490 | try sema.ensureDeclAnalyzed(type_enum_ty_decl_index); | ||
| 16491 | const type_enum_ty_decl = mod.declPtr(type_enum_ty_decl_index); | ||
| 16492 | break :t type_enum_ty_decl.val.toType(); | ||
| 16493 | }; | ||
| 16241 | 16494 | ||
| 16242 | const field_values = try sema.arena.create([4]Value); | 16495 | const field_values = .{ |
| 16243 | field_values.* = .{ | ||
| 16244 | // tag_type: type, | 16496 | // tag_type: type, |
| 16245 | try Value.Tag.ty.create(sema.arena, int_tag_ty), | 16497 | ip.indexToKey(ty.toIntern()).enum_type.tag_ty, |
| 16246 | // fields: []const EnumField, | 16498 | // fields: []const EnumField, |
| 16247 | fields_val, | 16499 | fields_val, |
| 16248 | // decls: []const Declaration, | 16500 | // decls: []const Declaration, |
| 16249 | decls_val, | 16501 | decls_val, |
| 16250 | // is_exhaustive: bool, | 16502 | // is_exhaustive: bool, |
| 16251 | is_exhaustive, | 16503 | is_exhaustive.toIntern(), |
| 16252 | }; | 16504 | }; |
| 16253 | 16505 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16254 | return sema.addConstant( | 16506 | .ty = type_info_ty.toIntern(), |
| 16255 | type_info_ty, | 16507 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Enum))).toIntern(), |
| 16256 | try Value.Tag.@"union".create(sema.arena, .{ | 16508 | .val = try mod.intern(.{ .aggregate = .{ |
| 16257 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Enum)), | 16509 | .ty = type_enum_ty.toIntern(), |
| 16258 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16510 | .storage = .{ .elems = &field_values }, |
| 16259 | }), | 16511 | } }), |
| 16260 | ); | 16512 | } })).toValue()); |
| 16261 | }, | 16513 | }, |
| 16262 | .Union => { | 16514 | .Union => { |
| 16263 | // TODO: look into memoizing this result. | 16515 | // TODO: look into memoizing this result. |
| ... | @@ -16265,91 +16517,135 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16265,91 +16517,135 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16265 | var fields_anon_decl = try block.startAnonDecl(); | 16517 | var fields_anon_decl = try block.startAnonDecl(); |
| 16266 | defer fields_anon_decl.deinit(); | 16518 | defer fields_anon_decl.deinit(); |
| 16267 | 16519 | ||
| 16520 | const type_union_ty = t: { | ||
| 16521 | const type_union_ty_decl_index = (try sema.namespaceLookup( | ||
| 16522 | block, | ||
| 16523 | src, | ||
| 16524 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | ||
| 16525 | try ip.getOrPutString(gpa, "Union"), | ||
| 16526 | )).?; | ||
| 16527 | try mod.declareDeclDependency(sema.owner_decl_index, type_union_ty_decl_index); | ||
| 16528 | try sema.ensureDeclAnalyzed(type_union_ty_decl_index); | ||
| 16529 | const type_union_ty_decl = mod.declPtr(type_union_ty_decl_index); | ||
| 16530 | break :t type_union_ty_decl.val.toType(); | ||
| 16531 | }; | ||
| 16532 | |||
| 16268 | const union_field_ty = t: { | 16533 | const union_field_ty = t: { |
| 16269 | const union_field_ty_decl_index = (try sema.namespaceLookup( | 16534 | const union_field_ty_decl_index = (try sema.namespaceLookup( |
| 16270 | block, | 16535 | block, |
| 16271 | src, | 16536 | src, |
| 16272 | type_info_ty.getNamespace().?, | 16537 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 16273 | "UnionField", | 16538 | try ip.getOrPutString(gpa, "UnionField"), |
| 16274 | )).?; | 16539 | )).?; |
| 16275 | try sema.mod.declareDeclDependency(sema.owner_decl_index, union_field_ty_decl_index); | 16540 | try mod.declareDeclDependency(sema.owner_decl_index, union_field_ty_decl_index); |
| 16276 | try sema.ensureDeclAnalyzed(union_field_ty_decl_index); | 16541 | try sema.ensureDeclAnalyzed(union_field_ty_decl_index); |
| 16277 | const union_field_ty_decl = sema.mod.declPtr(union_field_ty_decl_index); | 16542 | const union_field_ty_decl = mod.declPtr(union_field_ty_decl_index); |
| 16278 | var buffer: Value.ToTypeBuffer = undefined; | 16543 | break :t union_field_ty_decl.val.toType(); |
| 16279 | break :t try union_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); | ||
| 16280 | }; | 16544 | }; |
| 16281 | 16545 | ||
| 16282 | const union_ty = try sema.resolveTypeFields(ty); | 16546 | const union_ty = try sema.resolveTypeFields(ty); |
| 16283 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout | 16547 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout |
| 16284 | const layout = union_ty.containerLayout(); | 16548 | const layout = union_ty.containerLayout(mod); |
| 16285 | 16549 | ||
| 16286 | const union_fields = union_ty.unionFields(); | 16550 | const union_fields = union_ty.unionFields(mod); |
| 16287 | const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count()); | 16551 | const union_field_vals = try gpa.alloc(InternPool.Index, union_fields.count()); |
| 16552 | defer gpa.free(union_field_vals); | ||
| 16288 | 16553 | ||
| 16289 | for (union_field_vals, 0..) |*field_val, i| { | 16554 | for (union_field_vals, 0..) |*field_val, i| { |
| 16290 | const field = union_fields.values()[i]; | 16555 | const field = union_fields.values()[i]; |
| 16291 | const name = union_fields.keys()[i]; | 16556 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 16557 | const name = try sema.arena.dupe(u8, ip.stringToSlice(union_fields.keys()[i])); | ||
| 16292 | const name_val = v: { | 16558 | const name_val = v: { |
| 16293 | var anon_decl = try block.startAnonDecl(); | 16559 | var anon_decl = try block.startAnonDecl(); |
| 16294 | defer anon_decl.deinit(); | 16560 | defer anon_decl.deinit(); |
| 16295 | const bytes = try anon_decl.arena().dupeZ(u8, name); | 16561 | const new_decl_ty = try mod.arrayType(.{ |
| 16562 | .len = name.len, | ||
| 16563 | .child = .u8_type, | ||
| 16564 | }); | ||
| 16296 | const new_decl = try anon_decl.finish( | 16565 | const new_decl = try anon_decl.finish( |
| 16297 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | 16566 | new_decl_ty, |
| 16298 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | 16567 | (try mod.intern(.{ .aggregate = .{ |
| 16568 | .ty = new_decl_ty.toIntern(), | ||
| 16569 | .storage = .{ .bytes = name }, | ||
| 16570 | } })).toValue(), | ||
| 16299 | 0, // default alignment | 16571 | 0, // default alignment |
| 16300 | ); | 16572 | ); |
| 16301 | break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl); | 16573 | break :v try mod.intern(.{ .ptr = .{ |
| 16574 | .ty = .slice_const_u8_type, | ||
| 16575 | .addr = .{ .decl = new_decl }, | ||
| 16576 | .len = (try mod.intValue(Type.usize, name.len)).toIntern(), | ||
| 16577 | } }); | ||
| 16302 | }; | 16578 | }; |
| 16303 | 16579 | ||
| 16304 | const union_field_fields = try fields_anon_decl.arena().create([3]Value); | ||
| 16305 | const alignment = switch (layout) { | 16580 | const alignment = switch (layout) { |
| 16306 | .Auto, .Extern => try sema.unionFieldAlignment(field), | 16581 | .Auto, .Extern => try sema.unionFieldAlignment(field), |
| 16307 | .Packed => 0, | 16582 | .Packed => 0, |
| 16308 | }; | 16583 | }; |
| 16309 | 16584 | ||
| 16310 | union_field_fields.* = .{ | 16585 | const union_field_fields = .{ |
| 16311 | // name: []const u8, | 16586 | // name: []const u8, |
| 16312 | name_val, | 16587 | name_val, |
| 16313 | // type: type, | 16588 | // type: type, |
| 16314 | try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty), | 16589 | field.ty.toIntern(), |
| 16315 | // alignment: comptime_int, | 16590 | // alignment: comptime_int, |
| 16316 | try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment), | 16591 | (try mod.intValue(Type.comptime_int, alignment)).toIntern(), |
| 16317 | }; | 16592 | }; |
| 16318 | field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), union_field_fields); | 16593 | field_val.* = try mod.intern(.{ .aggregate = .{ |
| 16594 | .ty = union_field_ty.toIntern(), | ||
| 16595 | .storage = .{ .elems = &union_field_fields }, | ||
| 16596 | } }); | ||
| 16319 | } | 16597 | } |
| 16320 | 16598 | ||
| 16321 | const fields_val = v: { | 16599 | const fields_val = v: { |
| 16600 | const array_fields_ty = try mod.arrayType(.{ | ||
| 16601 | .len = union_field_vals.len, | ||
| 16602 | .child = union_field_ty.toIntern(), | ||
| 16603 | .sentinel = .none, | ||
| 16604 | }); | ||
| 16322 | const new_decl = try fields_anon_decl.finish( | 16605 | const new_decl = try fields_anon_decl.finish( |
| 16323 | try Type.Tag.array.create(fields_anon_decl.arena(), .{ | 16606 | array_fields_ty, |
| 16324 | .len = union_field_vals.len, | 16607 | (try mod.intern(.{ .aggregate = .{ |
| 16325 | .elem_type = union_field_ty, | 16608 | .ty = array_fields_ty.toIntern(), |
| 16326 | }), | 16609 | .storage = .{ .elems = union_field_vals }, |
| 16327 | try Value.Tag.aggregate.create( | 16610 | } })).toValue(), |
| 16328 | fields_anon_decl.arena(), | ||
| 16329 | try fields_anon_decl.arena().dupe(Value, union_field_vals), | ||
| 16330 | ), | ||
| 16331 | 0, // default alignment | 16611 | 0, // default alignment |
| 16332 | ); | 16612 | ); |
| 16333 | break :v try Value.Tag.slice.create(sema.arena, .{ | 16613 | break :v try mod.intern(.{ .ptr = .{ |
| 16334 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | 16614 | .ty = (try mod.ptrType(.{ |
| 16335 | .len = try Value.Tag.int_u64.create(sema.arena, union_field_vals.len), | 16615 | .child = union_field_ty.toIntern(), |
| 16336 | }); | 16616 | .flags = .{ |
| 16617 | .size = .Slice, | ||
| 16618 | .is_const = true, | ||
| 16619 | }, | ||
| 16620 | })).toIntern(), | ||
| 16621 | .addr = .{ .decl = new_decl }, | ||
| 16622 | .len = (try mod.intValue(Type.usize, union_field_vals.len)).toIntern(), | ||
| 16623 | } }); | ||
| 16337 | }; | 16624 | }; |
| 16338 | 16625 | ||
| 16339 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace()); | 16626 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespaceIndex(mod)); |
| 16340 | 16627 | ||
| 16341 | const enum_tag_ty_val = if (union_ty.unionTagType()) |tag_ty| v: { | 16628 | const enum_tag_ty_val = try mod.intern(.{ .opt = .{ |
| 16342 | const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty); | 16629 | .ty = (try mod.optionalType(.type_type)).toIntern(), |
| 16343 | break :v try Value.Tag.opt_payload.create(sema.arena, ty_val); | 16630 | .val = if (union_ty.unionTagType(mod)) |tag_ty| tag_ty.toIntern() else .none, |
| 16344 | } else Value.null; | 16631 | } }); |
| 16632 | |||
| 16633 | const container_layout_ty = t: { | ||
| 16634 | const decl_index = (try sema.namespaceLookup( | ||
| 16635 | block, | ||
| 16636 | src, | ||
| 16637 | (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?, | ||
| 16638 | try ip.getOrPutString(gpa, "ContainerLayout"), | ||
| 16639 | )).?; | ||
| 16640 | try mod.declareDeclDependency(sema.owner_decl_index, decl_index); | ||
| 16641 | try sema.ensureDeclAnalyzed(decl_index); | ||
| 16642 | const decl = mod.declPtr(decl_index); | ||
| 16643 | break :t decl.val.toType(); | ||
| 16644 | }; | ||
| 16345 | 16645 | ||
| 16346 | const field_values = try sema.arena.create([4]Value); | 16646 | const field_values = .{ |
| 16347 | field_values.* = .{ | ||
| 16348 | // layout: ContainerLayout, | 16647 | // layout: ContainerLayout, |
| 16349 | try Value.Tag.enum_field_index.create( | 16648 | (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).toIntern(), |
| 16350 | sema.arena, | ||
| 16351 | @enumToInt(layout), | ||
| 16352 | ), | ||
| 16353 | 16649 | ||
| 16354 | // tag_type: ?type, | 16650 | // tag_type: ?type, |
| 16355 | enum_tag_ty_val, | 16651 | enum_tag_ty_val, |
| ... | @@ -16358,14 +16654,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16358,14 +16654,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16358 | // decls: []const Declaration, | 16654 | // decls: []const Declaration, |
| 16359 | decls_val, | 16655 | decls_val, |
| 16360 | }; | 16656 | }; |
| 16361 | 16657 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16362 | return sema.addConstant( | 16658 | .ty = type_info_ty.toIntern(), |
| 16363 | type_info_ty, | 16659 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Union))).toIntern(), |
| 16364 | try Value.Tag.@"union".create(sema.arena, .{ | 16660 | .val = try mod.intern(.{ .aggregate = .{ |
| 16365 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Union)), | 16661 | .ty = type_union_ty.toIntern(), |
| 16366 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16662 | .storage = .{ .elems = &field_values }, |
| 16367 | }), | 16663 | } }), |
| 16368 | ); | 16664 | } })).toValue()); |
| 16369 | }, | 16665 | }, |
| 16370 | .Struct => { | 16666 | .Struct => { |
| 16371 | // TODO: look into memoizing this result. | 16667 | // TODO: look into memoizing this result. |
| ... | @@ -16373,154 +16669,212 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16373,154 +16669,212 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16373 | var fields_anon_decl = try block.startAnonDecl(); | 16669 | var fields_anon_decl = try block.startAnonDecl(); |
| 16374 | defer fields_anon_decl.deinit(); | 16670 | defer fields_anon_decl.deinit(); |
| 16375 | 16671 | ||
| 16376 | const struct_field_ty = t: { | 16672 | const type_struct_ty = t: { |
| 16377 | const struct_field_ty_decl_index = (try sema.namespaceLookup( | 16673 | const type_struct_ty_decl_index = (try sema.namespaceLookup( |
| 16378 | block, | 16674 | block, |
| 16379 | src, | 16675 | src, |
| 16380 | type_info_ty.getNamespace().?, | 16676 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 16381 | "StructField", | 16677 | try ip.getOrPutString(gpa, "Struct"), |
| 16382 | )).?; | 16678 | )).?; |
| 16383 | try sema.mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index); | 16679 | try mod.declareDeclDependency(sema.owner_decl_index, type_struct_ty_decl_index); |
| 16384 | try sema.ensureDeclAnalyzed(struct_field_ty_decl_index); | 16680 | try sema.ensureDeclAnalyzed(type_struct_ty_decl_index); |
| 16385 | const struct_field_ty_decl = sema.mod.declPtr(struct_field_ty_decl_index); | 16681 | const type_struct_ty_decl = mod.declPtr(type_struct_ty_decl_index); |
| 16386 | var buffer: Value.ToTypeBuffer = undefined; | 16682 | break :t type_struct_ty_decl.val.toType(); |
| 16387 | break :t try struct_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena()); | ||
| 16388 | }; | 16683 | }; |
| 16389 | const struct_ty = try sema.resolveTypeFields(ty); | ||
| 16390 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout | ||
| 16391 | const layout = struct_ty.containerLayout(); | ||
| 16392 | |||
| 16393 | const struct_field_vals = fv: { | ||
| 16394 | if (struct_ty.isSimpleTupleOrAnonStruct()) { | ||
| 16395 | const tuple = struct_ty.tupleFields(); | ||
| 16396 | const field_types = tuple.types; | ||
| 16397 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len); | ||
| 16398 | for (struct_field_vals, 0..) |*struct_field_val, i| { | ||
| 16399 | const field_ty = field_types[i]; | ||
| 16400 | const name_val = v: { | ||
| 16401 | var anon_decl = try block.startAnonDecl(); | ||
| 16402 | defer anon_decl.deinit(); | ||
| 16403 | const bytes = if (struct_ty.castTag(.anon_struct)) |payload| | ||
| 16404 | try anon_decl.arena().dupeZ(u8, payload.data.names[i]) | ||
| 16405 | else | ||
| 16406 | try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i}); | ||
| 16407 | const new_decl = try anon_decl.finish( | ||
| 16408 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | ||
| 16409 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | ||
| 16410 | 0, // default alignment | ||
| 16411 | ); | ||
| 16412 | break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ | ||
| 16413 | .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), | ||
| 16414 | .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len), | ||
| 16415 | }); | ||
| 16416 | }; | ||
| 16417 | 16684 | ||
| 16418 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); | 16685 | const struct_field_ty = t: { |
| 16419 | const field_val = tuple.values[i]; | 16686 | const struct_field_ty_decl_index = (try sema.namespaceLookup( |
| 16420 | const is_comptime = field_val.tag() != .unreachable_value; | 16687 | block, |
| 16421 | const opt_default_val = if (is_comptime) field_val else null; | 16688 | src, |
| 16422 | const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val); | 16689 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 16423 | struct_field_fields.* = .{ | 16690 | try ip.getOrPutString(gpa, "StructField"), |
| 16424 | // name: []const u8, | 16691 | )).?; |
| 16425 | name_val, | 16692 | try mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index); |
| 16426 | // type: type, | 16693 | try sema.ensureDeclAnalyzed(struct_field_ty_decl_index); |
| 16427 | try Value.Tag.ty.create(fields_anon_decl.arena(), field_ty), | 16694 | const struct_field_ty_decl = mod.declPtr(struct_field_ty_decl_index); |
| 16428 | // default_value: ?*const anyopaque, | 16695 | break :t struct_field_ty_decl.val.toType(); |
| 16429 | try default_val_ptr.copy(fields_anon_decl.arena()), | 16696 | }; |
| 16430 | // is_comptime: bool, | 16697 | |
| 16431 | Value.makeBool(is_comptime), | 16698 | const struct_ty = try sema.resolveTypeFields(ty); |
| 16432 | // alignment: comptime_int, | 16699 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout |
| 16433 | try field_ty.lazyAbiAlignment(target, fields_anon_decl.arena()), | 16700 | const layout = struct_ty.containerLayout(mod); |
| 16434 | }; | 16701 | |
| 16435 | struct_field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields); | 16702 | var struct_field_vals: []InternPool.Index = &.{}; |
| 16436 | } | 16703 | defer gpa.free(struct_field_vals); |
| 16437 | break :fv struct_field_vals; | 16704 | fv: { |
| 16438 | } | 16705 | const struct_type = switch (ip.indexToKey(struct_ty.toIntern())) { |
| 16439 | const struct_fields = struct_ty.structFields(); | 16706 | .anon_struct_type => |tuple| { |
| 16440 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_fields.count()); | 16707 | struct_field_vals = try gpa.alloc(InternPool.Index, tuple.types.len); |
| 16708 | for (struct_field_vals, 0..) |*struct_field_val, i| { | ||
| 16709 | const anon_struct_type = ip.indexToKey(struct_ty.toIntern()).anon_struct_type; | ||
| 16710 | const field_ty = anon_struct_type.types[i]; | ||
| 16711 | const field_val = anon_struct_type.values[i]; | ||
| 16712 | const name_val = v: { | ||
| 16713 | var anon_decl = try block.startAnonDecl(); | ||
| 16714 | defer anon_decl.deinit(); | ||
| 16715 | // TODO: write something like getCoercedInts to avoid needing to dupe | ||
| 16716 | const bytes = if (tuple.names.len != 0) | ||
| 16717 | // https://github.com/ziglang/zig/issues/15709 | ||
| 16718 | try sema.arena.dupe(u8, ip.stringToSlice(ip.indexToKey(struct_ty.toIntern()).anon_struct_type.names[i])) | ||
| 16719 | else | ||
| 16720 | try std.fmt.allocPrint(sema.arena, "{d}", .{i}); | ||
| 16721 | const new_decl_ty = try mod.arrayType(.{ | ||
| 16722 | .len = bytes.len, | ||
| 16723 | .child = .u8_type, | ||
| 16724 | }); | ||
| 16725 | const new_decl = try anon_decl.finish( | ||
| 16726 | new_decl_ty, | ||
| 16727 | (try mod.intern(.{ .aggregate = .{ | ||
| 16728 | .ty = new_decl_ty.toIntern(), | ||
| 16729 | .storage = .{ .bytes = bytes }, | ||
| 16730 | } })).toValue(), | ||
| 16731 | 0, // default alignment | ||
| 16732 | ); | ||
| 16733 | break :v try mod.intern(.{ .ptr = .{ | ||
| 16734 | .ty = .slice_const_u8_type, | ||
| 16735 | .addr = .{ .decl = new_decl }, | ||
| 16736 | .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(), | ||
| 16737 | } }); | ||
| 16738 | }; | ||
| 16441 | 16739 | ||
| 16442 | for (struct_field_vals, 0..) |*field_val, i| { | 16740 | const is_comptime = field_val != .none; |
| 16443 | const field = struct_fields.values()[i]; | 16741 | const opt_default_val = if (is_comptime) field_val.toValue() else null; |
| 16444 | const name = struct_fields.keys()[i]; | 16742 | const default_val_ptr = try sema.optRefValue(block, field_ty.toType(), opt_default_val); |
| 16743 | const struct_field_fields = .{ | ||
| 16744 | // name: []const u8, | ||
| 16745 | name_val, | ||
| 16746 | // type: type, | ||
| 16747 | field_ty, | ||
| 16748 | // default_value: ?*const anyopaque, | ||
| 16749 | default_val_ptr.toIntern(), | ||
| 16750 | // is_comptime: bool, | ||
| 16751 | Value.makeBool(is_comptime).toIntern(), | ||
| 16752 | // alignment: comptime_int, | ||
| 16753 | (try mod.intValue(Type.comptime_int, field_ty.toType().abiAlignment(mod))).toIntern(), | ||
| 16754 | }; | ||
| 16755 | struct_field_val.* = try mod.intern(.{ .aggregate = .{ | ||
| 16756 | .ty = struct_field_ty.toIntern(), | ||
| 16757 | .storage = .{ .elems = &struct_field_fields }, | ||
| 16758 | } }); | ||
| 16759 | } | ||
| 16760 | break :fv; | ||
| 16761 | }, | ||
| 16762 | .struct_type => |s| s, | ||
| 16763 | else => unreachable, | ||
| 16764 | }; | ||
| 16765 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :fv; | ||
| 16766 | struct_field_vals = try gpa.alloc(InternPool.Index, struct_obj.fields.count()); | ||
| 16767 | |||
| 16768 | for ( | ||
| 16769 | struct_field_vals, | ||
| 16770 | struct_obj.fields.keys(), | ||
| 16771 | struct_obj.fields.values(), | ||
| 16772 | ) |*field_val, name_nts, field| { | ||
| 16773 | // TODO: write something like getCoercedInts to avoid needing to dupe | ||
| 16774 | const name = try sema.arena.dupe(u8, ip.stringToSlice(name_nts)); | ||
| 16445 | const name_val = v: { | 16775 | const name_val = v: { |
| 16446 | var anon_decl = try block.startAnonDecl(); | 16776 | var anon_decl = try block.startAnonDecl(); |
| 16447 | defer anon_decl.deinit(); | 16777 | defer anon_decl.deinit(); |
| 16448 | const bytes = try anon_decl.arena().dupeZ(u8, name); | 16778 | const new_decl_ty = try mod.arrayType(.{ |
| 16779 | .len = name.len, | ||
| 16780 | .child = .u8_type, | ||
| 16781 | }); | ||
| 16449 | const new_decl = try anon_decl.finish( | 16782 | const new_decl = try anon_decl.finish( |
| 16450 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | 16783 | new_decl_ty, |
| 16451 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | 16784 | (try mod.intern(.{ .aggregate = .{ |
| 16785 | .ty = new_decl_ty.toIntern(), | ||
| 16786 | .storage = .{ .bytes = name }, | ||
| 16787 | } })).toValue(), | ||
| 16452 | 0, // default alignment | 16788 | 0, // default alignment |
| 16453 | ); | 16789 | ); |
| 16454 | break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ | 16790 | break :v try mod.intern(.{ .ptr = .{ |
| 16455 | .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), | 16791 | .ty = .slice_const_u8_type, |
| 16456 | .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len), | 16792 | .addr = .{ .decl = new_decl }, |
| 16457 | }); | 16793 | .len = (try mod.intValue(Type.usize, name.len)).toIntern(), |
| 16794 | } }); | ||
| 16458 | }; | 16795 | }; |
| 16459 | 16796 | ||
| 16460 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); | 16797 | const opt_default_val = if (field.default_val == .none) |
| 16461 | const opt_default_val = if (field.default_val.tag() == .unreachable_value) | ||
| 16462 | null | 16798 | null |
| 16463 | else | 16799 | else |
| 16464 | field.default_val; | 16800 | field.default_val.toValue(); |
| 16465 | const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val); | 16801 | const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val); |
| 16466 | const alignment = field.alignment(target, layout); | 16802 | const alignment = field.alignment(mod, layout); |
| 16467 | 16803 | ||
| 16468 | struct_field_fields.* = .{ | 16804 | const struct_field_fields = .{ |
| 16469 | // name: []const u8, | 16805 | // name: []const u8, |
| 16470 | name_val, | 16806 | name_val, |
| 16471 | // type: type, | 16807 | // type: type, |
| 16472 | try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty), | 16808 | field.ty.toIntern(), |
| 16473 | // default_value: ?*const anyopaque, | 16809 | // default_value: ?*const anyopaque, |
| 16474 | try default_val_ptr.copy(fields_anon_decl.arena()), | 16810 | default_val_ptr.toIntern(), |
| 16475 | // is_comptime: bool, | 16811 | // is_comptime: bool, |
| 16476 | Value.makeBool(field.is_comptime), | 16812 | Value.makeBool(field.is_comptime).toIntern(), |
| 16477 | // alignment: comptime_int, | 16813 | // alignment: comptime_int, |
| 16478 | try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment), | 16814 | (try mod.intValue(Type.comptime_int, alignment)).toIntern(), |
| 16479 | }; | 16815 | }; |
| 16480 | field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields); | 16816 | field_val.* = try mod.intern(.{ .aggregate = .{ |
| 16817 | .ty = struct_field_ty.toIntern(), | ||
| 16818 | .storage = .{ .elems = &struct_field_fields }, | ||
| 16819 | } }); | ||
| 16481 | } | 16820 | } |
| 16482 | break :fv struct_field_vals; | 16821 | } |
| 16483 | }; | ||
| 16484 | 16822 | ||
| 16485 | const fields_val = v: { | 16823 | const fields_val = v: { |
| 16824 | const array_fields_ty = try mod.arrayType(.{ | ||
| 16825 | .len = struct_field_vals.len, | ||
| 16826 | .child = struct_field_ty.toIntern(), | ||
| 16827 | .sentinel = .none, | ||
| 16828 | }); | ||
| 16486 | const new_decl = try fields_anon_decl.finish( | 16829 | const new_decl = try fields_anon_decl.finish( |
| 16487 | try Type.Tag.array.create(fields_anon_decl.arena(), .{ | 16830 | array_fields_ty, |
| 16488 | .len = struct_field_vals.len, | 16831 | (try mod.intern(.{ .aggregate = .{ |
| 16489 | .elem_type = struct_field_ty, | 16832 | .ty = array_fields_ty.toIntern(), |
| 16490 | }), | 16833 | .storage = .{ .elems = struct_field_vals }, |
| 16491 | try Value.Tag.aggregate.create( | 16834 | } })).toValue(), |
| 16492 | fields_anon_decl.arena(), | ||
| 16493 | try fields_anon_decl.arena().dupe(Value, struct_field_vals), | ||
| 16494 | ), | ||
| 16495 | 0, // default alignment | 16835 | 0, // default alignment |
| 16496 | ); | 16836 | ); |
| 16497 | break :v try Value.Tag.slice.create(sema.arena, .{ | 16837 | break :v try mod.intern(.{ .ptr = .{ |
| 16498 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | 16838 | .ty = (try mod.ptrType(.{ |
| 16499 | .len = try Value.Tag.int_u64.create(sema.arena, struct_field_vals.len), | 16839 | .child = struct_field_ty.toIntern(), |
| 16500 | }); | 16840 | .flags = .{ |
| 16841 | .size = .Slice, | ||
| 16842 | .is_const = true, | ||
| 16843 | }, | ||
| 16844 | })).toIntern(), | ||
| 16845 | .addr = .{ .decl = new_decl }, | ||
| 16846 | .len = (try mod.intValue(Type.usize, struct_field_vals.len)).toIntern(), | ||
| 16847 | } }); | ||
| 16501 | }; | 16848 | }; |
| 16502 | 16849 | ||
| 16503 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespace()); | 16850 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespaceIndex(mod)); |
| 16504 | 16851 | ||
| 16505 | const backing_integer_val = blk: { | 16852 | const backing_integer_val = try mod.intern(.{ .opt = .{ |
| 16506 | if (layout == .Packed) { | 16853 | .ty = (try mod.optionalType(.type_type)).toIntern(), |
| 16507 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 16854 | .val = if (layout == .Packed) val: { |
| 16855 | const struct_obj = mod.typeToStruct(struct_ty).?; | ||
| 16508 | assert(struct_obj.haveLayout()); | 16856 | assert(struct_obj.haveLayout()); |
| 16509 | assert(struct_obj.backing_int_ty.isInt()); | 16857 | assert(struct_obj.backing_int_ty.isInt(mod)); |
| 16510 | const backing_int_ty_val = try Value.Tag.ty.create(sema.arena, struct_obj.backing_int_ty); | 16858 | break :val struct_obj.backing_int_ty.toIntern(); |
| 16511 | break :blk try Value.Tag.opt_payload.create(sema.arena, backing_int_ty_val); | 16859 | } else .none, |
| 16512 | } else { | 16860 | } }); |
| 16513 | break :blk Value.initTag(.null_value); | 16861 | |
| 16514 | } | 16862 | const container_layout_ty = t: { |
| 16863 | const decl_index = (try sema.namespaceLookup( | ||
| 16864 | block, | ||
| 16865 | src, | ||
| 16866 | (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?, | ||
| 16867 | try ip.getOrPutString(gpa, "ContainerLayout"), | ||
| 16868 | )).?; | ||
| 16869 | try mod.declareDeclDependency(sema.owner_decl_index, decl_index); | ||
| 16870 | try sema.ensureDeclAnalyzed(decl_index); | ||
| 16871 | const decl = mod.declPtr(decl_index); | ||
| 16872 | break :t decl.val.toType(); | ||
| 16515 | }; | 16873 | }; |
| 16516 | 16874 | ||
| 16517 | const field_values = try sema.arena.create([5]Value); | 16875 | const field_values = [_]InternPool.Index{ |
| 16518 | field_values.* = .{ | ||
| 16519 | // layout: ContainerLayout, | 16876 | // layout: ContainerLayout, |
| 16520 | try Value.Tag.enum_field_index.create( | 16877 | (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).toIntern(), |
| 16521 | sema.arena, | ||
| 16522 | @enumToInt(layout), | ||
| 16523 | ), | ||
| 16524 | // backing_integer: ?type, | 16878 | // backing_integer: ?type, |
| 16525 | backing_integer_val, | 16879 | backing_integer_val, |
| 16526 | // fields: []const StructField, | 16880 | // fields: []const StructField, |
| ... | @@ -16528,36 +16882,48 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16528,36 +16882,48 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16528 | // decls: []const Declaration, | 16882 | // decls: []const Declaration, |
| 16529 | decls_val, | 16883 | decls_val, |
| 16530 | // is_tuple: bool, | 16884 | // is_tuple: bool, |
| 16531 | Value.makeBool(struct_ty.isTuple()), | 16885 | Value.makeBool(struct_ty.isTuple(mod)).toIntern(), |
| 16532 | }; | 16886 | }; |
| 16533 | 16887 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16534 | return sema.addConstant( | 16888 | .ty = type_info_ty.toIntern(), |
| 16535 | type_info_ty, | 16889 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Struct))).toIntern(), |
| 16536 | try Value.Tag.@"union".create(sema.arena, .{ | 16890 | .val = try mod.intern(.{ .aggregate = .{ |
| 16537 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Struct)), | 16891 | .ty = type_struct_ty.toIntern(), |
| 16538 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16892 | .storage = .{ .elems = &field_values }, |
| 16539 | }), | 16893 | } }), |
| 16540 | ); | 16894 | } })).toValue()); |
| 16541 | }, | 16895 | }, |
| 16542 | .Opaque => { | 16896 | .Opaque => { |
| 16543 | // TODO: look into memoizing this result. | 16897 | // TODO: look into memoizing this result. |
| 16544 | 16898 | ||
| 16899 | const type_opaque_ty = t: { | ||
| 16900 | const type_opaque_ty_decl_index = (try sema.namespaceLookup( | ||
| 16901 | block, | ||
| 16902 | src, | ||
| 16903 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | ||
| 16904 | try ip.getOrPutString(gpa, "Opaque"), | ||
| 16905 | )).?; | ||
| 16906 | try mod.declareDeclDependency(sema.owner_decl_index, type_opaque_ty_decl_index); | ||
| 16907 | try sema.ensureDeclAnalyzed(type_opaque_ty_decl_index); | ||
| 16908 | const type_opaque_ty_decl = mod.declPtr(type_opaque_ty_decl_index); | ||
| 16909 | break :t type_opaque_ty_decl.val.toType(); | ||
| 16910 | }; | ||
| 16911 | |||
| 16545 | const opaque_ty = try sema.resolveTypeFields(ty); | 16912 | const opaque_ty = try sema.resolveTypeFields(ty); |
| 16546 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespace()); | 16913 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespaceIndex(mod)); |
| 16547 | 16914 | ||
| 16548 | const field_values = try sema.arena.create([1]Value); | 16915 | const field_values = .{ |
| 16549 | field_values.* = .{ | ||
| 16550 | // decls: []const Declaration, | 16916 | // decls: []const Declaration, |
| 16551 | decls_val, | 16917 | decls_val, |
| 16552 | }; | 16918 | }; |
| 16553 | 16919 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16554 | return sema.addConstant( | 16920 | .ty = type_info_ty.toIntern(), |
| 16555 | type_info_ty, | 16921 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Opaque))).toIntern(), |
| 16556 | try Value.Tag.@"union".create(sema.arena, .{ | 16922 | .val = try mod.intern(.{ .aggregate = .{ |
| 16557 | .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Opaque)), | 16923 | .ty = type_opaque_ty.toIntern(), |
| 16558 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | 16924 | .storage = .{ .elems = &field_values }, |
| 16559 | }), | 16925 | } }), |
| 16560 | ); | 16926 | } })).toValue()); |
| 16561 | }, | 16927 | }, |
| 16562 | .Frame => return sema.failWithUseOfAsync(block, src), | 16928 | .Frame => return sema.failWithUseOfAsync(block, src), |
| 16563 | .AnyFrame => return sema.failWithUseOfAsync(block, src), | 16929 | .AnyFrame => return sema.failWithUseOfAsync(block, src), |
| ... | @@ -16569,8 +16935,11 @@ fn typeInfoDecls( | ... | @@ -16569,8 +16935,11 @@ fn typeInfoDecls( |
| 16569 | block: *Block, | 16935 | block: *Block, |
| 16570 | src: LazySrcLoc, | 16936 | src: LazySrcLoc, |
| 16571 | type_info_ty: Type, | 16937 | type_info_ty: Type, |
| 16572 | opt_namespace: ?*Module.Namespace, | 16938 | opt_namespace: Module.Namespace.OptionalIndex, |
| 16573 | ) CompileError!Value { | 16939 | ) CompileError!InternPool.Index { |
| 16940 | const mod = sema.mod; | ||
| 16941 | const gpa = sema.gpa; | ||
| 16942 | |||
| 16574 | var decls_anon_decl = try block.startAnonDecl(); | 16943 | var decls_anon_decl = try block.startAnonDecl(); |
| 16575 | defer decls_anon_decl.deinit(); | 16944 | defer decls_anon_decl.deinit(); |
| 16576 | 16945 | ||
| ... | @@ -16578,89 +16947,110 @@ fn typeInfoDecls( | ... | @@ -16578,89 +16947,110 @@ fn typeInfoDecls( |
| 16578 | const declaration_ty_decl_index = (try sema.namespaceLookup( | 16947 | const declaration_ty_decl_index = (try sema.namespaceLookup( |
| 16579 | block, | 16948 | block, |
| 16580 | src, | 16949 | src, |
| 16581 | type_info_ty.getNamespace().?, | 16950 | type_info_ty.getNamespaceIndex(mod).unwrap().?, |
| 16582 | "Declaration", | 16951 | try mod.intern_pool.getOrPutString(gpa, "Declaration"), |
| 16583 | )).?; | 16952 | )).?; |
| 16584 | try sema.mod.declareDeclDependency(sema.owner_decl_index, declaration_ty_decl_index); | 16953 | try mod.declareDeclDependency(sema.owner_decl_index, declaration_ty_decl_index); |
| 16585 | try sema.ensureDeclAnalyzed(declaration_ty_decl_index); | 16954 | try sema.ensureDeclAnalyzed(declaration_ty_decl_index); |
| 16586 | const declaration_ty_decl = sema.mod.declPtr(declaration_ty_decl_index); | 16955 | const declaration_ty_decl = mod.declPtr(declaration_ty_decl_index); |
| 16587 | var buffer: Value.ToTypeBuffer = undefined; | 16956 | break :t declaration_ty_decl.val.toType(); |
| 16588 | break :t try declaration_ty_decl.val.toType(&buffer).copy(decls_anon_decl.arena()); | ||
| 16589 | }; | 16957 | }; |
| 16590 | try sema.queueFullTypeResolution(try declaration_ty.copy(sema.arena)); | 16958 | try sema.queueFullTypeResolution(declaration_ty); |
| 16591 | 16959 | ||
| 16592 | var decl_vals = std.ArrayList(Value).init(sema.gpa); | 16960 | var decl_vals = std.ArrayList(InternPool.Index).init(gpa); |
| 16593 | defer decl_vals.deinit(); | 16961 | defer decl_vals.deinit(); |
| 16594 | 16962 | ||
| 16595 | var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa); | 16963 | var seen_namespaces = std.AutoHashMap(*Namespace, void).init(gpa); |
| 16596 | defer seen_namespaces.deinit(); | 16964 | defer seen_namespaces.deinit(); |
| 16597 | 16965 | ||
| 16598 | if (opt_namespace) |some| { | 16966 | if (opt_namespace.unwrap()) |namespace_index| { |
| 16599 | try sema.typeInfoNamespaceDecls(block, decls_anon_decl.arena(), some, &decl_vals, &seen_namespaces); | 16967 | const namespace = mod.namespacePtr(namespace_index); |
| 16968 | try sema.typeInfoNamespaceDecls(block, namespace, declaration_ty, &decl_vals, &seen_namespaces); | ||
| 16600 | } | 16969 | } |
| 16601 | 16970 | ||
| 16971 | const array_decl_ty = try mod.arrayType(.{ | ||
| 16972 | .len = decl_vals.items.len, | ||
| 16973 | .child = declaration_ty.toIntern(), | ||
| 16974 | .sentinel = .none, | ||
| 16975 | }); | ||
| 16602 | const new_decl = try decls_anon_decl.finish( | 16976 | const new_decl = try decls_anon_decl.finish( |
| 16603 | try Type.Tag.array.create(decls_anon_decl.arena(), .{ | 16977 | array_decl_ty, |
| 16604 | .len = decl_vals.items.len, | 16978 | (try mod.intern(.{ .aggregate = .{ |
| 16605 | .elem_type = declaration_ty, | 16979 | .ty = array_decl_ty.toIntern(), |
| 16606 | }), | 16980 | .storage = .{ .elems = decl_vals.items }, |
| 16607 | try Value.Tag.aggregate.create( | 16981 | } })).toValue(), |
| 16608 | decls_anon_decl.arena(), | ||
| 16609 | try decls_anon_decl.arena().dupe(Value, decl_vals.items), | ||
| 16610 | ), | ||
| 16611 | 0, // default alignment | 16982 | 0, // default alignment |
| 16612 | ); | 16983 | ); |
| 16613 | return try Value.Tag.slice.create(sema.arena, .{ | 16984 | return try mod.intern(.{ .ptr = .{ |
| 16614 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | 16985 | .ty = (try mod.ptrType(.{ |
| 16615 | .len = try Value.Tag.int_u64.create(sema.arena, decl_vals.items.len), | 16986 | .child = declaration_ty.toIntern(), |
| 16616 | }); | 16987 | .flags = .{ |
| 16988 | .size = .Slice, | ||
| 16989 | .is_const = true, | ||
| 16990 | }, | ||
| 16991 | })).toIntern(), | ||
| 16992 | .addr = .{ .decl = new_decl }, | ||
| 16993 | .len = (try mod.intValue(Type.usize, decl_vals.items.len)).toIntern(), | ||
| 16994 | } }); | ||
| 16617 | } | 16995 | } |
| 16618 | 16996 | ||
| 16619 | fn typeInfoNamespaceDecls( | 16997 | fn typeInfoNamespaceDecls( |
| 16620 | sema: *Sema, | 16998 | sema: *Sema, |
| 16621 | block: *Block, | 16999 | block: *Block, |
| 16622 | decls_anon_decl: Allocator, | ||
| 16623 | namespace: *Namespace, | 17000 | namespace: *Namespace, |
| 16624 | decl_vals: *std.ArrayList(Value), | 17001 | declaration_ty: Type, |
| 17002 | decl_vals: *std.ArrayList(InternPool.Index), | ||
| 16625 | seen_namespaces: *std.AutoHashMap(*Namespace, void), | 17003 | seen_namespaces: *std.AutoHashMap(*Namespace, void), |
| 16626 | ) !void { | 17004 | ) !void { |
| 17005 | const mod = sema.mod; | ||
| 17006 | const ip = &mod.intern_pool; | ||
| 16627 | const gop = try seen_namespaces.getOrPut(namespace); | 17007 | const gop = try seen_namespaces.getOrPut(namespace); |
| 16628 | if (gop.found_existing) return; | 17008 | if (gop.found_existing) return; |
| 16629 | const decls = namespace.decls.keys(); | 17009 | const decls = namespace.decls.keys(); |
| 16630 | for (decls) |decl_index| { | 17010 | for (decls) |decl_index| { |
| 16631 | const decl = sema.mod.declPtr(decl_index); | 17011 | const decl = mod.declPtr(decl_index); |
| 16632 | if (decl.kind == .@"usingnamespace") { | 17012 | if (decl.kind == .@"usingnamespace") { |
| 16633 | if (decl.analysis == .in_progress) continue; | 17013 | if (decl.analysis == .in_progress) continue; |
| 16634 | try sema.mod.ensureDeclAnalyzed(decl_index); | 17014 | try mod.ensureDeclAnalyzed(decl_index); |
| 16635 | var buf: Value.ToTypeBuffer = undefined; | 17015 | const new_ns = decl.val.toType().getNamespace(mod).?; |
| 16636 | const new_ns = decl.val.toType(&buf).getNamespace().?; | 17016 | try sema.typeInfoNamespaceDecls(block, new_ns, declaration_ty, decl_vals, seen_namespaces); |
| 16637 | try sema.typeInfoNamespaceDecls(block, decls_anon_decl, new_ns, decl_vals, seen_namespaces); | ||
| 16638 | continue; | 17017 | continue; |
| 16639 | } | 17018 | } |
| 16640 | if (decl.kind != .named) continue; | 17019 | if (decl.kind != .named) continue; |
| 16641 | const name_val = v: { | 17020 | const name_val = v: { |
| 16642 | var anon_decl = try block.startAnonDecl(); | 17021 | var anon_decl = try block.startAnonDecl(); |
| 16643 | defer anon_decl.deinit(); | 17022 | defer anon_decl.deinit(); |
| 16644 | const bytes = try anon_decl.arena().dupeZ(u8, mem.sliceTo(decl.name, 0)); | 17023 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 17024 | const name = try sema.arena.dupe(u8, ip.stringToSlice(decl.name)); | ||
| 17025 | const new_decl_ty = try mod.arrayType(.{ | ||
| 17026 | .len = name.len, | ||
| 17027 | .child = .u8_type, | ||
| 17028 | }); | ||
| 16645 | const new_decl = try anon_decl.finish( | 17029 | const new_decl = try anon_decl.finish( |
| 16646 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | 17030 | new_decl_ty, |
| 16647 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | 17031 | (try mod.intern(.{ .aggregate = .{ |
| 17032 | .ty = new_decl_ty.toIntern(), | ||
| 17033 | .storage = .{ .bytes = name }, | ||
| 17034 | } })).toValue(), | ||
| 16648 | 0, // default alignment | 17035 | 0, // default alignment |
| 16649 | ); | 17036 | ); |
| 16650 | break :v try Value.Tag.slice.create(decls_anon_decl, .{ | 17037 | break :v try mod.intern(.{ .ptr = .{ |
| 16651 | .ptr = try Value.Tag.decl_ref.create(decls_anon_decl, new_decl), | 17038 | .ty = .slice_const_u8_type, |
| 16652 | .len = try Value.Tag.int_u64.create(decls_anon_decl, bytes.len), | 17039 | .addr = .{ .decl = new_decl }, |
| 16653 | }); | 17040 | .len = (try mod.intValue(Type.usize, name.len)).toIntern(), |
| 17041 | } }); | ||
| 16654 | }; | 17042 | }; |
| 16655 | 17043 | ||
| 16656 | const fields = try decls_anon_decl.create([2]Value); | 17044 | const fields = .{ |
| 16657 | fields.* = .{ | ||
| 16658 | //name: []const u8, | 17045 | //name: []const u8, |
| 16659 | name_val, | 17046 | name_val, |
| 16660 | //is_pub: bool, | 17047 | //is_pub: bool, |
| 16661 | Value.makeBool(decl.is_pub), | 17048 | Value.makeBool(decl.is_pub).toIntern(), |
| 16662 | }; | 17049 | }; |
| 16663 | try decl_vals.append(try Value.Tag.aggregate.create(decls_anon_decl, fields)); | 17050 | try decl_vals.append(try mod.intern(.{ .aggregate = .{ |
| 17051 | .ty = declaration_ty.toIntern(), | ||
| 17052 | .storage = .{ .elems = &fields }, | ||
| 17053 | } })); | ||
| 16664 | } | 17054 | } |
| 16665 | } | 17055 | } |
| 16666 | 17056 | ||
| ... | @@ -16695,7 +17085,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -16695,7 +17085,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 16695 | 17085 | ||
| 16696 | const operand = try sema.resolveBody(&child_block, body, inst); | 17086 | const operand = try sema.resolveBody(&child_block, body, inst); |
| 16697 | const operand_ty = sema.typeOf(operand); | 17087 | const operand_ty = sema.typeOf(operand); |
| 16698 | if (operand_ty.tag() == .generic_poison) return error.GenericPoison; | 17088 | if (operand_ty.isGenericPoison()) return error.GenericPoison; |
| 16699 | return sema.addType(operand_ty); | 17089 | return sema.addType(operand_ty); |
| 16700 | } | 17090 | } |
| 16701 | 17091 | ||
| ... | @@ -16709,10 +17099,11 @@ fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil | ... | @@ -16709,10 +17099,11 @@ fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil |
| 16709 | } | 17099 | } |
| 16710 | 17100 | ||
| 16711 | fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type { | 17101 | fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type { |
| 16712 | switch (operand.zigTypeTag()) { | 17102 | const mod = sema.mod; |
| 17103 | switch (operand.zigTypeTag(mod)) { | ||
| 16713 | .ComptimeInt => return Type.comptime_int, | 17104 | .ComptimeInt => return Type.comptime_int, |
| 16714 | .Int => { | 17105 | .Int => { |
| 16715 | const bits = operand.bitSize(sema.mod.getTarget()); | 17106 | const bits = operand.bitSize(mod); |
| 16716 | const count = if (bits == 0) | 17107 | const count = if (bits == 0) |
| 16717 | 0 | 17108 | 0 |
| 16718 | else blk: { | 17109 | else blk: { |
| ... | @@ -16723,14 +17114,14 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi | ... | @@ -16723,14 +17114,14 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi |
| 16723 | } | 17114 | } |
| 16724 | break :blk count; | 17115 | break :blk count; |
| 16725 | }; | 17116 | }; |
| 16726 | return Module.makeIntType(sema.arena, .unsigned, count); | 17117 | return mod.intType(.unsigned, count); |
| 16727 | }, | 17118 | }, |
| 16728 | .Vector => { | 17119 | .Vector => { |
| 16729 | const elem_ty = operand.elemType2(); | 17120 | const elem_ty = operand.elemType2(mod); |
| 16730 | const log2_elem_ty = try sema.log2IntType(block, elem_ty, src); | 17121 | const log2_elem_ty = try sema.log2IntType(block, elem_ty, src); |
| 16731 | return Type.Tag.vector.create(sema.arena, .{ | 17122 | return mod.vectorType(.{ |
| 16732 | .len = operand.vectorLen(), | 17123 | .len = operand.vectorLen(mod), |
| 16733 | .elem_type = log2_elem_ty, | 17124 | .child = log2_elem_ty.toIntern(), |
| 16734 | }); | 17125 | }); |
| 16735 | }, | 17126 | }, |
| 16736 | else => {}, | 17127 | else => {}, |
| ... | @@ -16739,7 +17130,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi | ... | @@ -16739,7 +17130,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi |
| 16739 | block, | 17130 | block, |
| 16740 | src, | 17131 | src, |
| 16741 | "bit shifting operation expected integer type, found '{}'", | 17132 | "bit shifting operation expected integer type, found '{}'", |
| 16742 | .{operand.fmt(sema.mod)}, | 17133 | .{operand.fmt(mod)}, |
| 16743 | ); | 17134 | ); |
| 16744 | } | 17135 | } |
| 16745 | 17136 | ||
| ... | @@ -16790,6 +17181,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -16790,6 +17181,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 16790 | const tracy = trace(@src()); | 17181 | const tracy = trace(@src()); |
| 16791 | defer tracy.end(); | 17182 | defer tracy.end(); |
| 16792 | 17183 | ||
| 17184 | const mod = sema.mod; | ||
| 16793 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 17185 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 16794 | const src = inst_data.src(); | 17186 | const src = inst_data.src(); |
| 16795 | const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; | 17187 | const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node }; |
| ... | @@ -16797,7 +17189,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -16797,7 +17189,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 16797 | 17189 | ||
| 16798 | const operand = try sema.coerce(block, Type.bool, uncasted_operand, operand_src); | 17190 | const operand = try sema.coerce(block, Type.bool, uncasted_operand, operand_src); |
| 16799 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 17191 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 16800 | return if (val.isUndef()) | 17192 | return if (val.isUndef(mod)) |
| 16801 | sema.addConstUndef(Type.bool) | 17193 | sema.addConstUndef(Type.bool) |
| 16802 | else if (val.toBool()) | 17194 | else if (val.toBool()) |
| 16803 | Air.Inst.Ref.bool_false | 17195 | Air.Inst.Ref.bool_false |
| ... | @@ -16817,6 +17209,7 @@ fn zirBoolBr( | ... | @@ -16817,6 +17209,7 @@ fn zirBoolBr( |
| 16817 | const tracy = trace(@src()); | 17209 | const tracy = trace(@src()); |
| 16818 | defer tracy.end(); | 17210 | defer tracy.end(); |
| 16819 | 17211 | ||
| 17212 | const mod = sema.mod; | ||
| 16820 | const datas = sema.code.instructions.items(.data); | 17213 | const datas = sema.code.instructions.items(.data); |
| 16821 | const inst_data = datas[inst].bool_br; | 17214 | const inst_data = datas[inst].bool_br; |
| 16822 | const lhs = try sema.resolveInst(inst_data.lhs); | 17215 | const lhs = try sema.resolveInst(inst_data.lhs); |
| ... | @@ -16865,12 +17258,12 @@ fn zirBoolBr( | ... | @@ -16865,12 +17258,12 @@ fn zirBoolBr( |
| 16865 | _ = try lhs_block.addBr(block_inst, lhs_result); | 17258 | _ = try lhs_block.addBr(block_inst, lhs_result); |
| 16866 | 17259 | ||
| 16867 | const rhs_result = try sema.resolveBody(rhs_block, body, inst); | 17260 | const rhs_result = try sema.resolveBody(rhs_block, body, inst); |
| 16868 | if (!sema.typeOf(rhs_result).isNoReturn()) { | 17261 | if (!sema.typeOf(rhs_result).isNoReturn(mod)) { |
| 16869 | _ = try rhs_block.addBr(block_inst, rhs_result); | 17262 | _ = try rhs_block.addBr(block_inst, rhs_result); |
| 16870 | } | 17263 | } |
| 16871 | 17264 | ||
| 16872 | const result = sema.finishCondBr(parent_block, &child_block, &then_block, &else_block, lhs, block_inst); | 17265 | const result = sema.finishCondBr(parent_block, &child_block, &then_block, &else_block, lhs, block_inst); |
| 16873 | if (!sema.typeOf(rhs_result).isNoReturn()) { | 17266 | if (!sema.typeOf(rhs_result).isNoReturn(mod)) { |
| 16874 | if (try sema.resolveDefinedValue(rhs_block, sema.src, rhs_result)) |rhs_val| { | 17267 | if (try sema.resolveDefinedValue(rhs_block, sema.src, rhs_result)) |rhs_val| { |
| 16875 | if (is_bool_or and rhs_val.toBool()) { | 17268 | if (is_bool_or and rhs_val.toBool()) { |
| 16876 | return Air.Inst.Ref.bool_true; | 17269 | return Air.Inst.Ref.bool_true; |
| ... | @@ -16920,9 +17313,10 @@ fn finishCondBr( | ... | @@ -16920,9 +17313,10 @@ fn finishCondBr( |
| 16920 | } | 17313 | } |
| 16921 | 17314 | ||
| 16922 | fn checkNullableType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { | 17315 | fn checkNullableType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { |
| 16923 | switch (ty.zigTypeTag()) { | 17316 | const mod = sema.mod; |
| 17317 | switch (ty.zigTypeTag(mod)) { | ||
| 16924 | .Optional, .Null, .Undefined => return, | 17318 | .Optional, .Null, .Undefined => return, |
| 16925 | .Pointer => if (ty.isPtrLikeOptional()) return, | 17319 | .Pointer => if (ty.isPtrLikeOptional(mod)) return, |
| 16926 | else => {}, | 17320 | else => {}, |
| 16927 | } | 17321 | } |
| 16928 | return sema.failWithExpectedOptionalType(block, src, ty); | 17322 | return sema.failWithExpectedOptionalType(block, src, ty); |
| ... | @@ -16951,10 +17345,11 @@ fn zirIsNonNullPtr( | ... | @@ -16951,10 +17345,11 @@ fn zirIsNonNullPtr( |
| 16951 | const tracy = trace(@src()); | 17345 | const tracy = trace(@src()); |
| 16952 | defer tracy.end(); | 17346 | defer tracy.end(); |
| 16953 | 17347 | ||
| 17348 | const mod = sema.mod; | ||
| 16954 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 17349 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 16955 | const src = inst_data.src(); | 17350 | const src = inst_data.src(); |
| 16956 | const ptr = try sema.resolveInst(inst_data.operand); | 17351 | const ptr = try sema.resolveInst(inst_data.operand); |
| 16957 | try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2()); | 17352 | try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2(mod)); |
| 16958 | if ((try sema.resolveMaybeUndefVal(ptr)) == null) { | 17353 | if ((try sema.resolveMaybeUndefVal(ptr)) == null) { |
| 16959 | return block.addUnOp(.is_non_null_ptr, ptr); | 17354 | return block.addUnOp(.is_non_null_ptr, ptr); |
| 16960 | } | 17355 | } |
| ... | @@ -16963,10 +17358,11 @@ fn zirIsNonNullPtr( | ... | @@ -16963,10 +17358,11 @@ fn zirIsNonNullPtr( |
| 16963 | } | 17358 | } |
| 16964 | 17359 | ||
| 16965 | fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { | 17360 | fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { |
| 16966 | switch (ty.zigTypeTag()) { | 17361 | const mod = sema.mod; |
| 17362 | switch (ty.zigTypeTag(mod)) { | ||
| 16967 | .ErrorSet, .ErrorUnion, .Undefined => return, | 17363 | .ErrorSet, .ErrorUnion, .Undefined => return, |
| 16968 | else => return sema.fail(block, src, "expected error union type, found '{}'", .{ | 17364 | else => return sema.fail(block, src, "expected error union type, found '{}'", .{ |
| 16969 | ty.fmt(sema.mod), | 17365 | ty.fmt(mod), |
| 16970 | }), | 17366 | }), |
| 16971 | } | 17367 | } |
| 16972 | } | 17368 | } |
| ... | @@ -16986,10 +17382,11 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -16986,10 +17382,11 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 16986 | const tracy = trace(@src()); | 17382 | const tracy = trace(@src()); |
| 16987 | defer tracy.end(); | 17383 | defer tracy.end(); |
| 16988 | 17384 | ||
| 17385 | const mod = sema.mod; | ||
| 16989 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 17386 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 16990 | const src = inst_data.src(); | 17387 | const src = inst_data.src(); |
| 16991 | const ptr = try sema.resolveInst(inst_data.operand); | 17388 | const ptr = try sema.resolveInst(inst_data.operand); |
| 16992 | try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2()); | 17389 | try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2(mod)); |
| 16993 | const loaded = try sema.analyzeLoad(block, src, ptr, src); | 17390 | const loaded = try sema.analyzeLoad(block, src, ptr, src); |
| 16994 | return sema.analyzeIsNonErr(block, src, loaded); | 17391 | return sema.analyzeIsNonErr(block, src, loaded); |
| 16995 | } | 17392 | } |
| ... | @@ -17012,6 +17409,7 @@ fn zirCondbr( | ... | @@ -17012,6 +17409,7 @@ fn zirCondbr( |
| 17012 | const tracy = trace(@src()); | 17409 | const tracy = trace(@src()); |
| 17013 | defer tracy.end(); | 17410 | defer tracy.end(); |
| 17014 | 17411 | ||
| 17412 | const mod = sema.mod; | ||
| 17015 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 17413 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 17016 | const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; | 17414 | const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node }; |
| 17017 | const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); | 17415 | const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index); |
| ... | @@ -17052,8 +17450,8 @@ fn zirCondbr( | ... | @@ -17052,8 +17450,8 @@ fn zirCondbr( |
| 17052 | const err_inst_data = sema.code.instructions.items(.data)[index].un_node; | 17450 | const err_inst_data = sema.code.instructions.items(.data)[index].un_node; |
| 17053 | const err_operand = try sema.resolveInst(err_inst_data.operand); | 17451 | const err_operand = try sema.resolveInst(err_inst_data.operand); |
| 17054 | const operand_ty = sema.typeOf(err_operand); | 17452 | const operand_ty = sema.typeOf(err_operand); |
| 17055 | assert(operand_ty.zigTypeTag() == .ErrorUnion); | 17453 | assert(operand_ty.zigTypeTag(mod) == .ErrorUnion); |
| 17056 | const result_ty = operand_ty.errorUnionSet(); | 17454 | const result_ty = operand_ty.errorUnionSet(mod); |
| 17057 | break :blk try sub_block.addTyOp(.unwrap_errunion_err, result_ty, err_operand); | 17455 | break :blk try sub_block.addTyOp(.unwrap_errunion_err, result_ty, err_operand); |
| 17058 | }; | 17456 | }; |
| 17059 | 17457 | ||
| ... | @@ -17079,7 +17477,7 @@ fn zirCondbr( | ... | @@ -17079,7 +17477,7 @@ fn zirCondbr( |
| 17079 | return always_noreturn; | 17477 | return always_noreturn; |
| 17080 | } | 17478 | } |
| 17081 | 17479 | ||
| 17082 | fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref { | 17480 | fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 17083 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 17481 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 17084 | const src = inst_data.src(); | 17482 | const src = inst_data.src(); |
| 17085 | const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | 17483 | const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| ... | @@ -17087,9 +17485,10 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -17087,9 +17485,10 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError! |
| 17087 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; | 17485 | const body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 17088 | const err_union = try sema.resolveInst(extra.data.operand); | 17486 | const err_union = try sema.resolveInst(extra.data.operand); |
| 17089 | const err_union_ty = sema.typeOf(err_union); | 17487 | const err_union_ty = sema.typeOf(err_union); |
| 17090 | if (err_union_ty.zigTypeTag() != .ErrorUnion) { | 17488 | const mod = sema.mod; |
| 17489 | if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) { | ||
| 17091 | return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ | 17490 | return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ |
| 17092 | err_union_ty.fmt(sema.mod), | 17491 | err_union_ty.fmt(mod), |
| 17093 | }); | 17492 | }); |
| 17094 | } | 17493 | } |
| 17095 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union); | 17494 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union); |
| ... | @@ -17124,7 +17523,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -17124,7 +17523,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError! |
| 17124 | return try_inst; | 17523 | return try_inst; |
| 17125 | } | 17524 | } |
| 17126 | 17525 | ||
| 17127 | fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref { | 17526 | fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 17128 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 17527 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 17129 | const src = inst_data.src(); | 17528 | const src = inst_data.src(); |
| 17130 | const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | 17529 | const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| ... | @@ -17133,9 +17532,10 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -17133,9 +17532,10 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr |
| 17133 | const operand = try sema.resolveInst(extra.data.operand); | 17532 | const operand = try sema.resolveInst(extra.data.operand); |
| 17134 | const err_union = try sema.analyzeLoad(parent_block, src, operand, operand_src); | 17533 | const err_union = try sema.analyzeLoad(parent_block, src, operand, operand_src); |
| 17135 | const err_union_ty = sema.typeOf(err_union); | 17534 | const err_union_ty = sema.typeOf(err_union); |
| 17136 | if (err_union_ty.zigTypeTag() != .ErrorUnion) { | 17535 | const mod = sema.mod; |
| 17536 | if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) { | ||
| 17137 | return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ | 17537 | return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{ |
| 17138 | err_union_ty.fmt(sema.mod), | 17538 | err_union_ty.fmt(mod), |
| 17139 | }); | 17539 | }); |
| 17140 | } | 17540 | } |
| 17141 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union); | 17541 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union); |
| ... | @@ -17156,9 +17556,9 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr | ... | @@ -17156,9 +17556,9 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr |
| 17156 | _ = try sema.analyzeBodyInner(&sub_block, body); | 17556 | _ = try sema.analyzeBodyInner(&sub_block, body); |
| 17157 | 17557 | ||
| 17158 | const operand_ty = sema.typeOf(operand); | 17558 | const operand_ty = sema.typeOf(operand); |
| 17159 | const ptr_info = operand_ty.ptrInfo().data; | 17559 | const ptr_info = operand_ty.ptrInfo(mod); |
| 17160 | const res_ty = try Type.ptr(sema.arena, sema.mod, .{ | 17560 | const res_ty = try Type.ptr(sema.arena, mod, .{ |
| 17161 | .pointee_type = err_union_ty.errorUnionPayload(), | 17561 | .pointee_type = err_union_ty.errorUnionPayload(mod), |
| 17162 | .@"addrspace" = ptr_info.@"addrspace", | 17562 | .@"addrspace" = ptr_info.@"addrspace", |
| 17163 | .mutable = ptr_info.mutable, | 17563 | .mutable = ptr_info.mutable, |
| 17164 | .@"allowzero" = ptr_info.@"allowzero", | 17564 | .@"allowzero" = ptr_info.@"allowzero", |
| ... | @@ -17254,16 +17654,17 @@ fn zirRetErrValue( | ... | @@ -17254,16 +17654,17 @@ fn zirRetErrValue( |
| 17254 | block: *Block, | 17654 | block: *Block, |
| 17255 | inst: Zir.Inst.Index, | 17655 | inst: Zir.Inst.Index, |
| 17256 | ) CompileError!Zir.Inst.Index { | 17656 | ) CompileError!Zir.Inst.Index { |
| 17657 | const mod = sema.mod; | ||
| 17257 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; | 17658 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 17258 | const err_name = inst_data.get(sema.code); | 17659 | const err_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); |
| 17660 | _ = try mod.getErrorValue(err_name); | ||
| 17259 | const src = inst_data.src(); | 17661 | const src = inst_data.src(); |
| 17260 | |||
| 17261 | // Return the error code from the function. | 17662 | // Return the error code from the function. |
| 17262 | const kv = try sema.mod.getErrorValue(err_name); | 17663 | const error_set_type = try mod.singleErrorSetType(err_name); |
| 17263 | const result_inst = try sema.addConstant( | 17664 | const result_inst = try sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ |
| 17264 | try Type.Tag.error_set_single.create(sema.arena, kv.key), | 17665 | .ty = error_set_type.toIntern(), |
| 17265 | try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }), | 17666 | .name = err_name, |
| 17266 | ); | 17667 | } })).toValue()); |
| 17267 | return sema.analyzeRet(block, result_inst, src); | 17668 | return sema.analyzeRet(block, result_inst, src); |
| 17268 | } | 17669 | } |
| 17269 | 17670 | ||
| ... | @@ -17275,16 +17676,17 @@ fn zirRetImplicit( | ... | @@ -17275,16 +17676,17 @@ fn zirRetImplicit( |
| 17275 | const tracy = trace(@src()); | 17676 | const tracy = trace(@src()); |
| 17276 | defer tracy.end(); | 17677 | defer tracy.end(); |
| 17277 | 17678 | ||
| 17679 | const mod = sema.mod; | ||
| 17278 | const inst_data = sema.code.instructions.items(.data)[inst].un_tok; | 17680 | const inst_data = sema.code.instructions.items(.data)[inst].un_tok; |
| 17279 | const operand = try sema.resolveInst(inst_data.operand); | 17681 | const operand = try sema.resolveInst(inst_data.operand); |
| 17280 | 17682 | ||
| 17281 | const r_brace_src = inst_data.src(); | 17683 | const r_brace_src = inst_data.src(); |
| 17282 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; | 17684 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 17283 | const base_tag = sema.fn_ret_ty.baseZigTypeTag(); | 17685 | const base_tag = sema.fn_ret_ty.baseZigTypeTag(mod); |
| 17284 | if (base_tag == .NoReturn) { | 17686 | if (base_tag == .NoReturn) { |
| 17285 | const msg = msg: { | 17687 | const msg = msg: { |
| 17286 | const msg = try sema.errMsg(block, ret_ty_src, "function declared '{}' implicitly returns", .{ | 17688 | const msg = try sema.errMsg(block, ret_ty_src, "function declared '{}' implicitly returns", .{ |
| 17287 | sema.fn_ret_ty.fmt(sema.mod), | 17689 | sema.fn_ret_ty.fmt(mod), |
| 17288 | }); | 17690 | }); |
| 17289 | errdefer msg.destroy(sema.gpa); | 17691 | errdefer msg.destroy(sema.gpa); |
| 17290 | try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); | 17692 | try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); |
| ... | @@ -17294,7 +17696,7 @@ fn zirRetImplicit( | ... | @@ -17294,7 +17696,7 @@ fn zirRetImplicit( |
| 17294 | } else if (base_tag != .Void) { | 17696 | } else if (base_tag != .Void) { |
| 17295 | const msg = msg: { | 17697 | const msg = msg: { |
| 17296 | const msg = try sema.errMsg(block, ret_ty_src, "function with non-void return type '{}' implicitly returns", .{ | 17698 | const msg = try sema.errMsg(block, ret_ty_src, "function with non-void return type '{}' implicitly returns", .{ |
| 17297 | sema.fn_ret_ty.fmt(sema.mod), | 17699 | sema.fn_ret_ty.fmt(mod), |
| 17298 | }); | 17700 | }); |
| 17299 | errdefer msg.destroy(sema.gpa); | 17701 | errdefer msg.destroy(sema.gpa); |
| 17300 | try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); | 17702 | try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{}); |
| ... | @@ -17346,6 +17748,7 @@ fn retWithErrTracing( | ... | @@ -17346,6 +17748,7 @@ fn retWithErrTracing( |
| 17346 | ret_tag: Air.Inst.Tag, | 17748 | ret_tag: Air.Inst.Tag, |
| 17347 | operand: Air.Inst.Ref, | 17749 | operand: Air.Inst.Ref, |
| 17348 | ) CompileError!Zir.Inst.Index { | 17750 | ) CompileError!Zir.Inst.Index { |
| 17751 | const mod = sema.mod; | ||
| 17349 | const need_check = switch (is_non_err) { | 17752 | const need_check = switch (is_non_err) { |
| 17350 | .bool_true => { | 17753 | .bool_true => { |
| 17351 | _ = try block.addUnOp(ret_tag, operand); | 17754 | _ = try block.addUnOp(ret_tag, operand); |
| ... | @@ -17357,7 +17760,7 @@ fn retWithErrTracing( | ... | @@ -17357,7 +17760,7 @@ fn retWithErrTracing( |
| 17357 | const gpa = sema.gpa; | 17760 | const gpa = sema.gpa; |
| 17358 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); | 17761 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 17359 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); | 17762 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); |
| 17360 | const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); | 17763 | const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); |
| 17361 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); | 17764 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 17362 | const return_err_fn = try sema.getBuiltin("returnError"); | 17765 | const return_err_fn = try sema.getBuiltin("returnError"); |
| 17363 | const args: [1]Air.Inst.Ref = .{err_return_trace}; | 17766 | const args: [1]Air.Inst.Ref = .{err_return_trace}; |
| ... | @@ -17397,17 +17800,19 @@ fn retWithErrTracing( | ... | @@ -17397,17 +17800,19 @@ fn retWithErrTracing( |
| 17397 | } | 17800 | } |
| 17398 | 17801 | ||
| 17399 | fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { | 17802 | fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { |
| 17400 | if (!sema.mod.backendSupportsFeature(.error_return_trace)) return false; | 17803 | const mod = sema.mod; |
| 17804 | if (!mod.backendSupportsFeature(.error_return_trace)) return false; | ||
| 17401 | 17805 | ||
| 17402 | return fn_ret_ty.isError() and | 17806 | return fn_ret_ty.isError(mod) and |
| 17403 | sema.mod.comp.bin_file.options.error_return_tracing; | 17807 | mod.comp.bin_file.options.error_return_tracing; |
| 17404 | } | 17808 | } |
| 17405 | 17809 | ||
| 17406 | fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 17810 | fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 17811 | const mod = sema.mod; | ||
| 17407 | const inst_data = sema.code.instructions.items(.data)[inst].save_err_ret_index; | 17812 | const inst_data = sema.code.instructions.items(.data)[inst].save_err_ret_index; |
| 17408 | 17813 | ||
| 17409 | if (!sema.mod.backendSupportsFeature(.error_return_trace)) return; | 17814 | if (!mod.backendSupportsFeature(.error_return_trace)) return; |
| 17410 | if (!sema.mod.comp.bin_file.options.error_return_tracing) return; | 17815 | if (!mod.comp.bin_file.options.error_return_tracing) return; |
| 17411 | 17816 | ||
| 17412 | // This is only relevant at runtime. | 17817 | // This is only relevant at runtime. |
| 17413 | if (block.is_comptime or block.is_typeof) return; | 17818 | if (block.is_comptime or block.is_typeof) return; |
| ... | @@ -17415,7 +17820,7 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -17415,7 +17820,7 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 17415 | const save_index = inst_data.operand == .none or b: { | 17820 | const save_index = inst_data.operand == .none or b: { |
| 17416 | const operand = try sema.resolveInst(inst_data.operand); | 17821 | const operand = try sema.resolveInst(inst_data.operand); |
| 17417 | const operand_ty = sema.typeOf(operand); | 17822 | const operand_ty = sema.typeOf(operand); |
| 17418 | break :b operand_ty.isError(); | 17823 | break :b operand_ty.isError(mod); |
| 17419 | }; | 17824 | }; |
| 17420 | 17825 | ||
| 17421 | if (save_index) | 17826 | if (save_index) |
| ... | @@ -17436,7 +17841,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) | ... | @@ -17436,7 +17841,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) |
| 17436 | const tracy = trace(@src()); | 17841 | const tracy = trace(@src()); |
| 17437 | defer tracy.end(); | 17842 | defer tracy.end(); |
| 17438 | 17843 | ||
| 17439 | const saved_index = if (Zir.refToIndex(inst_data.block)) |zir_block| b: { | 17844 | const saved_index = if (Zir.refToIndexAllowNone(inst_data.block)) |zir_block| b: { |
| 17440 | var block = start_block; | 17845 | var block = start_block; |
| 17441 | while (true) { | 17846 | while (true) { |
| 17442 | if (block.label) |label| { | 17847 | if (block.label) |label| { |
| ... | @@ -17462,22 +17867,21 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) | ... | @@ -17462,22 +17867,21 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) |
| 17462 | 17867 | ||
| 17463 | assert(saved_index != .none); // The .error_return_trace_index field was dropped somewhere | 17868 | assert(saved_index != .none); // The .error_return_trace_index field was dropped somewhere |
| 17464 | 17869 | ||
| 17465 | const operand = try sema.resolveInst(inst_data.operand); | 17870 | const operand = try sema.resolveInstAllowNone(inst_data.operand); |
| 17466 | return sema.popErrorReturnTrace(start_block, src, operand, saved_index); | 17871 | return sema.popErrorReturnTrace(start_block, src, operand, saved_index); |
| 17467 | } | 17872 | } |
| 17468 | 17873 | ||
| 17469 | fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { | 17874 | fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { |
| 17470 | assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion); | 17875 | const mod = sema.mod; |
| 17876 | const gpa = sema.gpa; | ||
| 17877 | const ip = &mod.intern_pool; | ||
| 17878 | assert(sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion); | ||
| 17471 | 17879 | ||
| 17472 | if (sema.fn_ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| { | 17880 | if (mod.typeToInferredErrorSet(sema.fn_ret_ty.errorUnionSet(mod))) |ies| { |
| 17473 | const op_ty = sema.typeOf(uncasted_operand); | 17881 | const op_ty = sema.typeOf(uncasted_operand); |
| 17474 | switch (op_ty.zigTypeTag()) { | 17882 | switch (op_ty.zigTypeTag(mod)) { |
| 17475 | .ErrorSet => { | 17883 | .ErrorSet => try ies.addErrorSet(op_ty, ip, gpa), |
| 17476 | try payload.data.addErrorSet(sema.gpa, op_ty); | 17884 | .ErrorUnion => try ies.addErrorSet(op_ty.errorUnionSet(mod), ip, gpa), |
| 17477 | }, | ||
| 17478 | .ErrorUnion => { | ||
| 17479 | try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet()); | ||
| 17480 | }, | ||
| 17481 | else => {}, | 17885 | else => {}, |
| 17482 | } | 17886 | } |
| 17483 | } | 17887 | } |
| ... | @@ -17492,7 +17896,8 @@ fn analyzeRet( | ... | @@ -17492,7 +17896,8 @@ fn analyzeRet( |
| 17492 | // Special case for returning an error to an inferred error set; we need to | 17896 | // Special case for returning an error to an inferred error set; we need to |
| 17493 | // add the error tag to the inferred error set of the in-scope function, so | 17897 | // add the error tag to the inferred error set of the in-scope function, so |
| 17494 | // that the coercion below works correctly. | 17898 | // that the coercion below works correctly. |
| 17495 | if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) { | 17899 | const mod = sema.mod; |
| 17900 | if (sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion) { | ||
| 17496 | try sema.addToInferredErrorSet(uncasted_operand); | 17901 | try sema.addToInferredErrorSet(uncasted_operand); |
| 17497 | } | 17902 | } |
| 17498 | const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, .{ .is_ret = true }) catch |err| switch (err) { | 17903 | const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, .{ .is_ret = true }) catch |err| switch (err) { |
| ... | @@ -17540,6 +17945,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -17540,6 +17945,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 17540 | const tracy = trace(@src()); | 17945 | const tracy = trace(@src()); |
| 17541 | defer tracy.end(); | 17946 | defer tracy.end(); |
| 17542 | 17947 | ||
| 17948 | const mod = sema.mod; | ||
| 17543 | const inst_data = sema.code.instructions.items(.data)[inst].ptr_type; | 17949 | const inst_data = sema.code.instructions.items(.data)[inst].ptr_type; |
| 17544 | const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index); | 17950 | const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index); |
| 17545 | const elem_ty_src: LazySrcLoc = .{ .node_offset_ptr_elem = extra.data.src_node }; | 17951 | const elem_ty_src: LazySrcLoc = .{ .node_offset_ptr_elem = extra.data.src_node }; |
| ... | @@ -17552,46 +17958,54 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -17552,46 +17958,54 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 17552 | const elem_ty = blk: { | 17958 | const elem_ty = blk: { |
| 17553 | const air_inst = try sema.resolveInst(extra.data.elem_type); | 17959 | const air_inst = try sema.resolveInst(extra.data.elem_type); |
| 17554 | const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| { | 17960 | const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| { |
| 17555 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer()) { | 17961 | if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(mod)) { |
| 17556 | try sema.errNote(block, elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{}); | 17962 | try sema.errNote(block, elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{}); |
| 17557 | } | 17963 | } |
| 17558 | return err; | 17964 | return err; |
| 17559 | }; | 17965 | }; |
| 17560 | if (ty.tag() == .generic_poison) return error.GenericPoison; | 17966 | if (ty.isGenericPoison()) return error.GenericPoison; |
| 17561 | break :blk ty; | 17967 | break :blk ty; |
| 17562 | }; | 17968 | }; |
| 17563 | const target = sema.mod.getTarget(); | 17969 | |
| 17970 | if (elem_ty.zigTypeTag(mod) == .NoReturn) | ||
| 17971 | return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}); | ||
| 17972 | |||
| 17973 | const target = mod.getTarget(); | ||
| 17564 | 17974 | ||
| 17565 | var extra_i = extra.end; | 17975 | var extra_i = extra.end; |
| 17566 | 17976 | ||
| 17567 | const sentinel = if (inst_data.flags.has_sentinel) blk: { | 17977 | const sentinel = if (inst_data.flags.has_sentinel) blk: { |
| 17568 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); | 17978 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); |
| 17569 | extra_i += 1; | 17979 | extra_i += 1; |
| 17570 | break :blk (try sema.resolveInstConst(block, sentinel_src, ref, "pointer sentinel value must be comptime-known")).val; | 17980 | const coerced = try sema.coerce(block, elem_ty, try sema.resolveInst(ref), sentinel_src); |
| 17571 | } else null; | 17981 | const val = try sema.resolveConstValue(block, sentinel_src, coerced, "pointer sentinel value must be comptime-known"); |
| 17982 | break :blk val.toIntern(); | ||
| 17983 | } else .none; | ||
| 17572 | 17984 | ||
| 17573 | const abi_align: u32 = if (inst_data.flags.has_align) blk: { | 17985 | const abi_align: InternPool.Alignment = if (inst_data.flags.has_align) blk: { |
| 17574 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); | 17986 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); |
| 17575 | extra_i += 1; | 17987 | extra_i += 1; |
| 17576 | const coerced = try sema.coerce(block, Type.u32, try sema.resolveInst(ref), align_src); | 17988 | const coerced = try sema.coerce(block, Type.u32, try sema.resolveInst(ref), align_src); |
| 17577 | const val = try sema.resolveConstValue(block, align_src, coerced, "pointer alignment must be comptime-known"); | 17989 | const val = try sema.resolveConstValue(block, align_src, coerced, "pointer alignment must be comptime-known"); |
| 17578 | // Check if this happens to be the lazy alignment of our element type, in | 17990 | // Check if this happens to be the lazy alignment of our element type, in |
| 17579 | // which case we can make this 0 without resolving it. | 17991 | // which case we can make this 0 without resolving it. |
| 17580 | if (val.castTag(.lazy_align)) |payload| { | 17992 | switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 17581 | if (payload.data.eql(elem_ty, sema.mod)) { | 17993 | .int => |int| switch (int.storage) { |
| 17582 | break :blk 0; | 17994 | .lazy_align => |lazy_ty| if (lazy_ty == elem_ty.toIntern()) break :blk .none, |
| 17583 | } | 17995 | else => {}, |
| 17996 | }, | ||
| 17997 | else => {}, | ||
| 17584 | } | 17998 | } |
| 17585 | const abi_align = @intCast(u32, (try val.getUnsignedIntAdvanced(target, sema)).?); | 17999 | const abi_align = @intCast(u32, (try val.getUnsignedIntAdvanced(mod, sema)).?); |
| 17586 | try sema.validateAlign(block, align_src, abi_align); | 18000 | try sema.validateAlign(block, align_src, abi_align); |
| 17587 | break :blk abi_align; | 18001 | break :blk InternPool.Alignment.fromByteUnits(abi_align); |
| 17588 | } else 0; | 18002 | } else .none; |
| 17589 | 18003 | ||
| 17590 | const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: { | 18004 | const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: { |
| 17591 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); | 18005 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); |
| 17592 | extra_i += 1; | 18006 | extra_i += 1; |
| 17593 | break :blk try sema.analyzeAddressSpace(block, addrspace_src, ref, .pointer); | 18007 | break :blk try sema.analyzeAddressSpace(block, addrspace_src, ref, .pointer); |
| 17594 | } else if (elem_ty.zigTypeTag() == .Fn and target.cpu.arch == .avr) .flash else .generic; | 18008 | } else if (elem_ty.zigTypeTag(mod) == .Fn and target.cpu.arch == .avr) .flash else .generic; |
| 17595 | 18009 | ||
| 17596 | const bit_offset = if (inst_data.flags.has_bit_range) blk: { | 18010 | const bit_offset = if (inst_data.flags.has_bit_range) blk: { |
| 17597 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); | 18011 | const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]); |
| ... | @@ -17611,50 +18025,52 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -17611,50 +18025,52 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 17611 | return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{}); | 18025 | return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{}); |
| 17612 | } | 18026 | } |
| 17613 | 18027 | ||
| 17614 | if (elem_ty.zigTypeTag() == .NoReturn) { | 18028 | if (elem_ty.zigTypeTag(mod) == .Fn) { |
| 17615 | return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{}); | ||
| 17616 | } else if (elem_ty.zigTypeTag() == .Fn) { | ||
| 17617 | if (inst_data.size != .One) { | 18029 | if (inst_data.size != .One) { |
| 17618 | return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{}); | 18030 | return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{}); |
| 17619 | } | 18031 | } |
| 17620 | const fn_align = elem_ty.fnInfo().alignment; | 18032 | const fn_align = mod.typeToFunc(elem_ty).?.alignment; |
| 17621 | if (inst_data.flags.has_align and abi_align != 0 and fn_align != 0 and | 18033 | if (inst_data.flags.has_align and abi_align != .none and fn_align != .none and |
| 17622 | abi_align != fn_align) | 18034 | abi_align != fn_align) |
| 17623 | { | 18035 | { |
| 17624 | return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{}); | 18036 | return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{}); |
| 17625 | } | 18037 | } |
| 17626 | } else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) { | 18038 | } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { |
| 17627 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); | 18039 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); |
| 17628 | } else if (inst_data.size == .C) { | 18040 | } else if (inst_data.size == .C) { |
| 17629 | if (!try sema.validateExternType(elem_ty, .other)) { | 18041 | if (!try sema.validateExternType(elem_ty, .other)) { |
| 17630 | const msg = msg: { | 18042 | const msg = msg: { |
| 17631 | const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); | 18043 | const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(mod)}); |
| 17632 | errdefer msg.destroy(sema.gpa); | 18044 | errdefer msg.destroy(sema.gpa); |
| 17633 | 18045 | ||
| 17634 | const src_decl = sema.mod.declPtr(block.src_decl); | 18046 | const src_decl = mod.declPtr(block.src_decl); |
| 17635 | try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl), elem_ty, .other); | 18047 | try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl, mod), elem_ty, .other); |
| 17636 | 18048 | ||
| 17637 | try sema.addDeclaredHereNote(msg, elem_ty); | 18049 | try sema.addDeclaredHereNote(msg, elem_ty); |
| 17638 | break :msg msg; | 18050 | break :msg msg; |
| 17639 | }; | 18051 | }; |
| 17640 | return sema.failWithOwnedErrorMsg(msg); | 18052 | return sema.failWithOwnedErrorMsg(msg); |
| 17641 | } | 18053 | } |
| 17642 | if (elem_ty.zigTypeTag() == .Opaque) { | 18054 | if (elem_ty.zigTypeTag(mod) == .Opaque) { |
| 17643 | return sema.fail(block, elem_ty_src, "C pointers cannot point to opaque types", .{}); | 18055 | return sema.fail(block, elem_ty_src, "C pointers cannot point to opaque types", .{}); |
| 17644 | } | 18056 | } |
| 17645 | } | 18057 | } |
| 17646 | 18058 | ||
| 17647 | const ty = try Type.ptr(sema.arena, sema.mod, .{ | 18059 | const ty = try mod.ptrType(.{ |
| 17648 | .pointee_type = elem_ty, | 18060 | .child = elem_ty.toIntern(), |
| 17649 | .sentinel = sentinel, | 18061 | .sentinel = sentinel, |
| 17650 | .@"align" = abi_align, | 18062 | .flags = .{ |
| 17651 | .@"addrspace" = address_space, | 18063 | .alignment = abi_align, |
| 17652 | .bit_offset = bit_offset, | 18064 | .address_space = address_space, |
| 17653 | .host_size = host_size, | 18065 | .is_const = !inst_data.flags.is_mutable, |
| 17654 | .mutable = inst_data.flags.is_mutable, | 18066 | .is_allowzero = inst_data.flags.is_allowzero, |
| 17655 | .@"allowzero" = inst_data.flags.is_allowzero, | 18067 | .is_volatile = inst_data.flags.is_volatile, |
| 17656 | .@"volatile" = inst_data.flags.is_volatile, | 18068 | .size = inst_data.size, |
| 17657 | .size = inst_data.size, | 18069 | }, |
| 18070 | .packed_offset = .{ | ||
| 18071 | .bit_offset = bit_offset, | ||
| 18072 | .host_size = host_size, | ||
| 18073 | }, | ||
| 17658 | }); | 18074 | }); |
| 17659 | return sema.addType(ty); | 18075 | return sema.addType(ty); |
| 17660 | } | 18076 | } |
| ... | @@ -17666,8 +18082,9 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE | ... | @@ -17666,8 +18082,9 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 17666 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 18082 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 17667 | const src = inst_data.src(); | 18083 | const src = inst_data.src(); |
| 17668 | const obj_ty = try sema.resolveType(block, src, inst_data.operand); | 18084 | const obj_ty = try sema.resolveType(block, src, inst_data.operand); |
| 18085 | const mod = sema.mod; | ||
| 17669 | 18086 | ||
| 17670 | switch (obj_ty.zigTypeTag()) { | 18087 | switch (obj_ty.zigTypeTag(mod)) { |
| 17671 | .Struct => return sema.structInitEmpty(block, obj_ty, src, src), | 18088 | .Struct => return sema.structInitEmpty(block, obj_ty, src, src), |
| 17672 | .Array, .Vector => return sema.arrayInitEmpty(block, src, obj_ty), | 18089 | .Array, .Vector => return sema.arrayInitEmpty(block, src, obj_ty), |
| 17673 | .Void => return sema.addConstant(obj_ty, Value.void), | 18090 | .Void => return sema.addConstant(obj_ty, Value.void), |
| ... | @@ -17683,12 +18100,13 @@ fn structInitEmpty( | ... | @@ -17683,12 +18100,13 @@ fn structInitEmpty( |
| 17683 | dest_src: LazySrcLoc, | 18100 | dest_src: LazySrcLoc, |
| 17684 | init_src: LazySrcLoc, | 18101 | init_src: LazySrcLoc, |
| 17685 | ) CompileError!Air.Inst.Ref { | 18102 | ) CompileError!Air.Inst.Ref { |
| 18103 | const mod = sema.mod; | ||
| 17686 | const gpa = sema.gpa; | 18104 | const gpa = sema.gpa; |
| 17687 | // This logic must be synchronized with that in `zirStructInit`. | 18105 | // This logic must be synchronized with that in `zirStructInit`. |
| 17688 | const struct_ty = try sema.resolveTypeFields(obj_ty); | 18106 | const struct_ty = try sema.resolveTypeFields(obj_ty); |
| 17689 | 18107 | ||
| 17690 | // The init values to use for the struct instance. | 18108 | // The init values to use for the struct instance. |
| 17691 | const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount()); | 18109 | const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(mod)); |
| 17692 | defer gpa.free(field_inits); | 18110 | defer gpa.free(field_inits); |
| 17693 | @memset(field_inits, .none); | 18111 | @memset(field_inits, .none); |
| 17694 | 18112 | ||
| ... | @@ -17696,20 +18114,19 @@ fn structInitEmpty( | ... | @@ -17696,20 +18114,19 @@ fn structInitEmpty( |
| 17696 | } | 18114 | } |
| 17697 | 18115 | ||
| 17698 | fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref { | 18116 | fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref { |
| 17699 | const arr_len = obj_ty.arrayLen(); | 18117 | const mod = sema.mod; |
| 18118 | const arr_len = obj_ty.arrayLen(mod); | ||
| 17700 | if (arr_len != 0) { | 18119 | if (arr_len != 0) { |
| 17701 | if (obj_ty.zigTypeTag() == .Array) { | 18120 | if (obj_ty.zigTypeTag(mod) == .Array) { |
| 17702 | return sema.fail(block, src, "expected {d} array elements; found 0", .{arr_len}); | 18121 | return sema.fail(block, src, "expected {d} array elements; found 0", .{arr_len}); |
| 17703 | } else { | 18122 | } else { |
| 17704 | return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len}); | 18123 | return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len}); |
| 17705 | } | 18124 | } |
| 17706 | } | 18125 | } |
| 17707 | if (obj_ty.sentinel()) |sentinel| { | 18126 | return sema.addConstant(obj_ty, (try mod.intern(.{ .aggregate = .{ |
| 17708 | const val = try Value.Tag.empty_array_sentinel.create(sema.arena, sentinel); | 18127 | .ty = obj_ty.toIntern(), |
| 17709 | return sema.addConstant(obj_ty, val); | 18128 | .storage = .{ .elems = &.{} }, |
| 17710 | } else { | 18129 | } })).toValue()); |
| 17711 | return sema.addConstant(obj_ty, Value.initTag(.empty_array)); | ||
| 17712 | } | ||
| 17713 | } | 18130 | } |
| 17714 | 18131 | ||
| 17715 | fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 18132 | fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -17719,7 +18136,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -17719,7 +18136,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 17719 | const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; | 18136 | const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; |
| 17720 | const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; | 18137 | const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; |
| 17721 | const union_ty = try sema.resolveType(block, ty_src, extra.union_type); | 18138 | const union_ty = try sema.resolveType(block, ty_src, extra.union_type); |
| 17722 | const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "name of field being initialized must be comptime-known"); | 18139 | const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, "name of field being initialized must be comptime-known"); |
| 17723 | const init = try sema.resolveInst(extra.init); | 18140 | const init = try sema.resolveInst(extra.init); |
| 17724 | return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src); | 18141 | return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src); |
| 17725 | } | 18142 | } |
| ... | @@ -17731,21 +18148,23 @@ fn unionInit( | ... | @@ -17731,21 +18148,23 @@ fn unionInit( |
| 17731 | init_src: LazySrcLoc, | 18148 | init_src: LazySrcLoc, |
| 17732 | union_ty: Type, | 18149 | union_ty: Type, |
| 17733 | union_ty_src: LazySrcLoc, | 18150 | union_ty_src: LazySrcLoc, |
| 17734 | field_name: []const u8, | 18151 | field_name: InternPool.NullTerminatedString, |
| 17735 | field_src: LazySrcLoc, | 18152 | field_src: LazySrcLoc, |
| 17736 | ) CompileError!Air.Inst.Ref { | 18153 | ) CompileError!Air.Inst.Ref { |
| 18154 | const mod = sema.mod; | ||
| 17737 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src); | 18155 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src); |
| 17738 | const field = union_ty.unionFields().values()[field_index]; | 18156 | const field = union_ty.unionFields(mod).values()[field_index]; |
| 17739 | const init = try sema.coerce(block, field.ty, uncasted_init, init_src); | 18157 | const init = try sema.coerce(block, field.ty, uncasted_init, init_src); |
| 17740 | 18158 | ||
| 17741 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { | 18159 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { |
| 17742 | const tag_ty = union_ty.unionTagTypeHypothetical(); | 18160 | const tag_ty = union_ty.unionTagTypeHypothetical(mod); |
| 17743 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); | 18161 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); |
| 17744 | const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); | 18162 | const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); |
| 17745 | return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{ | 18163 | return sema.addConstant(union_ty, (try mod.intern(.{ .un = .{ |
| 17746 | .tag = tag_val, | 18164 | .ty = union_ty.toIntern(), |
| 17747 | .val = init_val, | 18165 | .tag = try tag_val.intern(tag_ty, mod), |
| 17748 | })); | 18166 | .val = try init_val.intern(field.ty, mod), |
| 18167 | } })).toValue()); | ||
| 17749 | } | 18168 | } |
| 17750 | 18169 | ||
| 17751 | try sema.requireRuntimeBlock(block, init_src, null); | 18170 | try sema.requireRuntimeBlock(block, init_src, null); |
| ... | @@ -17766,29 +18185,30 @@ fn zirStructInit( | ... | @@ -17766,29 +18185,30 @@ fn zirStructInit( |
| 17766 | const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index); | 18185 | const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index); |
| 17767 | const src = inst_data.src(); | 18186 | const src = inst_data.src(); |
| 17768 | 18187 | ||
| 18188 | const mod = sema.mod; | ||
| 17769 | const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; | 18189 | const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; |
| 17770 | const first_field_type_data = zir_datas[first_item.field_type].pl_node; | 18190 | const first_field_type_data = zir_datas[first_item.field_type].pl_node; |
| 17771 | const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data; | 18191 | const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data; |
| 17772 | const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type); | 18192 | const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type); |
| 17773 | try sema.resolveTypeLayout(resolved_ty); | 18193 | try sema.resolveTypeLayout(resolved_ty); |
| 17774 | 18194 | ||
| 17775 | if (resolved_ty.zigTypeTag() == .Struct) { | 18195 | if (resolved_ty.zigTypeTag(mod) == .Struct) { |
| 17776 | // This logic must be synchronized with that in `zirStructInitEmpty`. | 18196 | // This logic must be synchronized with that in `zirStructInitEmpty`. |
| 17777 | 18197 | ||
| 17778 | // Maps field index to field_type index of where it was already initialized. | 18198 | // Maps field index to field_type index of where it was already initialized. |
| 17779 | // For making sure all fields are accounted for and no fields are duplicated. | 18199 | // For making sure all fields are accounted for and no fields are duplicated. |
| 17780 | const found_fields = try gpa.alloc(Zir.Inst.Index, resolved_ty.structFieldCount()); | 18200 | const found_fields = try gpa.alloc(Zir.Inst.Index, resolved_ty.structFieldCount(mod)); |
| 17781 | defer gpa.free(found_fields); | 18201 | defer gpa.free(found_fields); |
| 17782 | 18202 | ||
| 17783 | // The init values to use for the struct instance. | 18203 | // The init values to use for the struct instance. |
| 17784 | const field_inits = try gpa.alloc(Air.Inst.Ref, resolved_ty.structFieldCount()); | 18204 | const field_inits = try gpa.alloc(Air.Inst.Ref, resolved_ty.structFieldCount(mod)); |
| 17785 | defer gpa.free(field_inits); | 18205 | defer gpa.free(field_inits); |
| 17786 | @memset(field_inits, .none); | 18206 | @memset(field_inits, .none); |
| 17787 | 18207 | ||
| 17788 | var field_i: u32 = 0; | 18208 | var field_i: u32 = 0; |
| 17789 | var extra_index = extra.end; | 18209 | var extra_index = extra.end; |
| 17790 | 18210 | ||
| 17791 | const is_packed = resolved_ty.containerLayout() == .Packed; | 18211 | const is_packed = resolved_ty.containerLayout(mod) == .Packed; |
| 17792 | while (field_i < extra.data.fields_len) : (field_i += 1) { | 18212 | while (field_i < extra.data.fields_len) : (field_i += 1) { |
| 17793 | const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index); | 18213 | const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index); |
| 17794 | extra_index = item.end; | 18214 | extra_index = item.end; |
| ... | @@ -17796,8 +18216,8 @@ fn zirStructInit( | ... | @@ -17796,8 +18216,8 @@ fn zirStructInit( |
| 17796 | const field_type_data = zir_datas[item.data.field_type].pl_node; | 18216 | const field_type_data = zir_datas[item.data.field_type].pl_node; |
| 17797 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; | 18217 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; |
| 17798 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; | 18218 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; |
| 17799 | const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); | 18219 | const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start)); |
| 17800 | const field_index = if (resolved_ty.isTuple()) | 18220 | const field_index = if (resolved_ty.isTuple(mod)) |
| 17801 | try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src) | 18221 | try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src) |
| 17802 | else | 18222 | else |
| 17803 | try sema.structFieldIndex(block, resolved_ty, field_name, field_src); | 18223 | try sema.structFieldIndex(block, resolved_ty, field_name, field_src); |
| ... | @@ -17815,19 +18235,19 @@ fn zirStructInit( | ... | @@ -17815,19 +18235,19 @@ fn zirStructInit( |
| 17815 | } | 18235 | } |
| 17816 | found_fields[field_index] = item.data.field_type; | 18236 | found_fields[field_index] = item.data.field_type; |
| 17817 | field_inits[field_index] = try sema.resolveInst(item.data.init); | 18237 | field_inits[field_index] = try sema.resolveInst(item.data.init); |
| 17818 | if (!is_packed) if (resolved_ty.structFieldValueComptime(field_index)) |default_value| { | 18238 | if (!is_packed) if (try resolved_ty.structFieldValueComptime(mod, field_index)) |default_value| { |
| 17819 | const init_val = (try sema.resolveMaybeUndefVal(field_inits[field_index])) orelse { | 18239 | const init_val = (try sema.resolveMaybeUndefVal(field_inits[field_index])) orelse { |
| 17820 | return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); | 18240 | return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); |
| 17821 | }; | 18241 | }; |
| 17822 | 18242 | ||
| 17823 | if (!init_val.eql(default_value, resolved_ty.structFieldType(field_index), sema.mod)) { | 18243 | if (!init_val.eql(default_value, resolved_ty.structFieldType(field_index, mod), mod)) { |
| 17824 | return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index); | 18244 | return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index); |
| 17825 | } | 18245 | } |
| 17826 | }; | 18246 | }; |
| 17827 | } | 18247 | } |
| 17828 | 18248 | ||
| 17829 | return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref); | 18249 | return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref); |
| 17830 | } else if (resolved_ty.zigTypeTag() == .Union) { | 18250 | } else if (resolved_ty.zigTypeTag(mod) == .Union) { |
| 17831 | if (extra.data.fields_len != 1) { | 18251 | if (extra.data.fields_len != 1) { |
| 17832 | return sema.fail(block, src, "union initialization expects exactly one field", .{}); | 18252 | return sema.fail(block, src, "union initialization expects exactly one field", .{}); |
| 17833 | } | 18253 | } |
| ... | @@ -17837,32 +18257,32 @@ fn zirStructInit( | ... | @@ -17837,32 +18257,32 @@ fn zirStructInit( |
| 17837 | const field_type_data = zir_datas[item.data.field_type].pl_node; | 18257 | const field_type_data = zir_datas[item.data.field_type].pl_node; |
| 17838 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; | 18258 | const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; |
| 17839 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; | 18259 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; |
| 17840 | const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); | 18260 | const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start)); |
| 17841 | const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src); | 18261 | const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src); |
| 17842 | const tag_ty = resolved_ty.unionTagTypeHypothetical(); | 18262 | const tag_ty = resolved_ty.unionTagTypeHypothetical(mod); |
| 17843 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); | 18263 | const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); |
| 17844 | const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); | 18264 | const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); |
| 17845 | 18265 | ||
| 17846 | const init_inst = try sema.resolveInst(item.data.init); | 18266 | const init_inst = try sema.resolveInst(item.data.init); |
| 17847 | if (try sema.resolveMaybeUndefVal(init_inst)) |val| { | 18267 | if (try sema.resolveMaybeUndefVal(init_inst)) |val| { |
| 17848 | return sema.addConstantMaybeRef( | 18268 | const field = resolved_ty.unionFields(mod).values()[field_index]; |
| 17849 | block, | 18269 | return sema.addConstantMaybeRef(block, resolved_ty, (try mod.intern(.{ .un = .{ |
| 17850 | resolved_ty, | 18270 | .ty = resolved_ty.toIntern(), |
| 17851 | try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = val }), | 18271 | .tag = try tag_val.intern(tag_ty, mod), |
| 17852 | is_ref, | 18272 | .val = try val.intern(field.ty, mod), |
| 17853 | ); | 18273 | } })).toValue(), is_ref); |
| 17854 | } | 18274 | } |
| 17855 | 18275 | ||
| 17856 | if (is_ref) { | 18276 | if (is_ref) { |
| 17857 | const target = sema.mod.getTarget(); | 18277 | const target = mod.getTarget(); |
| 17858 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18278 | const alloc_ty = try Type.ptr(sema.arena, mod, .{ |
| 17859 | .pointee_type = resolved_ty, | 18279 | .pointee_type = resolved_ty, |
| 17860 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18280 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 17861 | }); | 18281 | }); |
| 17862 | const alloc = try block.addTy(.alloc, alloc_ty); | 18282 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 17863 | const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true); | 18283 | const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true); |
| 17864 | try sema.storePtr(block, src, field_ptr, init_inst); | 18284 | try sema.storePtr(block, src, field_ptr, init_inst); |
| 17865 | const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val); | 18285 | const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(mod), tag_val); |
| 17866 | _ = try block.addBinOp(.set_union_tag, alloc, new_tag); | 18286 | _ = try block.addBinOp(.set_union_tag, alloc, new_tag); |
| 17867 | return sema.makePtrConst(block, alloc); | 18287 | return sema.makePtrConst(block, alloc); |
| 17868 | } | 18288 | } |
| ... | @@ -17870,7 +18290,7 @@ fn zirStructInit( | ... | @@ -17870,7 +18290,7 @@ fn zirStructInit( |
| 17870 | try sema.requireRuntimeBlock(block, src, null); | 18290 | try sema.requireRuntimeBlock(block, src, null); |
| 17871 | try sema.queueFullTypeResolution(resolved_ty); | 18291 | try sema.queueFullTypeResolution(resolved_ty); |
| 17872 | return block.addUnionInit(resolved_ty, field_index, init_inst); | 18292 | return block.addUnionInit(resolved_ty, field_index, init_inst); |
| 17873 | } else if (resolved_ty.isAnonStruct()) { | 18293 | } else if (resolved_ty.isAnonStruct(mod)) { |
| 17874 | return sema.fail(block, src, "TODO anon struct init validation", .{}); | 18294 | return sema.fail(block, src, "TODO anon struct init validation", .{}); |
| 17875 | } | 18295 | } |
| 17876 | unreachable; | 18296 | unreachable; |
| ... | @@ -17885,76 +18305,70 @@ fn finishStructInit( | ... | @@ -17885,76 +18305,70 @@ fn finishStructInit( |
| 17885 | struct_ty: Type, | 18305 | struct_ty: Type, |
| 17886 | is_ref: bool, | 18306 | is_ref: bool, |
| 17887 | ) CompileError!Air.Inst.Ref { | 18307 | ) CompileError!Air.Inst.Ref { |
| 17888 | const gpa = sema.gpa; | 18308 | const mod = sema.mod; |
| 18309 | const ip = &mod.intern_pool; | ||
| 17889 | 18310 | ||
| 17890 | var root_msg: ?*Module.ErrorMsg = null; | 18311 | var root_msg: ?*Module.ErrorMsg = null; |
| 17891 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); | 18312 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 17892 | 18313 | ||
| 17893 | if (struct_ty.isAnonStruct()) { | 18314 | switch (ip.indexToKey(struct_ty.toIntern())) { |
| 17894 | const struct_obj = struct_ty.castTag(.anon_struct).?.data; | 18315 | .anon_struct_type => |anon_struct| { |
| 17895 | for (struct_obj.values, 0..) |default_val, i| { | 18316 | for (anon_struct.types, anon_struct.values, 0..) |field_ty, default_val, i| { |
| 17896 | if (field_inits[i] != .none) continue; | 18317 | if (field_inits[i] != .none) continue; |
| 17897 | |||
| 17898 | if (default_val.tag() == .unreachable_value) { | ||
| 17899 | const field_name = struct_obj.names[i]; | ||
| 17900 | const template = "missing struct field: {s}"; | ||
| 17901 | const args = .{field_name}; | ||
| 17902 | if (root_msg) |msg| { | ||
| 17903 | try sema.errNote(block, init_src, msg, template, args); | ||
| 17904 | } else { | ||
| 17905 | root_msg = try sema.errMsg(block, init_src, template, args); | ||
| 17906 | } | ||
| 17907 | } else { | ||
| 17908 | field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val); | ||
| 17909 | } | ||
| 17910 | } | ||
| 17911 | } else if (struct_ty.isTuple()) { | ||
| 17912 | var i: u32 = 0; | ||
| 17913 | const len = struct_ty.structFieldCount(); | ||
| 17914 | while (i < len) : (i += 1) { | ||
| 17915 | if (field_inits[i] != .none) continue; | ||
| 17916 | 18318 | ||
| 17917 | const default_val = struct_ty.structFieldDefaultValue(i); | 18319 | if (default_val == .none) { |
| 17918 | if (default_val.tag() == .unreachable_value) { | 18320 | if (anon_struct.names.len == 0) { |
| 17919 | const template = "missing tuple field with index {d}"; | 18321 | const template = "missing tuple field with index {d}"; |
| 17920 | if (root_msg) |msg| { | 18322 | if (root_msg) |msg| { |
| 17921 | try sema.errNote(block, init_src, msg, template, .{i}); | 18323 | try sema.errNote(block, init_src, msg, template, .{i}); |
| 18324 | } else { | ||
| 18325 | root_msg = try sema.errMsg(block, init_src, template, .{i}); | ||
| 18326 | } | ||
| 18327 | } else { | ||
| 18328 | const field_name = anon_struct.names[i]; | ||
| 18329 | const template = "missing struct field: {}"; | ||
| 18330 | const args = .{field_name.fmt(ip)}; | ||
| 18331 | if (root_msg) |msg| { | ||
| 18332 | try sema.errNote(block, init_src, msg, template, args); | ||
| 18333 | } else { | ||
| 18334 | root_msg = try sema.errMsg(block, init_src, template, args); | ||
| 18335 | } | ||
| 18336 | } | ||
| 17922 | } else { | 18337 | } else { |
| 17923 | root_msg = try sema.errMsg(block, init_src, template, .{i}); | 18338 | field_inits[i] = try sema.addConstant(field_ty.toType(), default_val.toValue()); |
| 17924 | } | 18339 | } |
| 17925 | } else { | ||
| 17926 | field_inits[i] = try sema.addConstant(struct_ty.structFieldType(i), default_val); | ||
| 17927 | } | 18340 | } |
| 17928 | } | 18341 | }, |
| 17929 | } else { | 18342 | .struct_type => |struct_type| { |
| 17930 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 18343 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 17931 | for (struct_obj.fields.values(), 0..) |field, i| { | 18344 | for (struct_obj.fields.values(), 0..) |field, i| { |
| 17932 | if (field_inits[i] != .none) continue; | 18345 | if (field_inits[i] != .none) continue; |
| 17933 | 18346 | ||
| 17934 | if (field.default_val.tag() == .unreachable_value) { | 18347 | if (field.default_val == .none) { |
| 17935 | const field_name = struct_obj.fields.keys()[i]; | 18348 | const field_name = struct_obj.fields.keys()[i]; |
| 17936 | const template = "missing struct field: {s}"; | 18349 | const template = "missing struct field: {}"; |
| 17937 | const args = .{field_name}; | 18350 | const args = .{field_name.fmt(ip)}; |
| 17938 | if (root_msg) |msg| { | 18351 | if (root_msg) |msg| { |
| 17939 | try sema.errNote(block, init_src, msg, template, args); | 18352 | try sema.errNote(block, init_src, msg, template, args); |
| 18353 | } else { | ||
| 18354 | root_msg = try sema.errMsg(block, init_src, template, args); | ||
| 18355 | } | ||
| 17940 | } else { | 18356 | } else { |
| 17941 | root_msg = try sema.errMsg(block, init_src, template, args); | 18357 | field_inits[i] = try sema.addConstant(field.ty, field.default_val.toValue()); |
| 17942 | } | 18358 | } |
| 17943 | } else { | ||
| 17944 | field_inits[i] = try sema.addConstant(field.ty, field.default_val); | ||
| 17945 | } | 18359 | } |
| 17946 | } | 18360 | }, |
| 18361 | else => unreachable, | ||
| 17947 | } | 18362 | } |
| 17948 | 18363 | ||
| 17949 | if (root_msg) |msg| { | 18364 | if (root_msg) |msg| { |
| 17950 | if (struct_ty.castTag(.@"struct")) |struct_obj| { | 18365 | if (mod.typeToStruct(struct_ty)) |struct_obj| { |
| 17951 | const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod); | 18366 | const fqn = try struct_obj.getFullyQualifiedName(mod); |
| 17952 | defer gpa.free(fqn); | 18367 | try mod.errNoteNonLazy( |
| 17953 | try sema.mod.errNoteNonLazy( | 18368 | struct_obj.srcLoc(mod), |
| 17954 | struct_obj.data.srcLoc(sema.mod), | ||
| 17955 | msg, | 18369 | msg, |
| 17956 | "struct '{s}' declared here", | 18370 | "struct '{}' declared here", |
| 17957 | .{fqn}, | 18371 | .{fqn.fmt(ip)}, |
| 17958 | ); | 18372 | ); |
| 17959 | } | 18373 | } |
| 17960 | root_msg = null; | 18374 | root_msg = null; |
| ... | @@ -17969,18 +18383,22 @@ fn finishStructInit( | ... | @@ -17969,18 +18383,22 @@ fn finishStructInit( |
| 17969 | } else null; | 18383 | } else null; |
| 17970 | 18384 | ||
| 17971 | const runtime_index = opt_runtime_index orelse { | 18385 | const runtime_index = opt_runtime_index orelse { |
| 17972 | const values = try sema.arena.alloc(Value, field_inits.len); | 18386 | const elems = try sema.arena.alloc(InternPool.Index, field_inits.len); |
| 17973 | for (field_inits, 0..) |field_init, i| { | 18387 | for (elems, field_inits, 0..) |*elem, field_init, field_i| { |
| 17974 | values[i] = (sema.resolveMaybeUndefVal(field_init) catch unreachable).?; | 18388 | elem.* = try (sema.resolveMaybeUndefVal(field_init) catch unreachable).? |
| 17975 | } | 18389 | .intern(struct_ty.structFieldType(field_i, mod), mod); |
| 17976 | const struct_val = try Value.Tag.aggregate.create(sema.arena, values); | 18390 | } |
| 17977 | return sema.addConstantMaybeRef(block, struct_ty, struct_val, is_ref); | 18391 | const struct_val = try mod.intern(.{ .aggregate = .{ |
| 18392 | .ty = struct_ty.toIntern(), | ||
| 18393 | .storage = .{ .elems = elems }, | ||
| 18394 | } }); | ||
| 18395 | return sema.addConstantMaybeRef(block, struct_ty, struct_val.toValue(), is_ref); | ||
| 17978 | }; | 18396 | }; |
| 17979 | 18397 | ||
| 17980 | if (is_ref) { | 18398 | if (is_ref) { |
| 17981 | try sema.resolveStructLayout(struct_ty); | 18399 | try sema.resolveStructLayout(struct_ty); |
| 17982 | const target = sema.mod.getTarget(); | 18400 | const target = sema.mod.getTarget(); |
| 17983 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18401 | const alloc_ty = try Type.ptr(sema.arena, mod, .{ |
| 17984 | .pointee_type = struct_ty, | 18402 | .pointee_type = struct_ty, |
| 17985 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18403 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 17986 | }); | 18404 | }); |
| ... | @@ -17997,8 +18415,8 @@ fn finishStructInit( | ... | @@ -17997,8 +18415,8 @@ fn finishStructInit( |
| 17997 | 18415 | ||
| 17998 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { | 18416 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { |
| 17999 | error.NeededSourceLocation => { | 18417 | error.NeededSourceLocation => { |
| 18000 | const decl = sema.mod.declPtr(block.src_decl); | 18418 | const decl = mod.declPtr(block.src_decl); |
| 18001 | const field_src = Module.initSrc(dest_src.node_offset.x, sema.gpa, decl, runtime_index); | 18419 | const field_src = mod.initSrc(dest_src.node_offset.x, decl, runtime_index); |
| 18002 | try sema.requireRuntimeBlock(block, dest_src, field_src); | 18420 | try sema.requireRuntimeBlock(block, dest_src, field_src); |
| 18003 | unreachable; | 18421 | unreachable; |
| 18004 | }, | 18422 | }, |
| ... | @@ -18014,79 +18432,85 @@ fn zirStructInitAnon( | ... | @@ -18014,79 +18432,85 @@ fn zirStructInitAnon( |
| 18014 | inst: Zir.Inst.Index, | 18432 | inst: Zir.Inst.Index, |
| 18015 | is_ref: bool, | 18433 | is_ref: bool, |
| 18016 | ) CompileError!Air.Inst.Ref { | 18434 | ) CompileError!Air.Inst.Ref { |
| 18435 | const mod = sema.mod; | ||
| 18436 | const gpa = sema.gpa; | ||
| 18017 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 18437 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 18018 | const src = inst_data.src(); | 18438 | const src = inst_data.src(); |
| 18019 | const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); | 18439 | const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); |
| 18020 | const types = try sema.arena.alloc(Type, extra.data.fields_len); | 18440 | const types = try sema.arena.alloc(InternPool.Index, extra.data.fields_len); |
| 18021 | const values = try sema.arena.alloc(Value, types.len); | 18441 | const values = try sema.arena.alloc(InternPool.Index, types.len); |
| 18022 | var fields = std.StringArrayHashMapUnmanaged(u32){}; | 18442 | var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena); |
| 18023 | defer fields.deinit(sema.gpa); | 18443 | try fields.ensureUnusedCapacity(types.len); |
| 18024 | try fields.ensureUnusedCapacity(sema.gpa, types.len); | ||
| 18025 | 18444 | ||
| 18026 | // Find which field forces the expression to be runtime, if any. | 18445 | // Find which field forces the expression to be runtime, if any. |
| 18027 | const opt_runtime_index = rs: { | 18446 | const opt_runtime_index = rs: { |
| 18028 | var runtime_index: ?usize = null; | 18447 | var runtime_index: ?usize = null; |
| 18029 | var extra_index = extra.end; | 18448 | var extra_index = extra.end; |
| 18030 | for (types, 0..) |*field_ty, i| { | 18449 | for (types, 0..) |*field_ty, i_usize| { |
| 18450 | const i = @intCast(u32, i_usize); | ||
| 18031 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); | 18451 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); |
| 18032 | extra_index = item.end; | 18452 | extra_index = item.end; |
| 18033 | 18453 | ||
| 18034 | const name = sema.code.nullTerminatedString(item.data.field_name); | 18454 | const name = sema.code.nullTerminatedString(item.data.field_name); |
| 18035 | const gop = fields.getOrPutAssumeCapacity(name); | 18455 | const name_ip = try mod.intern_pool.getOrPutString(gpa, name); |
| 18456 | const gop = fields.getOrPutAssumeCapacity(name_ip); | ||
| 18036 | if (gop.found_existing) { | 18457 | if (gop.found_existing) { |
| 18037 | const msg = msg: { | 18458 | const msg = msg: { |
| 18038 | const decl = sema.mod.declPtr(block.src_decl); | 18459 | const decl = mod.declPtr(block.src_decl); |
| 18039 | const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i); | 18460 | const field_src = mod.initSrc(src.node_offset.x, decl, i); |
| 18040 | const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); | 18461 | const msg = try sema.errMsg(block, field_src, "duplicate field", .{}); |
| 18041 | errdefer msg.destroy(sema.gpa); | 18462 | errdefer msg.destroy(gpa); |
| 18042 | 18463 | ||
| 18043 | const prev_source = Module.initSrc(src.node_offset.x, sema.gpa, decl, gop.value_ptr.*); | 18464 | const prev_source = mod.initSrc(src.node_offset.x, decl, gop.value_ptr.*); |
| 18044 | try sema.errNote(block, prev_source, msg, "other field here", .{}); | 18465 | try sema.errNote(block, prev_source, msg, "other field here", .{}); |
| 18045 | break :msg msg; | 18466 | break :msg msg; |
| 18046 | }; | 18467 | }; |
| 18047 | return sema.failWithOwnedErrorMsg(msg); | 18468 | return sema.failWithOwnedErrorMsg(msg); |
| 18048 | } | 18469 | } |
| 18049 | gop.value_ptr.* = @intCast(u32, i); | 18470 | gop.value_ptr.* = i; |
| 18050 | 18471 | ||
| 18051 | const init = try sema.resolveInst(item.data.init); | 18472 | const init = try sema.resolveInst(item.data.init); |
| 18052 | field_ty.* = sema.typeOf(init); | 18473 | field_ty.* = sema.typeOf(init).toIntern(); |
| 18053 | if (types[i].zigTypeTag() == .Opaque) { | 18474 | if (field_ty.toType().zigTypeTag(mod) == .Opaque) { |
| 18054 | const msg = msg: { | 18475 | const msg = msg: { |
| 18055 | const decl = sema.mod.declPtr(block.src_decl); | 18476 | const decl = mod.declPtr(block.src_decl); |
| 18056 | const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i); | 18477 | const field_src = mod.initSrc(src.node_offset.x, decl, i); |
| 18057 | const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); | 18478 | const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 18058 | errdefer msg.destroy(sema.gpa); | 18479 | errdefer msg.destroy(sema.gpa); |
| 18059 | 18480 | ||
| 18060 | try sema.addDeclaredHereNote(msg, types[i]); | 18481 | try sema.addDeclaredHereNote(msg, field_ty.toType()); |
| 18061 | break :msg msg; | 18482 | break :msg msg; |
| 18062 | }; | 18483 | }; |
| 18063 | return sema.failWithOwnedErrorMsg(msg); | 18484 | return sema.failWithOwnedErrorMsg(msg); |
| 18064 | } | 18485 | } |
| 18065 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { | 18486 | if (try sema.resolveMaybeUndefVal(init)) |init_val| { |
| 18066 | values[i] = init_val; | 18487 | values[i] = try init_val.intern(field_ty.toType(), mod); |
| 18067 | } else { | 18488 | } else { |
| 18068 | values[i] = Value.initTag(.unreachable_value); | 18489 | values[i] = .none; |
| 18069 | runtime_index = i; | 18490 | runtime_index = i; |
| 18070 | } | 18491 | } |
| 18071 | } | 18492 | } |
| 18072 | break :rs runtime_index; | 18493 | break :rs runtime_index; |
| 18073 | }; | 18494 | }; |
| 18074 | 18495 | ||
| 18075 | const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{ | 18496 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ |
| 18076 | .names = try sema.arena.dupe([]const u8, fields.keys()), | 18497 | .names = fields.keys(), |
| 18077 | .types = types, | 18498 | .types = types, |
| 18078 | .values = values, | 18499 | .values = values, |
| 18079 | }); | 18500 | } }); |
| 18080 | 18501 | ||
| 18081 | const runtime_index = opt_runtime_index orelse { | 18502 | const runtime_index = opt_runtime_index orelse { |
| 18082 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | 18503 | const tuple_val = try mod.intern(.{ .aggregate = .{ |
| 18083 | return sema.addConstantMaybeRef(block, tuple_ty, tuple_val, is_ref); | 18504 | .ty = tuple_ty, |
| 18505 | .storage = .{ .elems = values }, | ||
| 18506 | } }); | ||
| 18507 | return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref); | ||
| 18084 | }; | 18508 | }; |
| 18085 | 18509 | ||
| 18086 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { | 18510 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { |
| 18087 | error.NeededSourceLocation => { | 18511 | error.NeededSourceLocation => { |
| 18088 | const decl = sema.mod.declPtr(block.src_decl); | 18512 | const decl = mod.declPtr(block.src_decl); |
| 18089 | const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, runtime_index); | 18513 | const field_src = mod.initSrc(src.node_offset.x, decl, runtime_index); |
| 18090 | try sema.requireRuntimeBlock(block, src, field_src); | 18514 | try sema.requireRuntimeBlock(block, src, field_src); |
| 18091 | unreachable; | 18515 | unreachable; |
| 18092 | }, | 18516 | }, |
| ... | @@ -18094,9 +18518,9 @@ fn zirStructInitAnon( | ... | @@ -18094,9 +18518,9 @@ fn zirStructInitAnon( |
| 18094 | }; | 18518 | }; |
| 18095 | 18519 | ||
| 18096 | if (is_ref) { | 18520 | if (is_ref) { |
| 18097 | const target = sema.mod.getTarget(); | 18521 | const target = mod.getTarget(); |
| 18098 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18522 | const alloc_ty = try Type.ptr(sema.arena, mod, .{ |
| 18099 | .pointee_type = tuple_ty, | 18523 | .pointee_type = tuple_ty.toType(), |
| 18100 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18524 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18101 | }); | 18525 | }); |
| 18102 | const alloc = try block.addTy(.alloc, alloc_ty); | 18526 | const alloc = try block.addTy(.alloc, alloc_ty); |
| ... | @@ -18106,12 +18530,12 @@ fn zirStructInitAnon( | ... | @@ -18106,12 +18530,12 @@ fn zirStructInitAnon( |
| 18106 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); | 18530 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); |
| 18107 | extra_index = item.end; | 18531 | extra_index = item.end; |
| 18108 | 18532 | ||
| 18109 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18533 | const field_ptr_ty = try Type.ptr(sema.arena, mod, .{ |
| 18110 | .mutable = true, | 18534 | .mutable = true, |
| 18111 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18535 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18112 | .pointee_type = field_ty, | 18536 | .pointee_type = field_ty.toType(), |
| 18113 | }); | 18537 | }); |
| 18114 | if (values[i].tag() == .unreachable_value) { | 18538 | if (values[i] == .none) { |
| 18115 | const init = try sema.resolveInst(item.data.init); | 18539 | const init = try sema.resolveInst(item.data.init); |
| 18116 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); | 18540 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 18117 | _ = try block.addBinOp(.store, field_ptr, init); | 18541 | _ = try block.addBinOp(.store, field_ptr, init); |
| ... | @@ -18129,7 +18553,7 @@ fn zirStructInitAnon( | ... | @@ -18129,7 +18553,7 @@ fn zirStructInitAnon( |
| 18129 | element_refs[i] = try sema.resolveInst(item.data.init); | 18553 | element_refs[i] = try sema.resolveInst(item.data.init); |
| 18130 | } | 18554 | } |
| 18131 | 18555 | ||
| 18132 | return block.addAggregateInit(tuple_ty, element_refs); | 18556 | return block.addAggregateInit(tuple_ty.toType(), element_refs); |
| 18133 | } | 18557 | } |
| 18134 | 18558 | ||
| 18135 | fn zirArrayInit( | 18559 | fn zirArrayInit( |
| ... | @@ -18138,6 +18562,7 @@ fn zirArrayInit( | ... | @@ -18138,6 +18562,7 @@ fn zirArrayInit( |
| 18138 | inst: Zir.Inst.Index, | 18562 | inst: Zir.Inst.Index, |
| 18139 | is_ref: bool, | 18563 | is_ref: bool, |
| 18140 | ) CompileError!Air.Inst.Ref { | 18564 | ) CompileError!Air.Inst.Ref { |
| 18565 | const mod = sema.mod; | ||
| 18141 | const gpa = sema.gpa; | 18566 | const gpa = sema.gpa; |
| 18142 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 18567 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 18143 | const src = inst_data.src(); | 18568 | const src = inst_data.src(); |
| ... | @@ -18147,20 +18572,20 @@ fn zirArrayInit( | ... | @@ -18147,20 +18572,20 @@ fn zirArrayInit( |
| 18147 | assert(args.len >= 2); // array_ty + at least one element | 18572 | assert(args.len >= 2); // array_ty + at least one element |
| 18148 | 18573 | ||
| 18149 | const array_ty = try sema.resolveType(block, src, args[0]); | 18574 | const array_ty = try sema.resolveType(block, src, args[0]); |
| 18150 | const sentinel_val = array_ty.sentinel(); | 18575 | const sentinel_val = array_ty.sentinel(mod); |
| 18151 | 18576 | ||
| 18152 | const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null)); | 18577 | const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null)); |
| 18153 | defer gpa.free(resolved_args); | 18578 | defer gpa.free(resolved_args); |
| 18154 | for (args[1..], 0..) |arg, i| { | 18579 | for (args[1..], 0..) |arg, i| { |
| 18155 | const resolved_arg = try sema.resolveInst(arg); | 18580 | const resolved_arg = try sema.resolveInst(arg); |
| 18156 | const elem_ty = if (array_ty.zigTypeTag() == .Struct) | 18581 | const elem_ty = if (array_ty.zigTypeTag(mod) == .Struct) |
| 18157 | array_ty.structFieldType(i) | 18582 | array_ty.structFieldType(i, mod) |
| 18158 | else | 18583 | else |
| 18159 | array_ty.elemType2(); | 18584 | array_ty.elemType2(mod); |
| 18160 | resolved_args[i] = sema.coerce(block, elem_ty, resolved_arg, .unneeded) catch |err| switch (err) { | 18585 | resolved_args[i] = sema.coerce(block, elem_ty, resolved_arg, .unneeded) catch |err| switch (err) { |
| 18161 | error.NeededSourceLocation => { | 18586 | error.NeededSourceLocation => { |
| 18162 | const decl = sema.mod.declPtr(block.src_decl); | 18587 | const decl = mod.declPtr(block.src_decl); |
| 18163 | const elem_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i); | 18588 | const elem_src = mod.initSrc(src.node_offset.x, decl, i); |
| 18164 | _ = try sema.coerce(block, elem_ty, resolved_arg, elem_src); | 18589 | _ = try sema.coerce(block, elem_ty, resolved_arg, elem_src); |
| 18165 | unreachable; | 18590 | unreachable; |
| 18166 | }, | 18591 | }, |
| ... | @@ -18169,7 +18594,7 @@ fn zirArrayInit( | ... | @@ -18169,7 +18594,7 @@ fn zirArrayInit( |
| 18169 | } | 18594 | } |
| 18170 | 18595 | ||
| 18171 | if (sentinel_val) |some| { | 18596 | if (sentinel_val) |some| { |
| 18172 | resolved_args[resolved_args.len - 1] = try sema.addConstant(array_ty.elemType2(), some); | 18597 | resolved_args[resolved_args.len - 1] = try sema.addConstant(array_ty.elemType2(mod), some); |
| 18173 | } | 18598 | } |
| 18174 | 18599 | ||
| 18175 | const opt_runtime_index: ?u32 = for (resolved_args, 0..) |arg, i| { | 18600 | const opt_runtime_index: ?u32 = for (resolved_args, 0..) |arg, i| { |
| ... | @@ -18178,21 +18603,25 @@ fn zirArrayInit( | ... | @@ -18178,21 +18603,25 @@ fn zirArrayInit( |
| 18178 | } else null; | 18603 | } else null; |
| 18179 | 18604 | ||
| 18180 | const runtime_index = opt_runtime_index orelse { | 18605 | const runtime_index = opt_runtime_index orelse { |
| 18181 | const elem_vals = try sema.arena.alloc(Value, resolved_args.len); | 18606 | const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len); |
| 18182 | 18607 | for (elem_vals, resolved_args, 0..) |*val, arg, i| { | |
| 18183 | for (resolved_args, 0..) |arg, i| { | 18608 | const elem_ty = if (array_ty.zigTypeTag(mod) == .Struct) |
| 18609 | array_ty.structFieldType(i, mod) | ||
| 18610 | else | ||
| 18611 | array_ty.elemType2(mod); | ||
| 18184 | // We checked that all args are comptime above. | 18612 | // We checked that all args are comptime above. |
| 18185 | elem_vals[i] = (sema.resolveMaybeUndefVal(arg) catch unreachable).?; | 18613 | val.* = try ((sema.resolveMaybeUndefVal(arg) catch unreachable).?).intern(elem_ty, mod); |
| 18186 | } | 18614 | } |
| 18187 | 18615 | return sema.addConstantMaybeRef(block, array_ty, (try mod.intern(.{ .aggregate = .{ | |
| 18188 | const array_val = try Value.Tag.aggregate.create(sema.arena, elem_vals); | 18616 | .ty = array_ty.toIntern(), |
| 18189 | return sema.addConstantMaybeRef(block, array_ty, array_val, is_ref); | 18617 | .storage = .{ .elems = elem_vals }, |
| 18618 | } })).toValue(), is_ref); | ||
| 18190 | }; | 18619 | }; |
| 18191 | 18620 | ||
| 18192 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { | 18621 | sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) { |
| 18193 | error.NeededSourceLocation => { | 18622 | error.NeededSourceLocation => { |
| 18194 | const decl = sema.mod.declPtr(block.src_decl); | 18623 | const decl = mod.declPtr(block.src_decl); |
| 18195 | const elem_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, runtime_index); | 18624 | const elem_src = mod.initSrc(src.node_offset.x, decl, runtime_index); |
| 18196 | try sema.requireRuntimeBlock(block, src, elem_src); | 18625 | try sema.requireRuntimeBlock(block, src, elem_src); |
| 18197 | unreachable; | 18626 | unreachable; |
| 18198 | }, | 18627 | }, |
| ... | @@ -18201,19 +18630,19 @@ fn zirArrayInit( | ... | @@ -18201,19 +18630,19 @@ fn zirArrayInit( |
| 18201 | try sema.queueFullTypeResolution(array_ty); | 18630 | try sema.queueFullTypeResolution(array_ty); |
| 18202 | 18631 | ||
| 18203 | if (is_ref) { | 18632 | if (is_ref) { |
| 18204 | const target = sema.mod.getTarget(); | 18633 | const target = mod.getTarget(); |
| 18205 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18634 | const alloc_ty = try Type.ptr(sema.arena, mod, .{ |
| 18206 | .pointee_type = array_ty, | 18635 | .pointee_type = array_ty, |
| 18207 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18636 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18208 | }); | 18637 | }); |
| 18209 | const alloc = try block.addTy(.alloc, alloc_ty); | 18638 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 18210 | 18639 | ||
| 18211 | if (array_ty.isTuple()) { | 18640 | if (array_ty.isTuple(mod)) { |
| 18212 | for (resolved_args, 0..) |arg, i| { | 18641 | for (resolved_args, 0..) |arg, i| { |
| 18213 | const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18642 | const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{ |
| 18214 | .mutable = true, | 18643 | .mutable = true, |
| 18215 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18644 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18216 | .pointee_type = array_ty.structFieldType(i), | 18645 | .pointee_type = array_ty.structFieldType(i, mod), |
| 18217 | }); | 18646 | }); |
| 18218 | const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); | 18647 | const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); |
| 18219 | 18648 | ||
| ... | @@ -18224,10 +18653,10 @@ fn zirArrayInit( | ... | @@ -18224,10 +18653,10 @@ fn zirArrayInit( |
| 18224 | return sema.makePtrConst(block, alloc); | 18653 | return sema.makePtrConst(block, alloc); |
| 18225 | } | 18654 | } |
| 18226 | 18655 | ||
| 18227 | const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18656 | const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{ |
| 18228 | .mutable = true, | 18657 | .mutable = true, |
| 18229 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18658 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18230 | .pointee_type = array_ty.elemType2(), | 18659 | .pointee_type = array_ty.elemType2(mod), |
| 18231 | }); | 18660 | }); |
| 18232 | const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); | 18661 | const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty); |
| 18233 | 18662 | ||
| ... | @@ -18252,44 +18681,49 @@ fn zirArrayInitAnon( | ... | @@ -18252,44 +18681,49 @@ fn zirArrayInitAnon( |
| 18252 | const src = inst_data.src(); | 18681 | const src = inst_data.src(); |
| 18253 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); | 18682 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); |
| 18254 | const operands = sema.code.refSlice(extra.end, extra.data.operands_len); | 18683 | const operands = sema.code.refSlice(extra.end, extra.data.operands_len); |
| 18684 | const mod = sema.mod; | ||
| 18255 | 18685 | ||
| 18256 | const types = try sema.arena.alloc(Type, operands.len); | 18686 | const types = try sema.arena.alloc(InternPool.Index, operands.len); |
| 18257 | const values = try sema.arena.alloc(Value, operands.len); | 18687 | const values = try sema.arena.alloc(InternPool.Index, operands.len); |
| 18258 | 18688 | ||
| 18259 | const opt_runtime_src = rs: { | 18689 | const opt_runtime_src = rs: { |
| 18260 | var runtime_src: ?LazySrcLoc = null; | 18690 | var runtime_src: ?LazySrcLoc = null; |
| 18261 | for (operands, 0..) |operand, i| { | 18691 | for (operands, 0..) |operand, i| { |
| 18262 | const operand_src = src; // TODO better source location | 18692 | const operand_src = src; // TODO better source location |
| 18263 | const elem = try sema.resolveInst(operand); | 18693 | const elem = try sema.resolveInst(operand); |
| 18264 | types[i] = sema.typeOf(elem); | 18694 | types[i] = sema.typeOf(elem).toIntern(); |
| 18265 | if (types[i].zigTypeTag() == .Opaque) { | 18695 | if (types[i].toType().zigTypeTag(mod) == .Opaque) { |
| 18266 | const msg = msg: { | 18696 | const msg = msg: { |
| 18267 | const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); | 18697 | const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 18268 | errdefer msg.destroy(sema.gpa); | 18698 | errdefer msg.destroy(sema.gpa); |
| 18269 | 18699 | ||
| 18270 | try sema.addDeclaredHereNote(msg, types[i]); | 18700 | try sema.addDeclaredHereNote(msg, types[i].toType()); |
| 18271 | break :msg msg; | 18701 | break :msg msg; |
| 18272 | }; | 18702 | }; |
| 18273 | return sema.failWithOwnedErrorMsg(msg); | 18703 | return sema.failWithOwnedErrorMsg(msg); |
| 18274 | } | 18704 | } |
| 18275 | if (try sema.resolveMaybeUndefVal(elem)) |val| { | 18705 | if (try sema.resolveMaybeUndefVal(elem)) |val| { |
| 18276 | values[i] = val; | 18706 | values[i] = val.toIntern(); |
| 18277 | } else { | 18707 | } else { |
| 18278 | values[i] = Value.initTag(.unreachable_value); | 18708 | values[i] = .none; |
| 18279 | runtime_src = operand_src; | 18709 | runtime_src = operand_src; |
| 18280 | } | 18710 | } |
| 18281 | } | 18711 | } |
| 18282 | break :rs runtime_src; | 18712 | break :rs runtime_src; |
| 18283 | }; | 18713 | }; |
| 18284 | 18714 | ||
| 18285 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ | 18715 | const tuple_ty = try mod.intern(.{ .anon_struct_type = .{ |
| 18286 | .types = types, | 18716 | .types = types, |
| 18287 | .values = values, | 18717 | .values = values, |
| 18288 | }); | 18718 | .names = &.{}, |
| 18719 | } }); | ||
| 18289 | 18720 | ||
| 18290 | const runtime_src = opt_runtime_src orelse { | 18721 | const runtime_src = opt_runtime_src orelse { |
| 18291 | const tuple_val = try Value.Tag.aggregate.create(sema.arena, values); | 18722 | const tuple_val = try mod.intern(.{ .aggregate = .{ |
| 18292 | return sema.addConstantMaybeRef(block, tuple_ty, tuple_val, is_ref); | 18723 | .ty = tuple_ty, |
| 18724 | .storage = .{ .elems = values }, | ||
| 18725 | } }); | ||
| 18726 | return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref); | ||
| 18293 | }; | 18727 | }; |
| 18294 | 18728 | ||
| 18295 | try sema.requireRuntimeBlock(block, src, runtime_src); | 18729 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | @@ -18297,7 +18731,7 @@ fn zirArrayInitAnon( | ... | @@ -18297,7 +18731,7 @@ fn zirArrayInitAnon( |
| 18297 | if (is_ref) { | 18731 | if (is_ref) { |
| 18298 | const target = sema.mod.getTarget(); | 18732 | const target = sema.mod.getTarget(); |
| 18299 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18733 | const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18300 | .pointee_type = tuple_ty, | 18734 | .pointee_type = tuple_ty.toType(), |
| 18301 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18735 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18302 | }); | 18736 | }); |
| 18303 | const alloc = try block.addTy(.alloc, alloc_ty); | 18737 | const alloc = try block.addTy(.alloc, alloc_ty); |
| ... | @@ -18306,9 +18740,9 @@ fn zirArrayInitAnon( | ... | @@ -18306,9 +18740,9 @@ fn zirArrayInitAnon( |
| 18306 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ | 18740 | const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| 18307 | .mutable = true, | 18741 | .mutable = true, |
| 18308 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), | 18742 | .@"addrspace" = target_util.defaultAddressSpace(target, .local), |
| 18309 | .pointee_type = types[i], | 18743 | .pointee_type = types[i].toType(), |
| 18310 | }); | 18744 | }); |
| 18311 | if (values[i].tag() == .unreachable_value) { | 18745 | if (values[i] == .none) { |
| 18312 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); | 18746 | const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty); |
| 18313 | _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand)); | 18747 | _ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand)); |
| 18314 | } | 18748 | } |
| ... | @@ -18322,7 +18756,7 @@ fn zirArrayInitAnon( | ... | @@ -18322,7 +18756,7 @@ fn zirArrayInitAnon( |
| 18322 | element_refs[i] = try sema.resolveInst(operand); | 18756 | element_refs[i] = try sema.resolveInst(operand); |
| 18323 | } | 18757 | } |
| 18324 | 18758 | ||
| 18325 | return block.addAggregateInit(tuple_ty, element_refs); | 18759 | return block.addAggregateInit(tuple_ty.toType(), element_refs); |
| 18326 | } | 18760 | } |
| 18327 | 18761 | ||
| 18328 | fn addConstantMaybeRef( | 18762 | fn addConstantMaybeRef( |
| ... | @@ -18337,8 +18771,8 @@ fn addConstantMaybeRef( | ... | @@ -18337,8 +18771,8 @@ fn addConstantMaybeRef( |
| 18337 | var anon_decl = try block.startAnonDecl(); | 18771 | var anon_decl = try block.startAnonDecl(); |
| 18338 | defer anon_decl.deinit(); | 18772 | defer anon_decl.deinit(); |
| 18339 | const decl = try anon_decl.finish( | 18773 | const decl = try anon_decl.finish( |
| 18340 | try ty.copy(anon_decl.arena()), | 18774 | ty, |
| 18341 | try val.copy(anon_decl.arena()), | 18775 | val, |
| 18342 | 0, // default alignment | 18776 | 0, // default alignment |
| 18343 | ); | 18777 | ); |
| 18344 | return sema.analyzeDeclRef(decl); | 18778 | return sema.analyzeDeclRef(decl); |
| ... | @@ -18350,11 +18784,13 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro | ... | @@ -18350,11 +18784,13 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 18350 | const ty_src = inst_data.src(); | 18784 | const ty_src = inst_data.src(); |
| 18351 | const field_src = inst_data.src(); | 18785 | const field_src = inst_data.src(); |
| 18352 | const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); | 18786 | const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); |
| 18353 | const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "field name must be comptime-known"); | 18787 | const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, "field name must be comptime-known"); |
| 18354 | return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); | 18788 | return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); |
| 18355 | } | 18789 | } |
| 18356 | 18790 | ||
| 18357 | fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 18791 | fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 18792 | const mod = sema.mod; | ||
| 18793 | const ip = &mod.intern_pool; | ||
| 18358 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 18794 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 18359 | const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; | 18795 | const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; |
| 18360 | const ty_src = inst_data.src(); | 18796 | const ty_src = inst_data.src(); |
| ... | @@ -18367,7 +18803,8 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -18367,7 +18803,8 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 18367 | error.GenericPoison => return Air.Inst.Ref.generic_poison_type, | 18803 | error.GenericPoison => return Air.Inst.Ref.generic_poison_type, |
| 18368 | else => |e| return e, | 18804 | else => |e| return e, |
| 18369 | }; | 18805 | }; |
| 18370 | const field_name = sema.code.nullTerminatedString(extra.name_start); | 18806 | const zir_field_name = sema.code.nullTerminatedString(extra.name_start); |
| 18807 | const field_name = try ip.getOrPutString(sema.gpa, zir_field_name); | ||
| 18371 | return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src); | 18808 | return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src); |
| 18372 | } | 18809 | } |
| 18373 | 18810 | ||
| ... | @@ -18375,41 +18812,43 @@ fn fieldType( | ... | @@ -18375,41 +18812,43 @@ fn fieldType( |
| 18375 | sema: *Sema, | 18812 | sema: *Sema, |
| 18376 | block: *Block, | 18813 | block: *Block, |
| 18377 | aggregate_ty: Type, | 18814 | aggregate_ty: Type, |
| 18378 | field_name: []const u8, | 18815 | field_name: InternPool.NullTerminatedString, |
| 18379 | field_src: LazySrcLoc, | 18816 | field_src: LazySrcLoc, |
| 18380 | ty_src: LazySrcLoc, | 18817 | ty_src: LazySrcLoc, |
| 18381 | ) CompileError!Air.Inst.Ref { | 18818 | ) CompileError!Air.Inst.Ref { |
| 18819 | const mod = sema.mod; | ||
| 18382 | var cur_ty = aggregate_ty; | 18820 | var cur_ty = aggregate_ty; |
| 18383 | while (true) { | 18821 | while (true) { |
| 18384 | const resolved_ty = try sema.resolveTypeFields(cur_ty); | 18822 | const resolved_ty = try sema.resolveTypeFields(cur_ty); |
| 18385 | cur_ty = resolved_ty; | 18823 | cur_ty = resolved_ty; |
| 18386 | switch (cur_ty.zigTypeTag()) { | 18824 | switch (cur_ty.zigTypeTag(mod)) { |
| 18387 | .Struct => { | 18825 | .Struct => switch (mod.intern_pool.indexToKey(cur_ty.toIntern())) { |
| 18388 | if (cur_ty.isAnonStruct()) { | 18826 | .anon_struct_type => |anon_struct| { |
| 18389 | const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src); | 18827 | const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src); |
| 18390 | return sema.addType(cur_ty.tupleFields().types[field_index]); | 18828 | return sema.addType(anon_struct.types[field_index].toType()); |
| 18391 | } | 18829 | }, |
| 18392 | const struct_obj = cur_ty.castTag(.@"struct").?.data; | 18830 | .struct_type => |struct_type| { |
| 18393 | const field = struct_obj.fields.get(field_name) orelse | 18831 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 18394 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | 18832 | const field = struct_obj.fields.get(field_name) orelse |
| 18395 | return sema.addType(field.ty); | 18833 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); |
| 18834 | return sema.addType(field.ty); | ||
| 18835 | }, | ||
| 18836 | else => unreachable, | ||
| 18396 | }, | 18837 | }, |
| 18397 | .Union => { | 18838 | .Union => { |
| 18398 | const union_obj = cur_ty.cast(Type.Payload.Union).?.data; | 18839 | const union_obj = mod.typeToUnion(cur_ty).?; |
| 18399 | const field = union_obj.fields.get(field_name) orelse | 18840 | const field = union_obj.fields.get(field_name) orelse |
| 18400 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); | 18841 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); |
| 18401 | return sema.addType(field.ty); | 18842 | return sema.addType(field.ty); |
| 18402 | }, | 18843 | }, |
| 18403 | .Optional => { | 18844 | .Optional => { |
| 18404 | if (cur_ty.castTag(.optional)) |some| { | 18845 | // Struct/array init through optional requires the child type to not be a pointer. |
| 18405 | // Struct/array init through optional requires the child type to not be a pointer. | 18846 | // If the child of .optional is a pointer it'll error on the next loop. |
| 18406 | // If the child of .optional is a pointer it'll error on the next loop. | 18847 | cur_ty = mod.intern_pool.indexToKey(cur_ty.toIntern()).opt_type.toType(); |
| 18407 | cur_ty = some.data; | 18848 | continue; |
| 18408 | continue; | ||
| 18409 | } | ||
| 18410 | }, | 18849 | }, |
| 18411 | .ErrorUnion => { | 18850 | .ErrorUnion => { |
| 18412 | cur_ty = cur_ty.errorUnionPayload(); | 18851 | cur_ty = cur_ty.errorUnionPayload(mod); |
| 18413 | continue; | 18852 | continue; |
| 18414 | }, | 18853 | }, |
| 18415 | else => {}, | 18854 | else => {}, |
| ... | @@ -18425,18 +18864,23 @@ fn zirErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { | ... | @@ -18425,18 +18864,23 @@ fn zirErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 18425 | } | 18864 | } |
| 18426 | 18865 | ||
| 18427 | fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { | 18866 | fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 18867 | const mod = sema.mod; | ||
| 18428 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); | 18868 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 18429 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); | 18869 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); |
| 18430 | const opt_ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty); | 18870 | const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); |
| 18871 | const opt_ptr_stack_trace_ty = try Type.optional(sema.arena, ptr_stack_trace_ty, mod); | ||
| 18431 | 18872 | ||
| 18432 | if (sema.owner_func != null and | 18873 | if (sema.owner_func != null and |
| 18433 | sema.owner_func.?.calls_or_awaits_errorable_fn and | 18874 | sema.owner_func.?.calls_or_awaits_errorable_fn and |
| 18434 | sema.mod.comp.bin_file.options.error_return_tracing and | 18875 | mod.comp.bin_file.options.error_return_tracing and |
| 18435 | sema.mod.backendSupportsFeature(.error_return_trace)) | 18876 | mod.backendSupportsFeature(.error_return_trace)) |
| 18436 | { | 18877 | { |
| 18437 | return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); | 18878 | return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); |
| 18438 | } | 18879 | } |
| 18439 | return sema.addConstant(opt_ptr_stack_trace_ty, Value.null); | 18880 | return sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{ |
| 18881 | .ty = opt_ptr_stack_trace_ty.toIntern(), | ||
| 18882 | .val = .none, | ||
| 18883 | } })).toValue()); | ||
| 18440 | } | 18884 | } |
| 18441 | 18885 | ||
| 18442 | fn zirFrame( | 18886 | fn zirFrame( |
| ... | @@ -18449,27 +18893,28 @@ fn zirFrame( | ... | @@ -18449,27 +18893,28 @@ fn zirFrame( |
| 18449 | } | 18893 | } |
| 18450 | 18894 | ||
| 18451 | fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 18895 | fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 18896 | const mod = sema.mod; | ||
| 18452 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 18897 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 18453 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 18898 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 18454 | const ty = try sema.resolveType(block, operand_src, inst_data.operand); | 18899 | const ty = try sema.resolveType(block, operand_src, inst_data.operand); |
| 18455 | if (ty.isNoReturn()) { | 18900 | if (ty.isNoReturn(mod)) { |
| 18456 | return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)}); | 18901 | return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)}); |
| 18457 | } | 18902 | } |
| 18458 | const target = sema.mod.getTarget(); | 18903 | const val = try ty.lazyAbiAlignment(mod); |
| 18459 | const val = try ty.lazyAbiAlignment(target, sema.arena); | 18904 | if (val.isLazyAlign(mod)) { |
| 18460 | if (val.tag() == .lazy_align) { | ||
| 18461 | try sema.queueFullTypeResolution(ty); | 18905 | try sema.queueFullTypeResolution(ty); |
| 18462 | } | 18906 | } |
| 18463 | return sema.addConstant(Type.comptime_int, val); | 18907 | return sema.addConstant(Type.comptime_int, val); |
| 18464 | } | 18908 | } |
| 18465 | 18909 | ||
| 18466 | fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 18910 | fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 18911 | const mod = sema.mod; | ||
| 18467 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 18912 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 18468 | const operand = try sema.resolveInst(inst_data.operand); | 18913 | const operand = try sema.resolveInst(inst_data.operand); |
| 18469 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 18914 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 18470 | if (val.isUndef()) return sema.addConstUndef(Type.u1); | 18915 | if (val.isUndef(mod)) return sema.addConstUndef(Type.u1); |
| 18471 | if (val.toBool()) return sema.addConstant(Type.u1, Value.one); | 18916 | if (val.toBool()) return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 1)); |
| 18472 | return sema.addConstant(Type.u1, Value.zero); | 18917 | return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0)); |
| 18473 | } | 18918 | } |
| 18474 | return block.addUnOp(.bool_to_int, operand); | 18919 | return block.addUnOp(.bool_to_int, operand); |
| 18475 | } | 18920 | } |
| ... | @@ -18480,8 +18925,8 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -18480,8 +18925,8 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 18480 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 18925 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 18481 | 18926 | ||
| 18482 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { | 18927 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { |
| 18483 | const bytes = val.castTag(.@"error").?.data.name; | 18928 | const err_name = sema.mod.intern_pool.indexToKey(val.toIntern()).err.name; |
| 18484 | return sema.addStrLit(block, bytes); | 18929 | return sema.addStrLit(block, sema.mod.intern_pool.stringToSlice(err_name)); |
| 18485 | } | 18930 | } |
| 18486 | 18931 | ||
| 18487 | // Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass | 18932 | // Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass |
| ... | @@ -18499,16 +18944,17 @@ fn zirUnaryMath( | ... | @@ -18499,16 +18944,17 @@ fn zirUnaryMath( |
| 18499 | const tracy = trace(@src()); | 18944 | const tracy = trace(@src()); |
| 18500 | defer tracy.end(); | 18945 | defer tracy.end(); |
| 18501 | 18946 | ||
| 18947 | const mod = sema.mod; | ||
| 18502 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 18948 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 18503 | const operand = try sema.resolveInst(inst_data.operand); | 18949 | const operand = try sema.resolveInst(inst_data.operand); |
| 18504 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 18950 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 18505 | const operand_ty = sema.typeOf(operand); | 18951 | const operand_ty = sema.typeOf(operand); |
| 18506 | 18952 | ||
| 18507 | switch (operand_ty.zigTypeTag()) { | 18953 | switch (operand_ty.zigTypeTag(mod)) { |
| 18508 | .ComptimeFloat, .Float => {}, | 18954 | .ComptimeFloat, .Float => {}, |
| 18509 | .Vector => { | 18955 | .Vector => { |
| 18510 | const scalar_ty = operand_ty.scalarType(); | 18956 | const scalar_ty = operand_ty.scalarType(mod); |
| 18511 | switch (scalar_ty.zigTypeTag()) { | 18957 | switch (scalar_ty.zigTypeTag(mod)) { |
| 18512 | .ComptimeFloat, .Float => {}, | 18958 | .ComptimeFloat, .Float => {}, |
| 18513 | else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(sema.mod)}), | 18959 | else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(sema.mod)}), |
| 18514 | } | 18960 | } |
| ... | @@ -18516,25 +18962,27 @@ fn zirUnaryMath( | ... | @@ -18516,25 +18962,27 @@ fn zirUnaryMath( |
| 18516 | else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(sema.mod)}), | 18962 | else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(sema.mod)}), |
| 18517 | } | 18963 | } |
| 18518 | 18964 | ||
| 18519 | switch (operand_ty.zigTypeTag()) { | 18965 | switch (operand_ty.zigTypeTag(mod)) { |
| 18520 | .Vector => { | 18966 | .Vector => { |
| 18521 | const scalar_ty = operand_ty.scalarType(); | 18967 | const scalar_ty = operand_ty.scalarType(mod); |
| 18522 | const vec_len = operand_ty.vectorLen(); | 18968 | const vec_len = operand_ty.vectorLen(mod); |
| 18523 | const result_ty = try Type.vector(sema.arena, vec_len, scalar_ty); | 18969 | const result_ty = try mod.vectorType(.{ |
| 18970 | .len = vec_len, | ||
| 18971 | .child = scalar_ty.toIntern(), | ||
| 18972 | }); | ||
| 18524 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 18973 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 18525 | if (val.isUndef()) | 18974 | if (val.isUndef(mod)) |
| 18526 | return sema.addConstUndef(result_ty); | 18975 | return sema.addConstUndef(result_ty); |
| 18527 | 18976 | ||
| 18528 | var elem_buf: Value.ElemValueBuffer = undefined; | 18977 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); |
| 18529 | const elems = try sema.arena.alloc(Value, vec_len); | ||
| 18530 | for (elems, 0..) |*elem, i| { | 18978 | for (elems, 0..) |*elem, i| { |
| 18531 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); | 18979 | const elem_val = try val.elemValue(sema.mod, i); |
| 18532 | elem.* = try eval(elem_val, scalar_ty, sema.arena, sema.mod); | 18980 | elem.* = try (try eval(elem_val, scalar_ty, sema.arena, sema.mod)).intern(scalar_ty, mod); |
| 18533 | } | 18981 | } |
| 18534 | return sema.addConstant( | 18982 | return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{ |
| 18535 | result_ty, | 18983 | .ty = result_ty.toIntern(), |
| 18536 | try Value.Tag.aggregate.create(sema.arena, elems), | 18984 | .storage = .{ .elems = elems }, |
| 18537 | ); | 18985 | } })).toValue()); |
| 18538 | } | 18986 | } |
| 18539 | 18987 | ||
| 18540 | try sema.requireRuntimeBlock(block, operand_src, null); | 18988 | try sema.requireRuntimeBlock(block, operand_src, null); |
| ... | @@ -18542,7 +18990,7 @@ fn zirUnaryMath( | ... | @@ -18542,7 +18990,7 @@ fn zirUnaryMath( |
| 18542 | }, | 18990 | }, |
| 18543 | .ComptimeFloat, .Float => { | 18991 | .ComptimeFloat, .Float => { |
| 18544 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { | 18992 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { |
| 18545 | if (operand_val.isUndef()) | 18993 | if (operand_val.isUndef(mod)) |
| 18546 | return sema.addConstUndef(operand_ty); | 18994 | return sema.addConstUndef(operand_ty); |
| 18547 | const result_val = try eval(operand_val, operand_ty, sema.arena, sema.mod); | 18995 | const result_val = try eval(operand_val, operand_ty, sema.arena, sema.mod); |
| 18548 | return sema.addConstant(operand_ty, result_val); | 18996 | return sema.addConstant(operand_ty, result_val); |
| ... | @@ -18562,16 +19010,17 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -18562,16 +19010,17 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18562 | const operand = try sema.resolveInst(inst_data.operand); | 19010 | const operand = try sema.resolveInst(inst_data.operand); |
| 18563 | const operand_ty = sema.typeOf(operand); | 19011 | const operand_ty = sema.typeOf(operand); |
| 18564 | const mod = sema.mod; | 19012 | const mod = sema.mod; |
| 19013 | const ip = &mod.intern_pool; | ||
| 18565 | 19014 | ||
| 18566 | try sema.resolveTypeLayout(operand_ty); | 19015 | try sema.resolveTypeLayout(operand_ty); |
| 18567 | const enum_ty = switch (operand_ty.zigTypeTag()) { | 19016 | const enum_ty = switch (operand_ty.zigTypeTag(mod)) { |
| 18568 | .EnumLiteral => { | 19017 | .EnumLiteral => { |
| 18569 | const val = try sema.resolveConstValue(block, .unneeded, operand, ""); | 19018 | const val = try sema.resolveConstValue(block, .unneeded, operand, ""); |
| 18570 | const bytes = val.castTag(.enum_literal).?.data; | 19019 | const tag_name = ip.indexToKey(val.toIntern()).enum_literal; |
| 18571 | return sema.addStrLit(block, bytes); | 19020 | return sema.addStrLit(block, ip.stringToSlice(tag_name)); |
| 18572 | }, | 19021 | }, |
| 18573 | .Enum => operand_ty, | 19022 | .Enum => operand_ty, |
| 18574 | .Union => operand_ty.unionTagType() orelse { | 19023 | .Union => operand_ty.unionTagType(mod) orelse { |
| 18575 | const msg = msg: { | 19024 | const msg = msg: { |
| 18576 | const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{ | 19025 | const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{ |
| 18577 | operand_ty.fmt(sema.mod), | 19026 | operand_ty.fmt(sema.mod), |
| ... | @@ -18586,30 +19035,31 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -18586,30 +19035,31 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18586 | operand_ty.fmt(mod), | 19035 | operand_ty.fmt(mod), |
| 18587 | }), | 19036 | }), |
| 18588 | }; | 19037 | }; |
| 18589 | if (enum_ty.enumFieldCount() == 0) { | 19038 | if (enum_ty.enumFieldCount(mod) == 0) { |
| 18590 | // TODO I don't think this is the correct way to handle this but | 19039 | // TODO I don't think this is the correct way to handle this but |
| 18591 | // it prevents a crash. | 19040 | // it prevents a crash. |
| 18592 | return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{ | 19041 | return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{ |
| 18593 | enum_ty.fmt(mod), | 19042 | enum_ty.fmt(mod), |
| 18594 | }); | 19043 | }); |
| 18595 | } | 19044 | } |
| 18596 | const enum_decl_index = enum_ty.getOwnerDecl(); | 19045 | const enum_decl_index = enum_ty.getOwnerDecl(mod); |
| 18597 | const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src); | 19046 | const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src); |
| 18598 | if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { | 19047 | if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| { |
| 18599 | const field_index = enum_ty.enumTagFieldIndex(val, mod) orelse { | 19048 | const field_index = enum_ty.enumTagFieldIndex(val, mod) orelse { |
| 18600 | const enum_decl = mod.declPtr(enum_decl_index); | 19049 | const enum_decl = mod.declPtr(enum_decl_index); |
| 18601 | const msg = msg: { | 19050 | const msg = msg: { |
| 18602 | const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{s}'", .{ | 19051 | const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{}'", .{ |
| 18603 | val.fmtValue(enum_ty, sema.mod), enum_decl.name, | 19052 | val.fmtValue(enum_ty, sema.mod), enum_decl.name.fmt(ip), |
| 18604 | }); | 19053 | }); |
| 18605 | errdefer msg.destroy(sema.gpa); | 19054 | errdefer msg.destroy(sema.gpa); |
| 18606 | try mod.errNoteNonLazy(enum_decl.srcLoc(), msg, "declared here", .{}); | 19055 | try mod.errNoteNonLazy(enum_decl.srcLoc(mod), msg, "declared here", .{}); |
| 18607 | break :msg msg; | 19056 | break :msg msg; |
| 18608 | }; | 19057 | }; |
| 18609 | return sema.failWithOwnedErrorMsg(msg); | 19058 | return sema.failWithOwnedErrorMsg(msg); |
| 18610 | }; | 19059 | }; |
| 18611 | const field_name = enum_ty.enumFieldName(field_index); | 19060 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 18612 | return sema.addStrLit(block, field_name); | 19061 | const field_name = enum_ty.enumFieldName(field_index, mod); |
| 19062 | return sema.addStrLit(block, ip.stringToSlice(field_name)); | ||
| 18613 | } | 19063 | } |
| 18614 | try sema.requireRuntimeBlock(block, src, operand_src); | 19064 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 18615 | if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) { | 19065 | if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) { |
| ... | @@ -18622,8 +19072,15 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -18622,8 +19072,15 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18622 | return block.addUnOp(.tag_name, casted_operand); | 19072 | return block.addUnOp(.tag_name, casted_operand); |
| 18623 | } | 19073 | } |
| 18624 | 19074 | ||
| 18625 | fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 19075 | fn zirReify( |
| 19076 | sema: *Sema, | ||
| 19077 | block: *Block, | ||
| 19078 | extended: Zir.Inst.Extended.InstData, | ||
| 19079 | inst: Zir.Inst.Index, | ||
| 19080 | ) CompileError!Air.Inst.Ref { | ||
| 18626 | const mod = sema.mod; | 19081 | const mod = sema.mod; |
| 19082 | const gpa = sema.gpa; | ||
| 19083 | const ip = &mod.intern_pool; | ||
| 18627 | const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small); | 19084 | const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small); |
| 18628 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | 19085 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 18629 | const src = LazySrcLoc.nodeOffset(extra.node); | 19086 | const src = LazySrcLoc.nodeOffset(extra.node); |
| ... | @@ -18632,10 +19089,10 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in | ... | @@ -18632,10 +19089,10 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 18632 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 19089 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 18633 | const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); | 19090 | const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); |
| 18634 | const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime-known"); | 19091 | const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime-known"); |
| 18635 | const union_val = val.cast(Value.Payload.Union).?.data; | 19092 | const union_val = ip.indexToKey(val.toIntern()).un; |
| 18636 | const target = mod.getTarget(); | 19093 | const target = mod.getTarget(); |
| 18637 | const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag, mod).?; | 19094 | if (try union_val.val.toValue().anyUndef(mod)) return sema.failWithUseOfUndef(block, src); |
| 18638 | if (union_val.val.anyUndef(mod)) return sema.failWithUseOfUndef(block, src); | 19095 | const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag.toValue(), mod).?; |
| 18639 | switch (@intToEnum(std.builtin.TypeId, tag_index)) { | 19096 | switch (@intToEnum(std.builtin.TypeId, tag_index)) { |
| 18640 | .Type => return Air.Inst.Ref.type_type, | 19097 | .Type => return Air.Inst.Ref.type_type, |
| 18641 | .Void => return Air.Inst.Ref.void_type, | 19098 | .Void => return Air.Inst.Ref.void_type, |
| ... | @@ -18648,41 +19105,48 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in | ... | @@ -18648,41 +19105,48 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 18648 | .AnyFrame => return sema.failWithUseOfAsync(block, src), | 19105 | .AnyFrame => return sema.failWithUseOfAsync(block, src), |
| 18649 | .EnumLiteral => return Air.Inst.Ref.enum_literal_type, | 19106 | .EnumLiteral => return Air.Inst.Ref.enum_literal_type, |
| 18650 | .Int => { | 19107 | .Int => { |
| 18651 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 19108 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 18652 | // TODO use reflection instead of magic numbers here | 19109 | const signedness_val = try union_val.val.toValue().fieldValue( |
| 18653 | const signedness_val = struct_val[0]; | 19110 | mod, |
| 18654 | const bits_val = struct_val[1]; | 19111 | fields.getIndex(try ip.getOrPutString(gpa, "signedness")).?, |
| 18655 | 19112 | ); | |
| 18656 | const signedness = signedness_val.toEnum(std.builtin.Signedness); | 19113 | const bits_val = try union_val.val.toValue().fieldValue( |
| 18657 | const bits = @intCast(u16, bits_val.toUnsignedInt(target)); | 19114 | mod, |
| 18658 | const ty = switch (signedness) { | 19115 | fields.getIndex(try ip.getOrPutString(gpa, "bits")).?, |
| 18659 | .signed => try Type.Tag.int_signed.create(sema.arena, bits), | 19116 | ); |
| 18660 | .unsigned => try Type.Tag.int_unsigned.create(sema.arena, bits), | 19117 | |
| 18661 | }; | 19118 | const signedness = mod.toEnum(std.builtin.Signedness, signedness_val); |
| 19119 | const bits = @intCast(u16, bits_val.toUnsignedInt(mod)); | ||
| 19120 | const ty = try mod.intType(signedness, bits); | ||
| 18662 | return sema.addType(ty); | 19121 | return sema.addType(ty); |
| 18663 | }, | 19122 | }, |
| 18664 | .Vector => { | 19123 | .Vector => { |
| 18665 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 19124 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 18666 | // TODO use reflection instead of magic numbers here | 19125 | const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18667 | const len_val = struct_val[0]; | 19126 | try ip.getOrPutString(gpa, "len"), |
| 18668 | const child_val = struct_val[1]; | 19127 | ).?); |
| 19128 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | ||
| 19129 | try ip.getOrPutString(gpa, "child"), | ||
| 19130 | ).?); | ||
| 18669 | 19131 | ||
| 18670 | const len = len_val.toUnsignedInt(target); | 19132 | const len = @intCast(u32, len_val.toUnsignedInt(mod)); |
| 18671 | var buffer: Value.ToTypeBuffer = undefined; | 19133 | const child_ty = child_val.toType(); |
| 18672 | const child_ty = child_val.toType(&buffer); | ||
| 18673 | 19134 | ||
| 18674 | try sema.checkVectorElemType(block, src, child_ty); | 19135 | try sema.checkVectorElemType(block, src, child_ty); |
| 18675 | 19136 | ||
| 18676 | const ty = try Type.vector(sema.arena, len, try child_ty.copy(sema.arena)); | 19137 | const ty = try mod.vectorType(.{ |
| 19138 | .len = len, | ||
| 19139 | .child = child_ty.toIntern(), | ||
| 19140 | }); | ||
| 18677 | return sema.addType(ty); | 19141 | return sema.addType(ty); |
| 18678 | }, | 19142 | }, |
| 18679 | .Float => { | 19143 | .Float => { |
| 18680 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 19144 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 18681 | // TODO use reflection instead of magic numbers here | 19145 | const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18682 | // bits: comptime_int, | 19146 | try ip.getOrPutString(gpa, "bits"), |
| 18683 | const bits_val = struct_val[0]; | 19147 | ).?); |
| 18684 | 19148 | ||
| 18685 | const bits = @intCast(u16, bits_val.toUnsignedInt(target)); | 19149 | const bits = @intCast(u16, bits_val.toUnsignedInt(mod)); |
| 18686 | const ty = switch (bits) { | 19150 | const ty = switch (bits) { |
| 18687 | 16 => Type.f16, | 19151 | 16 => Type.f16, |
| 18688 | 32 => Type.f32, | 19152 | 32 => Type.f32, |
| ... | @@ -18694,25 +19158,42 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in | ... | @@ -18694,25 +19158,42 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 18694 | return sema.addType(ty); | 19158 | return sema.addType(ty); |
| 18695 | }, | 19159 | }, |
| 18696 | .Pointer => { | 19160 | .Pointer => { |
| 18697 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 19161 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 18698 | // TODO use reflection instead of magic numbers here | 19162 | const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18699 | const size_val = struct_val[0]; | 19163 | try ip.getOrPutString(gpa, "size"), |
| 18700 | const is_const_val = struct_val[1]; | 19164 | ).?); |
| 18701 | const is_volatile_val = struct_val[2]; | 19165 | const is_const_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18702 | const alignment_val = struct_val[3]; | 19166 | try ip.getOrPutString(gpa, "is_const"), |
| 18703 | const address_space_val = struct_val[4]; | 19167 | ).?); |
| 18704 | const child_val = struct_val[5]; | 19168 | const is_volatile_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18705 | const is_allowzero_val = struct_val[6]; | 19169 | try ip.getOrPutString(gpa, "is_volatile"), |
| 18706 | const sentinel_val = struct_val[7]; | 19170 | ).?); |
| 19171 | const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | ||
| 19172 | try ip.getOrPutString(gpa, "alignment"), | ||
| 19173 | ).?); | ||
| 19174 | const address_space_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | ||
| 19175 | try ip.getOrPutString(gpa, "address_space"), | ||
| 19176 | ).?); | ||
| 19177 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | ||
| 19178 | try ip.getOrPutString(gpa, "child"), | ||
| 19179 | ).?); | ||
| 19180 | const is_allowzero_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | ||
| 19181 | try ip.getOrPutString(gpa, "is_allowzero"), | ||
| 19182 | ).?); | ||
| 19183 | const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | ||
| 19184 | try ip.getOrPutString(gpa, "sentinel"), | ||
| 19185 | ).?); | ||
| 18707 | 19186 | ||
| 18708 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { | 19187 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { |
| 18709 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); | 19188 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); |
| 18710 | } | 19189 | } |
| 18711 | const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema)).?); | ||
| 18712 | 19190 | ||
| 18713 | var buffer: Value.ToTypeBuffer = undefined; | 19191 | const abi_align = InternPool.Alignment.fromByteUnits( |
| 18714 | const unresolved_elem_ty = child_val.toType(&buffer); | 19192 | (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?, |
| 18715 | const elem_ty = if (abi_align == 0) | 19193 | ); |
| 19194 | |||
| 19195 | const unresolved_elem_ty = child_val.toType(); | ||
| 19196 | const elem_ty = if (abi_align == .none) | ||
| 18716 | unresolved_elem_ty | 19197 | unresolved_elem_ty |
| 18717 | else t: { | 19198 | else t: { |
| 18718 | const elem_ty = try sema.resolveTypeFields(unresolved_elem_ty); | 19199 | const elem_ty = try sema.resolveTypeFields(unresolved_elem_ty); |
| ... | @@ -18720,301 +19201,282 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in | ... | @@ -18720,301 +19201,282 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 18720 | break :t elem_ty; | 19201 | break :t elem_ty; |
| 18721 | }; | 19202 | }; |
| 18722 | 19203 | ||
| 18723 | const ptr_size = size_val.toEnum(std.builtin.Type.Pointer.Size); | 19204 | const ptr_size = mod.toEnum(std.builtin.Type.Pointer.Size, size_val); |
| 18724 | 19205 | ||
| 18725 | var actual_sentinel: ?Value = null; | 19206 | const actual_sentinel: InternPool.Index = s: { |
| 18726 | if (!sentinel_val.isNull()) { | 19207 | if (!sentinel_val.isNull(mod)) { |
| 18727 | if (ptr_size == .One or ptr_size == .C) { | 19208 | if (ptr_size == .One or ptr_size == .C) { |
| 18728 | return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{}); | 19209 | return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{}); |
| 19210 | } | ||
| 19211 | const sentinel_ptr_val = sentinel_val.optionalValue(mod).?; | ||
| 19212 | const ptr_ty = try Type.ptr(sema.arena, mod, .{ | ||
| 19213 | .@"addrspace" = .generic, | ||
| 19214 | .pointee_type = elem_ty, | ||
| 19215 | }); | ||
| 19216 | const sent_val = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?; | ||
| 19217 | break :s sent_val.toIntern(); | ||
| 18729 | } | 19218 | } |
| 18730 | const sentinel_ptr_val = sentinel_val.castTag(.opt_payload).?.data; | 19219 | break :s .none; |
| 18731 | const ptr_ty = try Type.ptr(sema.arena, mod, .{ | 19220 | }; |
| 18732 | .@"addrspace" = .generic, | ||
| 18733 | .pointee_type = try elem_ty.copy(sema.arena), | ||
| 18734 | }); | ||
| 18735 | actual_sentinel = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?; | ||
| 18736 | } | ||
| 18737 | 19221 | ||
| 18738 | if (elem_ty.zigTypeTag() == .NoReturn) { | 19222 | if (elem_ty.zigTypeTag(mod) == .NoReturn) { |
| 18739 | return sema.fail(block, src, "pointer to noreturn not allowed", .{}); | 19223 | return sema.fail(block, src, "pointer to noreturn not allowed", .{}); |
| 18740 | } else if (elem_ty.zigTypeTag() == .Fn) { | 19224 | } else if (elem_ty.zigTypeTag(mod) == .Fn) { |
| 18741 | if (ptr_size != .One) { | 19225 | if (ptr_size != .One) { |
| 18742 | return sema.fail(block, src, "function pointers must be single pointers", .{}); | 19226 | return sema.fail(block, src, "function pointers must be single pointers", .{}); |
| 18743 | } | 19227 | } |
| 18744 | const fn_align = elem_ty.fnInfo().alignment; | 19228 | const fn_align = mod.typeToFunc(elem_ty).?.alignment; |
| 18745 | if (abi_align != 0 and fn_align != 0 and | 19229 | if (abi_align != .none and fn_align != .none and |
| 18746 | abi_align != fn_align) | 19230 | abi_align != fn_align) |
| 18747 | { | 19231 | { |
| 18748 | return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{}); | 19232 | return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{}); |
| 18749 | } | 19233 | } |
| 18750 | } else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) { | 19234 | } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { |
| 18751 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); | 19235 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); |
| 18752 | } else if (ptr_size == .C) { | 19236 | } else if (ptr_size == .C) { |
| 18753 | if (!try sema.validateExternType(elem_ty, .other)) { | 19237 | if (!try sema.validateExternType(elem_ty, .other)) { |
| 18754 | const msg = msg: { | 19238 | const msg = msg: { |
| 18755 | const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); | 19239 | const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(mod)}); |
| 18756 | errdefer msg.destroy(sema.gpa); | 19240 | errdefer msg.destroy(gpa); |
| 18757 | 19241 | ||
| 18758 | const src_decl = sema.mod.declPtr(block.src_decl); | 19242 | const src_decl = mod.declPtr(block.src_decl); |
| 18759 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), elem_ty, .other); | 19243 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), elem_ty, .other); |
| 18760 | 19244 | ||
| 18761 | try sema.addDeclaredHereNote(msg, elem_ty); | 19245 | try sema.addDeclaredHereNote(msg, elem_ty); |
| 18762 | break :msg msg; | 19246 | break :msg msg; |
| 18763 | }; | 19247 | }; |
| 18764 | return sema.failWithOwnedErrorMsg(msg); | 19248 | return sema.failWithOwnedErrorMsg(msg); |
| 18765 | } | 19249 | } |
| 18766 | if (elem_ty.zigTypeTag() == .Opaque) { | 19250 | if (elem_ty.zigTypeTag(mod) == .Opaque) { |
| 18767 | return sema.fail(block, src, "C pointers cannot point to opaque types", .{}); | 19251 | return sema.fail(block, src, "C pointers cannot point to opaque types", .{}); |
| 18768 | } | 19252 | } |
| 18769 | } | 19253 | } |
| 18770 | 19254 | ||
| 18771 | const ty = try Type.ptr(sema.arena, mod, .{ | 19255 | const ty = try mod.ptrType(.{ |
| 18772 | .size = ptr_size, | 19256 | .child = elem_ty.toIntern(), |
| 18773 | .mutable = !is_const_val.toBool(), | ||
| 18774 | .@"volatile" = is_volatile_val.toBool(), | ||
| 18775 | .@"align" = abi_align, | ||
| 18776 | .@"addrspace" = address_space_val.toEnum(std.builtin.AddressSpace), | ||
| 18777 | .pointee_type = try elem_ty.copy(sema.arena), | ||
| 18778 | .@"allowzero" = is_allowzero_val.toBool(), | ||
| 18779 | .sentinel = actual_sentinel, | 19257 | .sentinel = actual_sentinel, |
| 19258 | .flags = .{ | ||
| 19259 | .size = ptr_size, | ||
| 19260 | .is_const = is_const_val.toBool(), | ||
| 19261 | .is_volatile = is_volatile_val.toBool(), | ||
| 19262 | .alignment = abi_align, | ||
| 19263 | .address_space = mod.toEnum(std.builtin.AddressSpace, address_space_val), | ||
| 19264 | .is_allowzero = is_allowzero_val.toBool(), | ||
| 19265 | }, | ||
| 18780 | }); | 19266 | }); |
| 18781 | return sema.addType(ty); | 19267 | return sema.addType(ty); |
| 18782 | }, | 19268 | }, |
| 18783 | .Array => { | 19269 | .Array => { |
| 18784 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 19270 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 18785 | // TODO use reflection instead of magic numbers here | 19271 | const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18786 | // len: comptime_int, | 19272 | try ip.getOrPutString(gpa, "len"), |
| 18787 | const len_val = struct_val[0]; | 19273 | ).?); |
| 18788 | // child: type, | 19274 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18789 | const child_val = struct_val[1]; | 19275 | try ip.getOrPutString(gpa, "child"), |
| 18790 | // sentinel: ?*const anyopaque, | 19276 | ).?); |
| 18791 | const sentinel_val = struct_val[2]; | 19277 | const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18792 | 19278 | try ip.getOrPutString(gpa, "sentinel"), | |
| 18793 | const len = len_val.toUnsignedInt(target); | 19279 | ).?); |
| 18794 | var buffer: Value.ToTypeBuffer = undefined; | 19280 | |
| 18795 | const child_ty = try child_val.toType(&buffer).copy(sema.arena); | 19281 | const len = len_val.toUnsignedInt(mod); |
| 18796 | const sentinel = if (sentinel_val.castTag(.opt_payload)) |p| blk: { | 19282 | const child_ty = child_val.toType(); |
| 19283 | const sentinel = if (sentinel_val.optionalValue(mod)) |p| blk: { | ||
| 18797 | const ptr_ty = try Type.ptr(sema.arena, mod, .{ | 19284 | const ptr_ty = try Type.ptr(sema.arena, mod, .{ |
| 18798 | .@"addrspace" = .generic, | 19285 | .@"addrspace" = .generic, |
| 18799 | .pointee_type = child_ty, | 19286 | .pointee_type = child_ty, |
| 18800 | }); | 19287 | }); |
| 18801 | break :blk (try sema.pointerDeref(block, src, p.data, ptr_ty)).?; | 19288 | break :blk (try sema.pointerDeref(block, src, p, ptr_ty)).?; |
| 18802 | } else null; | 19289 | } else null; |
| 18803 | 19290 | ||
| 18804 | const ty = try Type.array(sema.arena, len, sentinel, child_ty, sema.mod); | 19291 | const ty = try Type.array(sema.arena, len, sentinel, child_ty, mod); |
| 18805 | return sema.addType(ty); | 19292 | return sema.addType(ty); |
| 18806 | }, | 19293 | }, |
| 18807 | .Optional => { | 19294 | .Optional => { |
| 18808 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 19295 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 18809 | // TODO use reflection instead of magic numbers here | 19296 | const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18810 | // child: type, | 19297 | try ip.getOrPutString(gpa, "child"), |
| 18811 | const child_val = struct_val[0]; | 19298 | ).?); |
| 18812 | 19299 | ||
| 18813 | var buffer: Value.ToTypeBuffer = undefined; | 19300 | const child_ty = child_val.toType(); |
| 18814 | const child_ty = try child_val.toType(&buffer).copy(sema.arena); | ||
| 18815 | 19301 | ||
| 18816 | const ty = try Type.optional(sema.arena, child_ty); | 19302 | const ty = try Type.optional(sema.arena, child_ty, mod); |
| 18817 | return sema.addType(ty); | 19303 | return sema.addType(ty); |
| 18818 | }, | 19304 | }, |
| 18819 | .ErrorUnion => { | 19305 | .ErrorUnion => { |
| 18820 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 19306 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 18821 | // TODO use reflection instead of magic numbers here | 19307 | const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18822 | // error_set: type, | 19308 | try ip.getOrPutString(gpa, "error_set"), |
| 18823 | const error_set_val = struct_val[0]; | 19309 | ).?); |
| 18824 | // payload: type, | 19310 | const payload_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18825 | const payload_val = struct_val[1]; | 19311 | try ip.getOrPutString(gpa, "payload"), |
| 18826 | 19312 | ).?); | |
| 18827 | var buffer: Value.ToTypeBuffer = undefined; | 19313 | |
| 18828 | const error_set_ty = try error_set_val.toType(&buffer).copy(sema.arena); | 19314 | const error_set_ty = error_set_val.toType(); |
| 18829 | const payload_ty = try payload_val.toType(&buffer).copy(sema.arena); | 19315 | const payload_ty = payload_val.toType(); |
| 18830 | 19316 | ||
| 18831 | if (error_set_ty.zigTypeTag() != .ErrorSet) { | 19317 | if (error_set_ty.zigTypeTag(mod) != .ErrorSet) { |
| 18832 | return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{}); | 19318 | return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{}); |
| 18833 | } | 19319 | } |
| 18834 | 19320 | ||
| 18835 | const ty = try Type.Tag.error_union.create(sema.arena, .{ | 19321 | const ty = try mod.errorUnionType(error_set_ty, payload_ty); |
| 18836 | .error_set = error_set_ty, | ||
| 18837 | .payload = payload_ty, | ||
| 18838 | }); | ||
| 18839 | return sema.addType(ty); | 19322 | return sema.addType(ty); |
| 18840 | }, | 19323 | }, |
| 18841 | .ErrorSet => { | 19324 | .ErrorSet => { |
| 18842 | const payload_val = union_val.val.optionalValue() orelse | 19325 | const payload_val = union_val.val.toValue().optionalValue(mod) orelse |
| 18843 | return sema.addType(Type.initTag(.anyerror)); | 19326 | return sema.addType(Type.anyerror); |
| 18844 | const slice_val = payload_val.castTag(.slice).?.data; | ||
| 18845 | 19327 | ||
| 18846 | const len = try sema.usizeCast(block, src, slice_val.len.toUnsignedInt(mod.getTarget())); | 19328 | const len = try sema.usizeCast(block, src, payload_val.sliceLen(mod)); |
| 18847 | var names: Module.ErrorSet.NameMap = .{}; | 19329 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; |
| 18848 | try names.ensureUnusedCapacity(sema.arena, len); | 19330 | try names.ensureUnusedCapacity(sema.arena, len); |
| 18849 | var i: usize = 0; | 19331 | for (0..len) |i| { |
| 18850 | while (i < len) : (i += 1) { | 19332 | const elem_val = try payload_val.elemValue(mod, i); |
| 18851 | var buf: Value.ElemValueBuffer = undefined; | 19333 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); |
| 18852 | const elem_val = slice_val.ptr.elemValueBuffer(mod, i, &buf); | 19334 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 18853 | const struct_val = elem_val.castTag(.aggregate).?.data; | 19335 | try ip.getOrPutString(gpa, "name"), |
| 18854 | // TODO use reflection instead of magic numbers here | 19336 | ).?); |
| 18855 | // error_set: type, | 19337 | |
| 18856 | const name_val = struct_val[0]; | 19338 | const name = try name_val.toIpString(Type.slice_const_u8, mod); |
| 18857 | const name_str = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, sema.mod); | 19339 | _ = try mod.getErrorValue(name); |
| 18858 | 19340 | const gop = names.getOrPutAssumeCapacity(name); | |
| 18859 | const kv = try mod.getErrorValue(name_str); | ||
| 18860 | const gop = names.getOrPutAssumeCapacity(kv.key); | ||
| 18861 | if (gop.found_existing) { | 19341 | if (gop.found_existing) { |
| 18862 | return sema.fail(block, src, "duplicate error '{s}'", .{name_str}); | 19342 | return sema.fail(block, src, "duplicate error '{}'", .{ |
| 19343 | name.fmt(ip), | ||
| 19344 | }); | ||
| 18863 | } | 19345 | } |
| 18864 | } | 19346 | } |
| 18865 | 19347 | ||
| 18866 | // names must be sorted | 19348 | const ty = try mod.errorSetFromUnsortedNames(names.keys()); |
| 18867 | Module.ErrorSet.sortNames(&names); | ||
| 18868 | const ty = try Type.Tag.error_set_merged.create(sema.arena, names); | ||
| 18869 | return sema.addType(ty); | 19349 | return sema.addType(ty); |
| 18870 | }, | 19350 | }, |
| 18871 | .Struct => { | 19351 | .Struct => { |
| 18872 | // TODO use reflection instead of magic numbers here | 19352 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 18873 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 19353 | const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18874 | // layout: containerlayout, | 19354 | try ip.getOrPutString(gpa, "layout"), |
| 18875 | const layout_val = struct_val[0]; | 19355 | ).?); |
| 18876 | // backing_int: ?type, | 19356 | const backing_integer_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18877 | const backing_int_val = struct_val[1]; | 19357 | try ip.getOrPutString(gpa, "backing_integer"), |
| 18878 | // fields: []const enumfield, | 19358 | ).?); |
| 18879 | const fields_val = struct_val[2]; | 19359 | const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18880 | // decls: []const declaration, | 19360 | try ip.getOrPutString(gpa, "fields"), |
| 18881 | const decls_val = struct_val[3]; | 19361 | ).?); |
| 18882 | // is_tuple: bool, | 19362 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18883 | const is_tuple_val = struct_val[4]; | 19363 | try ip.getOrPutString(gpa, "decls"), |
| 18884 | assert(struct_val.len == 5); | 19364 | ).?); |
| 18885 | 19365 | const is_tuple_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | |
| 18886 | const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout); | 19366 | try ip.getOrPutString(gpa, "is_tuple"), |
| 19367 | ).?); | ||
| 19368 | |||
| 19369 | const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); | ||
| 18887 | 19370 | ||
| 18888 | // Decls | 19371 | // Decls |
| 18889 | if (decls_val.sliceLen(mod) > 0) { | 19372 | if (decls_val.sliceLen(mod) > 0) { |
| 18890 | return sema.fail(block, src, "reified structs must have no decls", .{}); | 19373 | return sema.fail(block, src, "reified structs must have no decls", .{}); |
| 18891 | } | 19374 | } |
| 18892 | 19375 | ||
| 18893 | if (layout != .Packed and !backing_int_val.isNull()) { | 19376 | if (layout != .Packed and !backing_integer_val.isNull(mod)) { |
| 18894 | return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); | 19377 | return sema.fail(block, src, "non-packed struct does not support backing integer type", .{}); |
| 18895 | } | 19378 | } |
| 18896 | 19379 | ||
| 18897 | return try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy, is_tuple_val.toBool()); | 19380 | return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool()); |
| 18898 | }, | 19381 | }, |
| 18899 | .Enum => { | 19382 | .Enum => { |
| 18900 | const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data; | 19383 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 18901 | // TODO use reflection instead of magic numbers here | 19384 | const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18902 | // tag_type: type, | 19385 | try ip.getOrPutString(gpa, "tag_type"), |
| 18903 | const tag_type_val = struct_val[0]; | 19386 | ).?); |
| 18904 | // fields: []const EnumField, | 19387 | const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18905 | const fields_val = struct_val[1]; | 19388 | try ip.getOrPutString(gpa, "fields"), |
| 18906 | // decls: []const Declaration, | 19389 | ).?); |
| 18907 | const decls_val = struct_val[2]; | 19390 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 18908 | // is_exhaustive: bool, | 19391 | try ip.getOrPutString(gpa, "decls"), |
| 18909 | const is_exhaustive_val = struct_val[3]; | 19392 | ).?); |
| 19393 | const is_exhaustive_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | ||
| 19394 | try ip.getOrPutString(gpa, "is_exhaustive"), | ||
| 19395 | ).?); | ||
| 18910 | 19396 | ||
| 18911 | // Decls | 19397 | // Decls |
| 18912 | if (decls_val.sliceLen(mod) > 0) { | 19398 | if (decls_val.sliceLen(mod) > 0) { |
| 18913 | return sema.fail(block, src, "reified enums must have no decls", .{}); | 19399 | return sema.fail(block, src, "reified enums must have no decls", .{}); |
| 18914 | } | 19400 | } |
| 18915 | 19401 | ||
| 18916 | const gpa = sema.gpa; | 19402 | const int_tag_ty = tag_type_val.toType(); |
| 18917 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | 19403 | if (int_tag_ty.zigTypeTag(mod) != .Int) { |
| 18918 | errdefer new_decl_arena.deinit(); | 19404 | return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); |
| 18919 | const new_decl_arena_allocator = new_decl_arena.allocator(); | 19405 | } |
| 19406 | |||
| 19407 | // Because these things each reference each other, `undefined` | ||
| 19408 | // placeholders are used before being set after the enum type gains | ||
| 19409 | // an InternPool index. | ||
| 18920 | 19410 | ||
| 18921 | // Define our empty enum decl | ||
| 18922 | const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull); | ||
| 18923 | const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull); | ||
| 18924 | enum_ty_payload.* = .{ | ||
| 18925 | .base = .{ | ||
| 18926 | .tag = if (!is_exhaustive_val.toBool()) | ||
| 18927 | .enum_nonexhaustive | ||
| 18928 | else | ||
| 18929 | .enum_full, | ||
| 18930 | }, | ||
| 18931 | .data = enum_obj, | ||
| 18932 | }; | ||
| 18933 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | ||
| 18934 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); | ||
| 18935 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ | 19411 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 18936 | .ty = Type.type, | 19412 | .ty = Type.noreturn, |
| 18937 | .val = enum_val, | 19413 | .val = Value.@"unreachable", |
| 18938 | }, name_strategy, "enum", inst); | 19414 | }, name_strategy, "enum", inst); |
| 18939 | const new_decl = mod.declPtr(new_decl_index); | 19415 | const new_decl = mod.declPtr(new_decl_index); |
| 18940 | new_decl.owns_tv = true; | 19416 | new_decl.owns_tv = true; |
| 18941 | errdefer mod.abortAnonDecl(new_decl_index); | 19417 | errdefer { |
| 19418 | new_decl.has_tv = false; // namespace and val were destroyed by later errdefers | ||
| 19419 | mod.abortAnonDecl(new_decl_index); | ||
| 19420 | } | ||
| 18942 | 19421 | ||
| 18943 | enum_obj.* = .{ | 19422 | // Define our empty enum decl |
| 18944 | .owner_decl = new_decl_index, | 19423 | const fields_len = @intCast(u32, try sema.usizeCast(block, src, fields_val.sliceLen(mod))); |
| 18945 | .tag_ty = Type.null, | 19424 | const incomplete_enum = try ip.getIncompleteEnum(gpa, .{ |
| 18946 | .tag_ty_inferred = false, | 19425 | .decl = new_decl_index, |
| 18947 | .fields = .{}, | 19426 | .namespace = .none, |
| 18948 | .values = .{}, | 19427 | .fields_len = fields_len, |
| 18949 | .namespace = .{ | 19428 | .has_values = true, |
| 18950 | .parent = block.namespace, | 19429 | .tag_mode = if (!is_exhaustive_val.toBool()) |
| 18951 | .ty = enum_ty, | 19430 | .nonexhaustive |
| 18952 | .file_scope = block.getFileScope(), | 19431 | else |
| 18953 | }, | 19432 | .explicit, |
| 18954 | }; | 19433 | .tag_ty = int_tag_ty.toIntern(), |
| 19434 | }); | ||
| 19435 | // TODO: figure out InternPool removals for incremental compilation | ||
| 19436 | //errdefer ip.remove(incomplete_enum.index); | ||
| 18955 | 19437 | ||
| 18956 | // Enum tag type | 19438 | new_decl.ty = Type.type; |
| 18957 | var buffer: Value.ToTypeBuffer = undefined; | 19439 | new_decl.val = incomplete_enum.index.toValue(); |
| 18958 | const int_tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator); | ||
| 18959 | 19440 | ||
| 18960 | if (int_tag_ty.zigTypeTag() != .Int) { | 19441 | for (0..fields_len) |field_i| { |
| 18961 | return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{}); | 19442 | const elem_val = try fields_val.elemValue(mod, field_i); |
| 18962 | } | 19443 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); |
| 18963 | enum_obj.tag_ty = int_tag_ty; | 19444 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 18964 | 19445 | try ip.getOrPutString(gpa, "name"), | |
| 18965 | // Fields | 19446 | ).?); |
| 18966 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); | 19447 | const value_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 18967 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); | 19448 | try ip.getOrPutString(gpa, "value"), |
| 18968 | try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ | 19449 | ).?); |
| 18969 | .ty = enum_obj.tag_ty, | ||
| 18970 | .mod = mod, | ||
| 18971 | }); | ||
| 18972 | 19450 | ||
| 18973 | var field_i: usize = 0; | 19451 | const field_name = try name_val.toIpString(Type.slice_const_u8, mod); |
| 18974 | while (field_i < fields_len) : (field_i += 1) { | ||
| 18975 | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, field_i); | ||
| 18976 | const field_struct_val: []const Value = elem_val.castTag(.aggregate).?.data; | ||
| 18977 | // TODO use reflection instead of magic numbers here | ||
| 18978 | // name: []const u8 | ||
| 18979 | const name_val = field_struct_val[0]; | ||
| 18980 | // value: comptime_int | ||
| 18981 | const value_val = field_struct_val[1]; | ||
| 18982 | |||
| 18983 | const field_name = try name_val.toAllocatedBytes( | ||
| 18984 | Type.initTag(.const_slice_u8), | ||
| 18985 | new_decl_arena_allocator, | ||
| 18986 | sema.mod, | ||
| 18987 | ); | ||
| 18988 | 19452 | ||
| 18989 | if (!try sema.intFitsInType(value_val, enum_obj.tag_ty, null)) { | 19453 | if (!try sema.intFitsInType(value_val, int_tag_ty, null)) { |
| 18990 | // TODO: better source location | 19454 | // TODO: better source location |
| 18991 | return sema.fail(block, src, "field '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{ | 19455 | return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{ |
| 18992 | field_name, | 19456 | field_name.fmt(ip), |
| 18993 | value_val.fmtValue(Type.comptime_int, mod), | 19457 | value_val.fmtValue(Type.comptime_int, mod), |
| 18994 | enum_obj.tag_ty.fmt(mod), | 19458 | int_tag_ty.fmt(mod), |
| 18995 | }); | 19459 | }); |
| 18996 | } | 19460 | } |
| 18997 | 19461 | ||
| 18998 | const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name); | 19462 | if (try incomplete_enum.addFieldName(ip, gpa, field_name)) |other_index| { |
| 18999 | if (gop_field.found_existing) { | ||
| 19000 | const msg = msg: { | 19463 | const msg = msg: { |
| 19001 | const msg = try sema.errMsg(block, src, "duplicate enum field '{s}'", .{field_name}); | 19464 | const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{ |
| 19465 | field_name.fmt(ip), | ||
| 19466 | }); | ||
| 19002 | errdefer msg.destroy(gpa); | 19467 | errdefer msg.destroy(gpa); |
| 19468 | _ = other_index; // TODO: this note is incorrect | ||
| 19003 | try sema.errNote(block, src, msg, "other field here", .{}); | 19469 | try sema.errNote(block, src, msg, "other field here", .{}); |
| 19004 | break :msg msg; | 19470 | break :msg msg; |
| 19005 | }; | 19471 | }; |
| 19006 | return sema.failWithOwnedErrorMsg(msg); | 19472 | return sema.failWithOwnedErrorMsg(msg); |
| 19007 | } | 19473 | } |
| 19008 | 19474 | ||
| 19009 | const copied_tag_val = try value_val.copy(new_decl_arena_allocator); | 19475 | if (try incomplete_enum.addFieldValue(ip, gpa, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| { |
| 19010 | const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{ | ||
| 19011 | .ty = enum_obj.tag_ty, | ||
| 19012 | .mod = mod, | ||
| 19013 | }); | ||
| 19014 | if (gop_val.found_existing) { | ||
| 19015 | const msg = msg: { | 19476 | const msg = msg: { |
| 19016 | const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)}); | 19477 | const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)}); |
| 19017 | errdefer msg.destroy(gpa); | 19478 | errdefer msg.destroy(gpa); |
| 19479 | _ = other; // TODO: this note is incorrect | ||
| 19018 | try sema.errNote(block, src, msg, "other enum tag value here", .{}); | 19480 | try sema.errNote(block, src, msg, "other enum tag value here", .{}); |
| 19019 | break :msg msg; | 19481 | break :msg msg; |
| 19020 | }; | 19482 | }; |
| ... | @@ -19022,182 +19484,209 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in | ... | @@ -19022,182 +19484,209 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 19022 | } | 19484 | } |
| 19023 | } | 19485 | } |
| 19024 | 19486 | ||
| 19025 | try new_decl.finalizeNewArena(&new_decl_arena); | 19487 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); |
| 19026 | return sema.analyzeDeclVal(block, src, new_decl_index); | 19488 | try mod.finalizeAnonDecl(new_decl_index); |
| 19489 | return decl_val; | ||
| 19027 | }, | 19490 | }, |
| 19028 | .Opaque => { | 19491 | .Opaque => { |
| 19029 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 19492 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 19030 | // decls: []const Declaration, | 19493 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 19031 | const decls_val = struct_val[0]; | 19494 | try ip.getOrPutString(gpa, "decls"), |
| 19495 | ).?); | ||
| 19032 | 19496 | ||
| 19033 | // Decls | 19497 | // Decls |
| 19034 | if (decls_val.sliceLen(mod) > 0) { | 19498 | if (decls_val.sliceLen(mod) > 0) { |
| 19035 | return sema.fail(block, src, "reified opaque must have no decls", .{}); | 19499 | return sema.fail(block, src, "reified opaque must have no decls", .{}); |
| 19036 | } | 19500 | } |
| 19037 | 19501 | ||
| 19038 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | 19502 | // Because these three things each reference each other, |
| 19039 | errdefer new_decl_arena.deinit(); | 19503 | // `undefined` placeholders are used in two places before being set |
| 19040 | const new_decl_arena_allocator = new_decl_arena.allocator(); | 19504 | // after the opaque type gains an InternPool index. |
| 19041 | 19505 | ||
| 19042 | const opaque_obj = try new_decl_arena_allocator.create(Module.Opaque); | ||
| 19043 | const opaque_ty_payload = try new_decl_arena_allocator.create(Type.Payload.Opaque); | ||
| 19044 | opaque_ty_payload.* = .{ | ||
| 19045 | .base = .{ .tag = .@"opaque" }, | ||
| 19046 | .data = opaque_obj, | ||
| 19047 | }; | ||
| 19048 | const opaque_ty = Type.initPayload(&opaque_ty_payload.base); | ||
| 19049 | const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty); | ||
| 19050 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ | 19506 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 19051 | .ty = Type.type, | 19507 | .ty = Type.noreturn, |
| 19052 | .val = opaque_val, | 19508 | .val = Value.@"unreachable", |
| 19053 | }, name_strategy, "opaque", inst); | 19509 | }, name_strategy, "opaque", inst); |
| 19054 | const new_decl = mod.declPtr(new_decl_index); | 19510 | const new_decl = mod.declPtr(new_decl_index); |
| 19055 | new_decl.owns_tv = true; | 19511 | new_decl.owns_tv = true; |
| 19056 | errdefer mod.abortAnonDecl(new_decl_index); | 19512 | errdefer { |
| 19513 | new_decl.has_tv = false; // namespace and val were destroyed by later errdefers | ||
| 19514 | mod.abortAnonDecl(new_decl_index); | ||
| 19515 | } | ||
| 19057 | 19516 | ||
| 19058 | opaque_obj.* = .{ | 19517 | const new_namespace_index = try mod.createNamespace(.{ |
| 19059 | .owner_decl = new_decl_index, | 19518 | .parent = block.namespace.toOptional(), |
| 19060 | .namespace = .{ | 19519 | .ty = undefined, |
| 19061 | .parent = block.namespace, | 19520 | .file_scope = block.getFileScope(mod), |
| 19062 | .ty = opaque_ty, | 19521 | }); |
| 19063 | .file_scope = block.getFileScope(), | 19522 | const new_namespace = mod.namespacePtr(new_namespace_index); |
| 19064 | }, | 19523 | errdefer mod.destroyNamespace(new_namespace_index); |
| 19065 | }; | ||
| 19066 | 19524 | ||
| 19067 | try new_decl.finalizeNewArena(&new_decl_arena); | 19525 | const opaque_ty = try mod.intern(.{ .opaque_type = .{ |
| 19068 | return sema.analyzeDeclVal(block, src, new_decl_index); | 19526 | .decl = new_decl_index, |
| 19527 | .namespace = new_namespace_index, | ||
| 19528 | } }); | ||
| 19529 | // TODO: figure out InternPool removals for incremental compilation | ||
| 19530 | //errdefer ip.remove(opaque_ty); | ||
| 19531 | |||
| 19532 | new_decl.ty = Type.type; | ||
| 19533 | new_decl.val = opaque_ty.toValue(); | ||
| 19534 | new_namespace.ty = opaque_ty.toType(); | ||
| 19535 | |||
| 19536 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); | ||
| 19537 | try mod.finalizeAnonDecl(new_decl_index); | ||
| 19538 | return decl_val; | ||
| 19069 | }, | 19539 | }, |
| 19070 | .Union => { | 19540 | .Union => { |
| 19071 | // TODO use reflection instead of magic numbers here | 19541 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 19072 | const struct_val = union_val.val.castTag(.aggregate).?.data; | 19542 | const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 19073 | // layout: containerlayout, | 19543 | try ip.getOrPutString(gpa, "layout"), |
| 19074 | const layout_val = struct_val[0]; | 19544 | ).?); |
| 19075 | // tag_type: ?type, | 19545 | const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 19076 | const tag_type_val = struct_val[1]; | 19546 | try ip.getOrPutString(gpa, "tag_type"), |
| 19077 | // fields: []const enumfield, | 19547 | ).?); |
| 19078 | const fields_val = struct_val[2]; | 19548 | const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 19079 | // decls: []const declaration, | 19549 | try ip.getOrPutString(gpa, "fields"), |
| 19080 | const decls_val = struct_val[3]; | 19550 | ).?); |
| 19551 | const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | ||
| 19552 | try ip.getOrPutString(gpa, "decls"), | ||
| 19553 | ).?); | ||
| 19081 | 19554 | ||
| 19082 | // Decls | 19555 | // Decls |
| 19083 | if (decls_val.sliceLen(mod) > 0) { | 19556 | if (decls_val.sliceLen(mod) > 0) { |
| 19084 | return sema.fail(block, src, "reified unions must have no decls", .{}); | 19557 | return sema.fail(block, src, "reified unions must have no decls", .{}); |
| 19085 | } | 19558 | } |
| 19086 | const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout); | 19559 | const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); |
| 19087 | 19560 | ||
| 19088 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | 19561 | // Because these three things each reference each other, `undefined` |
| 19089 | errdefer new_decl_arena.deinit(); | 19562 | // placeholders are used before being set after the union type gains an |
| 19090 | const new_decl_arena_allocator = new_decl_arena.allocator(); | 19563 | // InternPool index. |
| 19091 | 19564 | ||
| 19092 | const union_obj = try new_decl_arena_allocator.create(Module.Union); | ||
| 19093 | const type_tag = if (!tag_type_val.isNull()) | ||
| 19094 | Type.Tag.union_tagged | ||
| 19095 | else if (layout != .Auto) | ||
| 19096 | Type.Tag.@"union" | ||
| 19097 | else switch (block.sema.mod.optimizeMode()) { | ||
| 19098 | .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged, | ||
| 19099 | .ReleaseFast, .ReleaseSmall => Type.Tag.@"union", | ||
| 19100 | }; | ||
| 19101 | const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union); | ||
| 19102 | union_payload.* = .{ | ||
| 19103 | .base = .{ .tag = type_tag }, | ||
| 19104 | .data = union_obj, | ||
| 19105 | }; | ||
| 19106 | const union_ty = Type.initPayload(&union_payload.base); | ||
| 19107 | const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty); | ||
| 19108 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ | 19565 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 19109 | .ty = Type.type, | 19566 | .ty = Type.noreturn, |
| 19110 | .val = new_union_val, | 19567 | .val = Value.@"unreachable", |
| 19111 | }, name_strategy, "union", inst); | 19568 | }, name_strategy, "union", inst); |
| 19112 | const new_decl = mod.declPtr(new_decl_index); | 19569 | const new_decl = mod.declPtr(new_decl_index); |
| 19113 | new_decl.owns_tv = true; | 19570 | new_decl.owns_tv = true; |
| 19114 | errdefer mod.abortAnonDecl(new_decl_index); | 19571 | errdefer { |
| 19115 | union_obj.* = .{ | 19572 | new_decl.has_tv = false; // namespace and val were destroyed by later errdefers |
| 19573 | mod.abortAnonDecl(new_decl_index); | ||
| 19574 | } | ||
| 19575 | |||
| 19576 | const new_namespace_index = try mod.createNamespace(.{ | ||
| 19577 | .parent = block.namespace.toOptional(), | ||
| 19578 | .ty = undefined, | ||
| 19579 | .file_scope = block.getFileScope(mod), | ||
| 19580 | }); | ||
| 19581 | const new_namespace = mod.namespacePtr(new_namespace_index); | ||
| 19582 | errdefer mod.destroyNamespace(new_namespace_index); | ||
| 19583 | |||
| 19584 | const union_index = try mod.createUnion(.{ | ||
| 19116 | .owner_decl = new_decl_index, | 19585 | .owner_decl = new_decl_index, |
| 19117 | .tag_ty = Type.initTag(.null), | 19586 | .tag_ty = Type.null, |
| 19118 | .fields = .{}, | 19587 | .fields = .{}, |
| 19119 | .zir_index = inst, | 19588 | .zir_index = inst, |
| 19120 | .layout = layout, | 19589 | .layout = layout, |
| 19121 | .status = .have_field_types, | 19590 | .status = .have_field_types, |
| 19122 | .namespace = .{ | 19591 | .namespace = new_namespace_index, |
| 19123 | .parent = block.namespace, | 19592 | }); |
| 19124 | .ty = union_ty, | 19593 | const union_obj = mod.unionPtr(union_index); |
| 19125 | .file_scope = block.getFileScope(), | 19594 | errdefer mod.destroyUnion(union_index); |
| 19595 | |||
| 19596 | const union_ty = try ip.get(gpa, .{ .union_type = .{ | ||
| 19597 | .index = union_index, | ||
| 19598 | .runtime_tag = if (!tag_type_val.isNull(mod)) | ||
| 19599 | .tagged | ||
| 19600 | else if (layout != .Auto) | ||
| 19601 | .none | ||
| 19602 | else switch (mod.optimizeMode()) { | ||
| 19603 | .Debug, .ReleaseSafe => .safety, | ||
| 19604 | .ReleaseFast, .ReleaseSmall => .none, | ||
| 19126 | }, | 19605 | }, |
| 19127 | }; | 19606 | } }); |
| 19607 | // TODO: figure out InternPool removals for incremental compilation | ||
| 19608 | //errdefer ip.remove(union_ty); | ||
| 19609 | |||
| 19610 | new_decl.ty = Type.type; | ||
| 19611 | new_decl.val = union_ty.toValue(); | ||
| 19612 | new_namespace.ty = union_ty.toType(); | ||
| 19128 | 19613 | ||
| 19129 | // Tag type | 19614 | // Tag type |
| 19130 | var tag_ty_field_names: ?Module.EnumFull.NameMap = null; | ||
| 19131 | var enum_field_names: ?*Module.EnumNumbered.NameMap = null; | ||
| 19132 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); | 19615 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); |
| 19133 | if (tag_type_val.optionalValue()) |payload_val| { | 19616 | var explicit_tags_seen: []bool = &.{}; |
| 19134 | var buffer: Value.ToTypeBuffer = undefined; | 19617 | var enum_field_names: []InternPool.NullTerminatedString = &.{}; |
| 19135 | union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator); | 19618 | if (tag_type_val.optionalValue(mod)) |payload_val| { |
| 19619 | union_obj.tag_ty = payload_val.toType(); | ||
| 19620 | |||
| 19621 | const enum_type = switch (ip.indexToKey(union_obj.tag_ty.toIntern())) { | ||
| 19622 | .enum_type => |x| x, | ||
| 19623 | else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}), | ||
| 19624 | }; | ||
| 19136 | 19625 | ||
| 19137 | if (union_obj.tag_ty.zigTypeTag() != .Enum) { | 19626 | explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len); |
| 19138 | return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}); | 19627 | @memset(explicit_tags_seen, false); |
| 19139 | } | ||
| 19140 | tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena); | ||
| 19141 | } else { | 19628 | } else { |
| 19142 | union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null); | 19629 | enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); |
| 19143 | enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; | ||
| 19144 | } | 19630 | } |
| 19145 | 19631 | ||
| 19146 | // Fields | 19632 | // Fields |
| 19147 | try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); | 19633 | try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); |
| 19148 | 19634 | ||
| 19149 | var i: usize = 0; | 19635 | for (0..fields_len) |i| { |
| 19150 | while (i < fields_len) : (i += 1) { | 19636 | const elem_val = try fields_val.elemValue(mod, i); |
| 19151 | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); | 19637 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); |
| 19152 | const field_struct_val = elem_val.castTag(.aggregate).?.data; | 19638 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 19153 | // TODO use reflection instead of magic numbers here | 19639 | try ip.getOrPutString(gpa, "name"), |
| 19154 | // name: []const u8 | 19640 | ).?); |
| 19155 | const name_val = field_struct_val[0]; | 19641 | const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 19156 | // type: type, | 19642 | try ip.getOrPutString(gpa, "type"), |
| 19157 | const type_val = field_struct_val[1]; | 19643 | ).?); |
| 19158 | // alignment: comptime_int, | 19644 | const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 19159 | const alignment_val = field_struct_val[2]; | 19645 | try ip.getOrPutString(gpa, "alignment"), |
| 19160 | 19646 | ).?); | |
| 19161 | const field_name = try name_val.toAllocatedBytes( | 19647 | |
| 19162 | Type.initTag(.const_slice_u8), | 19648 | const field_name = try name_val.toIpString(Type.slice_const_u8, mod); |
| 19163 | new_decl_arena_allocator, | 19649 | |
| 19164 | sema.mod, | 19650 | if (enum_field_names.len != 0) { |
| 19165 | ); | 19651 | enum_field_names[i] = field_name; |
| 19166 | 19652 | } | |
| 19167 | if (enum_field_names) |set| { | 19653 | |
| 19168 | set.putAssumeCapacity(field_name, {}); | 19654 | if (explicit_tags_seen.len > 0) { |
| 19169 | } | 19655 | const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type; |
| 19170 | 19656 | const enum_index = tag_info.nameIndex(ip, field_name) orelse { | |
| 19171 | if (tag_ty_field_names) |*names| { | ||
| 19172 | const enum_has_field = names.orderedRemove(field_name); | ||
| 19173 | if (!enum_has_field) { | ||
| 19174 | const msg = msg: { | 19657 | const msg = msg: { |
| 19175 | const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); | 19658 | const msg = try sema.errMsg(block, src, "no field named '{}' in enum '{}'", .{ |
| 19176 | errdefer msg.destroy(sema.gpa); | 19659 | field_name.fmt(ip), |
| 19660 | union_obj.tag_ty.fmt(mod), | ||
| 19661 | }); | ||
| 19662 | errdefer msg.destroy(gpa); | ||
| 19177 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); | 19663 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 19178 | break :msg msg; | 19664 | break :msg msg; |
| 19179 | }; | 19665 | }; |
| 19180 | return sema.failWithOwnedErrorMsg(msg); | 19666 | return sema.failWithOwnedErrorMsg(msg); |
| 19181 | } | 19667 | }; |
| 19668 | // No check for duplicate because the check already happened in order | ||
| 19669 | // to create the enum type in the first place. | ||
| 19670 | assert(!explicit_tags_seen[enum_index]); | ||
| 19671 | explicit_tags_seen[enum_index] = true; | ||
| 19182 | } | 19672 | } |
| 19183 | 19673 | ||
| 19184 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); | 19674 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 19185 | if (gop.found_existing) { | 19675 | if (gop.found_existing) { |
| 19186 | // TODO: better source location | 19676 | // TODO: better source location |
| 19187 | return sema.fail(block, src, "duplicate union field {s}", .{field_name}); | 19677 | return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)}); |
| 19188 | } | 19678 | } |
| 19189 | 19679 | ||
| 19190 | var buffer: Value.ToTypeBuffer = undefined; | 19680 | const field_ty = type_val.toType(); |
| 19191 | const field_ty = try type_val.toType(&buffer).copy(new_decl_arena_allocator); | ||
| 19192 | gop.value_ptr.* = .{ | 19681 | gop.value_ptr.* = .{ |
| 19193 | .ty = field_ty, | 19682 | .ty = field_ty, |
| 19194 | .abi_align = @intCast(u32, (try alignment_val.getUnsignedIntAdvanced(target, sema)).?), | 19683 | .abi_align = @intCast(u32, (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?), |
| 19195 | }; | 19684 | }; |
| 19196 | 19685 | ||
| 19197 | if (field_ty.zigTypeTag() == .Opaque) { | 19686 | if (field_ty.zigTypeTag(mod) == .Opaque) { |
| 19198 | const msg = msg: { | 19687 | const msg = msg: { |
| 19199 | const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); | 19688 | const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); |
| 19200 | errdefer msg.destroy(sema.gpa); | 19689 | errdefer msg.destroy(gpa); |
| 19201 | 19690 | ||
| 19202 | try sema.addDeclaredHereNote(msg, field_ty); | 19691 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19203 | break :msg msg; | 19692 | break :msg msg; |
| ... | @@ -19206,23 +19695,23 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in | ... | @@ -19206,23 +19695,23 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 19206 | } | 19695 | } |
| 19207 | if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) { | 19696 | if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) { |
| 19208 | const msg = msg: { | 19697 | const msg = msg: { |
| 19209 | const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | 19698 | const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); |
| 19210 | errdefer msg.destroy(sema.gpa); | 19699 | errdefer msg.destroy(gpa); |
| 19211 | 19700 | ||
| 19212 | const src_decl = sema.mod.declPtr(block.src_decl); | 19701 | const src_decl = mod.declPtr(block.src_decl); |
| 19213 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), field_ty, .union_field); | 19702 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .union_field); |
| 19214 | 19703 | ||
| 19215 | try sema.addDeclaredHereNote(msg, field_ty); | 19704 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19216 | break :msg msg; | 19705 | break :msg msg; |
| 19217 | }; | 19706 | }; |
| 19218 | return sema.failWithOwnedErrorMsg(msg); | 19707 | return sema.failWithOwnedErrorMsg(msg); |
| 19219 | } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) { | 19708 | } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) { |
| 19220 | const msg = msg: { | 19709 | const msg = msg: { |
| 19221 | const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | 19710 | const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); |
| 19222 | errdefer msg.destroy(sema.gpa); | 19711 | errdefer msg.destroy(gpa); |
| 19223 | 19712 | ||
| 19224 | const src_decl = sema.mod.declPtr(block.src_decl); | 19713 | const src_decl = mod.declPtr(block.src_decl); |
| 19225 | try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl), field_ty); | 19714 | try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty); |
| 19226 | 19715 | ||
| 19227 | try sema.addDeclaredHereNote(msg, field_ty); | 19716 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19228 | break :msg msg; | 19717 | break :msg msg; |
| ... | @@ -19231,47 +19720,61 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in | ... | @@ -19231,47 +19720,61 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 19231 | } | 19720 | } |
| 19232 | } | 19721 | } |
| 19233 | 19722 | ||
| 19234 | if (tag_ty_field_names) |names| { | 19723 | if (explicit_tags_seen.len > 0) { |
| 19235 | if (names.count() > 0) { | 19724 | const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type; |
| 19725 | if (tag_info.names.len > fields_len) { | ||
| 19236 | const msg = msg: { | 19726 | const msg = msg: { |
| 19237 | const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{}); | 19727 | const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{}); |
| 19238 | errdefer msg.destroy(sema.gpa); | 19728 | errdefer msg.destroy(gpa); |
| 19239 | 19729 | ||
| 19240 | const enum_ty = union_obj.tag_ty; | 19730 | const enum_ty = union_obj.tag_ty; |
| 19241 | for (names.keys()) |field_name| { | 19731 | for (tag_info.names, 0..) |field_name, field_index| { |
| 19242 | const field_index = enum_ty.enumFieldIndex(field_name).?; | 19732 | if (explicit_tags_seen[field_index]) continue; |
| 19243 | try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); | 19733 | try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{}' missing, declared here", .{ |
| 19734 | field_name.fmt(ip), | ||
| 19735 | }); | ||
| 19244 | } | 19736 | } |
| 19245 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); | 19737 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 19246 | break :msg msg; | 19738 | break :msg msg; |
| 19247 | }; | 19739 | }; |
| 19248 | return sema.failWithOwnedErrorMsg(msg); | 19740 | return sema.failWithOwnedErrorMsg(msg); |
| 19249 | } | 19741 | } |
| 19742 | } else { | ||
| 19743 | union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, null); | ||
| 19250 | } | 19744 | } |
| 19251 | 19745 | ||
| 19252 | try new_decl.finalizeNewArena(&new_decl_arena); | 19746 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); |
| 19253 | return sema.analyzeDeclVal(block, src, new_decl_index); | 19747 | try mod.finalizeAnonDecl(new_decl_index); |
| 19748 | return decl_val; | ||
| 19254 | }, | 19749 | }, |
| 19255 | .Fn => { | 19750 | .Fn => { |
| 19256 | const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data; | 19751 | const fields = ip.typeOf(union_val.val).toType().structFields(mod); |
| 19257 | // TODO use reflection instead of magic numbers here | 19752 | const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 19258 | // calling_convention: CallingConvention, | 19753 | try ip.getOrPutString(gpa, "calling_convention"), |
| 19259 | const cc = struct_val[0].toEnum(std.builtin.CallingConvention); | 19754 | ).?); |
| 19260 | // alignment: comptime_int, | 19755 | const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 19261 | const alignment_val = struct_val[1]; | 19756 | try ip.getOrPutString(gpa, "alignment"), |
| 19262 | // is_generic: bool, | 19757 | ).?); |
| 19263 | const is_generic = struct_val[2].toBool(); | 19758 | const is_generic_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 19264 | // is_var_args: bool, | 19759 | try ip.getOrPutString(gpa, "is_generic"), |
| 19265 | const is_var_args = struct_val[3].toBool(); | 19760 | ).?); |
| 19266 | // return_type: ?type, | 19761 | const is_var_args_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 19267 | const return_type_val = struct_val[4]; | 19762 | try ip.getOrPutString(gpa, "is_var_args"), |
| 19268 | // args: []const Param, | 19763 | ).?); |
| 19269 | const args_val = struct_val[5]; | 19764 | const return_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( |
| 19270 | 19765 | try ip.getOrPutString(gpa, "return_type"), | |
| 19766 | ).?); | ||
| 19767 | const params_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( | ||
| 19768 | try ip.getOrPutString(gpa, "params"), | ||
| 19769 | ).?); | ||
| 19770 | |||
| 19771 | const is_generic = is_generic_val.toBool(); | ||
| 19271 | if (is_generic) { | 19772 | if (is_generic) { |
| 19272 | return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{}); | 19773 | return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{}); |
| 19273 | } | 19774 | } |
| 19274 | 19775 | ||
| 19776 | const is_var_args = is_var_args_val.toBool(); | ||
| 19777 | const cc = mod.toEnum(std.builtin.CallingConvention, calling_convention_val); | ||
| 19275 | if (is_var_args and cc != .C) { | 19778 | if (is_var_args and cc != .C) { |
| 19276 | return sema.fail(block, src, "varargs functions must have C calling convention", .{}); | 19779 | return sema.fail(block, src, "varargs functions must have C calling convention", .{}); |
| 19277 | } | 19780 | } |
| ... | @@ -19280,63 +19783,55 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in | ... | @@ -19280,63 +19783,55 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 19280 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { | 19783 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { |
| 19281 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); | 19784 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); |
| 19282 | } | 19785 | } |
| 19283 | const alignment = @intCast(u29, alignment_val.toUnsignedInt(target)); | 19786 | const alignment = @intCast(u29, alignment_val.toUnsignedInt(mod)); |
| 19284 | if (alignment == target_util.defaultFunctionAlignment(target)) { | 19787 | if (alignment == target_util.defaultFunctionAlignment(target)) { |
| 19285 | break :alignment 0; | 19788 | break :alignment .none; |
| 19286 | } else { | 19789 | } else { |
| 19287 | break :alignment alignment; | 19790 | break :alignment InternPool.Alignment.fromByteUnits(alignment); |
| 19288 | } | 19791 | } |
| 19289 | }; | 19792 | }; |
| 19290 | const return_type = return_type_val.optionalValue() orelse | 19793 | const return_type = return_type_val.optionalValue(mod) orelse |
| 19291 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); | 19794 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); |
| 19292 | 19795 | ||
| 19293 | var buf: Value.ToTypeBuffer = undefined; | 19796 | const args_len = try sema.usizeCast(block, src, params_val.sliceLen(mod)); |
| 19294 | 19797 | const param_types = try sema.arena.alloc(InternPool.Index, args_len); | |
| 19295 | const args_slice_val = args_val.castTag(.slice).?.data; | ||
| 19296 | const args_len = try sema.usizeCast(block, src, args_slice_val.len.toUnsignedInt(mod.getTarget())); | ||
| 19297 | |||
| 19298 | const param_types = try sema.arena.alloc(Type, args_len); | ||
| 19299 | const comptime_params = try sema.arena.alloc(bool, args_len); | ||
| 19300 | 19798 | ||
| 19301 | var noalias_bits: u32 = 0; | 19799 | var noalias_bits: u32 = 0; |
| 19302 | var i: usize = 0; | 19800 | for (param_types, 0..) |*param_type, i| { |
| 19303 | while (i < args_len) : (i += 1) { | 19801 | const elem_val = try params_val.elemValue(mod, i); |
| 19304 | var arg_buf: Value.ElemValueBuffer = undefined; | 19802 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); |
| 19305 | const arg = args_slice_val.ptr.elemValueBuffer(mod, i, &arg_buf); | 19803 | const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 19306 | const arg_val = arg.castTag(.aggregate).?.data; | 19804 | try ip.getOrPutString(gpa, "is_generic"), |
| 19307 | // TODO use reflection instead of magic numbers here | 19805 | ).?); |
| 19308 | // is_generic: bool, | 19806 | const param_is_noalias_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 19309 | const arg_is_generic = arg_val[0].toBool(); | 19807 | try ip.getOrPutString(gpa, "is_noalias"), |
| 19310 | // is_noalias: bool, | 19808 | ).?); |
| 19311 | const arg_is_noalias = arg_val[1].toBool(); | 19809 | const opt_param_type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 19312 | // type: ?type, | 19810 | try ip.getOrPutString(gpa, "type"), |
| 19313 | const param_type_opt_val = arg_val[2]; | 19811 | ).?); |
| 19314 | 19812 | ||
| 19315 | if (arg_is_generic) { | 19813 | if (param_is_generic_val.toBool()) { |
| 19316 | return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{}); | 19814 | return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{}); |
| 19317 | } | 19815 | } |
| 19318 | 19816 | ||
| 19319 | const param_type_val = param_type_opt_val.optionalValue() orelse | 19817 | const param_type_val = opt_param_type_val.optionalValue(mod) orelse |
| 19320 | return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{}); | 19818 | return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{}); |
| 19321 | const param_type = try param_type_val.toType(&buf).copy(sema.arena); | 19819 | param_type.* = param_type_val.toIntern(); |
| 19322 | 19820 | ||
| 19323 | if (arg_is_noalias) { | 19821 | if (param_is_noalias_val.toBool()) { |
| 19324 | if (!param_type.isPtrAtRuntime()) { | 19822 | if (!param_type.toType().isPtrAtRuntime(mod)) { |
| 19325 | return sema.fail(block, src, "non-pointer parameter declared noalias", .{}); | 19823 | return sema.fail(block, src, "non-pointer parameter declared noalias", .{}); |
| 19326 | } | 19824 | } |
| 19327 | noalias_bits |= @as(u32, 1) << (std.math.cast(u5, i) orelse | 19825 | noalias_bits |= @as(u32, 1) << (std.math.cast(u5, i) orelse |
| 19328 | return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); | 19826 | return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{})); |
| 19329 | } | 19827 | } |
| 19330 | |||
| 19331 | param_types[i] = param_type; | ||
| 19332 | comptime_params[i] = false; | ||
| 19333 | } | 19828 | } |
| 19334 | 19829 | ||
| 19335 | var fn_info = Type.Payload.Function.Data{ | 19830 | const ty = try mod.funcType(.{ |
| 19336 | .param_types = param_types, | 19831 | .param_types = param_types, |
| 19337 | .comptime_params = comptime_params.ptr, | 19832 | .comptime_bits = 0, |
| 19338 | .noalias_bits = noalias_bits, | 19833 | .noalias_bits = noalias_bits, |
| 19339 | .return_type = try return_type.toType(&buf).copy(sema.arena), | 19834 | .return_type = return_type.toIntern(), |
| 19340 | .alignment = alignment, | 19835 | .alignment = alignment, |
| 19341 | .cc = cc, | 19836 | .cc = cc, |
| 19342 | .is_var_args = is_var_args, | 19837 | .is_var_args = is_var_args, |
| ... | @@ -19346,9 +19841,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in | ... | @@ -19346,9 +19841,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 19346 | .cc_is_generic = false, | 19841 | .cc_is_generic = false, |
| 19347 | .section_is_generic = false, | 19842 | .section_is_generic = false, |
| 19348 | .addrspace_is_generic = false, | 19843 | .addrspace_is_generic = false, |
| 19349 | }; | 19844 | }); |
| 19350 | |||
| 19351 | const ty = try Type.Tag.function.create(sema.arena, fn_info); | ||
| 19352 | return sema.addType(ty); | 19845 | return sema.addType(ty); |
| 19353 | }, | 19846 | }, |
| 19354 | .Frame => return sema.failWithUseOfAsync(block, src), | 19847 | .Frame => return sema.failWithUseOfAsync(block, src), |
| ... | @@ -19366,22 +19859,34 @@ fn reifyStruct( | ... | @@ -19366,22 +19859,34 @@ fn reifyStruct( |
| 19366 | name_strategy: Zir.Inst.NameStrategy, | 19859 | name_strategy: Zir.Inst.NameStrategy, |
| 19367 | is_tuple: bool, | 19860 | is_tuple: bool, |
| 19368 | ) CompileError!Air.Inst.Ref { | 19861 | ) CompileError!Air.Inst.Ref { |
| 19369 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | ||
| 19370 | errdefer new_decl_arena.deinit(); | ||
| 19371 | const new_decl_arena_allocator = new_decl_arena.allocator(); | ||
| 19372 | |||
| 19373 | const struct_obj = try new_decl_arena_allocator.create(Module.Struct); | ||
| 19374 | const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj); | ||
| 19375 | const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty); | ||
| 19376 | const mod = sema.mod; | 19862 | const mod = sema.mod; |
| 19863 | const gpa = sema.gpa; | ||
| 19864 | const ip = &mod.intern_pool; | ||
| 19865 | |||
| 19866 | // Because these three things each reference each other, `undefined` | ||
| 19867 | // placeholders are used before being set after the struct type gains an | ||
| 19868 | // InternPool index. | ||
| 19869 | |||
| 19377 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ | 19870 | const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{ |
| 19378 | .ty = Type.type, | 19871 | .ty = Type.noreturn, |
| 19379 | .val = new_struct_val, | 19872 | .val = Value.@"unreachable", |
| 19380 | }, name_strategy, "struct", inst); | 19873 | }, name_strategy, "struct", inst); |
| 19381 | const new_decl = mod.declPtr(new_decl_index); | 19874 | const new_decl = mod.declPtr(new_decl_index); |
| 19382 | new_decl.owns_tv = true; | 19875 | new_decl.owns_tv = true; |
| 19383 | errdefer mod.abortAnonDecl(new_decl_index); | 19876 | errdefer { |
| 19384 | struct_obj.* = .{ | 19877 | new_decl.has_tv = false; // namespace and val were destroyed by later errdefers |
| 19878 | mod.abortAnonDecl(new_decl_index); | ||
| 19879 | } | ||
| 19880 | |||
| 19881 | const new_namespace_index = try mod.createNamespace(.{ | ||
| 19882 | .parent = block.namespace.toOptional(), | ||
| 19883 | .ty = undefined, | ||
| 19884 | .file_scope = block.getFileScope(mod), | ||
| 19885 | }); | ||
| 19886 | const new_namespace = mod.namespacePtr(new_namespace_index); | ||
| 19887 | errdefer mod.destroyNamespace(new_namespace_index); | ||
| 19888 | |||
| 19889 | const struct_index = try mod.createStruct(.{ | ||
| 19385 | .owner_decl = new_decl_index, | 19890 | .owner_decl = new_decl_index, |
| 19386 | .fields = .{}, | 19891 | .fields = .{}, |
| 19387 | .zir_index = inst, | 19892 | .zir_index = inst, |
| ... | @@ -19389,38 +19894,49 @@ fn reifyStruct( | ... | @@ -19389,38 +19894,49 @@ fn reifyStruct( |
| 19389 | .status = .have_field_types, | 19894 | .status = .have_field_types, |
| 19390 | .known_non_opv = false, | 19895 | .known_non_opv = false, |
| 19391 | .is_tuple = is_tuple, | 19896 | .is_tuple = is_tuple, |
| 19392 | .namespace = .{ | 19897 | .namespace = new_namespace_index, |
| 19393 | .parent = block.namespace, | 19898 | }); |
| 19394 | .ty = struct_ty, | 19899 | const struct_obj = mod.structPtr(struct_index); |
| 19395 | .file_scope = block.getFileScope(), | 19900 | errdefer mod.destroyStruct(struct_index); |
| 19396 | }, | ||
| 19397 | }; | ||
| 19398 | 19901 | ||
| 19399 | const target = mod.getTarget(); | 19902 | const struct_ty = try ip.get(gpa, .{ .struct_type = .{ |
| 19903 | .index = struct_index.toOptional(), | ||
| 19904 | .namespace = new_namespace_index.toOptional(), | ||
| 19905 | } }); | ||
| 19906 | // TODO: figure out InternPool removals for incremental compilation | ||
| 19907 | //errdefer ip.remove(struct_ty); | ||
| 19908 | |||
| 19909 | new_decl.ty = Type.type; | ||
| 19910 | new_decl.val = struct_ty.toValue(); | ||
| 19911 | new_namespace.ty = struct_ty.toType(); | ||
| 19400 | 19912 | ||
| 19401 | // Fields | 19913 | // Fields |
| 19402 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); | 19914 | const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod)); |
| 19403 | try struct_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); | 19915 | try struct_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); |
| 19404 | var i: usize = 0; | 19916 | var i: usize = 0; |
| 19405 | while (i < fields_len) : (i += 1) { | 19917 | while (i < fields_len) : (i += 1) { |
| 19406 | const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i); | 19918 | const elem_val = try fields_val.elemValue(mod, i); |
| 19407 | const field_struct_val = elem_val.castTag(.aggregate).?.data; | 19919 | const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); |
| 19408 | // TODO use reflection instead of magic numbers here | 19920 | const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 19409 | // name: []const u8 | 19921 | try ip.getOrPutString(gpa, "name"), |
| 19410 | const name_val = field_struct_val[0]; | 19922 | ).?); |
| 19411 | // type: type, | 19923 | const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 19412 | const type_val = field_struct_val[1]; | 19924 | try ip.getOrPutString(gpa, "type"), |
| 19413 | // default_value: ?*const anyopaque, | 19925 | ).?); |
| 19414 | const default_value_val = field_struct_val[2]; | 19926 | const default_value_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 19415 | // is_comptime: bool, | 19927 | try ip.getOrPutString(gpa, "default_value"), |
| 19416 | const is_comptime_val = field_struct_val[3]; | 19928 | ).?); |
| 19417 | // alignment: comptime_int, | 19929 | const is_comptime_val = try elem_val.fieldValue(mod, elem_fields.getIndex( |
| 19418 | const alignment_val = field_struct_val[4]; | 19930 | try ip.getOrPutString(gpa, "is_comptime"), |
| 19931 | ).?); | ||
| 19932 | const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex( | ||
| 19933 | try ip.getOrPutString(gpa, "alignment"), | ||
| 19934 | ).?); | ||
| 19419 | 19935 | ||
| 19420 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { | 19936 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { |
| 19421 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); | 19937 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); |
| 19422 | } | 19938 | } |
| 19423 | const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema)).?); | 19939 | const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?); |
| 19424 | 19940 | ||
| 19425 | if (layout == .Packed) { | 19941 | if (layout == .Packed) { |
| 19426 | if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{}); | 19942 | if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{}); |
| ... | @@ -19430,21 +19946,15 @@ fn reifyStruct( | ... | @@ -19430,21 +19946,15 @@ fn reifyStruct( |
| 19430 | return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}); | 19946 | return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}); |
| 19431 | } | 19947 | } |
| 19432 | 19948 | ||
| 19433 | const field_name = try name_val.toAllocatedBytes( | 19949 | const field_name = try name_val.toIpString(Type.slice_const_u8, mod); |
| 19434 | Type.initTag(.const_slice_u8), | ||
| 19435 | new_decl_arena_allocator, | ||
| 19436 | mod, | ||
| 19437 | ); | ||
| 19438 | 19950 | ||
| 19439 | if (is_tuple) { | 19951 | if (is_tuple) { |
| 19440 | const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch { | 19952 | const field_index = field_name.toUnsigned(ip) orelse return sema.fail( |
| 19441 | return sema.fail( | 19953 | block, |
| 19442 | block, | 19954 | src, |
| 19443 | src, | 19955 | "tuple cannot have non-numeric field '{}'", |
| 19444 | "tuple cannot have non-numeric field '{s}'", | 19956 | .{field_name.fmt(ip)}, |
| 19445 | .{field_name}, | 19957 | ); |
| 19446 | ); | ||
| 19447 | }; | ||
| 19448 | 19958 | ||
| 19449 | if (field_index >= fields_len) { | 19959 | if (field_index >= fields_len) { |
| 19450 | return sema.fail( | 19960 | return sema.fail( |
| ... | @@ -19458,22 +19968,19 @@ fn reifyStruct( | ... | @@ -19458,22 +19968,19 @@ fn reifyStruct( |
| 19458 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); | 19968 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); |
| 19459 | if (gop.found_existing) { | 19969 | if (gop.found_existing) { |
| 19460 | // TODO: better source location | 19970 | // TODO: better source location |
| 19461 | return sema.fail(block, src, "duplicate struct field {s}", .{field_name}); | 19971 | return sema.fail(block, src, "duplicate struct field {}", .{field_name.fmt(ip)}); |
| 19462 | } | 19972 | } |
| 19463 | 19973 | ||
| 19464 | const default_val = if (default_value_val.optionalValue()) |opt_val| blk: { | 19974 | const field_ty = type_val.toType(); |
| 19465 | const payload_val = if (opt_val.pointerDecl()) |opt_decl| | 19975 | const default_val = if (default_value_val.optionalValue(mod)) |opt_val| |
| 19466 | mod.declPtr(opt_decl).val | 19976 | (try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse |
| 19467 | else | 19977 | return sema.failWithNeededComptime(block, src, "struct field default value must be comptime-known")).toIntern() |
| 19468 | opt_val; | 19978 | else |
| 19469 | break :blk try payload_val.copy(new_decl_arena_allocator); | 19979 | .none; |
| 19470 | } else Value.initTag(.unreachable_value); | 19980 | if (is_comptime_val.toBool() and default_val == .none) { |
| 19471 | if (is_comptime_val.toBool() and default_val.tag() == .unreachable_value) { | ||
| 19472 | return sema.fail(block, src, "comptime field without default initialization value", .{}); | 19981 | return sema.fail(block, src, "comptime field without default initialization value", .{}); |
| 19473 | } | 19982 | } |
| 19474 | 19983 | ||
| 19475 | var buffer: Value.ToTypeBuffer = undefined; | ||
| 19476 | const field_ty = try type_val.toType(&buffer).copy(new_decl_arena_allocator); | ||
| 19477 | gop.value_ptr.* = .{ | 19984 | gop.value_ptr.* = .{ |
| 19478 | .ty = field_ty, | 19985 | .ty = field_ty, |
| 19479 | .abi_align = abi_align, | 19986 | .abi_align = abi_align, |
| ... | @@ -19482,20 +19989,20 @@ fn reifyStruct( | ... | @@ -19482,20 +19989,20 @@ fn reifyStruct( |
| 19482 | .offset = undefined, | 19989 | .offset = undefined, |
| 19483 | }; | 19990 | }; |
| 19484 | 19991 | ||
| 19485 | if (field_ty.zigTypeTag() == .Opaque) { | 19992 | if (field_ty.zigTypeTag(mod) == .Opaque) { |
| 19486 | const msg = msg: { | 19993 | const msg = msg: { |
| 19487 | const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); | 19994 | const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); |
| 19488 | errdefer msg.destroy(sema.gpa); | 19995 | errdefer msg.destroy(gpa); |
| 19489 | 19996 | ||
| 19490 | try sema.addDeclaredHereNote(msg, field_ty); | 19997 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19491 | break :msg msg; | 19998 | break :msg msg; |
| 19492 | }; | 19999 | }; |
| 19493 | return sema.failWithOwnedErrorMsg(msg); | 20000 | return sema.failWithOwnedErrorMsg(msg); |
| 19494 | } | 20001 | } |
| 19495 | if (field_ty.zigTypeTag() == .NoReturn) { | 20002 | if (field_ty.zigTypeTag(mod) == .NoReturn) { |
| 19496 | const msg = msg: { | 20003 | const msg = msg: { |
| 19497 | const msg = try sema.errMsg(block, src, "struct fields cannot be 'noreturn'", .{}); | 20004 | const msg = try sema.errMsg(block, src, "struct fields cannot be 'noreturn'", .{}); |
| 19498 | errdefer msg.destroy(sema.gpa); | 20005 | errdefer msg.destroy(gpa); |
| 19499 | 20006 | ||
| 19500 | try sema.addDeclaredHereNote(msg, field_ty); | 20007 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19501 | break :msg msg; | 20008 | break :msg msg; |
| ... | @@ -19505,22 +20012,22 @@ fn reifyStruct( | ... | @@ -19505,22 +20012,22 @@ fn reifyStruct( |
| 19505 | if (struct_obj.layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) { | 20012 | if (struct_obj.layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) { |
| 19506 | const msg = msg: { | 20013 | const msg = msg: { |
| 19507 | const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | 20014 | const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); |
| 19508 | errdefer msg.destroy(sema.gpa); | 20015 | errdefer msg.destroy(gpa); |
| 19509 | 20016 | ||
| 19510 | const src_decl = sema.mod.declPtr(block.src_decl); | 20017 | const src_decl = sema.mod.declPtr(block.src_decl); |
| 19511 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), field_ty, .struct_field); | 20018 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .struct_field); |
| 19512 | 20019 | ||
| 19513 | try sema.addDeclaredHereNote(msg, field_ty); | 20020 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19514 | break :msg msg; | 20021 | break :msg msg; |
| 19515 | }; | 20022 | }; |
| 19516 | return sema.failWithOwnedErrorMsg(msg); | 20023 | return sema.failWithOwnedErrorMsg(msg); |
| 19517 | } else if (struct_obj.layout == .Packed and !(validatePackedType(field_ty))) { | 20024 | } else if (struct_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) { |
| 19518 | const msg = msg: { | 20025 | const msg = msg: { |
| 19519 | const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | 20026 | const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); |
| 19520 | errdefer msg.destroy(sema.gpa); | 20027 | errdefer msg.destroy(gpa); |
| 19521 | 20028 | ||
| 19522 | const src_decl = sema.mod.declPtr(block.src_decl); | 20029 | const src_decl = sema.mod.declPtr(block.src_decl); |
| 19523 | try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl), field_ty); | 20030 | try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty); |
| 19524 | 20031 | ||
| 19525 | try sema.addDeclaredHereNote(msg, field_ty); | 20032 | try sema.addDeclaredHereNote(msg, field_ty); |
| 19526 | break :msg msg; | 20033 | break :msg msg; |
| ... | @@ -19536,7 +20043,7 @@ fn reifyStruct( | ... | @@ -19536,7 +20043,7 @@ fn reifyStruct( |
| 19536 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { | 20043 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { |
| 19537 | error.AnalysisFail => { | 20044 | error.AnalysisFail => { |
| 19538 | const msg = sema.err orelse return err; | 20045 | const msg = sema.err orelse return err; |
| 19539 | try sema.addFieldErrNote(struct_ty, index, msg, "while checking this field", .{}); | 20046 | try sema.addFieldErrNote(struct_ty.toType(), index, msg, "while checking this field", .{}); |
| 19540 | return err; | 20047 | return err; |
| 19541 | }, | 20048 | }, |
| 19542 | else => return err, | 20049 | else => return err, |
| ... | @@ -19545,30 +20052,27 @@ fn reifyStruct( | ... | @@ -19545,30 +20052,27 @@ fn reifyStruct( |
| 19545 | 20052 | ||
| 19546 | var fields_bit_sum: u64 = 0; | 20053 | var fields_bit_sum: u64 = 0; |
| 19547 | for (struct_obj.fields.values()) |field| { | 20054 | for (struct_obj.fields.values()) |field| { |
| 19548 | fields_bit_sum += field.ty.bitSize(target); | 20055 | fields_bit_sum += field.ty.bitSize(mod); |
| 19549 | } | 20056 | } |
| 19550 | 20057 | ||
| 19551 | if (backing_int_val.optionalValue()) |payload| { | 20058 | if (backing_int_val.optionalValue(mod)) |payload| { |
| 19552 | var buf: Value.ToTypeBuffer = undefined; | 20059 | const backing_int_ty = payload.toType(); |
| 19553 | const backing_int_ty = payload.toType(&buf); | ||
| 19554 | try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum); | 20060 | try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum); |
| 19555 | struct_obj.backing_int_ty = try backing_int_ty.copy(new_decl_arena_allocator); | 20061 | struct_obj.backing_int_ty = backing_int_ty; |
| 19556 | } else { | 20062 | } else { |
| 19557 | var buf: Type.Payload.Bits = .{ | 20063 | struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum)); |
| 19558 | .base = .{ .tag = .int_unsigned }, | ||
| 19559 | .data = @intCast(u16, fields_bit_sum), | ||
| 19560 | }; | ||
| 19561 | struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(new_decl_arena_allocator); | ||
| 19562 | } | 20064 | } |
| 19563 | 20065 | ||
| 19564 | struct_obj.status = .have_layout; | 20066 | struct_obj.status = .have_layout; |
| 19565 | } | 20067 | } |
| 19566 | 20068 | ||
| 19567 | try new_decl.finalizeNewArena(&new_decl_arena); | 20069 | const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); |
| 19568 | return sema.analyzeDeclVal(block, src, new_decl_index); | 20070 | try mod.finalizeAnonDecl(new_decl_index); |
| 20071 | return decl_val; | ||
| 19569 | } | 20072 | } |
| 19570 | 20073 | ||
| 19571 | fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 20074 | fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 20075 | const mod = sema.mod; | ||
| 19572 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | 20076 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 19573 | const src = LazySrcLoc.nodeOffset(extra.node); | 20077 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 19574 | const addrspace_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 20078 | const addrspace_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| ... | @@ -19580,7 +20084,7 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst | ... | @@ -19580,7 +20084,7 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 19580 | 20084 | ||
| 19581 | try sema.checkPtrOperand(block, ptr_src, ptr_ty); | 20085 | try sema.checkPtrOperand(block, ptr_src, ptr_ty); |
| 19582 | 20086 | ||
| 19583 | var ptr_info = ptr_ty.ptrInfo().data; | 20087 | var ptr_info = ptr_ty.ptrInfo(mod); |
| 19584 | const src_addrspace = ptr_info.@"addrspace"; | 20088 | const src_addrspace = ptr_info.@"addrspace"; |
| 19585 | if (!target_util.addrSpaceCastIsValid(sema.mod.getTarget(), src_addrspace, dest_addrspace)) { | 20089 | if (!target_util.addrSpaceCastIsValid(sema.mod.getTarget(), src_addrspace, dest_addrspace)) { |
| 19586 | const msg = msg: { | 20090 | const msg = msg: { |
| ... | @@ -19594,8 +20098,8 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst | ... | @@ -19594,8 +20098,8 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 19594 | 20098 | ||
| 19595 | ptr_info.@"addrspace" = dest_addrspace; | 20099 | ptr_info.@"addrspace" = dest_addrspace; |
| 19596 | const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); | 20100 | const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); |
| 19597 | const dest_ty = if (ptr_ty.zigTypeTag() == .Optional) | 20101 | const dest_ty = if (ptr_ty.zigTypeTag(mod) == .Optional) |
| 19598 | try Type.optional(sema.arena, dest_ptr_ty) | 20102 | try Type.optional(sema.arena, dest_ptr_ty, mod) |
| 19599 | else | 20103 | else |
| 19600 | dest_ptr_ty; | 20104 | dest_ptr_ty; |
| 19601 | 20105 | ||
| ... | @@ -19624,6 +20128,7 @@ fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.In | ... | @@ -19624,6 +20128,7 @@ fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.In |
| 19624 | } | 20128 | } |
| 19625 | 20129 | ||
| 19626 | fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 20130 | fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 20131 | const mod = sema.mod; | ||
| 19627 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | 20132 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 19628 | const src = LazySrcLoc.nodeOffset(extra.node); | 20133 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 19629 | const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 20134 | const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| ... | @@ -19638,7 +20143,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C | ... | @@ -19638,7 +20143,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C |
| 19638 | errdefer msg.destroy(sema.gpa); | 20143 | errdefer msg.destroy(sema.gpa); |
| 19639 | 20144 | ||
| 19640 | const src_decl = sema.mod.declPtr(block.src_decl); | 20145 | const src_decl = sema.mod.declPtr(block.src_decl); |
| 19641 | try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl), arg_ty, .param_ty); | 20146 | try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), arg_ty, .param_ty); |
| 19642 | 20147 | ||
| 19643 | try sema.addDeclaredHereNote(msg, arg_ty); | 20148 | try sema.addDeclaredHereNote(msg, arg_ty); |
| 19644 | break :msg msg; | 20149 | break :msg msg; |
| ... | @@ -19685,6 +20190,7 @@ fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) | ... | @@ -19685,6 +20190,7 @@ fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) |
| 19685 | } | 20190 | } |
| 19686 | 20191 | ||
| 19687 | fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 20192 | fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20193 | const mod = sema.mod; | ||
| 19688 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 20194 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 19689 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 20195 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 19690 | const ty = try sema.resolveType(block, ty_src, inst_data.operand); | 20196 | const ty = try sema.resolveType(block, ty_src, inst_data.operand); |
| ... | @@ -19692,11 +20198,19 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -19692,11 +20198,19 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 19692 | var anon_decl = try block.startAnonDecl(); | 20198 | var anon_decl = try block.startAnonDecl(); |
| 19693 | defer anon_decl.deinit(); | 20199 | defer anon_decl.deinit(); |
| 19694 | 20200 | ||
| 19695 | const bytes = try ty.nameAllocArena(anon_decl.arena(), sema.mod); | 20201 | const bytes = try ty.nameAllocArena(sema.arena, mod); |
| 19696 | 20202 | ||
| 20203 | const decl_ty = try mod.arrayType(.{ | ||
| 20204 | .len = bytes.len, | ||
| 20205 | .child = .u8_type, | ||
| 20206 | .sentinel = .zero_u8, | ||
| 20207 | }); | ||
| 19697 | const new_decl = try anon_decl.finish( | 20208 | const new_decl = try anon_decl.finish( |
| 19698 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | 20209 | decl_ty, |
| 19699 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | 20210 | (try mod.intern(.{ .aggregate = .{ |
| 20211 | .ty = decl_ty.toIntern(), | ||
| 20212 | .storage = .{ .bytes = bytes }, | ||
| 20213 | } })).toValue(), | ||
| 19700 | 0, // default alignment | 20214 | 0, // default alignment |
| 19701 | ); | 20215 | ); |
| 19702 | 20216 | ||
| ... | @@ -19716,6 +20230,7 @@ fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -19716,6 +20230,7 @@ fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 19716 | } | 20230 | } |
| 19717 | 20231 | ||
| 19718 | fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 20232 | fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20233 | const mod = sema.mod; | ||
| 19719 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 20234 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19720 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 20235 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 19721 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 20236 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| ... | @@ -19730,24 +20245,24 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -19730,24 +20245,24 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 19730 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 20245 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 19731 | const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty); | 20246 | const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty); |
| 19732 | return sema.addConstant(dest_ty, result_val); | 20247 | return sema.addConstant(dest_ty, result_val); |
| 19733 | } else if (dest_ty.zigTypeTag() == .ComptimeInt) { | 20248 | } else if (dest_ty.zigTypeTag(mod) == .ComptimeInt) { |
| 19734 | return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_int' must be comptime-known"); | 20249 | return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_int' must be comptime-known"); |
| 19735 | } | 20250 | } |
| 19736 | 20251 | ||
| 19737 | try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); | 20252 | try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); |
| 19738 | if (dest_ty.intInfo(sema.mod.getTarget()).bits == 0) { | 20253 | if (dest_ty.intInfo(mod).bits == 0) { |
| 19739 | if (block.wantSafety()) { | 20254 | if (block.wantSafety()) { |
| 19740 | const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, try sema.addConstant(operand_ty, Value.zero)); | 20255 | const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0))); |
| 19741 | try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds); | 20256 | try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds); |
| 19742 | } | 20257 | } |
| 19743 | return sema.addConstant(dest_ty, Value.zero); | 20258 | return sema.addConstant(dest_ty, try mod.intValue(dest_ty, 0)); |
| 19744 | } | 20259 | } |
| 19745 | const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand); | 20260 | const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand); |
| 19746 | if (block.wantSafety()) { | 20261 | if (block.wantSafety()) { |
| 19747 | const back = try block.addTyOp(.int_to_float, operand_ty, result); | 20262 | const back = try block.addTyOp(.int_to_float, operand_ty, result); |
| 19748 | const diff = try block.addBinOp(.sub, operand, back); | 20263 | const diff = try block.addBinOp(.sub, operand, back); |
| 19749 | const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(operand_ty, Value.one)); | 20264 | const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(operand_ty, try mod.floatValue(operand_ty, 1.0))); |
| 19750 | const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(operand_ty, Value.negative_one)); | 20265 | const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(operand_ty, try mod.floatValue(operand_ty, -1.0))); |
| 19751 | const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg); | 20266 | const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg); |
| 19752 | try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds); | 20267 | try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds); |
| 19753 | } | 20268 | } |
| ... | @@ -19755,6 +20270,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -19755,6 +20270,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 19755 | } | 20270 | } |
| 19756 | 20271 | ||
| 19757 | fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 20272 | fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20273 | const mod = sema.mod; | ||
| 19758 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 20274 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19759 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 20275 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 19760 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 20276 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| ... | @@ -19769,7 +20285,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -19769,7 +20285,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 19769 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 20285 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 19770 | const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, sema.mod, sema); | 20286 | const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, sema.mod, sema); |
| 19771 | return sema.addConstant(dest_ty, result_val); | 20287 | return sema.addConstant(dest_ty, result_val); |
| 19772 | } else if (dest_ty.zigTypeTag() == .ComptimeFloat) { | 20288 | } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) { |
| 19773 | return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime-known"); | 20289 | return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime-known"); |
| 19774 | } | 20290 | } |
| 19775 | 20291 | ||
| ... | @@ -19778,6 +20294,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -19778,6 +20294,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 19778 | } | 20294 | } |
| 19779 | 20295 | ||
| 19780 | fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 20296 | fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20297 | const mod = sema.mod; | ||
| 19781 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 20298 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19782 | const src = inst_data.src(); | 20299 | const src = inst_data.src(); |
| 19783 | 20300 | ||
| ... | @@ -19790,11 +20307,10 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -19790,11 +20307,10 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 19790 | const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 20307 | const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 19791 | const ptr_ty = try sema.resolveType(block, src, extra.lhs); | 20308 | const ptr_ty = try sema.resolveType(block, src, extra.lhs); |
| 19792 | try sema.checkPtrType(block, type_src, ptr_ty); | 20309 | try sema.checkPtrType(block, type_src, ptr_ty); |
| 19793 | const elem_ty = ptr_ty.elemType2(); | 20310 | const elem_ty = ptr_ty.elemType2(mod); |
| 19794 | const target = sema.mod.getTarget(); | 20311 | const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema); |
| 19795 | const ptr_align = try ptr_ty.ptrAlignmentAdvanced(target, sema); | ||
| 19796 | 20312 | ||
| 19797 | if (ptr_ty.isSlice()) { | 20313 | if (ptr_ty.isSlice(mod)) { |
| 19798 | const msg = msg: { | 20314 | const msg = msg: { |
| 19799 | const msg = try sema.errMsg(block, type_src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(sema.mod)}); | 20315 | const msg = try sema.errMsg(block, type_src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(sema.mod)}); |
| 19800 | errdefer msg.destroy(sema.gpa); | 20316 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -19805,36 +20321,26 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -19805,36 +20321,26 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 19805 | } | 20321 | } |
| 19806 | 20322 | ||
| 19807 | if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| { | 20323 | if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| { |
| 19808 | const addr = val.toUnsignedInt(target); | 20324 | const addr = val.toUnsignedInt(mod); |
| 19809 | if (!ptr_ty.isAllowzeroPtr() and addr == 0) | 20325 | if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0) |
| 19810 | return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)}); | 20326 | return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)}); |
| 19811 | if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0) | 20327 | if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0) |
| 19812 | return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)}); | 20328 | return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)}); |
| 19813 | 20329 | ||
| 19814 | const val_payload = try sema.arena.create(Value.Payload.U64); | 20330 | return sema.addConstant(ptr_ty, try mod.ptrIntValue(ptr_ty, addr)); |
| 19815 | val_payload.* = .{ | ||
| 19816 | .base = .{ .tag = .int_u64 }, | ||
| 19817 | .data = addr, | ||
| 19818 | }; | ||
| 19819 | return sema.addConstant(ptr_ty, Value.initPayload(&val_payload.base)); | ||
| 19820 | } | 20331 | } |
| 19821 | 20332 | ||
| 19822 | try sema.requireRuntimeBlock(block, src, operand_src); | 20333 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 19823 | if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag() == .Fn)) { | 20334 | if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag(mod) == .Fn)) { |
| 19824 | if (!ptr_ty.isAllowzeroPtr()) { | 20335 | if (!ptr_ty.isAllowzeroPtr(mod)) { |
| 19825 | const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize); | 20336 | const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize); |
| 19826 | try sema.addSafetyCheck(block, is_non_zero, .cast_to_null); | 20337 | try sema.addSafetyCheck(block, is_non_zero, .cast_to_null); |
| 19827 | } | 20338 | } |
| 19828 | 20339 | ||
| 19829 | if (ptr_align > 1) { | 20340 | if (ptr_align > 1) { |
| 19830 | const val_payload = try sema.arena.create(Value.Payload.U64); | ||
| 19831 | val_payload.* = .{ | ||
| 19832 | .base = .{ .tag = .int_u64 }, | ||
| 19833 | .data = ptr_align - 1, | ||
| 19834 | }; | ||
| 19835 | const align_minus_1 = try sema.addConstant( | 20341 | const align_minus_1 = try sema.addConstant( |
| 19836 | Type.usize, | 20342 | Type.usize, |
| 19837 | Value.initPayload(&val_payload.base), | 20343 | try mod.intValue(Type.usize, ptr_align - 1), |
| 19838 | ); | 20344 | ); |
| 19839 | const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1); | 20345 | const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1); |
| 19840 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); | 20346 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); |
| ... | @@ -19845,6 +20351,8 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -19845,6 +20351,8 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 19845 | } | 20351 | } |
| 19846 | 20352 | ||
| 19847 | fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 20353 | fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 20354 | const mod = sema.mod; | ||
| 20355 | const ip = &mod.intern_pool; | ||
| 19848 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | 20356 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 19849 | const src = LazySrcLoc.nodeOffset(extra.node); | 20357 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 19850 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 20358 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| ... | @@ -19860,22 +20368,27 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -19860,22 +20368,27 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 19860 | 20368 | ||
| 19861 | if (disjoint: { | 20369 | if (disjoint: { |
| 19862 | // Try avoiding resolving inferred error sets if we can | 20370 | // Try avoiding resolving inferred error sets if we can |
| 19863 | if (!dest_ty.isAnyError() and dest_ty.errorSetNames().len == 0) break :disjoint true; | 20371 | if (!dest_ty.isAnyError(mod) and dest_ty.errorSetNames(mod).len == 0) break :disjoint true; |
| 19864 | if (!operand_ty.isAnyError() and operand_ty.errorSetNames().len == 0) break :disjoint true; | 20372 | if (!operand_ty.isAnyError(mod) and operand_ty.errorSetNames(mod).len == 0) break :disjoint true; |
| 19865 | if (dest_ty.isAnyError()) break :disjoint false; | 20373 | if (dest_ty.isAnyError(mod)) break :disjoint false; |
| 19866 | if (operand_ty.isAnyError()) break :disjoint false; | 20374 | if (operand_ty.isAnyError(mod)) break :disjoint false; |
| 19867 | for (dest_ty.errorSetNames()) |dest_err_name| | 20375 | for (dest_ty.errorSetNames(mod)) |dest_err_name| { |
| 19868 | if (operand_ty.errorSetHasField(dest_err_name)) | 20376 | if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name)) |
| 19869 | break :disjoint false; | 20377 | break :disjoint false; |
| 20378 | } | ||
| 19870 | 20379 | ||
| 19871 | if (dest_ty.tag() != .error_set_inferred and operand_ty.tag() != .error_set_inferred) | 20380 | if (!ip.isInferredErrorSetType(dest_ty.toIntern()) and |
| 20381 | !ip.isInferredErrorSetType(operand_ty.toIntern())) | ||
| 20382 | { | ||
| 19872 | break :disjoint true; | 20383 | break :disjoint true; |
| 20384 | } | ||
| 19873 | 20385 | ||
| 19874 | try sema.resolveInferredErrorSetTy(block, dest_ty_src, dest_ty); | 20386 | try sema.resolveInferredErrorSetTy(block, dest_ty_src, dest_ty); |
| 19875 | try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty); | 20387 | try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty); |
| 19876 | for (dest_ty.errorSetNames()) |dest_err_name| | 20388 | for (dest_ty.errorSetNames(mod)) |dest_err_name| { |
| 19877 | if (operand_ty.errorSetHasField(dest_err_name)) | 20389 | if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name)) |
| 19878 | break :disjoint false; | 20390 | break :disjoint false; |
| 20391 | } | ||
| 19879 | 20392 | ||
| 19880 | break :disjoint true; | 20393 | break :disjoint true; |
| 19881 | }) { | 20394 | }) { |
| ... | @@ -19895,15 +20408,15 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -19895,15 +20408,15 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 19895 | } | 20408 | } |
| 19896 | 20409 | ||
| 19897 | if (maybe_operand_val) |val| { | 20410 | if (maybe_operand_val) |val| { |
| 19898 | if (!dest_ty.isAnyError()) { | 20411 | if (!dest_ty.isAnyError(mod)) { |
| 19899 | const error_name = val.castTag(.@"error").?.data.name; | 20412 | const error_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; |
| 19900 | if (!dest_ty.errorSetHasField(error_name)) { | 20413 | if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), error_name)) { |
| 19901 | const msg = msg: { | 20414 | const msg = msg: { |
| 19902 | const msg = try sema.errMsg( | 20415 | const msg = try sema.errMsg( |
| 19903 | block, | 20416 | block, |
| 19904 | src, | 20417 | src, |
| 19905 | "'error.{s}' not a member of error set '{}'", | 20418 | "'error.{}' not a member of error set '{}'", |
| 19906 | .{ error_name, dest_ty.fmt(sema.mod) }, | 20419 | .{ error_name.fmt(ip), dest_ty.fmt(sema.mod) }, |
| 19907 | ); | 20420 | ); |
| 19908 | errdefer msg.destroy(sema.gpa); | 20421 | errdefer msg.destroy(sema.gpa); |
| 19909 | try sema.addDeclaredHereNote(msg, dest_ty); | 20422 | try sema.addDeclaredHereNote(msg, dest_ty); |
| ... | @@ -19913,11 +20426,11 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -19913,11 +20426,11 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 19913 | } | 20426 | } |
| 19914 | } | 20427 | } |
| 19915 | 20428 | ||
| 19916 | return sema.addConstant(dest_ty, val); | 20429 | return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty)); |
| 19917 | } | 20430 | } |
| 19918 | 20431 | ||
| 19919 | try sema.requireRuntimeBlock(block, src, operand_src); | 20432 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 19920 | if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.backendSupportsFeature(.error_set_has_value)) { | 20433 | if (block.wantSafety() and !dest_ty.isAnyError(mod) and sema.mod.backendSupportsFeature(.error_set_has_value)) { |
| 19921 | const err_int_inst = try block.addBitCast(Type.err_int, operand); | 20434 | const err_int_inst = try block.addBitCast(Type.err_int, operand); |
| 19922 | const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst); | 20435 | const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst); |
| 19923 | try sema.addSafetyCheck(block, ok, .invalid_error_code); | 20436 | try sema.addSafetyCheck(block, ok, .invalid_error_code); |
| ... | @@ -19926,6 +20439,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -19926,6 +20439,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 19926 | } | 20439 | } |
| 19927 | 20440 | ||
| 19928 | fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 20441 | fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20442 | const mod = sema.mod; | ||
| 19929 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 20443 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19930 | const src = inst_data.src(); | 20444 | const src = inst_data.src(); |
| 19931 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 20445 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| ... | @@ -19934,13 +20448,12 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -19934,13 +20448,12 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19934 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); | 20448 | const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs); |
| 19935 | const operand = try sema.resolveInst(extra.rhs); | 20449 | const operand = try sema.resolveInst(extra.rhs); |
| 19936 | const operand_ty = sema.typeOf(operand); | 20450 | const operand_ty = sema.typeOf(operand); |
| 19937 | const target = sema.mod.getTarget(); | ||
| 19938 | 20451 | ||
| 19939 | try sema.checkPtrType(block, dest_ty_src, dest_ty); | 20452 | try sema.checkPtrType(block, dest_ty_src, dest_ty); |
| 19940 | try sema.checkPtrOperand(block, operand_src, operand_ty); | 20453 | try sema.checkPtrOperand(block, operand_src, operand_ty); |
| 19941 | 20454 | ||
| 19942 | const operand_info = operand_ty.ptrInfo().data; | 20455 | const operand_info = operand_ty.ptrInfo(mod); |
| 19943 | const dest_info = dest_ty.ptrInfo().data; | 20456 | const dest_info = dest_ty.ptrInfo(mod); |
| 19944 | if (!operand_info.mutable and dest_info.mutable) { | 20457 | if (!operand_info.mutable and dest_info.mutable) { |
| 19945 | const msg = msg: { | 20458 | const msg = msg: { |
| 19946 | const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{}); | 20459 | const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{}); |
| ... | @@ -19972,8 +20485,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -19972,8 +20485,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19972 | return sema.failWithOwnedErrorMsg(msg); | 20485 | return sema.failWithOwnedErrorMsg(msg); |
| 19973 | } | 20486 | } |
| 19974 | 20487 | ||
| 19975 | const dest_is_slice = dest_ty.isSlice(); | 20488 | const dest_is_slice = dest_ty.isSlice(mod); |
| 19976 | const operand_is_slice = operand_ty.isSlice(); | 20489 | const operand_is_slice = operand_ty.isSlice(mod); |
| 19977 | if (dest_is_slice and !operand_is_slice) { | 20490 | if (dest_is_slice and !operand_is_slice) { |
| 19978 | return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{}); | 20491 | return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{}); |
| 19979 | } | 20492 | } |
| ... | @@ -19982,32 +20495,31 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -19982,32 +20495,31 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19982 | else | 20495 | else |
| 19983 | operand; | 20496 | operand; |
| 19984 | 20497 | ||
| 19985 | const dest_elem_ty = dest_ty.elemType2(); | 20498 | const dest_elem_ty = dest_ty.elemType2(mod); |
| 19986 | try sema.resolveTypeLayout(dest_elem_ty); | 20499 | try sema.resolveTypeLayout(dest_elem_ty); |
| 19987 | const dest_align = dest_ty.ptrAlignment(target); | 20500 | const dest_align = dest_ty.ptrAlignment(mod); |
| 19988 | 20501 | ||
| 19989 | const operand_elem_ty = operand_ty.elemType2(); | 20502 | const operand_elem_ty = operand_ty.elemType2(mod); |
| 19990 | try sema.resolveTypeLayout(operand_elem_ty); | 20503 | try sema.resolveTypeLayout(operand_elem_ty); |
| 19991 | const operand_align = operand_ty.ptrAlignment(target); | 20504 | const operand_align = operand_ty.ptrAlignment(mod); |
| 19992 | 20505 | ||
| 19993 | // If the destination is less aligned than the source, preserve the source alignment | 20506 | // If the destination is less aligned than the source, preserve the source alignment |
| 19994 | const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: { | 20507 | const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: { |
| 19995 | // Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result | 20508 | // Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result |
| 19996 | if (dest_ty.zigTypeTag() == .Optional) { | 20509 | if (dest_ty.zigTypeTag(mod) == .Optional) { |
| 19997 | var buf: Type.Payload.ElemType = undefined; | 20510 | var dest_ptr_info = dest_ty.optionalChild(mod).ptrInfo(mod); |
| 19998 | var dest_ptr_info = dest_ty.optionalChild(&buf).ptrInfo().data; | ||
| 19999 | dest_ptr_info.@"align" = operand_align; | 20511 | dest_ptr_info.@"align" = operand_align; |
| 20000 | break :blk try Type.optional(sema.arena, try Type.ptr(sema.arena, sema.mod, dest_ptr_info)); | 20512 | break :blk try Type.optional(sema.arena, try Type.ptr(sema.arena, mod, dest_ptr_info), mod); |
| 20001 | } else { | 20513 | } else { |
| 20002 | var dest_ptr_info = dest_ty.ptrInfo().data; | 20514 | var dest_ptr_info = dest_ty.ptrInfo(mod); |
| 20003 | dest_ptr_info.@"align" = operand_align; | 20515 | dest_ptr_info.@"align" = operand_align; |
| 20004 | break :blk try Type.ptr(sema.arena, sema.mod, dest_ptr_info); | 20516 | break :blk try Type.ptr(sema.arena, mod, dest_ptr_info); |
| 20005 | } | 20517 | } |
| 20006 | }; | 20518 | }; |
| 20007 | 20519 | ||
| 20008 | if (dest_is_slice) { | 20520 | if (dest_is_slice) { |
| 20009 | const operand_elem_size = operand_elem_ty.abiSize(target); | 20521 | const operand_elem_size = operand_elem_ty.abiSize(mod); |
| 20010 | const dest_elem_size = dest_elem_ty.abiSize(target); | 20522 | const dest_elem_size = dest_elem_ty.abiSize(mod); |
| 20011 | if (operand_elem_size != dest_elem_size) { | 20523 | if (operand_elem_size != dest_elem_size) { |
| 20012 | return sema.fail(block, dest_ty_src, "TODO: implement @ptrCast between slices changing the length", .{}); | 20524 | return sema.fail(block, dest_ty_src, "TODO: implement @ptrCast between slices changing the length", .{}); |
| 20013 | } | 20525 | } |
| ... | @@ -20019,10 +20531,10 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -20019,10 +20531,10 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 20019 | errdefer msg.destroy(sema.gpa); | 20531 | errdefer msg.destroy(sema.gpa); |
| 20020 | 20532 | ||
| 20021 | try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{ | 20533 | try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{ |
| 20022 | operand_ty.fmt(sema.mod), operand_align, | 20534 | operand_ty.fmt(mod), operand_align, |
| 20023 | }); | 20535 | }); |
| 20024 | try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{ | 20536 | try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{ |
| 20025 | dest_ty.fmt(sema.mod), dest_align, | 20537 | dest_ty.fmt(mod), dest_align, |
| 20026 | }); | 20538 | }); |
| 20027 | 20539 | ||
| 20028 | try sema.errNote(block, src, msg, "consider using '@alignCast'", .{}); | 20540 | try sema.errNote(block, src, msg, "consider using '@alignCast'", .{}); |
| ... | @@ -20032,21 +20544,18 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -20032,21 +20544,18 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 20032 | } | 20544 | } |
| 20033 | 20545 | ||
| 20034 | if (try sema.resolveMaybeUndefVal(ptr)) |operand_val| { | 20546 | if (try sema.resolveMaybeUndefVal(ptr)) |operand_val| { |
| 20035 | if (!dest_ty.ptrAllowsZero() and operand_val.isUndef()) { | 20547 | if (!dest_ty.ptrAllowsZero(mod) and operand_val.isUndef(mod)) { |
| 20036 | return sema.failWithUseOfUndef(block, operand_src); | 20548 | return sema.failWithUseOfUndef(block, operand_src); |
| 20037 | } | 20549 | } |
| 20038 | if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) { | 20550 | if (!dest_ty.ptrAllowsZero(mod) and operand_val.isNull(mod)) { |
| 20039 | return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)}); | 20551 | return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)}); |
| 20040 | } | ||
| 20041 | if (dest_ty.zigTypeTag() == .Optional and sema.typeOf(ptr).zigTypeTag() != .Optional) { | ||
| 20042 | return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, operand_val)); | ||
| 20043 | } | 20552 | } |
| 20044 | return sema.addConstant(aligned_dest_ty, operand_val); | 20553 | return sema.addConstant(aligned_dest_ty, try mod.getCoerced(operand_val, aligned_dest_ty)); |
| 20045 | } | 20554 | } |
| 20046 | 20555 | ||
| 20047 | try sema.requireRuntimeBlock(block, src, null); | 20556 | try sema.requireRuntimeBlock(block, src, null); |
| 20048 | if (block.wantSafety() and operand_ty.ptrAllowsZero() and !dest_ty.ptrAllowsZero() and | 20557 | if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and |
| 20049 | (try sema.typeHasRuntimeBits(dest_ty.elemType2()) or dest_ty.elemType2().zigTypeTag() == .Fn)) | 20558 | (try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn)) |
| 20050 | { | 20559 | { |
| 20051 | const ptr_int = try block.addUnOp(.ptrtoint, ptr); | 20560 | const ptr_int = try block.addUnOp(.ptrtoint, ptr); |
| 20052 | const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize); | 20561 | const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize); |
| ... | @@ -20062,6 +20571,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -20062,6 +20571,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 20062 | } | 20571 | } |
| 20063 | 20572 | ||
| 20064 | fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 20573 | fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 20574 | const mod = sema.mod; | ||
| 20065 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | 20575 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 20066 | const src = LazySrcLoc.nodeOffset(extra.node); | 20576 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 20067 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 20577 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| ... | @@ -20069,12 +20579,12 @@ fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData | ... | @@ -20069,12 +20579,12 @@ fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData |
| 20069 | const operand_ty = sema.typeOf(operand); | 20579 | const operand_ty = sema.typeOf(operand); |
| 20070 | try sema.checkPtrOperand(block, operand_src, operand_ty); | 20580 | try sema.checkPtrOperand(block, operand_src, operand_ty); |
| 20071 | 20581 | ||
| 20072 | var ptr_info = operand_ty.ptrInfo().data; | 20582 | var ptr_info = operand_ty.ptrInfo(mod); |
| 20073 | ptr_info.mutable = true; | 20583 | ptr_info.mutable = true; |
| 20074 | const dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); | 20584 | const dest_ty = try Type.ptr(sema.arena, mod, ptr_info); |
| 20075 | 20585 | ||
| 20076 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { | 20586 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { |
| 20077 | return sema.addConstant(dest_ty, operand_val); | 20587 | return sema.addConstant(dest_ty, try mod.getCoerced(operand_val, dest_ty)); |
| 20078 | } | 20588 | } |
| 20079 | 20589 | ||
| 20080 | try sema.requireRuntimeBlock(block, src, null); | 20590 | try sema.requireRuntimeBlock(block, src, null); |
| ... | @@ -20082,6 +20592,7 @@ fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData | ... | @@ -20082,6 +20592,7 @@ fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData |
| 20082 | } | 20592 | } |
| 20083 | 20593 | ||
| 20084 | fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 20594 | fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 20595 | const mod = sema.mod; | ||
| 20085 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; | 20596 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 20086 | const src = LazySrcLoc.nodeOffset(extra.node); | 20597 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 20087 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 20598 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| ... | @@ -20089,9 +20600,9 @@ fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD | ... | @@ -20089,9 +20600,9 @@ fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 20089 | const operand_ty = sema.typeOf(operand); | 20600 | const operand_ty = sema.typeOf(operand); |
| 20090 | try sema.checkPtrOperand(block, operand_src, operand_ty); | 20601 | try sema.checkPtrOperand(block, operand_src, operand_ty); |
| 20091 | 20602 | ||
| 20092 | var ptr_info = operand_ty.ptrInfo().data; | 20603 | var ptr_info = operand_ty.ptrInfo(mod); |
| 20093 | ptr_info.@"volatile" = false; | 20604 | ptr_info.@"volatile" = false; |
| 20094 | const dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); | 20605 | const dest_ty = try Type.ptr(sema.arena, mod, ptr_info); |
| 20095 | 20606 | ||
| 20096 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { | 20607 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { |
| 20097 | return sema.addConstant(dest_ty, operand_val); | 20608 | return sema.addConstant(dest_ty, operand_val); |
| ... | @@ -20102,6 +20613,7 @@ fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD | ... | @@ -20102,6 +20613,7 @@ fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 20102 | } | 20613 | } |
| 20103 | 20614 | ||
| 20104 | fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 20615 | fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20616 | const mod = sema.mod; | ||
| 20105 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 20617 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 20106 | const src = inst_data.src(); | 20618 | const src = inst_data.src(); |
| 20107 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 20619 | const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| ... | @@ -20112,9 +20624,12 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -20112,9 +20624,12 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 20112 | const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty); | 20624 | const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty); |
| 20113 | const operand_ty = sema.typeOf(operand); | 20625 | const operand_ty = sema.typeOf(operand); |
| 20114 | const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); | 20626 | const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src); |
| 20115 | const is_vector = operand_ty.zigTypeTag() == .Vector; | 20627 | const is_vector = operand_ty.zigTypeTag(mod) == .Vector; |
| 20116 | const dest_ty = if (is_vector) | 20628 | const dest_ty = if (is_vector) |
| 20117 | try Type.vector(sema.arena, operand_ty.vectorLen(), dest_scalar_ty) | 20629 | try mod.vectorType(.{ |
| 20630 | .len = operand_ty.vectorLen(mod), | ||
| 20631 | .child = dest_scalar_ty.toIntern(), | ||
| 20632 | }) | ||
| 20118 | else | 20633 | else |
| 20119 | dest_scalar_ty; | 20634 | dest_scalar_ty; |
| 20120 | 20635 | ||
| ... | @@ -20122,22 +20637,21 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -20122,22 +20637,21 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 20122 | return sema.coerce(block, dest_ty, operand, operand_src); | 20637 | return sema.coerce(block, dest_ty, operand, operand_src); |
| 20123 | } | 20638 | } |
| 20124 | 20639 | ||
| 20125 | const target = sema.mod.getTarget(); | 20640 | const dest_info = dest_scalar_ty.intInfo(mod); |
| 20126 | const dest_info = dest_scalar_ty.intInfo(target); | ||
| 20127 | 20641 | ||
| 20128 | if (try sema.typeHasOnePossibleValue(dest_ty)) |val| { | 20642 | if (try sema.typeHasOnePossibleValue(dest_ty)) |val| { |
| 20129 | return sema.addConstant(dest_ty, val); | 20643 | return sema.addConstant(dest_ty, val); |
| 20130 | } | 20644 | } |
| 20131 | 20645 | ||
| 20132 | if (operand_scalar_ty.zigTypeTag() != .ComptimeInt) { | 20646 | if (operand_scalar_ty.zigTypeTag(mod) != .ComptimeInt) { |
| 20133 | const operand_info = operand_ty.intInfo(target); | 20647 | const operand_info = operand_ty.intInfo(mod); |
| 20134 | if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { | 20648 | if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { |
| 20135 | return sema.addConstant(operand_ty, val); | 20649 | return sema.addConstant(operand_ty, val); |
| 20136 | } | 20650 | } |
| 20137 | 20651 | ||
| 20138 | if (operand_info.signedness != dest_info.signedness) { | 20652 | if (operand_info.signedness != dest_info.signedness) { |
| 20139 | return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{ | 20653 | return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{ |
| 20140 | @tagName(dest_info.signedness), operand_ty.fmt(sema.mod), | 20654 | @tagName(dest_info.signedness), operand_ty.fmt(mod), |
| 20141 | }); | 20655 | }); |
| 20142 | } | 20656 | } |
| 20143 | if (operand_info.bits < dest_info.bits) { | 20657 | if (operand_info.bits < dest_info.bits) { |
| ... | @@ -20146,7 +20660,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -20146,7 +20660,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 20146 | block, | 20660 | block, |
| 20147 | src, | 20661 | src, |
| 20148 | "destination type '{}' has more bits than source type '{}'", | 20662 | "destination type '{}' has more bits than source type '{}'", |
| 20149 | .{ dest_ty.fmt(sema.mod), operand_ty.fmt(sema.mod) }, | 20663 | .{ dest_ty.fmt(mod), operand_ty.fmt(mod) }, |
| 20150 | ); | 20664 | ); |
| 20151 | errdefer msg.destroy(sema.gpa); | 20665 | errdefer msg.destroy(sema.gpa); |
| 20152 | try sema.errNote(block, dest_ty_src, msg, "destination type has {d} bits", .{ | 20666 | try sema.errNote(block, dest_ty_src, msg, "destination type has {d} bits", .{ |
| ... | @@ -20162,23 +20676,22 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -20162,23 +20676,22 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 20162 | } | 20676 | } |
| 20163 | 20677 | ||
| 20164 | if (try sema.resolveMaybeUndefValIntable(operand)) |val| { | 20678 | if (try sema.resolveMaybeUndefValIntable(operand)) |val| { |
| 20165 | if (val.isUndef()) return sema.addConstUndef(dest_ty); | 20679 | if (val.isUndef(mod)) return sema.addConstUndef(dest_ty); |
| 20166 | if (!is_vector) { | 20680 | if (!is_vector) { |
| 20167 | return sema.addConstant( | 20681 | return sema.addConstant(dest_ty, try mod.getCoerced( |
| 20682 | try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, mod), | ||
| 20168 | dest_ty, | 20683 | dest_ty, |
| 20169 | try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, sema.mod), | 20684 | )); |
| 20170 | ); | ||
| 20171 | } | 20685 | } |
| 20172 | var elem_buf: Value.ElemValueBuffer = undefined; | 20686 | const elems = try sema.arena.alloc(InternPool.Index, operand_ty.vectorLen(mod)); |
| 20173 | const elems = try sema.arena.alloc(Value, operand_ty.vectorLen()); | ||
| 20174 | for (elems, 0..) |*elem, i| { | 20687 | for (elems, 0..) |*elem, i| { |
| 20175 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); | 20688 | const elem_val = try val.elemValue(mod, i); |
| 20176 | elem.* = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, sema.mod); | 20689 | elem.* = try (try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, mod)).intern(dest_scalar_ty, mod); |
| 20177 | } | 20690 | } |
| 20178 | return sema.addConstant( | 20691 | return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{ |
| 20179 | dest_ty, | 20692 | .ty = dest_ty.toIntern(), |
| 20180 | try Value.Tag.aggregate.create(sema.arena, elems), | 20693 | .storage = .{ .elems = elems }, |
| 20181 | ); | 20694 | } })).toValue()); |
| 20182 | } | 20695 | } |
| 20183 | 20696 | ||
| 20184 | try sema.requireRuntimeBlock(block, src, operand_src); | 20697 | try sema.requireRuntimeBlock(block, src, operand_src); |
| ... | @@ -20186,6 +20699,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -20186,6 +20699,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 20186 | } | 20699 | } |
| 20187 | 20700 | ||
| 20188 | fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 20701 | fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20702 | const mod = sema.mod; | ||
| 20189 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 20703 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 20190 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 20704 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 20191 | const align_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 20705 | const align_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| ... | @@ -20196,43 +20710,38 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -20196,43 +20710,38 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 20196 | 20710 | ||
| 20197 | try sema.checkPtrOperand(block, ptr_src, ptr_ty); | 20711 | try sema.checkPtrOperand(block, ptr_src, ptr_ty); |
| 20198 | 20712 | ||
| 20199 | var ptr_info = ptr_ty.ptrInfo().data; | 20713 | var ptr_info = ptr_ty.ptrInfo(mod); |
| 20200 | ptr_info.@"align" = dest_align; | 20714 | ptr_info.@"align" = dest_align; |
| 20201 | var dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info); | 20715 | var dest_ty = try Type.ptr(sema.arena, mod, ptr_info); |
| 20202 | if (ptr_ty.zigTypeTag() == .Optional) { | 20716 | if (ptr_ty.zigTypeTag(mod) == .Optional) { |
| 20203 | dest_ty = try Type.Tag.optional.create(sema.arena, dest_ty); | 20717 | dest_ty = try mod.optionalType(dest_ty.toIntern()); |
| 20204 | } | 20718 | } |
| 20205 | 20719 | ||
| 20206 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| { | 20720 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| { |
| 20207 | if (try val.getUnsignedIntAdvanced(sema.mod.getTarget(), null)) |addr| { | 20721 | if (try val.getUnsignedIntAdvanced(mod, null)) |addr| { |
| 20208 | if (addr % dest_align != 0) { | 20722 | if (addr % dest_align != 0) { |
| 20209 | return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align }); | 20723 | return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align }); |
| 20210 | } | 20724 | } |
| 20211 | } | 20725 | } |
| 20212 | return sema.addConstant(dest_ty, val); | 20726 | return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty)); |
| 20213 | } | 20727 | } |
| 20214 | 20728 | ||
| 20215 | try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); | 20729 | try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src); |
| 20216 | if (block.wantSafety() and dest_align > 1 and | 20730 | if (block.wantSafety() and dest_align > 1 and |
| 20217 | try sema.typeHasRuntimeBits(ptr_info.pointee_type)) | 20731 | try sema.typeHasRuntimeBits(ptr_info.pointee_type)) |
| 20218 | { | 20732 | { |
| 20219 | const val_payload = try sema.arena.create(Value.Payload.U64); | ||
| 20220 | val_payload.* = .{ | ||
| 20221 | .base = .{ .tag = .int_u64 }, | ||
| 20222 | .data = dest_align - 1, | ||
| 20223 | }; | ||
| 20224 | const align_minus_1 = try sema.addConstant( | 20733 | const align_minus_1 = try sema.addConstant( |
| 20225 | Type.usize, | 20734 | Type.usize, |
| 20226 | Value.initPayload(&val_payload.base), | 20735 | try mod.intValue(Type.usize, dest_align - 1), |
| 20227 | ); | 20736 | ); |
| 20228 | const actual_ptr = if (ptr_ty.isSlice()) | 20737 | const actual_ptr = if (ptr_ty.isSlice(mod)) |
| 20229 | try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty) | 20738 | try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty) |
| 20230 | else | 20739 | else |
| 20231 | ptr; | 20740 | ptr; |
| 20232 | const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); | 20741 | const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); |
| 20233 | const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1); | 20742 | const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1); |
| 20234 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); | 20743 | const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize); |
| 20235 | const ok = if (ptr_ty.isSlice()) ok: { | 20744 | const ok = if (ptr_ty.isSlice(mod)) ok: { |
| 20236 | const len = try sema.analyzeSliceLen(block, ptr_src, ptr); | 20745 | const len = try sema.analyzeSliceLen(block, ptr_src, ptr); |
| 20237 | const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); | 20746 | const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); |
| 20238 | break :ok try block.addBinOp(.bit_or, len_zero, is_aligned); | 20747 | break :ok try block.addBinOp(.bit_or, len_zero, is_aligned); |
| ... | @@ -20247,51 +20756,52 @@ fn zirBitCount( | ... | @@ -20247,51 +20756,52 @@ fn zirBitCount( |
| 20247 | block: *Block, | 20756 | block: *Block, |
| 20248 | inst: Zir.Inst.Index, | 20757 | inst: Zir.Inst.Index, |
| 20249 | air_tag: Air.Inst.Tag, | 20758 | air_tag: Air.Inst.Tag, |
| 20250 | comptime comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64, | 20759 | comptime comptimeOp: fn (val: Value, ty: Type, mod: *Module) u64, |
| 20251 | ) CompileError!Air.Inst.Ref { | 20760 | ) CompileError!Air.Inst.Ref { |
| 20761 | const mod = sema.mod; | ||
| 20252 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 20762 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 20253 | const src = inst_data.src(); | 20763 | const src = inst_data.src(); |
| 20254 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 20764 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 20255 | const operand = try sema.resolveInst(inst_data.operand); | 20765 | const operand = try sema.resolveInst(inst_data.operand); |
| 20256 | const operand_ty = sema.typeOf(operand); | 20766 | const operand_ty = sema.typeOf(operand); |
| 20257 | _ = try sema.checkIntOrVector(block, operand, operand_src); | 20767 | _ = try sema.checkIntOrVector(block, operand, operand_src); |
| 20258 | const target = sema.mod.getTarget(); | 20768 | const bits = operand_ty.intInfo(mod).bits; |
| 20259 | const bits = operand_ty.intInfo(target).bits; | ||
| 20260 | 20769 | ||
| 20261 | if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { | 20770 | if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { |
| 20262 | return sema.addConstant(operand_ty, val); | 20771 | return sema.addConstant(operand_ty, val); |
| 20263 | } | 20772 | } |
| 20264 | 20773 | ||
| 20265 | const result_scalar_ty = try Type.smallestUnsignedInt(sema.arena, bits); | 20774 | const result_scalar_ty = try mod.smallestUnsignedInt(bits); |
| 20266 | switch (operand_ty.zigTypeTag()) { | 20775 | switch (operand_ty.zigTypeTag(mod)) { |
| 20267 | .Vector => { | 20776 | .Vector => { |
| 20268 | const vec_len = operand_ty.vectorLen(); | 20777 | const vec_len = operand_ty.vectorLen(mod); |
| 20269 | const result_ty = try Type.vector(sema.arena, vec_len, result_scalar_ty); | 20778 | const result_ty = try mod.vectorType(.{ |
| 20779 | .len = vec_len, | ||
| 20780 | .child = result_scalar_ty.toIntern(), | ||
| 20781 | }); | ||
| 20270 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 20782 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 20271 | if (val.isUndef()) return sema.addConstUndef(result_ty); | 20783 | if (val.isUndef(mod)) return sema.addConstUndef(result_ty); |
| 20272 | 20784 | ||
| 20273 | var elem_buf: Value.ElemValueBuffer = undefined; | 20785 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); |
| 20274 | const elems = try sema.arena.alloc(Value, vec_len); | 20786 | const scalar_ty = operand_ty.scalarType(mod); |
| 20275 | const scalar_ty = operand_ty.scalarType(); | ||
| 20276 | for (elems, 0..) |*elem, i| { | 20787 | for (elems, 0..) |*elem, i| { |
| 20277 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); | 20788 | const elem_val = try val.elemValue(mod, i); |
| 20278 | const count = comptimeOp(elem_val, scalar_ty, target); | 20789 | const count = comptimeOp(elem_val, scalar_ty, mod); |
| 20279 | elem.* = try Value.Tag.int_u64.create(sema.arena, count); | 20790 | elem.* = (try mod.intValue(result_scalar_ty, count)).toIntern(); |
| 20280 | } | 20791 | } |
| 20281 | return sema.addConstant( | 20792 | return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{ |
| 20282 | result_ty, | 20793 | .ty = result_ty.toIntern(), |
| 20283 | try Value.Tag.aggregate.create(sema.arena, elems), | 20794 | .storage = .{ .elems = elems }, |
| 20284 | ); | 20795 | } })).toValue()); |
| 20285 | } else { | 20796 | } else { |
| 20286 | try sema.requireRuntimeBlock(block, src, operand_src); | 20797 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 20287 | return block.addTyOp(air_tag, result_ty, operand); | 20798 | return block.addTyOp(air_tag, result_ty, operand); |
| 20288 | } | 20799 | } |
| 20289 | }, | 20800 | }, |
| 20290 | .Int => { | 20801 | .Int => { |
| 20291 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 20802 | if (try sema.resolveMaybeUndefLazyVal(operand)) |val| { |
| 20292 | if (val.isUndef()) return sema.addConstUndef(result_scalar_ty); | 20803 | if (val.isUndef(mod)) return sema.addConstUndef(result_scalar_ty); |
| 20293 | try sema.resolveLazyValue(val); | 20804 | return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, mod)); |
| 20294 | return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, target)); | ||
| 20295 | } else { | 20805 | } else { |
| 20296 | try sema.requireRuntimeBlock(block, src, operand_src); | 20806 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 20297 | return block.addTyOp(air_tag, result_scalar_ty, operand); | 20807 | return block.addTyOp(air_tag, result_scalar_ty, operand); |
| ... | @@ -20302,20 +20812,20 @@ fn zirBitCount( | ... | @@ -20302,20 +20812,20 @@ fn zirBitCount( |
| 20302 | } | 20812 | } |
| 20303 | 20813 | ||
| 20304 | fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 20814 | fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20815 | const mod = sema.mod; | ||
| 20305 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 20816 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 20306 | const src = inst_data.src(); | 20817 | const src = inst_data.src(); |
| 20307 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 20818 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 20308 | const operand = try sema.resolveInst(inst_data.operand); | 20819 | const operand = try sema.resolveInst(inst_data.operand); |
| 20309 | const operand_ty = sema.typeOf(operand); | 20820 | const operand_ty = sema.typeOf(operand); |
| 20310 | const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src); | 20821 | const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src); |
| 20311 | const target = sema.mod.getTarget(); | 20822 | const bits = scalar_ty.intInfo(mod).bits; |
| 20312 | const bits = scalar_ty.intInfo(target).bits; | ||
| 20313 | if (bits % 8 != 0) { | 20823 | if (bits % 8 != 0) { |
| 20314 | return sema.fail( | 20824 | return sema.fail( |
| 20315 | block, | 20825 | block, |
| 20316 | operand_src, | 20826 | operand_src, |
| 20317 | "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits", | 20827 | "@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits", |
| 20318 | .{ scalar_ty.fmt(sema.mod), bits }, | 20828 | .{ scalar_ty.fmt(mod), bits }, |
| 20319 | ); | 20829 | ); |
| 20320 | } | 20830 | } |
| 20321 | 20831 | ||
| ... | @@ -20323,11 +20833,11 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -20323,11 +20833,11 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 20323 | return sema.addConstant(operand_ty, val); | 20833 | return sema.addConstant(operand_ty, val); |
| 20324 | } | 20834 | } |
| 20325 | 20835 | ||
| 20326 | switch (operand_ty.zigTypeTag()) { | 20836 | switch (operand_ty.zigTypeTag(mod)) { |
| 20327 | .Int => { | 20837 | .Int => { |
| 20328 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { | 20838 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 20329 | if (val.isUndef()) return sema.addConstUndef(operand_ty); | 20839 | if (val.isUndef(mod)) return sema.addConstUndef(operand_ty); |
| 20330 | const result_val = try val.byteSwap(operand_ty, target, sema.arena); | 20840 | const result_val = try val.byteSwap(operand_ty, mod, sema.arena); |
| 20331 | return sema.addConstant(operand_ty, result_val); | 20841 | return sema.addConstant(operand_ty, result_val); |
| 20332 | } else operand_src; | 20842 | } else operand_src; |
| 20333 | 20843 | ||
| ... | @@ -20336,20 +20846,19 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -20336,20 +20846,19 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 20336 | }, | 20846 | }, |
| 20337 | .Vector => { | 20847 | .Vector => { |
| 20338 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { | 20848 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 20339 | if (val.isUndef()) | 20849 | if (val.isUndef(mod)) |
| 20340 | return sema.addConstUndef(operand_ty); | 20850 | return sema.addConstUndef(operand_ty); |
| 20341 | 20851 | ||
| 20342 | const vec_len = operand_ty.vectorLen(); | 20852 | const vec_len = operand_ty.vectorLen(mod); |
| 20343 | var elem_buf: Value.ElemValueBuffer = undefined; | 20853 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); |
| 20344 | const elems = try sema.arena.alloc(Value, vec_len); | ||
| 20345 | for (elems, 0..) |*elem, i| { | 20854 | for (elems, 0..) |*elem, i| { |
| 20346 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); | 20855 | const elem_val = try val.elemValue(mod, i); |
| 20347 | elem.* = try elem_val.byteSwap(operand_ty, target, sema.arena); | 20856 | elem.* = try (try elem_val.byteSwap(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod); |
| 20348 | } | 20857 | } |
| 20349 | return sema.addConstant( | 20858 | return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{ |
| 20350 | operand_ty, | 20859 | .ty = operand_ty.toIntern(), |
| 20351 | try Value.Tag.aggregate.create(sema.arena, elems), | 20860 | .storage = .{ .elems = elems }, |
| 20352 | ); | 20861 | } })).toValue()); |
| 20353 | } else operand_src; | 20862 | } else operand_src; |
| 20354 | 20863 | ||
| 20355 | try sema.requireRuntimeBlock(block, src, runtime_src); | 20864 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | @@ -20371,12 +20880,12 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -20371,12 +20880,12 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 20371 | return sema.addConstant(operand_ty, val); | 20880 | return sema.addConstant(operand_ty, val); |
| 20372 | } | 20881 | } |
| 20373 | 20882 | ||
| 20374 | const target = sema.mod.getTarget(); | 20883 | const mod = sema.mod; |
| 20375 | switch (operand_ty.zigTypeTag()) { | 20884 | switch (operand_ty.zigTypeTag(mod)) { |
| 20376 | .Int => { | 20885 | .Int => { |
| 20377 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { | 20886 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 20378 | if (val.isUndef()) return sema.addConstUndef(operand_ty); | 20887 | if (val.isUndef(mod)) return sema.addConstUndef(operand_ty); |
| 20379 | const result_val = try val.bitReverse(operand_ty, target, sema.arena); | 20888 | const result_val = try val.bitReverse(operand_ty, mod, sema.arena); |
| 20380 | return sema.addConstant(operand_ty, result_val); | 20889 | return sema.addConstant(operand_ty, result_val); |
| 20381 | } else operand_src; | 20890 | } else operand_src; |
| 20382 | 20891 | ||
| ... | @@ -20385,20 +20894,19 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -20385,20 +20894,19 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 20385 | }, | 20894 | }, |
| 20386 | .Vector => { | 20895 | .Vector => { |
| 20387 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { | 20896 | const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 20388 | if (val.isUndef()) | 20897 | if (val.isUndef(mod)) |
| 20389 | return sema.addConstUndef(operand_ty); | 20898 | return sema.addConstUndef(operand_ty); |
| 20390 | 20899 | ||
| 20391 | const vec_len = operand_ty.vectorLen(); | 20900 | const vec_len = operand_ty.vectorLen(mod); |
| 20392 | var elem_buf: Value.ElemValueBuffer = undefined; | 20901 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); |
| 20393 | const elems = try sema.arena.alloc(Value, vec_len); | ||
| 20394 | for (elems, 0..) |*elem, i| { | 20902 | for (elems, 0..) |*elem, i| { |
| 20395 | const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf); | 20903 | const elem_val = try val.elemValue(mod, i); |
| 20396 | elem.* = try elem_val.bitReverse(scalar_ty, target, sema.arena); | 20904 | elem.* = try (try elem_val.bitReverse(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod); |
| 20397 | } | 20905 | } |
| 20398 | return sema.addConstant( | 20906 | return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{ |
| 20399 | operand_ty, | 20907 | .ty = operand_ty.toIntern(), |
| 20400 | try Value.Tag.aggregate.create(sema.arena, elems), | 20908 | .storage = .{ .elems = elems }, |
| 20401 | ); | 20909 | } })).toValue()); |
| 20402 | } else operand_src; | 20910 | } else operand_src; |
| 20403 | 20911 | ||
| 20404 | try sema.requireRuntimeBlock(block, src, runtime_src); | 20912 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| ... | @@ -20428,15 +20936,15 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 | ... | @@ -20428,15 +20936,15 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 |
| 20428 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 20936 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 20429 | 20937 | ||
| 20430 | const ty = try sema.resolveType(block, lhs_src, extra.lhs); | 20938 | const ty = try sema.resolveType(block, lhs_src, extra.lhs); |
| 20431 | const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "name of field must be comptime-known"); | 20939 | const field_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, "name of field must be comptime-known"); |
| 20432 | const target = sema.mod.getTarget(); | ||
| 20433 | 20940 | ||
| 20941 | const mod = sema.mod; | ||
| 20434 | try sema.resolveTypeLayout(ty); | 20942 | try sema.resolveTypeLayout(ty); |
| 20435 | switch (ty.zigTypeTag()) { | 20943 | switch (ty.zigTypeTag(mod)) { |
| 20436 | .Struct => {}, | 20944 | .Struct => {}, |
| 20437 | else => { | 20945 | else => { |
| 20438 | const msg = msg: { | 20946 | const msg = msg: { |
| 20439 | const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(sema.mod)}); | 20947 | const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(mod)}); |
| 20440 | errdefer msg.destroy(sema.gpa); | 20948 | errdefer msg.destroy(sema.gpa); |
| 20441 | try sema.addDeclaredHereNote(msg, ty); | 20949 | try sema.addDeclaredHereNote(msg, ty); |
| 20442 | break :msg msg; | 20950 | break :msg msg; |
| ... | @@ -20445,45 +20953,47 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 | ... | @@ -20445,45 +20953,47 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 |
| 20445 | }, | 20953 | }, |
| 20446 | } | 20954 | } |
| 20447 | 20955 | ||
| 20448 | const field_index = if (ty.isTuple()) blk: { | 20956 | const field_index = if (ty.isTuple(mod)) blk: { |
| 20449 | if (mem.eql(u8, field_name, "len")) { | 20957 | if (mod.intern_pool.stringEqlSlice(field_name, "len")) { |
| 20450 | return sema.fail(block, src, "no offset available for 'len' field of tuple", .{}); | 20958 | return sema.fail(block, src, "no offset available for 'len' field of tuple", .{}); |
| 20451 | } | 20959 | } |
| 20452 | break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src); | 20960 | break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src); |
| 20453 | } else try sema.structFieldIndex(block, ty, field_name, rhs_src); | 20961 | } else try sema.structFieldIndex(block, ty, field_name, rhs_src); |
| 20454 | 20962 | ||
| 20455 | if (ty.structFieldIsComptime(field_index)) { | 20963 | if (ty.structFieldIsComptime(field_index, mod)) { |
| 20456 | return sema.fail(block, src, "no offset available for comptime field", .{}); | 20964 | return sema.fail(block, src, "no offset available for comptime field", .{}); |
| 20457 | } | 20965 | } |
| 20458 | 20966 | ||
| 20459 | switch (ty.containerLayout()) { | 20967 | switch (ty.containerLayout(mod)) { |
| 20460 | .Packed => { | 20968 | .Packed => { |
| 20461 | var bit_sum: u64 = 0; | 20969 | var bit_sum: u64 = 0; |
| 20462 | const fields = ty.structFields(); | 20970 | const fields = ty.structFields(mod); |
| 20463 | for (fields.values(), 0..) |field, i| { | 20971 | for (fields.values(), 0..) |field, i| { |
| 20464 | if (i == field_index) { | 20972 | if (i == field_index) { |
| 20465 | return bit_sum; | 20973 | return bit_sum; |
| 20466 | } | 20974 | } |
| 20467 | bit_sum += field.ty.bitSize(target); | 20975 | bit_sum += field.ty.bitSize(mod); |
| 20468 | } else unreachable; | 20976 | } else unreachable; |
| 20469 | }, | 20977 | }, |
| 20470 | else => return ty.structFieldOffset(field_index, target) * 8, | 20978 | else => return ty.structFieldOffset(field_index, mod) * 8, |
| 20471 | } | 20979 | } |
| 20472 | } | 20980 | } |
| 20473 | 20981 | ||
| 20474 | fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { | 20982 | fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { |
| 20475 | switch (ty.zigTypeTag()) { | 20983 | const mod = sema.mod; |
| 20984 | switch (ty.zigTypeTag(mod)) { | ||
| 20476 | .Struct, .Enum, .Union, .Opaque => return, | 20985 | .Struct, .Enum, .Union, .Opaque => return, |
| 20477 | else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(sema.mod)}), | 20986 | else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(mod)}), |
| 20478 | } | 20987 | } |
| 20479 | } | 20988 | } |
| 20480 | 20989 | ||
| 20481 | /// Returns `true` if the type was a comptime_int. | 20990 | /// Returns `true` if the type was a comptime_int. |
| 20482 | fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { | 20991 | fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { |
| 20483 | switch (try ty.zigTypeTagOrPoison()) { | 20992 | const mod = sema.mod; |
| 20993 | switch (try ty.zigTypeTagOrPoison(mod)) { | ||
| 20484 | .ComptimeInt => return true, | 20994 | .ComptimeInt => return true, |
| 20485 | .Int => return false, | 20995 | .Int => return false, |
| 20486 | else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(sema.mod)}), | 20996 | else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(mod)}), |
| 20487 | } | 20997 | } |
| 20488 | } | 20998 | } |
| 20489 | 20999 | ||
| ... | @@ -20493,8 +21003,9 @@ fn checkInvalidPtrArithmetic( | ... | @@ -20493,8 +21003,9 @@ fn checkInvalidPtrArithmetic( |
| 20493 | src: LazySrcLoc, | 21003 | src: LazySrcLoc, |
| 20494 | ty: Type, | 21004 | ty: Type, |
| 20495 | ) CompileError!void { | 21005 | ) CompileError!void { |
| 20496 | switch (try ty.zigTypeTagOrPoison()) { | 21006 | const mod = sema.mod; |
| 20497 | .Pointer => switch (ty.ptrSize()) { | 21007 | switch (try ty.zigTypeTagOrPoison(mod)) { |
| 21008 | .Pointer => switch (ty.ptrSize(mod)) { | ||
| 20498 | .One, .Slice => return, | 21009 | .One, .Slice => return, |
| 20499 | .Many, .C => return sema.fail( | 21010 | .Many, .C => return sema.fail( |
| 20500 | block, | 21011 | block, |
| ... | @@ -20532,7 +21043,8 @@ fn checkPtrOperand( | ... | @@ -20532,7 +21043,8 @@ fn checkPtrOperand( |
| 20532 | ty_src: LazySrcLoc, | 21043 | ty_src: LazySrcLoc, |
| 20533 | ty: Type, | 21044 | ty: Type, |
| 20534 | ) CompileError!void { | 21045 | ) CompileError!void { |
| 20535 | switch (ty.zigTypeTag()) { | 21046 | const mod = sema.mod; |
| 21047 | switch (ty.zigTypeTag(mod)) { | ||
| 20536 | .Pointer => return, | 21048 | .Pointer => return, |
| 20537 | .Fn => { | 21049 | .Fn => { |
| 20538 | const msg = msg: { | 21050 | const msg = msg: { |
| ... | @@ -20540,7 +21052,7 @@ fn checkPtrOperand( | ... | @@ -20540,7 +21052,7 @@ fn checkPtrOperand( |
| 20540 | block, | 21052 | block, |
| 20541 | ty_src, | 21053 | ty_src, |
| 20542 | "expected pointer, found '{}'", | 21054 | "expected pointer, found '{}'", |
| 20543 | .{ty.fmt(sema.mod)}, | 21055 | .{ty.fmt(mod)}, |
| 20544 | ); | 21056 | ); |
| 20545 | errdefer msg.destroy(sema.gpa); | 21057 | errdefer msg.destroy(sema.gpa); |
| 20546 | 21058 | ||
| ... | @@ -20550,10 +21062,10 @@ fn checkPtrOperand( | ... | @@ -20550,10 +21062,10 @@ fn checkPtrOperand( |
| 20550 | }; | 21062 | }; |
| 20551 | return sema.failWithOwnedErrorMsg(msg); | 21063 | return sema.failWithOwnedErrorMsg(msg); |
| 20552 | }, | 21064 | }, |
| 20553 | .Optional => if (ty.isPtrLikeOptional()) return, | 21065 | .Optional => if (ty.isPtrLikeOptional(mod)) return, |
| 20554 | else => {}, | 21066 | else => {}, |
| 20555 | } | 21067 | } |
| 20556 | return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)}); | 21068 | return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)}); |
| 20557 | } | 21069 | } |
| 20558 | 21070 | ||
| 20559 | fn checkPtrType( | 21071 | fn checkPtrType( |
| ... | @@ -20562,7 +21074,8 @@ fn checkPtrType( | ... | @@ -20562,7 +21074,8 @@ fn checkPtrType( |
| 20562 | ty_src: LazySrcLoc, | 21074 | ty_src: LazySrcLoc, |
| 20563 | ty: Type, | 21075 | ty: Type, |
| 20564 | ) CompileError!void { | 21076 | ) CompileError!void { |
| 20565 | switch (ty.zigTypeTag()) { | 21077 | const mod = sema.mod; |
| 21078 | switch (ty.zigTypeTag(mod)) { | ||
| 20566 | .Pointer => return, | 21079 | .Pointer => return, |
| 20567 | .Fn => { | 21080 | .Fn => { |
| 20568 | const msg = msg: { | 21081 | const msg = msg: { |
| ... | @@ -20570,7 +21083,7 @@ fn checkPtrType( | ... | @@ -20570,7 +21083,7 @@ fn checkPtrType( |
| 20570 | block, | 21083 | block, |
| 20571 | ty_src, | 21084 | ty_src, |
| 20572 | "expected pointer type, found '{}'", | 21085 | "expected pointer type, found '{}'", |
| 20573 | .{ty.fmt(sema.mod)}, | 21086 | .{ty.fmt(mod)}, |
| 20574 | ); | 21087 | ); |
| 20575 | errdefer msg.destroy(sema.gpa); | 21088 | errdefer msg.destroy(sema.gpa); |
| 20576 | 21089 | ||
| ... | @@ -20580,10 +21093,10 @@ fn checkPtrType( | ... | @@ -20580,10 +21093,10 @@ fn checkPtrType( |
| 20580 | }; | 21093 | }; |
| 20581 | return sema.failWithOwnedErrorMsg(msg); | 21094 | return sema.failWithOwnedErrorMsg(msg); |
| 20582 | }, | 21095 | }, |
| 20583 | .Optional => if (ty.isPtrLikeOptional()) return, | 21096 | .Optional => if (ty.isPtrLikeOptional(mod)) return, |
| 20584 | else => {}, | 21097 | else => {}, |
| 20585 | } | 21098 | } |
| 20586 | return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)}); | 21099 | return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)}); |
| 20587 | } | 21100 | } |
| 20588 | 21101 | ||
| 20589 | fn checkVectorElemType( | 21102 | fn checkVectorElemType( |
| ... | @@ -20592,11 +21105,12 @@ fn checkVectorElemType( | ... | @@ -20592,11 +21105,12 @@ fn checkVectorElemType( |
| 20592 | ty_src: LazySrcLoc, | 21105 | ty_src: LazySrcLoc, |
| 20593 | ty: Type, | 21106 | ty: Type, |
| 20594 | ) CompileError!void { | 21107 | ) CompileError!void { |
| 20595 | switch (ty.zigTypeTag()) { | 21108 | const mod = sema.mod; |
| 21109 | switch (ty.zigTypeTag(mod)) { | ||
| 20596 | .Int, .Float, .Bool => return, | 21110 | .Int, .Float, .Bool => return, |
| 20597 | else => if (ty.isPtrAtRuntime()) return, | 21111 | else => if (ty.isPtrAtRuntime(mod)) return, |
| 20598 | } | 21112 | } |
| 20599 | return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(sema.mod)}); | 21113 | return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(mod)}); |
| 20600 | } | 21114 | } |
| 20601 | 21115 | ||
| 20602 | fn checkFloatType( | 21116 | fn checkFloatType( |
| ... | @@ -20605,9 +21119,10 @@ fn checkFloatType( | ... | @@ -20605,9 +21119,10 @@ fn checkFloatType( |
| 20605 | ty_src: LazySrcLoc, | 21119 | ty_src: LazySrcLoc, |
| 20606 | ty: Type, | 21120 | ty: Type, |
| 20607 | ) CompileError!void { | 21121 | ) CompileError!void { |
| 20608 | switch (ty.zigTypeTag()) { | 21122 | const mod = sema.mod; |
| 21123 | switch (ty.zigTypeTag(mod)) { | ||
| 20609 | .ComptimeInt, .ComptimeFloat, .Float => {}, | 21124 | .ComptimeInt, .ComptimeFloat, .Float => {}, |
| 20610 | else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(sema.mod)}), | 21125 | else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(mod)}), |
| 20611 | } | 21126 | } |
| 20612 | } | 21127 | } |
| 20613 | 21128 | ||
| ... | @@ -20617,13 +21132,14 @@ fn checkNumericType( | ... | @@ -20617,13 +21132,14 @@ fn checkNumericType( |
| 20617 | ty_src: LazySrcLoc, | 21132 | ty_src: LazySrcLoc, |
| 20618 | ty: Type, | 21133 | ty: Type, |
| 20619 | ) CompileError!void { | 21134 | ) CompileError!void { |
| 20620 | switch (ty.zigTypeTag()) { | 21135 | const mod = sema.mod; |
| 21136 | switch (ty.zigTypeTag(mod)) { | ||
| 20621 | .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, | 21137 | .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, |
| 20622 | .Vector => switch (ty.childType().zigTypeTag()) { | 21138 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { |
| 20623 | .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, | 21139 | .ComptimeFloat, .Float, .ComptimeInt, .Int => {}, |
| 20624 | else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}), | 21140 | else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}), |
| 20625 | }, | 21141 | }, |
| 20626 | else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(sema.mod)}), | 21142 | else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(mod)}), |
| 20627 | } | 21143 | } |
| 20628 | } | 21144 | } |
| 20629 | 21145 | ||
| ... | @@ -20637,9 +21153,10 @@ fn checkAtomicPtrOperand( | ... | @@ -20637,9 +21153,10 @@ fn checkAtomicPtrOperand( |
| 20637 | ptr_src: LazySrcLoc, | 21153 | ptr_src: LazySrcLoc, |
| 20638 | ptr_const: bool, | 21154 | ptr_const: bool, |
| 20639 | ) CompileError!Air.Inst.Ref { | 21155 | ) CompileError!Air.Inst.Ref { |
| 20640 | const target = sema.mod.getTarget(); | 21156 | const mod = sema.mod; |
| 20641 | var diag: target_util.AtomicPtrAlignmentDiagnostics = .{}; | 21157 | var diag: Module.AtomicPtrAlignmentDiagnostics = .{}; |
| 20642 | const alignment = target_util.atomicPtrAlignment(target, elem_ty, &diag) catch |err| switch (err) { | 21158 | const alignment = mod.atomicPtrAlignment(elem_ty, &diag) catch |err| switch (err) { |
| 21159 | error.OutOfMemory => return error.OutOfMemory, | ||
| 20643 | error.FloatTooBig => return sema.fail( | 21160 | error.FloatTooBig => return sema.fail( |
| 20644 | block, | 21161 | block, |
| 20645 | elem_ty_src, | 21162 | elem_ty_src, |
| ... | @@ -20656,7 +21173,7 @@ fn checkAtomicPtrOperand( | ... | @@ -20656,7 +21173,7 @@ fn checkAtomicPtrOperand( |
| 20656 | block, | 21173 | block, |
| 20657 | elem_ty_src, | 21174 | elem_ty_src, |
| 20658 | "expected bool, integer, float, enum, or pointer type; found '{}'", | 21175 | "expected bool, integer, float, enum, or pointer type; found '{}'", |
| 20659 | .{elem_ty.fmt(sema.mod)}, | 21176 | .{elem_ty.fmt(mod)}, |
| 20660 | ), | 21177 | ), |
| 20661 | }; | 21178 | }; |
| 20662 | 21179 | ||
| ... | @@ -20668,10 +21185,10 @@ fn checkAtomicPtrOperand( | ... | @@ -20668,10 +21185,10 @@ fn checkAtomicPtrOperand( |
| 20668 | }; | 21185 | }; |
| 20669 | 21186 | ||
| 20670 | const ptr_ty = sema.typeOf(ptr); | 21187 | const ptr_ty = sema.typeOf(ptr); |
| 20671 | const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison()) { | 21188 | const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) { |
| 20672 | .Pointer => ptr_ty.ptrInfo().data, | 21189 | .Pointer => ptr_ty.ptrInfo(mod), |
| 20673 | else => { | 21190 | else => { |
| 20674 | const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data); | 21191 | const wanted_ptr_ty = try Type.ptr(sema.arena, mod, wanted_ptr_data); |
| 20675 | _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); | 21192 | _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); |
| 20676 | unreachable; | 21193 | unreachable; |
| 20677 | }, | 21194 | }, |
| ... | @@ -20681,7 +21198,7 @@ fn checkAtomicPtrOperand( | ... | @@ -20681,7 +21198,7 @@ fn checkAtomicPtrOperand( |
| 20681 | wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero"; | 21198 | wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero"; |
| 20682 | wanted_ptr_data.@"volatile" = ptr_data.@"volatile"; | 21199 | wanted_ptr_data.@"volatile" = ptr_data.@"volatile"; |
| 20683 | 21200 | ||
| 20684 | const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data); | 21201 | const wanted_ptr_ty = try Type.ptr(sema.arena, mod, wanted_ptr_data); |
| 20685 | const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); | 21202 | const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); |
| 20686 | 21203 | ||
| 20687 | return casted_ptr; | 21204 | return casted_ptr; |
| ... | @@ -20695,7 +21212,7 @@ fn checkPtrIsNotComptimeMutable( | ... | @@ -20695,7 +21212,7 @@ fn checkPtrIsNotComptimeMutable( |
| 20695 | operand_src: LazySrcLoc, | 21212 | operand_src: LazySrcLoc, |
| 20696 | ) CompileError!void { | 21213 | ) CompileError!void { |
| 20697 | _ = operand_src; | 21214 | _ = operand_src; |
| 20698 | if (ptr_val.isComptimeMutablePtr()) { | 21215 | if (ptr_val.isComptimeMutablePtr(sema.mod)) { |
| 20699 | return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{}); | 21216 | return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{}); |
| 20700 | } | 21217 | } |
| 20701 | } | 21218 | } |
| ... | @@ -20704,7 +21221,7 @@ fn checkComptimeVarStore( | ... | @@ -20704,7 +21221,7 @@ fn checkComptimeVarStore( |
| 20704 | sema: *Sema, | 21221 | sema: *Sema, |
| 20705 | block: *Block, | 21222 | block: *Block, |
| 20706 | src: LazySrcLoc, | 21223 | src: LazySrcLoc, |
| 20707 | decl_ref_mut: Value.Payload.DeclRefMut.Data, | 21224 | decl_ref_mut: InternPool.Key.Ptr.Addr.MutDecl, |
| 20708 | ) CompileError!void { | 21225 | ) CompileError!void { |
| 20709 | if (@enumToInt(decl_ref_mut.runtime_index) < @enumToInt(block.runtime_index)) { | 21226 | if (@enumToInt(decl_ref_mut.runtime_index) < @enumToInt(block.runtime_index)) { |
| 20710 | if (block.runtime_cond) |cond_src| { | 21227 | if (block.runtime_cond) |cond_src| { |
| ... | @@ -20735,20 +21252,21 @@ fn checkIntOrVector( | ... | @@ -20735,20 +21252,21 @@ fn checkIntOrVector( |
| 20735 | operand: Air.Inst.Ref, | 21252 | operand: Air.Inst.Ref, |
| 20736 | operand_src: LazySrcLoc, | 21253 | operand_src: LazySrcLoc, |
| 20737 | ) CompileError!Type { | 21254 | ) CompileError!Type { |
| 21255 | const mod = sema.mod; | ||
| 20738 | const operand_ty = sema.typeOf(operand); | 21256 | const operand_ty = sema.typeOf(operand); |
| 20739 | switch (try operand_ty.zigTypeTagOrPoison()) { | 21257 | switch (try operand_ty.zigTypeTagOrPoison(mod)) { |
| 20740 | .Int => return operand_ty, | 21258 | .Int => return operand_ty, |
| 20741 | .Vector => { | 21259 | .Vector => { |
| 20742 | const elem_ty = operand_ty.childType(); | 21260 | const elem_ty = operand_ty.childType(mod); |
| 20743 | switch (try elem_ty.zigTypeTagOrPoison()) { | 21261 | switch (try elem_ty.zigTypeTagOrPoison(mod)) { |
| 20744 | .Int => return elem_ty, | 21262 | .Int => return elem_ty, |
| 20745 | else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ | 21263 | else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ |
| 20746 | elem_ty.fmt(sema.mod), | 21264 | elem_ty.fmt(mod), |
| 20747 | }), | 21265 | }), |
| 20748 | } | 21266 | } |
| 20749 | }, | 21267 | }, |
| 20750 | else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ | 21268 | else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ |
| 20751 | operand_ty.fmt(sema.mod), | 21269 | operand_ty.fmt(mod), |
| 20752 | }), | 21270 | }), |
| 20753 | } | 21271 | } |
| 20754 | } | 21272 | } |
| ... | @@ -20759,27 +21277,29 @@ fn checkIntOrVectorAllowComptime( | ... | @@ -20759,27 +21277,29 @@ fn checkIntOrVectorAllowComptime( |
| 20759 | operand_ty: Type, | 21277 | operand_ty: Type, |
| 20760 | operand_src: LazySrcLoc, | 21278 | operand_src: LazySrcLoc, |
| 20761 | ) CompileError!Type { | 21279 | ) CompileError!Type { |
| 20762 | switch (try operand_ty.zigTypeTagOrPoison()) { | 21280 | const mod = sema.mod; |
| 21281 | switch (try operand_ty.zigTypeTagOrPoison(mod)) { | ||
| 20763 | .Int, .ComptimeInt => return operand_ty, | 21282 | .Int, .ComptimeInt => return operand_ty, |
| 20764 | .Vector => { | 21283 | .Vector => { |
| 20765 | const elem_ty = operand_ty.childType(); | 21284 | const elem_ty = operand_ty.childType(mod); |
| 20766 | switch (try elem_ty.zigTypeTagOrPoison()) { | 21285 | switch (try elem_ty.zigTypeTagOrPoison(mod)) { |
| 20767 | .Int, .ComptimeInt => return elem_ty, | 21286 | .Int, .ComptimeInt => return elem_ty, |
| 20768 | else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ | 21287 | else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{ |
| 20769 | elem_ty.fmt(sema.mod), | 21288 | elem_ty.fmt(mod), |
| 20770 | }), | 21289 | }), |
| 20771 | } | 21290 | } |
| 20772 | }, | 21291 | }, |
| 20773 | else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ | 21292 | else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{ |
| 20774 | operand_ty.fmt(sema.mod), | 21293 | operand_ty.fmt(mod), |
| 20775 | }), | 21294 | }), |
| 20776 | } | 21295 | } |
| 20777 | } | 21296 | } |
| 20778 | 21297 | ||
| 20779 | fn checkErrorSetType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { | 21298 | fn checkErrorSetType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void { |
| 20780 | switch (ty.zigTypeTag()) { | 21299 | const mod = sema.mod; |
| 21300 | switch (ty.zigTypeTag(mod)) { | ||
| 20781 | .ErrorSet => return, | 21301 | .ErrorSet => return, |
| 20782 | else => return sema.fail(block, src, "expected error set type, found '{}'", .{ty.fmt(sema.mod)}), | 21302 | else => return sema.fail(block, src, "expected error set type, found '{}'", .{ty.fmt(mod)}), |
| 20783 | } | 21303 | } |
| 20784 | } | 21304 | } |
| 20785 | 21305 | ||
| ... | @@ -20805,11 +21325,12 @@ fn checkSimdBinOp( | ... | @@ -20805,11 +21325,12 @@ fn checkSimdBinOp( |
| 20805 | lhs_src: LazySrcLoc, | 21325 | lhs_src: LazySrcLoc, |
| 20806 | rhs_src: LazySrcLoc, | 21326 | rhs_src: LazySrcLoc, |
| 20807 | ) CompileError!SimdBinOp { | 21327 | ) CompileError!SimdBinOp { |
| 21328 | const mod = sema.mod; | ||
| 20808 | const lhs_ty = sema.typeOf(uncasted_lhs); | 21329 | const lhs_ty = sema.typeOf(uncasted_lhs); |
| 20809 | const rhs_ty = sema.typeOf(uncasted_rhs); | 21330 | const rhs_ty = sema.typeOf(uncasted_rhs); |
| 20810 | 21331 | ||
| 20811 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 21332 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 20812 | var vec_len: ?usize = if (lhs_ty.zigTypeTag() == .Vector) lhs_ty.vectorLen() else null; | 21333 | var vec_len: ?usize = if (lhs_ty.zigTypeTag(mod) == .Vector) lhs_ty.vectorLen(mod) else null; |
| 20813 | const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{ | 21334 | const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{ |
| 20814 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, | 21335 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 20815 | }); | 21336 | }); |
| ... | @@ -20823,7 +21344,7 @@ fn checkSimdBinOp( | ... | @@ -20823,7 +21344,7 @@ fn checkSimdBinOp( |
| 20823 | .lhs_val = try sema.resolveMaybeUndefVal(lhs), | 21344 | .lhs_val = try sema.resolveMaybeUndefVal(lhs), |
| 20824 | .rhs_val = try sema.resolveMaybeUndefVal(rhs), | 21345 | .rhs_val = try sema.resolveMaybeUndefVal(rhs), |
| 20825 | .result_ty = result_ty, | 21346 | .result_ty = result_ty, |
| 20826 | .scalar_ty = result_ty.scalarType(), | 21347 | .scalar_ty = result_ty.scalarType(mod), |
| 20827 | }; | 21348 | }; |
| 20828 | } | 21349 | } |
| 20829 | 21350 | ||
| ... | @@ -20836,8 +21357,9 @@ fn checkVectorizableBinaryOperands( | ... | @@ -20836,8 +21357,9 @@ fn checkVectorizableBinaryOperands( |
| 20836 | lhs_src: LazySrcLoc, | 21357 | lhs_src: LazySrcLoc, |
| 20837 | rhs_src: LazySrcLoc, | 21358 | rhs_src: LazySrcLoc, |
| 20838 | ) CompileError!void { | 21359 | ) CompileError!void { |
| 20839 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(); | 21360 | const mod = sema.mod; |
| 20840 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(); | 21361 | const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod); |
| 21362 | const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod); | ||
| 20841 | if (lhs_zig_ty_tag != .Vector and rhs_zig_ty_tag != .Vector) return; | 21363 | if (lhs_zig_ty_tag != .Vector and rhs_zig_ty_tag != .Vector) return; |
| 20842 | 21364 | ||
| 20843 | const lhs_is_vector = switch (lhs_zig_ty_tag) { | 21365 | const lhs_is_vector = switch (lhs_zig_ty_tag) { |
| ... | @@ -20850,8 +21372,8 @@ fn checkVectorizableBinaryOperands( | ... | @@ -20850,8 +21372,8 @@ fn checkVectorizableBinaryOperands( |
| 20850 | }; | 21372 | }; |
| 20851 | 21373 | ||
| 20852 | if (lhs_is_vector and rhs_is_vector) { | 21374 | if (lhs_is_vector and rhs_is_vector) { |
| 20853 | const lhs_len = lhs_ty.arrayLen(); | 21375 | const lhs_len = lhs_ty.arrayLen(mod); |
| 20854 | const rhs_len = rhs_ty.arrayLen(); | 21376 | const rhs_len = rhs_ty.arrayLen(mod); |
| 20855 | if (lhs_len != rhs_len) { | 21377 | if (lhs_len != rhs_len) { |
| 20856 | const msg = msg: { | 21378 | const msg = msg: { |
| 20857 | const msg = try sema.errMsg(block, src, "vector length mismatch", .{}); | 21379 | const msg = try sema.errMsg(block, src, "vector length mismatch", .{}); |
| ... | @@ -20865,7 +21387,7 @@ fn checkVectorizableBinaryOperands( | ... | @@ -20865,7 +21387,7 @@ fn checkVectorizableBinaryOperands( |
| 20865 | } else { | 21387 | } else { |
| 20866 | const msg = msg: { | 21388 | const msg = msg: { |
| 20867 | const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: '{}' and '{}'", .{ | 21389 | const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: '{}' and '{}'", .{ |
| 20868 | lhs_ty.fmt(sema.mod), rhs_ty.fmt(sema.mod), | 21390 | lhs_ty.fmt(mod), rhs_ty.fmt(mod), |
| 20869 | }); | 21391 | }); |
| 20870 | errdefer msg.destroy(sema.gpa); | 21392 | errdefer msg.destroy(sema.gpa); |
| 20871 | if (lhs_is_vector) { | 21393 | if (lhs_is_vector) { |
| ... | @@ -20883,7 +21405,8 @@ fn checkVectorizableBinaryOperands( | ... | @@ -20883,7 +21405,8 @@ fn checkVectorizableBinaryOperands( |
| 20883 | 21405 | ||
| 20884 | fn maybeOptionsSrc(sema: *Sema, block: *Block, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc { | 21406 | fn maybeOptionsSrc(sema: *Sema, block: *Block, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc { |
| 20885 | if (base_src == .unneeded) return .unneeded; | 21407 | if (base_src == .unneeded) return .unneeded; |
| 20886 | return Module.optionsSrc(sema.gpa, sema.mod.declPtr(block.src_decl), base_src, wanted); | 21408 | const mod = sema.mod; |
| 21409 | return mod.optionsSrc(mod.declPtr(block.src_decl), base_src, wanted); | ||
| 20887 | } | 21410 | } |
| 20888 | 21411 | ||
| 20889 | fn resolveExportOptions( | 21412 | fn resolveExportOptions( |
| ... | @@ -20891,7 +21414,10 @@ fn resolveExportOptions( | ... | @@ -20891,7 +21414,10 @@ fn resolveExportOptions( |
| 20891 | block: *Block, | 21414 | block: *Block, |
| 20892 | src: LazySrcLoc, | 21415 | src: LazySrcLoc, |
| 20893 | zir_ref: Zir.Inst.Ref, | 21416 | zir_ref: Zir.Inst.Ref, |
| 20894 | ) CompileError!std.builtin.ExportOptions { | 21417 | ) CompileError!Module.Export.Options { |
| 21418 | const mod = sema.mod; | ||
| 21419 | const gpa = sema.gpa; | ||
| 21420 | const ip = &mod.intern_pool; | ||
| 20895 | const export_options_ty = try sema.getBuiltinType("ExportOptions"); | 21421 | const export_options_ty = try sema.getBuiltinType("ExportOptions"); |
| 20896 | const air_ref = try sema.resolveInst(zir_ref); | 21422 | const air_ref = try sema.resolveInst(zir_ref); |
| 20897 | const options = try sema.coerce(block, export_options_ty, air_ref, src); | 21423 | const options = try sema.coerce(block, export_options_ty, air_ref, src); |
| ... | @@ -20901,26 +21427,26 @@ fn resolveExportOptions( | ... | @@ -20901,26 +21427,26 @@ fn resolveExportOptions( |
| 20901 | const section_src = sema.maybeOptionsSrc(block, src, "section"); | 21427 | const section_src = sema.maybeOptionsSrc(block, src, "section"); |
| 20902 | const visibility_src = sema.maybeOptionsSrc(block, src, "visibility"); | 21428 | const visibility_src = sema.maybeOptionsSrc(block, src, "visibility"); |
| 20903 | 21429 | ||
| 20904 | const name_operand = try sema.fieldVal(block, src, options, "name", name_src); | 21430 | const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src); |
| 20905 | const name_val = try sema.resolveConstValue(block, name_src, name_operand, "name of exported value must be comptime-known"); | 21431 | const name_val = try sema.resolveConstValue(block, name_src, name_operand, "name of exported value must be comptime-known"); |
| 20906 | const name_ty = Type.initTag(.const_slice_u8); | 21432 | const name_ty = Type.slice_const_u8; |
| 20907 | const name = try name_val.toAllocatedBytes(name_ty, sema.arena, sema.mod); | 21433 | const name = try name_val.toAllocatedBytes(name_ty, sema.arena, mod); |
| 20908 | 21434 | ||
| 20909 | const linkage_operand = try sema.fieldVal(block, src, options, "linkage", linkage_src); | 21435 | const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src); |
| 20910 | const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_operand, "linkage of exported value must be comptime-known"); | 21436 | const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_operand, "linkage of exported value must be comptime-known"); |
| 20911 | const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage); | 21437 | const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val); |
| 20912 | 21438 | ||
| 20913 | const section_operand = try sema.fieldVal(block, src, options, "section", section_src); | 21439 | const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "section"), section_src); |
| 20914 | const section_opt_val = try sema.resolveConstValue(block, section_src, section_operand, "linksection of exported value must be comptime-known"); | 21440 | const section_opt_val = try sema.resolveConstValue(block, section_src, section_operand, "linksection of exported value must be comptime-known"); |
| 20915 | const section_ty = Type.initTag(.const_slice_u8); | 21441 | const section_ty = Type.slice_const_u8; |
| 20916 | const section = if (section_opt_val.optionalValue()) |section_val| | 21442 | const section = if (section_opt_val.optionalValue(mod)) |section_val| |
| 20917 | try section_val.toAllocatedBytes(section_ty, sema.arena, sema.mod) | 21443 | try section_val.toAllocatedBytes(section_ty, sema.arena, mod) |
| 20918 | else | 21444 | else |
| 20919 | null; | 21445 | null; |
| 20920 | 21446 | ||
| 20921 | const visibility_operand = try sema.fieldVal(block, src, options, "visibility", visibility_src); | 21447 | const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "visibility"), visibility_src); |
| 20922 | const visibility_val = try sema.resolveConstValue(block, visibility_src, visibility_operand, "visibility of exported value must be comptime-known"); | 21448 | const visibility_val = try sema.resolveConstValue(block, visibility_src, visibility_operand, "visibility of exported value must be comptime-known"); |
| 20923 | const visibility = visibility_val.toEnum(std.builtin.SymbolVisibility); | 21449 | const visibility = mod.toEnum(std.builtin.SymbolVisibility, visibility_val); |
| 20924 | 21450 | ||
| 20925 | if (name.len < 1) { | 21451 | if (name.len < 1) { |
| 20926 | return sema.fail(block, name_src, "exported symbol name cannot be empty", .{}); | 21452 | return sema.fail(block, name_src, "exported symbol name cannot be empty", .{}); |
| ... | @@ -20932,10 +21458,10 @@ fn resolveExportOptions( | ... | @@ -20932,10 +21458,10 @@ fn resolveExportOptions( |
| 20932 | }); | 21458 | }); |
| 20933 | } | 21459 | } |
| 20934 | 21460 | ||
| 20935 | return std.builtin.ExportOptions{ | 21461 | return .{ |
| 20936 | .name = name, | 21462 | .name = try ip.getOrPutString(gpa, name), |
| 20937 | .linkage = linkage, | 21463 | .linkage = linkage, |
| 20938 | .section = section, | 21464 | .section = try ip.getOrPutStringOpt(gpa, section), |
| 20939 | .visibility = visibility, | 21465 | .visibility = visibility, |
| 20940 | }; | 21466 | }; |
| 20941 | } | 21467 | } |
| ... | @@ -20948,11 +21474,12 @@ fn resolveBuiltinEnum( | ... | @@ -20948,11 +21474,12 @@ fn resolveBuiltinEnum( |
| 20948 | comptime name: []const u8, | 21474 | comptime name: []const u8, |
| 20949 | reason: []const u8, | 21475 | reason: []const u8, |
| 20950 | ) CompileError!@field(std.builtin, name) { | 21476 | ) CompileError!@field(std.builtin, name) { |
| 21477 | const mod = sema.mod; | ||
| 20951 | const ty = try sema.getBuiltinType(name); | 21478 | const ty = try sema.getBuiltinType(name); |
| 20952 | const air_ref = try sema.resolveInst(zir_ref); | 21479 | const air_ref = try sema.resolveInst(zir_ref); |
| 20953 | const coerced = try sema.coerce(block, ty, air_ref, src); | 21480 | const coerced = try sema.coerce(block, ty, air_ref, src); |
| 20954 | const val = try sema.resolveConstValue(block, src, coerced, reason); | 21481 | const val = try sema.resolveConstValue(block, src, coerced, reason); |
| 20955 | return val.toEnum(@field(std.builtin, name)); | 21482 | return mod.toEnum(@field(std.builtin, name), val); |
| 20956 | } | 21483 | } |
| 20957 | 21484 | ||
| 20958 | fn resolveAtomicOrder( | 21485 | fn resolveAtomicOrder( |
| ... | @@ -20979,6 +21506,7 @@ fn zirCmpxchg( | ... | @@ -20979,6 +21506,7 @@ fn zirCmpxchg( |
| 20979 | block: *Block, | 21506 | block: *Block, |
| 20980 | extended: Zir.Inst.Extended.InstData, | 21507 | extended: Zir.Inst.Extended.InstData, |
| 20981 | ) CompileError!Air.Inst.Ref { | 21508 | ) CompileError!Air.Inst.Ref { |
| 21509 | const mod = sema.mod; | ||
| 20982 | const extra = sema.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data; | 21510 | const extra = sema.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data; |
| 20983 | const air_tag: Air.Inst.Tag = switch (extended.small) { | 21511 | const air_tag: Air.Inst.Tag = switch (extended.small) { |
| 20984 | 0 => .cmpxchg_weak, | 21512 | 0 => .cmpxchg_weak, |
| ... | @@ -20996,12 +21524,12 @@ fn zirCmpxchg( | ... | @@ -20996,12 +21524,12 @@ fn zirCmpxchg( |
| 20996 | // zig fmt: on | 21524 | // zig fmt: on |
| 20997 | const expected_value = try sema.resolveInst(extra.expected_value); | 21525 | const expected_value = try sema.resolveInst(extra.expected_value); |
| 20998 | const elem_ty = sema.typeOf(expected_value); | 21526 | const elem_ty = sema.typeOf(expected_value); |
| 20999 | if (elem_ty.zigTypeTag() == .Float) { | 21527 | if (elem_ty.zigTypeTag(mod) == .Float) { |
| 21000 | return sema.fail( | 21528 | return sema.fail( |
| 21001 | block, | 21529 | block, |
| 21002 | elem_ty_src, | 21530 | elem_ty_src, |
| 21003 | "expected bool, integer, enum, or pointer type; found '{}'", | 21531 | "expected bool, integer, enum, or pointer type; found '{}'", |
| 21004 | .{elem_ty.fmt(sema.mod)}, | 21532 | .{elem_ty.fmt(mod)}, |
| 21005 | ); | 21533 | ); |
| 21006 | } | 21534 | } |
| 21007 | const uncasted_ptr = try sema.resolveInst(extra.ptr); | 21535 | const uncasted_ptr = try sema.resolveInst(extra.ptr); |
| ... | @@ -21023,29 +21551,34 @@ fn zirCmpxchg( | ... | @@ -21023,29 +21551,34 @@ fn zirCmpxchg( |
| 21023 | return sema.fail(block, failure_order_src, "failure atomic ordering must not be Release or AcqRel", .{}); | 21551 | return sema.fail(block, failure_order_src, "failure atomic ordering must not be Release or AcqRel", .{}); |
| 21024 | } | 21552 | } |
| 21025 | 21553 | ||
| 21026 | const result_ty = try Type.optional(sema.arena, elem_ty); | 21554 | const result_ty = try Type.optional(sema.arena, elem_ty, mod); |
| 21027 | 21555 | ||
| 21028 | // special case zero bit types | 21556 | // special case zero bit types |
| 21029 | if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) { | 21557 | if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) { |
| 21030 | return sema.addConstant(result_ty, Value.null); | 21558 | return sema.addConstant(result_ty, (try mod.intern(.{ .opt = .{ |
| 21559 | .ty = result_ty.toIntern(), | ||
| 21560 | .val = .none, | ||
| 21561 | } })).toValue()); | ||
| 21031 | } | 21562 | } |
| 21032 | 21563 | ||
| 21033 | const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { | 21564 | const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { |
| 21034 | if (try sema.resolveMaybeUndefVal(expected_value)) |expected_val| { | 21565 | if (try sema.resolveMaybeUndefVal(expected_value)) |expected_val| { |
| 21035 | if (try sema.resolveMaybeUndefVal(new_value)) |new_val| { | 21566 | if (try sema.resolveMaybeUndefVal(new_value)) |new_val| { |
| 21036 | if (expected_val.isUndef() or new_val.isUndef()) { | 21567 | if (expected_val.isUndef(mod) or new_val.isUndef(mod)) { |
| 21037 | // TODO: this should probably cause the memory stored at the pointer | 21568 | // TODO: this should probably cause the memory stored at the pointer |
| 21038 | // to become undef as well | 21569 | // to become undef as well |
| 21039 | return sema.addConstUndef(result_ty); | 21570 | return sema.addConstUndef(result_ty); |
| 21040 | } | 21571 | } |
| 21041 | const ptr_ty = sema.typeOf(ptr); | 21572 | const ptr_ty = sema.typeOf(ptr); |
| 21042 | const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; | 21573 | const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; |
| 21043 | const result_val = if (stored_val.eql(expected_val, elem_ty, sema.mod)) blk: { | 21574 | const result_val = try mod.intern(.{ .opt = .{ |
| 21044 | try sema.storePtr(block, src, ptr, new_value); | 21575 | .ty = result_ty.toIntern(), |
| 21045 | break :blk Value.null; | 21576 | .val = if (stored_val.eql(expected_val, elem_ty, mod)) blk: { |
| 21046 | } else try Value.Tag.opt_payload.create(sema.arena, stored_val); | 21577 | try sema.storePtr(block, src, ptr, new_value); |
| 21047 | 21578 | break :blk .none; | |
| 21048 | return sema.addConstant(result_ty, result_val); | 21579 | } else stored_val.toIntern(), |
| 21580 | } }); | ||
| 21581 | return sema.addConstant(result_ty, result_val.toValue()); | ||
| 21049 | } else break :rs new_value_src; | 21582 | } else break :rs new_value_src; |
| 21050 | } else break :rs expected_src; | 21583 | } else break :rs expected_src; |
| 21051 | } else ptr_src; | 21584 | } else ptr_src; |
| ... | @@ -21069,6 +21602,7 @@ fn zirCmpxchg( | ... | @@ -21069,6 +21602,7 @@ fn zirCmpxchg( |
| 21069 | } | 21602 | } |
| 21070 | 21603 | ||
| 21071 | fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 21604 | fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 21605 | const mod = sema.mod; | ||
| 21072 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 21606 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 21073 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 21607 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 21074 | const len_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; | 21608 | const len_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| ... | @@ -21077,17 +21611,13 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I | ... | @@ -21077,17 +21611,13 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 21077 | const scalar = try sema.resolveInst(extra.rhs); | 21611 | const scalar = try sema.resolveInst(extra.rhs); |
| 21078 | const scalar_ty = sema.typeOf(scalar); | 21612 | const scalar_ty = sema.typeOf(scalar); |
| 21079 | try sema.checkVectorElemType(block, scalar_src, scalar_ty); | 21613 | try sema.checkVectorElemType(block, scalar_src, scalar_ty); |
| 21080 | const vector_ty = try Type.Tag.vector.create(sema.arena, .{ | 21614 | const vector_ty = try mod.vectorType(.{ |
| 21081 | .len = len, | 21615 | .len = len, |
| 21082 | .elem_type = scalar_ty, | 21616 | .child = scalar_ty.toIntern(), |
| 21083 | }); | 21617 | }); |
| 21084 | if (try sema.resolveMaybeUndefVal(scalar)) |scalar_val| { | 21618 | if (try sema.resolveMaybeUndefVal(scalar)) |scalar_val| { |
| 21085 | if (scalar_val.isUndef()) return sema.addConstUndef(vector_ty); | 21619 | if (scalar_val.isUndef(mod)) return sema.addConstUndef(vector_ty); |
| 21086 | 21620 | return sema.addConstant(vector_ty, try sema.splat(vector_ty, scalar_val)); | |
| 21087 | return sema.addConstant( | ||
| 21088 | vector_ty, | ||
| 21089 | try Value.Tag.repeated.create(sema.arena, scalar_val), | ||
| 21090 | ); | ||
| 21091 | } | 21621 | } |
| 21092 | 21622 | ||
| 21093 | try sema.requireRuntimeBlock(block, inst_data.src(), scalar_src); | 21623 | try sema.requireRuntimeBlock(block, inst_data.src(), scalar_src); |
| ... | @@ -21102,31 +21632,31 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -21102,31 +21632,31 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 21102 | const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", "@reduce operation must be comptime-known"); | 21632 | const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", "@reduce operation must be comptime-known"); |
| 21103 | const operand = try sema.resolveInst(extra.rhs); | 21633 | const operand = try sema.resolveInst(extra.rhs); |
| 21104 | const operand_ty = sema.typeOf(operand); | 21634 | const operand_ty = sema.typeOf(operand); |
| 21105 | const target = sema.mod.getTarget(); | 21635 | const mod = sema.mod; |
| 21106 | 21636 | ||
| 21107 | if (operand_ty.zigTypeTag() != .Vector) { | 21637 | if (operand_ty.zigTypeTag(mod) != .Vector) { |
| 21108 | return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(sema.mod)}); | 21638 | return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(mod)}); |
| 21109 | } | 21639 | } |
| 21110 | 21640 | ||
| 21111 | const scalar_ty = operand_ty.childType(); | 21641 | const scalar_ty = operand_ty.childType(mod); |
| 21112 | 21642 | ||
| 21113 | // Type-check depending on operation. | 21643 | // Type-check depending on operation. |
| 21114 | switch (operation) { | 21644 | switch (operation) { |
| 21115 | .And, .Or, .Xor => switch (scalar_ty.zigTypeTag()) { | 21645 | .And, .Or, .Xor => switch (scalar_ty.zigTypeTag(mod)) { |
| 21116 | .Int, .Bool => {}, | 21646 | .Int, .Bool => {}, |
| 21117 | else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{ | 21647 | else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{ |
| 21118 | @tagName(operation), operand_ty.fmt(sema.mod), | 21648 | @tagName(operation), operand_ty.fmt(mod), |
| 21119 | }), | 21649 | }), |
| 21120 | }, | 21650 | }, |
| 21121 | .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag()) { | 21651 | .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag(mod)) { |
| 21122 | .Int, .Float => {}, | 21652 | .Int, .Float => {}, |
| 21123 | else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{ | 21653 | else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{ |
| 21124 | @tagName(operation), operand_ty.fmt(sema.mod), | 21654 | @tagName(operation), operand_ty.fmt(mod), |
| 21125 | }), | 21655 | }), |
| 21126 | }, | 21656 | }, |
| 21127 | } | 21657 | } |
| 21128 | 21658 | ||
| 21129 | const vec_len = operand_ty.vectorLen(); | 21659 | const vec_len = operand_ty.vectorLen(mod); |
| 21130 | if (vec_len == 0) { | 21660 | if (vec_len == 0) { |
| 21131 | // TODO re-evaluate if we should introduce a "neutral value" for some operations, | 21661 | // TODO re-evaluate if we should introduce a "neutral value" for some operations, |
| 21132 | // e.g. zero for add and one for mul. | 21662 | // e.g. zero for add and one for mul. |
| ... | @@ -21134,21 +21664,20 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -21134,21 +21664,20 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 21134 | } | 21664 | } |
| 21135 | 21665 | ||
| 21136 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { | 21666 | if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { |
| 21137 | if (operand_val.isUndef()) return sema.addConstUndef(scalar_ty); | 21667 | if (operand_val.isUndef(mod)) return sema.addConstUndef(scalar_ty); |
| 21138 | 21668 | ||
| 21139 | var accum: Value = try operand_val.elemValue(sema.mod, sema.arena, 0); | 21669 | var accum: Value = try operand_val.elemValue(mod, 0); |
| 21140 | var elem_buf: Value.ElemValueBuffer = undefined; | ||
| 21141 | var i: u32 = 1; | 21670 | var i: u32 = 1; |
| 21142 | while (i < vec_len) : (i += 1) { | 21671 | while (i < vec_len) : (i += 1) { |
| 21143 | const elem_val = operand_val.elemValueBuffer(sema.mod, i, &elem_buf); | 21672 | const elem_val = try operand_val.elemValue(mod, i); |
| 21144 | switch (operation) { | 21673 | switch (operation) { |
| 21145 | .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, sema.mod), | 21674 | .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, mod), |
| 21146 | .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, sema.mod), | 21675 | .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, mod), |
| 21147 | .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, sema.mod), | 21676 | .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, mod), |
| 21148 | .Min => accum = accum.numberMin(elem_val, target), | 21677 | .Min => accum = accum.numberMin(elem_val, mod), |
| 21149 | .Max => accum = accum.numberMax(elem_val, target), | 21678 | .Max => accum = accum.numberMax(elem_val, mod), |
| 21150 | .Add => accum = try sema.numberAddWrapScalar(accum, elem_val, scalar_ty), | 21679 | .Add => accum = try sema.numberAddWrapScalar(accum, elem_val, scalar_ty), |
| 21151 | .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, sema.mod), | 21680 | .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, mod), |
| 21152 | } | 21681 | } |
| 21153 | } | 21682 | } |
| 21154 | return sema.addConstant(scalar_ty, accum); | 21683 | return sema.addConstant(scalar_ty, accum); |
| ... | @@ -21165,6 +21694,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -21165,6 +21694,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 21165 | } | 21694 | } |
| 21166 | 21695 | ||
| 21167 | fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 21696 | fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 21697 | const mod = sema.mod; | ||
| 21168 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 21698 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 21169 | const extra = sema.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data; | 21699 | const extra = sema.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data; |
| 21170 | const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 21700 | const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| ... | @@ -21177,13 +21707,13 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -21177,13 +21707,13 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 21177 | var mask = try sema.resolveInst(extra.mask); | 21707 | var mask = try sema.resolveInst(extra.mask); |
| 21178 | var mask_ty = sema.typeOf(mask); | 21708 | var mask_ty = sema.typeOf(mask); |
| 21179 | 21709 | ||
| 21180 | const mask_len = switch (sema.typeOf(mask).zigTypeTag()) { | 21710 | const mask_len = switch (sema.typeOf(mask).zigTypeTag(mod)) { |
| 21181 | .Array, .Vector => sema.typeOf(mask).arrayLen(), | 21711 | .Array, .Vector => sema.typeOf(mask).arrayLen(mod), |
| 21182 | else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(sema.mod)}), | 21712 | else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(sema.mod)}), |
| 21183 | }; | 21713 | }; |
| 21184 | mask_ty = try Type.Tag.vector.create(sema.arena, .{ | 21714 | mask_ty = try mod.vectorType(.{ |
| 21185 | .len = mask_len, | 21715 | .len = @intCast(u32, mask_len), |
| 21186 | .elem_type = Type.i32, | 21716 | .child = .i32_type, |
| 21187 | }); | 21717 | }); |
| 21188 | mask = try sema.coerce(block, mask_ty, mask, mask_src); | 21718 | mask = try sema.coerce(block, mask_ty, mask, mask_src); |
| 21189 | const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask, "shuffle mask must be comptime-known"); | 21719 | const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask, "shuffle mask must be comptime-known"); |
| ... | @@ -21200,27 +21730,28 @@ fn analyzeShuffle( | ... | @@ -21200,27 +21730,28 @@ fn analyzeShuffle( |
| 21200 | mask: Value, | 21730 | mask: Value, |
| 21201 | mask_len: u32, | 21731 | mask_len: u32, |
| 21202 | ) CompileError!Air.Inst.Ref { | 21732 | ) CompileError!Air.Inst.Ref { |
| 21733 | const mod = sema.mod; | ||
| 21203 | const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = src_node }; | 21734 | const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = src_node }; |
| 21204 | const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = src_node }; | 21735 | const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = src_node }; |
| 21205 | const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = src_node }; | 21736 | const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = src_node }; |
| 21206 | var a = a_arg; | 21737 | var a = a_arg; |
| 21207 | var b = b_arg; | 21738 | var b = b_arg; |
| 21208 | 21739 | ||
| 21209 | const res_ty = try Type.Tag.vector.create(sema.arena, .{ | 21740 | const res_ty = try mod.vectorType(.{ |
| 21210 | .len = mask_len, | 21741 | .len = mask_len, |
| 21211 | .elem_type = elem_ty, | 21742 | .child = elem_ty.toIntern(), |
| 21212 | }); | 21743 | }); |
| 21213 | 21744 | ||
| 21214 | var maybe_a_len = switch (sema.typeOf(a).zigTypeTag()) { | 21745 | var maybe_a_len = switch (sema.typeOf(a).zigTypeTag(mod)) { |
| 21215 | .Array, .Vector => sema.typeOf(a).arrayLen(), | 21746 | .Array, .Vector => sema.typeOf(a).arrayLen(mod), |
| 21216 | .Undefined => null, | 21747 | .Undefined => null, |
| 21217 | else => return sema.fail(block, a_src, "expected vector or array with element type '{}', found '{}'", .{ | 21748 | else => return sema.fail(block, a_src, "expected vector or array with element type '{}', found '{}'", .{ |
| 21218 | elem_ty.fmt(sema.mod), | 21749 | elem_ty.fmt(sema.mod), |
| 21219 | sema.typeOf(a).fmt(sema.mod), | 21750 | sema.typeOf(a).fmt(sema.mod), |
| 21220 | }), | 21751 | }), |
| 21221 | }; | 21752 | }; |
| 21222 | var maybe_b_len = switch (sema.typeOf(b).zigTypeTag()) { | 21753 | var maybe_b_len = switch (sema.typeOf(b).zigTypeTag(mod)) { |
| 21223 | .Array, .Vector => sema.typeOf(b).arrayLen(), | 21754 | .Array, .Vector => sema.typeOf(b).arrayLen(mod), |
| 21224 | .Undefined => null, | 21755 | .Undefined => null, |
| 21225 | else => return sema.fail(block, b_src, "expected vector or array with element type '{}', found '{}'", .{ | 21756 | else => return sema.fail(block, b_src, "expected vector or array with element type '{}', found '{}'", .{ |
| 21226 | elem_ty.fmt(sema.mod), | 21757 | elem_ty.fmt(sema.mod), |
| ... | @@ -21230,16 +21761,16 @@ fn analyzeShuffle( | ... | @@ -21230,16 +21761,16 @@ fn analyzeShuffle( |
| 21230 | if (maybe_a_len == null and maybe_b_len == null) { | 21761 | if (maybe_a_len == null and maybe_b_len == null) { |
| 21231 | return sema.addConstUndef(res_ty); | 21762 | return sema.addConstUndef(res_ty); |
| 21232 | } | 21763 | } |
| 21233 | const a_len = maybe_a_len orelse maybe_b_len.?; | 21764 | const a_len = @intCast(u32, maybe_a_len orelse maybe_b_len.?); |
| 21234 | const b_len = maybe_b_len orelse a_len; | 21765 | const b_len = @intCast(u32, maybe_b_len orelse a_len); |
| 21235 | 21766 | ||
| 21236 | const a_ty = try Type.Tag.vector.create(sema.arena, .{ | 21767 | const a_ty = try mod.vectorType(.{ |
| 21237 | .len = a_len, | 21768 | .len = a_len, |
| 21238 | .elem_type = elem_ty, | 21769 | .child = elem_ty.toIntern(), |
| 21239 | }); | 21770 | }); |
| 21240 | const b_ty = try Type.Tag.vector.create(sema.arena, .{ | 21771 | const b_ty = try mod.vectorType(.{ |
| 21241 | .len = b_len, | 21772 | .len = b_len, |
| 21242 | .elem_type = elem_ty, | 21773 | .child = elem_ty.toIntern(), |
| 21243 | }); | 21774 | }); |
| 21244 | 21775 | ||
| 21245 | if (maybe_a_len == null) a = try sema.addConstUndef(a_ty) else a = try sema.coerce(block, a_ty, a, a_src); | 21776 | if (maybe_a_len == null) a = try sema.addConstUndef(a_ty) else a = try sema.coerce(block, a_ty, a, a_src); |
| ... | @@ -21250,12 +21781,10 @@ fn analyzeShuffle( | ... | @@ -21250,12 +21781,10 @@ fn analyzeShuffle( |
| 21250 | .{ b_len, b_src, b_ty }, | 21781 | .{ b_len, b_src, b_ty }, |
| 21251 | }; | 21782 | }; |
| 21252 | 21783 | ||
| 21253 | var i: usize = 0; | 21784 | for (0..@intCast(usize, mask_len)) |i| { |
| 21254 | while (i < mask_len) : (i += 1) { | 21785 | const elem = try mask.elemValue(sema.mod, i); |
| 21255 | var buf: Value.ElemValueBuffer = undefined; | 21786 | if (elem.isUndef(mod)) continue; |
| 21256 | const elem = mask.elemValueBuffer(sema.mod, i, &buf); | 21787 | const int = elem.toSignedInt(mod); |
| 21257 | if (elem.isUndef()) continue; | ||
| 21258 | const int = elem.toSignedInt(sema.mod.getTarget()); | ||
| 21259 | var unsigned: u32 = undefined; | 21788 | var unsigned: u32 = undefined; |
| 21260 | var chosen: u32 = undefined; | 21789 | var chosen: u32 = undefined; |
| 21261 | if (int >= 0) { | 21790 | if (int >= 0) { |
| ... | @@ -21287,26 +21816,21 @@ fn analyzeShuffle( | ... | @@ -21287,26 +21816,21 @@ fn analyzeShuffle( |
| 21287 | 21816 | ||
| 21288 | if (try sema.resolveMaybeUndefVal(a)) |a_val| { | 21817 | if (try sema.resolveMaybeUndefVal(a)) |a_val| { |
| 21289 | if (try sema.resolveMaybeUndefVal(b)) |b_val| { | 21818 | if (try sema.resolveMaybeUndefVal(b)) |b_val| { |
| 21290 | const values = try sema.arena.alloc(Value, mask_len); | 21819 | const values = try sema.arena.alloc(InternPool.Index, mask_len); |
| 21291 | 21820 | for (values, 0..) |*value, i| { | |
| 21292 | i = 0; | 21821 | const mask_elem_val = try mask.elemValue(sema.mod, i); |
| 21293 | while (i < mask_len) : (i += 1) { | 21822 | if (mask_elem_val.isUndef(mod)) { |
| 21294 | var buf: Value.ElemValueBuffer = undefined; | 21823 | value.* = try mod.intern(.{ .undef = elem_ty.toIntern() }); |
| 21295 | const mask_elem_val = mask.elemValueBuffer(sema.mod, i, &buf); | ||
| 21296 | if (mask_elem_val.isUndef()) { | ||
| 21297 | values[i] = Value.undef; | ||
| 21298 | continue; | 21824 | continue; |
| 21299 | } | 21825 | } |
| 21300 | const int = mask_elem_val.toSignedInt(sema.mod.getTarget()); | 21826 | const int = mask_elem_val.toSignedInt(mod); |
| 21301 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int); | 21827 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int); |
| 21302 | if (int >= 0) { | 21828 | values[i] = try (try (if (int >= 0) a_val else b_val).elemValue(mod, unsigned)).intern(elem_ty, mod); |
| 21303 | values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned); | ||
| 21304 | } else { | ||
| 21305 | values[i] = try b_val.elemValue(sema.mod, sema.arena, unsigned); | ||
| 21306 | } | ||
| 21307 | } | 21829 | } |
| 21308 | const res_val = try Value.Tag.aggregate.create(sema.arena, values); | 21830 | return sema.addConstant(res_ty, (try mod.intern(.{ .aggregate = .{ |
| 21309 | return sema.addConstant(res_ty, res_val); | 21831 | .ty = res_ty.toIntern(), |
| 21832 | .storage = .{ .elems = values }, | ||
| 21833 | } })).toValue()); | ||
| 21310 | } | 21834 | } |
| 21311 | } | 21835 | } |
| 21312 | 21836 | ||
| ... | @@ -21320,27 +21844,27 @@ fn analyzeShuffle( | ... | @@ -21320,27 +21844,27 @@ fn analyzeShuffle( |
| 21320 | const max_src = if (a_len > b_len) a_src else b_src; | 21844 | const max_src = if (a_len > b_len) a_src else b_src; |
| 21321 | const max_len = try sema.usizeCast(block, max_src, std.math.max(a_len, b_len)); | 21845 | const max_len = try sema.usizeCast(block, max_src, std.math.max(a_len, b_len)); |
| 21322 | 21846 | ||
| 21323 | const expand_mask_values = try sema.arena.alloc(Value, max_len); | 21847 | const expand_mask_values = try sema.arena.alloc(InternPool.Index, max_len); |
| 21324 | i = 0; | 21848 | for (@intCast(usize, 0)..@intCast(usize, min_len)) |i| { |
| 21325 | while (i < min_len) : (i += 1) { | 21849 | expand_mask_values[i] = (try mod.intValue(Type.comptime_int, i)).toIntern(); |
| 21326 | expand_mask_values[i] = try Value.Tag.int_u64.create(sema.arena, i); | ||
| 21327 | } | 21850 | } |
| 21328 | while (i < max_len) : (i += 1) { | 21851 | for (@intCast(usize, min_len)..@intCast(usize, max_len)) |i| { |
| 21329 | expand_mask_values[i] = Value.negative_one; | 21852 | expand_mask_values[i] = (try mod.intValue(Type.comptime_int, -1)).toIntern(); |
| 21330 | } | 21853 | } |
| 21331 | const expand_mask = try Value.Tag.aggregate.create(sema.arena, expand_mask_values); | 21854 | const expand_mask = try mod.intern(.{ .aggregate = .{ |
| 21855 | .ty = (try mod.vectorType(.{ .len = @intCast(u32, max_len), .child = .comptime_int_type })).toIntern(), | ||
| 21856 | .storage = .{ .elems = expand_mask_values }, | ||
| 21857 | } }); | ||
| 21332 | 21858 | ||
| 21333 | if (a_len < b_len) { | 21859 | if (a_len < b_len) { |
| 21334 | const undef = try sema.addConstUndef(a_ty); | 21860 | const undef = try sema.addConstUndef(a_ty); |
| 21335 | a = try sema.analyzeShuffle(block, src_node, elem_ty, a, undef, expand_mask, @intCast(u32, max_len)); | 21861 | a = try sema.analyzeShuffle(block, src_node, elem_ty, a, undef, expand_mask.toValue(), @intCast(u32, max_len)); |
| 21336 | } else { | 21862 | } else { |
| 21337 | const undef = try sema.addConstUndef(b_ty); | 21863 | const undef = try sema.addConstUndef(b_ty); |
| 21338 | b = try sema.analyzeShuffle(block, src_node, elem_ty, b, undef, expand_mask, @intCast(u32, max_len)); | 21864 | b = try sema.analyzeShuffle(block, src_node, elem_ty, b, undef, expand_mask.toValue(), @intCast(u32, max_len)); |
| 21339 | } | 21865 | } |
| 21340 | } | 21866 | } |
| 21341 | 21867 | ||
| 21342 | const mask_index = @intCast(u32, sema.air_values.items.len); | ||
| 21343 | try sema.air_values.append(sema.gpa, mask); | ||
| 21344 | return block.addInst(.{ | 21868 | return block.addInst(.{ |
| 21345 | .tag = .shuffle, | 21869 | .tag = .shuffle, |
| 21346 | .data = .{ .ty_pl = .{ | 21870 | .data = .{ .ty_pl = .{ |
| ... | @@ -21348,7 +21872,7 @@ fn analyzeShuffle( | ... | @@ -21348,7 +21872,7 @@ fn analyzeShuffle( |
| 21348 | .payload = try block.sema.addExtra(Air.Shuffle{ | 21872 | .payload = try block.sema.addExtra(Air.Shuffle{ |
| 21349 | .a = a, | 21873 | .a = a, |
| 21350 | .b = b, | 21874 | .b = b, |
| 21351 | .mask = mask_index, | 21875 | .mask = mask.toIntern(), |
| 21352 | .mask_len = mask_len, | 21876 | .mask_len = mask_len, |
| 21353 | }), | 21877 | }), |
| 21354 | } }, | 21878 | } }, |
| ... | @@ -21356,6 +21880,7 @@ fn analyzeShuffle( | ... | @@ -21356,6 +21880,7 @@ fn analyzeShuffle( |
| 21356 | } | 21880 | } |
| 21357 | 21881 | ||
| 21358 | fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | 21882 | fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| 21883 | const mod = sema.mod; | ||
| 21359 | const extra = sema.code.extraData(Zir.Inst.Select, extended.operand).data; | 21884 | const extra = sema.code.extraData(Zir.Inst.Select, extended.operand).data; |
| 21360 | 21885 | ||
| 21361 | const src = LazySrcLoc.nodeOffset(extra.node); | 21886 | const src = LazySrcLoc.nodeOffset(extra.node); |
| ... | @@ -21369,16 +21894,22 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C | ... | @@ -21369,16 +21894,22 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C |
| 21369 | const pred_uncoerced = try sema.resolveInst(extra.pred); | 21894 | const pred_uncoerced = try sema.resolveInst(extra.pred); |
| 21370 | const pred_ty = sema.typeOf(pred_uncoerced); | 21895 | const pred_ty = sema.typeOf(pred_uncoerced); |
| 21371 | 21896 | ||
| 21372 | const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison()) { | 21897 | const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison(mod)) { |
| 21373 | .Vector, .Array => pred_ty.arrayLen(), | 21898 | .Vector, .Array => pred_ty.arrayLen(mod), |
| 21374 | else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(sema.mod)}), | 21899 | else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(mod)}), |
| 21375 | }; | 21900 | }; |
| 21376 | const vec_len = try sema.usizeCast(block, pred_src, vec_len_u64); | 21901 | const vec_len = @intCast(u32, try sema.usizeCast(block, pred_src, vec_len_u64)); |
| 21377 | 21902 | ||
| 21378 | const bool_vec_ty = try Type.vector(sema.arena, vec_len, Type.bool); | 21903 | const bool_vec_ty = try mod.vectorType(.{ |
| 21904 | .len = vec_len, | ||
| 21905 | .child = .bool_type, | ||
| 21906 | }); | ||
| 21379 | const pred = try sema.coerce(block, bool_vec_ty, pred_uncoerced, pred_src); | 21907 | const pred = try sema.coerce(block, bool_vec_ty, pred_uncoerced, pred_src); |
| 21380 | 21908 | ||
| 21381 | const vec_ty = try Type.vector(sema.arena, vec_len, elem_ty); | 21909 | const vec_ty = try mod.vectorType(.{ |
| 21910 | .len = vec_len, | ||
| 21911 | .child = elem_ty.toIntern(), | ||
| 21912 | }); | ||
| 21382 | const a = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.a), a_src); | 21913 | const a = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.a), a_src); |
| 21383 | const b = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.b), b_src); | 21914 | const b = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.b), b_src); |
| 21384 | 21915 | ||
| ... | @@ -21387,45 +21918,40 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C | ... | @@ -21387,45 +21918,40 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C |
| 21387 | const maybe_b = try sema.resolveMaybeUndefVal(b); | 21918 | const maybe_b = try sema.resolveMaybeUndefVal(b); |
| 21388 | 21919 | ||
| 21389 | const runtime_src = if (maybe_pred) |pred_val| rs: { | 21920 | const runtime_src = if (maybe_pred) |pred_val| rs: { |
| 21390 | if (pred_val.isUndef()) return sema.addConstUndef(vec_ty); | 21921 | if (pred_val.isUndef(mod)) return sema.addConstUndef(vec_ty); |
| 21391 | 21922 | ||
| 21392 | if (maybe_a) |a_val| { | 21923 | if (maybe_a) |a_val| { |
| 21393 | if (a_val.isUndef()) return sema.addConstUndef(vec_ty); | 21924 | if (a_val.isUndef(mod)) return sema.addConstUndef(vec_ty); |
| 21394 | 21925 | ||
| 21395 | if (maybe_b) |b_val| { | 21926 | if (maybe_b) |b_val| { |
| 21396 | if (b_val.isUndef()) return sema.addConstUndef(vec_ty); | 21927 | if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty); |
| 21397 | 21928 | ||
| 21398 | var buf: Value.ElemValueBuffer = undefined; | 21929 | const elems = try sema.gpa.alloc(InternPool.Index, vec_len); |
| 21399 | const elems = try sema.gpa.alloc(Value, vec_len); | ||
| 21400 | for (elems, 0..) |*elem, i| { | 21930 | for (elems, 0..) |*elem, i| { |
| 21401 | const pred_elem_val = pred_val.elemValueBuffer(sema.mod, i, &buf); | 21931 | const pred_elem_val = try pred_val.elemValue(mod, i); |
| 21402 | const should_choose_a = pred_elem_val.toBool(); | 21932 | const should_choose_a = pred_elem_val.toBool(); |
| 21403 | if (should_choose_a) { | 21933 | elem.* = try (try (if (should_choose_a) a_val else b_val).elemValue(mod, i)).intern(elem_ty, mod); |
| 21404 | elem.* = a_val.elemValueBuffer(sema.mod, i, &buf); | ||
| 21405 | } else { | ||
| 21406 | elem.* = b_val.elemValueBuffer(sema.mod, i, &buf); | ||
| 21407 | } | ||
| 21408 | } | 21934 | } |
| 21409 | 21935 | ||
| 21410 | return sema.addConstant( | 21936 | return sema.addConstant(vec_ty, (try mod.intern(.{ .aggregate = .{ |
| 21411 | vec_ty, | 21937 | .ty = vec_ty.toIntern(), |
| 21412 | try Value.Tag.aggregate.create(sema.arena, elems), | 21938 | .storage = .{ .elems = elems }, |
| 21413 | ); | 21939 | } })).toValue()); |
| 21414 | } else { | 21940 | } else { |
| 21415 | break :rs b_src; | 21941 | break :rs b_src; |
| 21416 | } | 21942 | } |
| 21417 | } else { | 21943 | } else { |
| 21418 | if (maybe_b) |b_val| { | 21944 | if (maybe_b) |b_val| { |
| 21419 | if (b_val.isUndef()) return sema.addConstUndef(vec_ty); | 21945 | if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty); |
| 21420 | } | 21946 | } |
| 21421 | break :rs a_src; | 21947 | break :rs a_src; |
| 21422 | } | 21948 | } |
| 21423 | } else rs: { | 21949 | } else rs: { |
| 21424 | if (maybe_a) |a_val| { | 21950 | if (maybe_a) |a_val| { |
| 21425 | if (a_val.isUndef()) return sema.addConstUndef(vec_ty); | 21951 | if (a_val.isUndef(mod)) return sema.addConstUndef(vec_ty); |
| 21426 | } | 21952 | } |
| 21427 | if (maybe_b) |b_val| { | 21953 | if (maybe_b) |b_val| { |
| 21428 | if (b_val.isUndef()) return sema.addConstUndef(vec_ty); | 21954 | if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty); |
| 21429 | } | 21955 | } |
| 21430 | break :rs pred_src; | 21956 | break :rs pred_src; |
| 21431 | }; | 21957 | }; |
| ... | @@ -21489,6 +22015,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -21489,6 +22015,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 21489 | } | 22015 | } |
| 21490 | 22016 | ||
| 21491 | fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 22017 | fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 22018 | const mod = sema.mod; | ||
| 21492 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 22019 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 21493 | const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data; | 22020 | const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data; |
| 21494 | const src = inst_data.src(); | 22021 | const src = inst_data.src(); |
| ... | @@ -21505,7 +22032,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -21505,7 +22032,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 21505 | const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); | 22032 | const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false); |
| 21506 | const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation); | 22033 | const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation); |
| 21507 | 22034 | ||
| 21508 | switch (elem_ty.zigTypeTag()) { | 22035 | switch (elem_ty.zigTypeTag(mod)) { |
| 21509 | .Enum => if (op != .Xchg) { | 22036 | .Enum => if (op != .Xchg) { |
| 21510 | return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{}); | 22037 | return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{}); |
| 21511 | }, | 22038 | }, |
| ... | @@ -21535,8 +22062,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -21535,8 +22062,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 21535 | try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); | 22062 | try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); |
| 21536 | break :rs operand_src; | 22063 | break :rs operand_src; |
| 21537 | }; | 22064 | }; |
| 21538 | if (ptr_val.isComptimeMutablePtr()) { | 22065 | if (ptr_val.isComptimeMutablePtr(mod)) { |
| 21539 | const target = sema.mod.getTarget(); | ||
| 21540 | const ptr_ty = sema.typeOf(ptr); | 22066 | const ptr_ty = sema.typeOf(ptr); |
| 21541 | const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; | 22067 | const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; |
| 21542 | const new_val = switch (op) { | 22068 | const new_val = switch (op) { |
| ... | @@ -21544,12 +22070,12 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -21544,12 +22070,12 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 21544 | .Xchg => operand_val, | 22070 | .Xchg => operand_val, |
| 21545 | .Add => try sema.numberAddWrapScalar(stored_val, operand_val, elem_ty), | 22071 | .Add => try sema.numberAddWrapScalar(stored_val, operand_val, elem_ty), |
| 21546 | .Sub => try sema.numberSubWrapScalar(stored_val, operand_val, elem_ty), | 22072 | .Sub => try sema.numberSubWrapScalar(stored_val, operand_val, elem_ty), |
| 21547 | .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, sema.mod), | 22073 | .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, mod), |
| 21548 | .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, sema.mod), | 22074 | .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, mod), |
| 21549 | .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, sema.mod), | 22075 | .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, mod), |
| 21550 | .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, sema.mod), | 22076 | .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, mod), |
| 21551 | .Max => stored_val.numberMax (operand_val, target), | 22077 | .Max => stored_val.numberMax (operand_val, mod), |
| 21552 | .Min => stored_val.numberMin (operand_val, target), | 22078 | .Min => stored_val.numberMin (operand_val, mod), |
| 21553 | // zig fmt: on | 22079 | // zig fmt: on |
| 21554 | }; | 22080 | }; |
| 21555 | try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty); | 22081 | try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty); |
| ... | @@ -21623,18 +22149,19 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -21623,18 +22149,19 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 21623 | const maybe_mulend1 = try sema.resolveMaybeUndefVal(mulend1); | 22149 | const maybe_mulend1 = try sema.resolveMaybeUndefVal(mulend1); |
| 21624 | const maybe_mulend2 = try sema.resolveMaybeUndefVal(mulend2); | 22150 | const maybe_mulend2 = try sema.resolveMaybeUndefVal(mulend2); |
| 21625 | const maybe_addend = try sema.resolveMaybeUndefVal(addend); | 22151 | const maybe_addend = try sema.resolveMaybeUndefVal(addend); |
| 22152 | const mod = sema.mod; | ||
| 21626 | 22153 | ||
| 21627 | switch (ty.zigTypeTag()) { | 22154 | switch (ty.zigTypeTag(mod)) { |
| 21628 | .ComptimeFloat, .Float, .Vector => {}, | 22155 | .ComptimeFloat, .Float, .Vector => {}, |
| 21629 | else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(sema.mod)}), | 22156 | else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(sema.mod)}), |
| 21630 | } | 22157 | } |
| 21631 | 22158 | ||
| 21632 | const runtime_src = if (maybe_mulend1) |mulend1_val| rs: { | 22159 | const runtime_src = if (maybe_mulend1) |mulend1_val| rs: { |
| 21633 | if (maybe_mulend2) |mulend2_val| { | 22160 | if (maybe_mulend2) |mulend2_val| { |
| 21634 | if (mulend2_val.isUndef()) return sema.addConstUndef(ty); | 22161 | if (mulend2_val.isUndef(mod)) return sema.addConstUndef(ty); |
| 21635 | 22162 | ||
| 21636 | if (maybe_addend) |addend_val| { | 22163 | if (maybe_addend) |addend_val| { |
| 21637 | if (addend_val.isUndef()) return sema.addConstUndef(ty); | 22164 | if (addend_val.isUndef(mod)) return sema.addConstUndef(ty); |
| 21638 | const result_val = try Value.mulAdd(ty, mulend1_val, mulend2_val, addend_val, sema.arena, sema.mod); | 22165 | const result_val = try Value.mulAdd(ty, mulend1_val, mulend2_val, addend_val, sema.arena, sema.mod); |
| 21639 | return sema.addConstant(ty, result_val); | 22166 | return sema.addConstant(ty, result_val); |
| 21640 | } else { | 22167 | } else { |
| ... | @@ -21642,16 +22169,16 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -21642,16 +22169,16 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 21642 | } | 22169 | } |
| 21643 | } else { | 22170 | } else { |
| 21644 | if (maybe_addend) |addend_val| { | 22171 | if (maybe_addend) |addend_val| { |
| 21645 | if (addend_val.isUndef()) return sema.addConstUndef(ty); | 22172 | if (addend_val.isUndef(mod)) return sema.addConstUndef(ty); |
| 21646 | } | 22173 | } |
| 21647 | break :rs mulend2_src; | 22174 | break :rs mulend2_src; |
| 21648 | } | 22175 | } |
| 21649 | } else rs: { | 22176 | } else rs: { |
| 21650 | if (maybe_mulend2) |mulend2_val| { | 22177 | if (maybe_mulend2) |mulend2_val| { |
| 21651 | if (mulend2_val.isUndef()) return sema.addConstUndef(ty); | 22178 | if (mulend2_val.isUndef(mod)) return sema.addConstUndef(ty); |
| 21652 | } | 22179 | } |
| 21653 | if (maybe_addend) |addend_val| { | 22180 | if (maybe_addend) |addend_val| { |
| 21654 | if (addend_val.isUndef()) return sema.addConstUndef(ty); | 22181 | if (addend_val.isUndef(mod)) return sema.addConstUndef(ty); |
| 21655 | } | 22182 | } |
| 21656 | break :rs mulend1_src; | 22183 | break :rs mulend1_src; |
| 21657 | }; | 22184 | }; |
| ... | @@ -21673,6 +22200,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -21673,6 +22200,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 21673 | const tracy = trace(@src()); | 22200 | const tracy = trace(@src()); |
| 21674 | defer tracy.end(); | 22201 | defer tracy.end(); |
| 21675 | 22202 | ||
| 22203 | const mod = sema.mod; | ||
| 21676 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 22204 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 21677 | const modifier_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 22205 | const modifier_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 21678 | const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; | 22206 | const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; |
| ... | @@ -21686,7 +22214,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -21686,7 +22214,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 21686 | const air_ref = try sema.resolveInst(extra.modifier); | 22214 | const air_ref = try sema.resolveInst(extra.modifier); |
| 21687 | const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src); | 22215 | const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src); |
| 21688 | const modifier_val = try sema.resolveConstValue(block, modifier_src, modifier_ref, "call modifier must be comptime-known"); | 22216 | const modifier_val = try sema.resolveConstValue(block, modifier_src, modifier_ref, "call modifier must be comptime-known"); |
| 21689 | var modifier = modifier_val.toEnum(std.builtin.CallModifier); | 22217 | var modifier = mod.toEnum(std.builtin.CallModifier, modifier_val); |
| 21690 | switch (modifier) { | 22218 | switch (modifier) { |
| 21691 | // These can be upgraded to comptime or nosuspend calls. | 22219 | // These can be upgraded to comptime or nosuspend calls. |
| 21692 | .auto, .never_tail, .no_async => { | 22220 | .auto, .never_tail, .no_async => { |
| ... | @@ -21732,18 +22260,17 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -21732,18 +22260,17 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 21732 | const args = try sema.resolveInst(extra.args); | 22260 | const args = try sema.resolveInst(extra.args); |
| 21733 | 22261 | ||
| 21734 | const args_ty = sema.typeOf(args); | 22262 | const args_ty = sema.typeOf(args); |
| 21735 | if (!args_ty.isTuple() and args_ty.tag() != .empty_struct_literal) { | 22263 | if (!args_ty.isTuple(mod) and args_ty.toIntern() != .empty_struct_type) { |
| 21736 | return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)}); | 22264 | return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)}); |
| 21737 | } | 22265 | } |
| 21738 | 22266 | ||
| 21739 | var resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount()); | 22267 | var resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount(mod)); |
| 21740 | for (resolved_args, 0..) |*resolved, i| { | 22268 | for (resolved_args, 0..) |*resolved, i| { |
| 21741 | resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); | 22269 | resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty); |
| 21742 | } | 22270 | } |
| 21743 | 22271 | ||
| 21744 | const callee_ty = sema.typeOf(func); | 22272 | const callee_ty = sema.typeOf(func); |
| 21745 | const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false); | 22273 | const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false); |
| 21746 | |||
| 21747 | const ensure_result_used = extra.flags.ensure_result_used; | 22274 | const ensure_result_used = extra.flags.ensure_result_used; |
| 21748 | return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null); | 22275 | return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null); |
| 21749 | } | 22276 | } |
| ... | @@ -21757,19 +22284,21 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -21757,19 +22284,21 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 21757 | const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; | 22284 | const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; |
| 21758 | 22285 | ||
| 21759 | const parent_ty = try sema.resolveType(block, ty_src, extra.parent_type); | 22286 | const parent_ty = try sema.resolveType(block, ty_src, extra.parent_type); |
| 21760 | const field_name = try sema.resolveConstString(block, name_src, extra.field_name, "field name must be comptime-known"); | 22287 | const field_name = try sema.resolveConstStringIntern(block, name_src, extra.field_name, "field name must be comptime-known"); |
| 21761 | const field_ptr = try sema.resolveInst(extra.field_ptr); | 22288 | const field_ptr = try sema.resolveInst(extra.field_ptr); |
| 21762 | const field_ptr_ty = sema.typeOf(field_ptr); | 22289 | const field_ptr_ty = sema.typeOf(field_ptr); |
| 22290 | const mod = sema.mod; | ||
| 22291 | const ip = &mod.intern_pool; | ||
| 21763 | 22292 | ||
| 21764 | if (parent_ty.zigTypeTag() != .Struct and parent_ty.zigTypeTag() != .Union) { | 22293 | if (parent_ty.zigTypeTag(mod) != .Struct and parent_ty.zigTypeTag(mod) != .Union) { |
| 21765 | return sema.fail(block, ty_src, "expected struct or union type, found '{}'", .{parent_ty.fmt(sema.mod)}); | 22294 | return sema.fail(block, ty_src, "expected struct or union type, found '{}'", .{parent_ty.fmt(sema.mod)}); |
| 21766 | } | 22295 | } |
| 21767 | try sema.resolveTypeLayout(parent_ty); | 22296 | try sema.resolveTypeLayout(parent_ty); |
| 21768 | 22297 | ||
| 21769 | const field_index = switch (parent_ty.zigTypeTag()) { | 22298 | const field_index = switch (parent_ty.zigTypeTag(mod)) { |
| 21770 | .Struct => blk: { | 22299 | .Struct => blk: { |
| 21771 | if (parent_ty.isTuple()) { | 22300 | if (parent_ty.isTuple(mod)) { |
| 21772 | if (mem.eql(u8, field_name, "len")) { | 22301 | if (ip.stringEqlSlice(field_name, "len")) { |
| 21773 | return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{}); | 22302 | return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{}); |
| 21774 | } | 22303 | } |
| 21775 | break :blk try sema.tupleFieldIndex(block, parent_ty, field_name, name_src); | 22304 | break :blk try sema.tupleFieldIndex(block, parent_ty, field_name, name_src); |
| ... | @@ -21781,27 +22310,27 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -21781,27 +22310,27 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 21781 | else => unreachable, | 22310 | else => unreachable, |
| 21782 | }; | 22311 | }; |
| 21783 | 22312 | ||
| 21784 | if (parent_ty.zigTypeTag() == .Struct and parent_ty.structFieldIsComptime(field_index)) { | 22313 | if (parent_ty.zigTypeTag(mod) == .Struct and parent_ty.structFieldIsComptime(field_index, mod)) { |
| 21785 | return sema.fail(block, src, "cannot get @fieldParentPtr of a comptime field", .{}); | 22314 | return sema.fail(block, src, "cannot get @fieldParentPtr of a comptime field", .{}); |
| 21786 | } | 22315 | } |
| 21787 | 22316 | ||
| 21788 | try sema.checkPtrOperand(block, ptr_src, field_ptr_ty); | 22317 | try sema.checkPtrOperand(block, ptr_src, field_ptr_ty); |
| 21789 | const field_ptr_ty_info = field_ptr_ty.ptrInfo().data; | 22318 | const field_ptr_ty_info = field_ptr_ty.ptrInfo(mod); |
| 21790 | 22319 | ||
| 21791 | var ptr_ty_data: Type.Payload.Pointer.Data = .{ | 22320 | var ptr_ty_data: Type.Payload.Pointer.Data = .{ |
| 21792 | .pointee_type = parent_ty.structFieldType(field_index), | 22321 | .pointee_type = parent_ty.structFieldType(field_index, mod), |
| 21793 | .mutable = field_ptr_ty_info.mutable, | 22322 | .mutable = field_ptr_ty_info.mutable, |
| 21794 | .@"addrspace" = field_ptr_ty_info.@"addrspace", | 22323 | .@"addrspace" = field_ptr_ty_info.@"addrspace", |
| 21795 | }; | 22324 | }; |
| 21796 | 22325 | ||
| 21797 | if (parent_ty.containerLayout() == .Packed) { | 22326 | if (parent_ty.containerLayout(mod) == .Packed) { |
| 21798 | return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{}); | 22327 | return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{}); |
| 21799 | } else { | 22328 | } else { |
| 21800 | ptr_ty_data.@"align" = blk: { | 22329 | ptr_ty_data.@"align" = blk: { |
| 21801 | if (parent_ty.castTag(.@"struct")) |struct_obj| { | 22330 | if (mod.typeToStruct(parent_ty)) |struct_obj| { |
| 21802 | break :blk struct_obj.data.fields.values()[field_index].abi_align; | 22331 | break :blk struct_obj.fields.values()[field_index].abi_align; |
| 21803 | } else if (parent_ty.cast(Type.Payload.Union)) |union_obj| { | 22332 | } else if (mod.typeToUnion(parent_ty)) |union_obj| { |
| 21804 | break :blk union_obj.data.fields.values()[field_index].abi_align; | 22333 | break :blk union_obj.fields.values()[field_index].abi_align; |
| 21805 | } else { | 22334 | } else { |
| 21806 | break :blk 0; | 22335 | break :blk 0; |
| 21807 | } | 22336 | } |
| ... | @@ -21815,19 +22344,24 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -21815,19 +22344,24 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 21815 | const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); | 22344 | const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); |
| 21816 | 22345 | ||
| 21817 | if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| { | 22346 | if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| { |
| 21818 | const payload = field_ptr_val.castTag(.field_ptr) orelse { | 22347 | const field = switch (ip.indexToKey(field_ptr_val.toIntern())) { |
| 21819 | return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{}); | 22348 | .ptr => |ptr| switch (ptr.addr) { |
| 21820 | }; | 22349 | .field => |field| field, |
| 21821 | if (payload.data.field_index != field_index) { | 22350 | else => null, |
| 22351 | }, | ||
| 22352 | else => null, | ||
| 22353 | } orelse return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{}); | ||
| 22354 | |||
| 22355 | if (field.index != field_index) { | ||
| 21822 | const msg = msg: { | 22356 | const msg = msg: { |
| 21823 | const msg = try sema.errMsg( | 22357 | const msg = try sema.errMsg( |
| 21824 | block, | 22358 | block, |
| 21825 | src, | 22359 | src, |
| 21826 | "field '{s}' has index '{d}' but pointer value is index '{d}' of struct '{}'", | 22360 | "field '{}' has index '{d}' but pointer value is index '{d}' of struct '{}'", |
| 21827 | .{ | 22361 | .{ |
| 21828 | field_name, | 22362 | field_name.fmt(ip), |
| 21829 | field_index, | 22363 | field_index, |
| 21830 | payload.data.field_index, | 22364 | field.index, |
| 21831 | parent_ty.fmt(sema.mod), | 22365 | parent_ty.fmt(sema.mod), |
| 21832 | }, | 22366 | }, |
| 21833 | ); | 22367 | ); |
| ... | @@ -21837,7 +22371,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr | ... | @@ -21837,7 +22371,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 21837 | }; | 22371 | }; |
| 21838 | return sema.failWithOwnedErrorMsg(msg); | 22372 | return sema.failWithOwnedErrorMsg(msg); |
| 21839 | } | 22373 | } |
| 21840 | return sema.addConstant(result_ptr, payload.data.container_ptr); | 22374 | return sema.addConstant(result_ptr, field.base.toValue()); |
| 21841 | } | 22375 | } |
| 21842 | 22376 | ||
| 21843 | try sema.requireRuntimeBlock(block, src, ptr_src); | 22377 | try sema.requireRuntimeBlock(block, src, ptr_src); |
| ... | @@ -21913,15 +22447,14 @@ fn analyzeMinMax( | ... | @@ -21913,15 +22447,14 @@ fn analyzeMinMax( |
| 21913 | ) CompileError!Air.Inst.Ref { | 22447 | ) CompileError!Air.Inst.Ref { |
| 21914 | assert(operands.len == operand_srcs.len); | 22448 | assert(operands.len == operand_srcs.len); |
| 21915 | assert(operands.len > 0); | 22449 | assert(operands.len > 0); |
| 22450 | const mod = sema.mod; | ||
| 21916 | 22451 | ||
| 21917 | if (operands.len == 1) return operands[0]; | 22452 | if (operands.len == 1) return operands[0]; |
| 21918 | 22453 | ||
| 21919 | const mod = sema.mod; | ||
| 21920 | const target = mod.getTarget(); | ||
| 21921 | const opFunc = switch (air_tag) { | 22454 | const opFunc = switch (air_tag) { |
| 21922 | .min => Value.numberMin, | 22455 | .min => Value.numberMin, |
| 21923 | .max => Value.numberMax, | 22456 | .max => Value.numberMax, |
| 21924 | else => unreachable, | 22457 | else => @compileError("unreachable"), |
| 21925 | }; | 22458 | }; |
| 21926 | 22459 | ||
| 21927 | // First, find all comptime-known arguments, and get their min/max | 22460 | // First, find all comptime-known arguments, and get their min/max |
| ... | @@ -21939,32 +22472,30 @@ fn analyzeMinMax( | ... | @@ -21939,32 +22472,30 @@ fn analyzeMinMax( |
| 21939 | 22472 | ||
| 21940 | runtime_known.unset(operand_idx); | 22473 | runtime_known.unset(operand_idx); |
| 21941 | 22474 | ||
| 21942 | if (cur_val.isUndef()) continue; // result is also undef | 22475 | if (cur_val.isUndef(mod)) continue; // result is also undef |
| 21943 | if (operand_val.isUndef()) { | 22476 | if (operand_val.isUndef(mod)) { |
| 21944 | cur_minmax = try sema.addConstUndef(simd_op.result_ty); | 22477 | cur_minmax = try sema.addConstUndef(simd_op.result_ty); |
| 21945 | continue; | 22478 | continue; |
| 21946 | } | 22479 | } |
| 21947 | 22480 | ||
| 21948 | try sema.resolveLazyValue(cur_val); | 22481 | const resolved_cur_val = try sema.resolveLazyValue(cur_val); |
| 21949 | try sema.resolveLazyValue(operand_val); | 22482 | const resolved_operand_val = try sema.resolveLazyValue(operand_val); |
| 21950 | 22483 | ||
| 21951 | const vec_len = simd_op.len orelse { | 22484 | const vec_len = simd_op.len orelse { |
| 21952 | const result_val = opFunc(cur_val, operand_val, target); | 22485 | const result_val = opFunc(resolved_cur_val, resolved_operand_val, mod); |
| 21953 | cur_minmax = try sema.addConstant(simd_op.result_ty, result_val); | 22486 | cur_minmax = try sema.addConstant(simd_op.result_ty, result_val); |
| 21954 | continue; | 22487 | continue; |
| 21955 | }; | 22488 | }; |
| 21956 | var lhs_buf: Value.ElemValueBuffer = undefined; | 22489 | const elems = try sema.arena.alloc(InternPool.Index, vec_len); |
| 21957 | var rhs_buf: Value.ElemValueBuffer = undefined; | ||
| 21958 | const elems = try sema.arena.alloc(Value, vec_len); | ||
| 21959 | for (elems, 0..) |*elem, i| { | 22490 | for (elems, 0..) |*elem, i| { |
| 21960 | const lhs_elem_val = cur_val.elemValueBuffer(mod, i, &lhs_buf); | 22491 | const lhs_elem_val = try resolved_cur_val.elemValue(mod, i); |
| 21961 | const rhs_elem_val = operand_val.elemValueBuffer(mod, i, &rhs_buf); | 22492 | const rhs_elem_val = try resolved_operand_val.elemValue(mod, i); |
| 21962 | elem.* = opFunc(lhs_elem_val, rhs_elem_val, target); | 22493 | elem.* = try opFunc(lhs_elem_val, rhs_elem_val, mod).intern(simd_op.scalar_ty, mod); |
| 21963 | } | 22494 | } |
| 21964 | cur_minmax = try sema.addConstant( | 22495 | cur_minmax = try sema.addConstant(simd_op.result_ty, (try mod.intern(.{ .aggregate = .{ |
| 21965 | simd_op.result_ty, | 22496 | .ty = simd_op.result_ty.toIntern(), |
| 21966 | try Value.Tag.aggregate.create(sema.arena, elems), | 22497 | .storage = .{ .elems = elems }, |
| 21967 | ); | 22498 | } })).toValue()); |
| 21968 | } else { | 22499 | } else { |
| 21969 | runtime_known.unset(operand_idx); | 22500 | runtime_known.unset(operand_idx); |
| 21970 | cur_minmax = try sema.addConstant(sema.typeOf(operand), uncasted_operand_val); | 22501 | cur_minmax = try sema.addConstant(sema.typeOf(operand), uncasted_operand_val); |
| ... | @@ -21984,28 +22515,31 @@ fn analyzeMinMax( | ... | @@ -21984,28 +22515,31 @@ fn analyzeMinMax( |
| 21984 | break :refined orig_ty; | 22515 | break :refined orig_ty; |
| 21985 | } | 22516 | } |
| 21986 | 22517 | ||
| 21987 | const refined_ty = if (orig_ty.zigTypeTag() == .Vector) blk: { | 22518 | const refined_ty = if (orig_ty.zigTypeTag(mod) == .Vector) blk: { |
| 21988 | const elem_ty = orig_ty.childType(); | 22519 | const elem_ty = orig_ty.childType(mod); |
| 21989 | const len = orig_ty.vectorLen(); | 22520 | const len = orig_ty.vectorLen(mod); |
| 21990 | 22521 | ||
| 21991 | if (len == 0) break :blk orig_ty; | 22522 | if (len == 0) break :blk orig_ty; |
| 21992 | if (elem_ty.isAnyFloat()) break :blk orig_ty; // can't refine floats | 22523 | if (elem_ty.isAnyFloat()) break :blk orig_ty; // can't refine floats |
| 21993 | 22524 | ||
| 21994 | var cur_min: Value = try val.elemValue(mod, sema.arena, 0); | 22525 | var cur_min: Value = try val.elemValue(mod, 0); |
| 21995 | var cur_max: Value = cur_min; | 22526 | var cur_max: Value = cur_min; |
| 21996 | for (1..len) |idx| { | 22527 | for (1..len) |idx| { |
| 21997 | const elem_val = try val.elemValue(mod, sema.arena, idx); | 22528 | const elem_val = try val.elemValue(mod, idx); |
| 21998 | if (elem_val.isUndef()) break :blk orig_ty; // can't refine undef | 22529 | if (elem_val.isUndef(mod)) break :blk orig_ty; // can't refine undef |
| 21999 | if (Value.order(elem_val, cur_min, target).compare(.lt)) cur_min = elem_val; | 22530 | if (Value.order(elem_val, cur_min, mod).compare(.lt)) cur_min = elem_val; |
| 22000 | if (Value.order(elem_val, cur_max, target).compare(.gt)) cur_max = elem_val; | 22531 | if (Value.order(elem_val, cur_max, mod).compare(.gt)) cur_max = elem_val; |
| 22001 | } | 22532 | } |
| 22002 | 22533 | ||
| 22003 | const refined_elem_ty = try Type.intFittingRange(target, sema.arena, cur_min, cur_max); | 22534 | const refined_elem_ty = try mod.intFittingRange(cur_min, cur_max); |
| 22004 | break :blk try Type.vector(sema.arena, len, refined_elem_ty); | 22535 | break :blk try mod.vectorType(.{ |
| 22536 | .len = len, | ||
| 22537 | .child = refined_elem_ty.toIntern(), | ||
| 22538 | }); | ||
| 22005 | } else blk: { | 22539 | } else blk: { |
| 22006 | if (orig_ty.isAnyFloat()) break :blk orig_ty; // can't refine floats | 22540 | if (orig_ty.isAnyFloat()) break :blk orig_ty; // can't refine floats |
| 22007 | if (val.isUndef()) break :blk orig_ty; // can't refine undef | 22541 | if (val.isUndef(mod)) break :blk orig_ty; // can't refine undef |
| 22008 | break :blk try Type.intFittingRange(target, sema.arena, val, val); | 22542 | break :blk try mod.intFittingRange(val, val); |
| 22009 | }; | 22543 | }; |
| 22010 | 22544 | ||
| 22011 | // Apply the refined type to the current value - this isn't strictly necessary in the | 22545 | // Apply the refined type to the current value - this isn't strictly necessary in the |
| ... | @@ -22016,7 +22550,7 @@ fn analyzeMinMax( | ... | @@ -22016,7 +22550,7 @@ fn analyzeMinMax( |
| 22016 | if (std.debug.runtime_safety) { | 22550 | if (std.debug.runtime_safety) { |
| 22017 | assert(try sema.intFitsInType(val, refined_ty, null)); | 22551 | assert(try sema.intFitsInType(val, refined_ty, null)); |
| 22018 | } | 22552 | } |
| 22019 | cur_minmax = try sema.addConstant(refined_ty, val); | 22553 | cur_minmax = try sema.coerceInMemory(block, val, orig_ty, refined_ty, src); |
| 22020 | } | 22554 | } |
| 22021 | 22555 | ||
| 22022 | break :refined refined_ty; | 22556 | break :refined refined_ty; |
| ... | @@ -22032,7 +22566,7 @@ fn analyzeMinMax( | ... | @@ -22032,7 +22566,7 @@ fn analyzeMinMax( |
| 22032 | // If the comptime-known part is undef we can avoid emitting actual instructions later | 22566 | // If the comptime-known part is undef we can avoid emitting actual instructions later |
| 22033 | const known_undef = if (cur_minmax) |operand| blk: { | 22567 | const known_undef = if (cur_minmax) |operand| blk: { |
| 22034 | const val = (try sema.resolveMaybeUndefVal(operand)).?; | 22568 | const val = (try sema.resolveMaybeUndefVal(operand)).?; |
| 22035 | break :blk val.isUndef(); | 22569 | break :blk val.isUndef(mod); |
| 22036 | } else false; | 22570 | } else false; |
| 22037 | 22571 | ||
| 22038 | if (cur_minmax == null) { | 22572 | if (cur_minmax == null) { |
| ... | @@ -22061,29 +22595,32 @@ fn analyzeMinMax( | ... | @@ -22061,29 +22595,32 @@ fn analyzeMinMax( |
| 22061 | // Finally, refine the type based on the comptime-known bound. | 22595 | // Finally, refine the type based on the comptime-known bound. |
| 22062 | if (known_undef) break :refine; // can't refine undef | 22596 | if (known_undef) break :refine; // can't refine undef |
| 22063 | const unrefined_ty = sema.typeOf(cur_minmax.?); | 22597 | const unrefined_ty = sema.typeOf(cur_minmax.?); |
| 22064 | const is_vector = unrefined_ty.zigTypeTag() == .Vector; | 22598 | const is_vector = unrefined_ty.zigTypeTag(mod) == .Vector; |
| 22065 | const comptime_elem_ty = if (is_vector) comptime_ty.childType() else comptime_ty; | 22599 | const comptime_elem_ty = if (is_vector) comptime_ty.childType(mod) else comptime_ty; |
| 22066 | const unrefined_elem_ty = if (is_vector) unrefined_ty.childType() else unrefined_ty; | 22600 | const unrefined_elem_ty = if (is_vector) unrefined_ty.childType(mod) else unrefined_ty; |
| 22067 | 22601 | ||
| 22068 | if (unrefined_elem_ty.isAnyFloat()) break :refine; // we can't refine floats | 22602 | if (unrefined_elem_ty.isAnyFloat()) break :refine; // we can't refine floats |
| 22069 | 22603 | ||
| 22070 | // Compute the final bounds based on the runtime type and the comptime-known bound type | 22604 | // Compute the final bounds based on the runtime type and the comptime-known bound type |
| 22071 | const min_val = switch (air_tag) { | 22605 | const min_val = switch (air_tag) { |
| 22072 | .min => try unrefined_elem_ty.minInt(sema.arena, target), | 22606 | .min => try unrefined_elem_ty.minInt(mod, unrefined_elem_ty), |
| 22073 | .max => try comptime_elem_ty.minInt(sema.arena, target), // @max(ct, rt) >= ct | 22607 | .max => try comptime_elem_ty.minInt(mod, comptime_elem_ty), // @max(ct, rt) >= ct |
| 22074 | else => unreachable, | 22608 | else => unreachable, |
| 22075 | }; | 22609 | }; |
| 22076 | const max_val = switch (air_tag) { | 22610 | const max_val = switch (air_tag) { |
| 22077 | .min => try comptime_elem_ty.maxInt(sema.arena, target), // @min(ct, rt) <= ct | 22611 | .min => try comptime_elem_ty.maxInt(mod, comptime_elem_ty), // @min(ct, rt) <= ct |
| 22078 | .max => try unrefined_elem_ty.maxInt(sema.arena, target), | 22612 | .max => try unrefined_elem_ty.maxInt(mod, unrefined_elem_ty), |
| 22079 | else => unreachable, | 22613 | else => unreachable, |
| 22080 | }; | 22614 | }; |
| 22081 | 22615 | ||
| 22082 | // Find the smallest type which can contain these bounds | 22616 | // Find the smallest type which can contain these bounds |
| 22083 | const final_elem_ty = try Type.intFittingRange(target, sema.arena, min_val, max_val); | 22617 | const final_elem_ty = try mod.intFittingRange(min_val, max_val); |
| 22084 | 22618 | ||
| 22085 | const final_ty = if (is_vector) | 22619 | const final_ty = if (is_vector) |
| 22086 | try Type.vector(sema.arena, unrefined_ty.vectorLen(), final_elem_ty) | 22620 | try mod.vectorType(.{ |
| 22621 | .len = unrefined_ty.vectorLen(mod), | ||
| 22622 | .child = final_elem_ty.toIntern(), | ||
| 22623 | }) | ||
| 22087 | else | 22624 | else |
| 22088 | final_elem_ty; | 22625 | final_elem_ty; |
| 22089 | 22626 | ||
| ... | @@ -22098,7 +22635,7 @@ fn analyzeMinMax( | ... | @@ -22098,7 +22635,7 @@ fn analyzeMinMax( |
| 22098 | 22635 | ||
| 22099 | fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !Air.Inst.Ref { | 22636 | fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !Air.Inst.Ref { |
| 22100 | const mod = sema.mod; | 22637 | const mod = sema.mod; |
| 22101 | const info = sema.typeOf(ptr).ptrInfo().data; | 22638 | const info = sema.typeOf(ptr).ptrInfo(mod); |
| 22102 | if (info.size == .One) { | 22639 | if (info.size == .One) { |
| 22103 | // Already an array pointer. | 22640 | // Already an array pointer. |
| 22104 | return ptr; | 22641 | return ptr; |
| ... | @@ -22132,8 +22669,9 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -22132,8 +22669,9 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22132 | const dest_len = try indexablePtrLenOrNone(sema, block, dest_src, dest_ptr); | 22669 | const dest_len = try indexablePtrLenOrNone(sema, block, dest_src, dest_ptr); |
| 22133 | const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr); | 22670 | const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr); |
| 22134 | const target = sema.mod.getTarget(); | 22671 | const target = sema.mod.getTarget(); |
| 22672 | const mod = sema.mod; | ||
| 22135 | 22673 | ||
| 22136 | if (dest_ty.isConstPtr()) { | 22674 | if (dest_ty.isConstPtr(mod)) { |
| 22137 | return sema.fail(block, dest_src, "cannot memcpy to constant pointer", .{}); | 22675 | return sema.fail(block, dest_src, "cannot memcpy to constant pointer", .{}); |
| 22138 | } | 22676 | } |
| 22139 | 22677 | ||
| ... | @@ -22194,9 +22732,9 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -22194,9 +22732,9 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22194 | } | 22732 | } |
| 22195 | 22733 | ||
| 22196 | const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: { | 22734 | const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: { |
| 22197 | if (!dest_ptr_val.isComptimeMutablePtr()) break :rs dest_src; | 22735 | if (!dest_ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src; |
| 22198 | if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| { | 22736 | if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| { |
| 22199 | const len_u64 = (try len_val.?.getUnsignedIntAdvanced(target, sema)).?; | 22737 | const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?; |
| 22200 | const len = try sema.usizeCast(block, dest_src, len_u64); | 22738 | const len = try sema.usizeCast(block, dest_src, len_u64); |
| 22201 | for (0..len) |i| { | 22739 | for (0..len) |i| { |
| 22202 | const elem_index = try sema.addIntUnsigned(Type.usize, i); | 22740 | const elem_index = try sema.addIntUnsigned(Type.usize, i); |
| ... | @@ -22239,12 +22777,12 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -22239,12 +22777,12 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22239 | // lowering. The AIR instruction requires pointers with element types of | 22777 | // lowering. The AIR instruction requires pointers with element types of |
| 22240 | // equal ABI size. | 22778 | // equal ABI size. |
| 22241 | 22779 | ||
| 22242 | if (dest_ty.zigTypeTag() != .Pointer or src_ty.zigTypeTag() != .Pointer) { | 22780 | if (dest_ty.zigTypeTag(mod) != .Pointer or src_ty.zigTypeTag(mod) != .Pointer) { |
| 22243 | return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the source or destination iterable is a tuple", .{}); | 22781 | return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the source or destination iterable is a tuple", .{}); |
| 22244 | } | 22782 | } |
| 22245 | 22783 | ||
| 22246 | const dest_elem_ty = dest_ty.elemType2(); | 22784 | const dest_elem_ty = dest_ty.elemType2(mod); |
| 22247 | const src_elem_ty = src_ty.elemType2(); | 22785 | const src_elem_ty = src_ty.elemType2(mod); |
| 22248 | if (.ok != try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, true, target, dest_src, src_src)) { | 22786 | if (.ok != try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, true, target, dest_src, src_src)) { |
| 22249 | return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the element types have different ABI sizes", .{}); | 22787 | return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the element types have different ABI sizes", .{}); |
| 22250 | } | 22788 | } |
| ... | @@ -22255,7 +22793,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -22255,7 +22793,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22255 | var new_dest_ptr = dest_ptr; | 22793 | var new_dest_ptr = dest_ptr; |
| 22256 | var new_src_ptr = src_ptr; | 22794 | var new_src_ptr = src_ptr; |
| 22257 | if (len_val) |val| { | 22795 | if (len_val) |val| { |
| 22258 | const len = val.toUnsignedInt(target); | 22796 | const len = val.toUnsignedInt(mod); |
| 22259 | if (len == 0) { | 22797 | if (len == 0) { |
| 22260 | // This AIR instruction guarantees length > 0 if it is comptime-known. | 22798 | // This AIR instruction guarantees length > 0 if it is comptime-known. |
| 22261 | return; | 22799 | return; |
| ... | @@ -22268,7 +22806,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -22268,7 +22806,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22268 | // Change the src from slice to a many pointer, to avoid multiple ptr | 22806 | // Change the src from slice to a many pointer, to avoid multiple ptr |
| 22269 | // slice extractions in AIR instructions. | 22807 | // slice extractions in AIR instructions. |
| 22270 | const new_src_ptr_ty = sema.typeOf(new_src_ptr); | 22808 | const new_src_ptr_ty = sema.typeOf(new_src_ptr); |
| 22271 | if (new_src_ptr_ty.isSlice()) { | 22809 | if (new_src_ptr_ty.isSlice(mod)) { |
| 22272 | new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty); | 22810 | new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty); |
| 22273 | } | 22811 | } |
| 22274 | } else if (dest_len == .none and len_val == null) { | 22812 | } else if (dest_len == .none and len_val == null) { |
| ... | @@ -22276,7 +22814,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -22276,7 +22814,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22276 | const dest_ptr_ptr = try sema.analyzeRef(block, dest_src, new_dest_ptr); | 22814 | const dest_ptr_ptr = try sema.analyzeRef(block, dest_src, new_dest_ptr); |
| 22277 | new_dest_ptr = try sema.analyzeSlice(block, dest_src, dest_ptr_ptr, .zero, src_len, .none, .unneeded, dest_src, dest_src, dest_src, false); | 22815 | new_dest_ptr = try sema.analyzeSlice(block, dest_src, dest_ptr_ptr, .zero, src_len, .none, .unneeded, dest_src, dest_src, dest_src, false); |
| 22278 | const new_src_ptr_ty = sema.typeOf(new_src_ptr); | 22816 | const new_src_ptr_ty = sema.typeOf(new_src_ptr); |
| 22279 | if (new_src_ptr_ty.isSlice()) { | 22817 | if (new_src_ptr_ty.isSlice(mod)) { |
| 22280 | new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty); | 22818 | new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty); |
| 22281 | } | 22819 | } |
| 22282 | } | 22820 | } |
| ... | @@ -22295,14 +22833,30 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -22295,14 +22833,30 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22295 | // Extract raw pointer from dest slice. The AIR instructions could support them, but | 22833 | // Extract raw pointer from dest slice. The AIR instructions could support them, but |
| 22296 | // it would cause redundant machine code instructions. | 22834 | // it would cause redundant machine code instructions. |
| 22297 | const new_dest_ptr_ty = sema.typeOf(new_dest_ptr); | 22835 | const new_dest_ptr_ty = sema.typeOf(new_dest_ptr); |
| 22298 | const raw_dest_ptr = if (new_dest_ptr_ty.isSlice()) | 22836 | const raw_dest_ptr = if (new_dest_ptr_ty.isSlice(mod)) |
| 22299 | try sema.analyzeSlicePtr(block, dest_src, new_dest_ptr, new_dest_ptr_ty) | 22837 | try sema.analyzeSlicePtr(block, dest_src, new_dest_ptr, new_dest_ptr_ty) |
| 22300 | else | 22838 | else if (new_dest_ptr_ty.ptrSize(mod) == .One) ptr: { |
| 22301 | new_dest_ptr; | 22839 | var dest_manyptr_ty_key = mod.intern_pool.indexToKey(new_dest_ptr_ty.toIntern()).ptr_type; |
| 22840 | assert(dest_manyptr_ty_key.flags.size == .One); | ||
| 22841 | dest_manyptr_ty_key.child = dest_elem_ty.toIntern(); | ||
| 22842 | dest_manyptr_ty_key.flags.size = .Many; | ||
| 22843 | break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src); | ||
| 22844 | } else new_dest_ptr; | ||
| 22845 | |||
| 22846 | const new_src_ptr_ty = sema.typeOf(new_src_ptr); | ||
| 22847 | const raw_src_ptr = if (new_src_ptr_ty.isSlice(mod)) | ||
| 22848 | try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty) | ||
| 22849 | else if (new_src_ptr_ty.ptrSize(mod) == .One) ptr: { | ||
| 22850 | var src_manyptr_ty_key = mod.intern_pool.indexToKey(new_src_ptr_ty.toIntern()).ptr_type; | ||
| 22851 | assert(src_manyptr_ty_key.flags.size == .One); | ||
| 22852 | src_manyptr_ty_key.child = src_elem_ty.toIntern(); | ||
| 22853 | src_manyptr_ty_key.flags.size = .Many; | ||
| 22854 | break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(src_manyptr_ty_key), new_src_ptr, src_src); | ||
| 22855 | } else new_src_ptr; | ||
| 22302 | 22856 | ||
| 22303 | // ok1: dest >= src + len | 22857 | // ok1: dest >= src + len |
| 22304 | // ok2: src >= dest + len | 22858 | // ok2: src >= dest + len |
| 22305 | const src_plus_len = try sema.analyzePtrArithmetic(block, src, new_src_ptr, len, .ptr_add, src_src, src); | 22859 | const src_plus_len = try sema.analyzePtrArithmetic(block, src, raw_src_ptr, len, .ptr_add, src_src, src); |
| 22306 | const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src); | 22860 | const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src); |
| 22307 | const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len); | 22861 | const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len); |
| 22308 | const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len); | 22862 | const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len); |
| ... | @@ -22320,6 +22874,9 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -22320,6 +22874,9 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22320 | } | 22874 | } |
| 22321 | 22875 | ||
| 22322 | fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 22876 | fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 22877 | const mod = sema.mod; | ||
| 22878 | const gpa = sema.gpa; | ||
| 22879 | const ip = &mod.intern_pool; | ||
| 22323 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 22880 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 22324 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | 22881 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 22325 | const src = inst_data.src(); | 22882 | const src = inst_data.src(); |
| ... | @@ -22330,25 +22887,24 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -22330,25 +22887,24 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22330 | const dest_ptr_ty = sema.typeOf(dest_ptr); | 22887 | const dest_ptr_ty = sema.typeOf(dest_ptr); |
| 22331 | try checkMemOperand(sema, block, dest_src, dest_ptr_ty); | 22888 | try checkMemOperand(sema, block, dest_src, dest_ptr_ty); |
| 22332 | 22889 | ||
| 22333 | if (dest_ptr_ty.isConstPtr()) { | 22890 | if (dest_ptr_ty.isConstPtr(mod)) { |
| 22334 | return sema.fail(block, dest_src, "cannot memset constant pointer", .{}); | 22891 | return sema.fail(block, dest_src, "cannot memset constant pointer", .{}); |
| 22335 | } | 22892 | } |
| 22336 | 22893 | ||
| 22337 | const dest_elem_ty = dest_ptr_ty.elemType2(); | 22894 | const dest_elem_ty = dest_ptr_ty.elemType2(mod); |
| 22338 | const target = sema.mod.getTarget(); | ||
| 22339 | 22895 | ||
| 22340 | const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: { | 22896 | const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: { |
| 22341 | const len_air_ref = try sema.fieldVal(block, src, dest_ptr, "len", dest_src); | 22897 | const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, "len"), dest_src); |
| 22342 | const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse | 22898 | const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse |
| 22343 | break :rs dest_src; | 22899 | break :rs dest_src; |
| 22344 | const len_u64 = (try len_val.getUnsignedIntAdvanced(target, sema)).?; | 22900 | const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, sema)).?; |
| 22345 | const len = try sema.usizeCast(block, dest_src, len_u64); | 22901 | const len = try sema.usizeCast(block, dest_src, len_u64); |
| 22346 | if (len == 0) { | 22902 | if (len == 0) { |
| 22347 | // This AIR instruction guarantees length > 0 if it is comptime-known. | 22903 | // This AIR instruction guarantees length > 0 if it is comptime-known. |
| 22348 | return; | 22904 | return; |
| 22349 | } | 22905 | } |
| 22350 | 22906 | ||
| 22351 | if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src; | 22907 | if (!ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src; |
| 22352 | if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| { | 22908 | if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| { |
| 22353 | for (0..len) |i| { | 22909 | for (0..len) |i| { |
| 22354 | const elem_index = try sema.addIntUnsigned(Type.usize, i); | 22910 | const elem_index = try sema.addIntUnsigned(Type.usize, i); |
| ... | @@ -22426,6 +22982,7 @@ fn zirVarExtended( | ... | @@ -22426,6 +22982,7 @@ fn zirVarExtended( |
| 22426 | block: *Block, | 22982 | block: *Block, |
| 22427 | extended: Zir.Inst.Extended.InstData, | 22983 | extended: Zir.Inst.Extended.InstData, |
| 22428 | ) CompileError!Air.Inst.Ref { | 22984 | ) CompileError!Air.Inst.Ref { |
| 22985 | const mod = sema.mod; | ||
| 22429 | const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand); | 22986 | const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand); |
| 22430 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 }; | 22987 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 }; |
| 22431 | const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 }; | 22988 | const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 }; |
| ... | @@ -22461,47 +23018,33 @@ fn zirVarExtended( | ... | @@ -22461,47 +23018,33 @@ fn zirVarExtended( |
| 22461 | else | 23018 | else |
| 22462 | uncasted_init; | 23019 | uncasted_init; |
| 22463 | 23020 | ||
| 22464 | break :blk (try sema.resolveMaybeUndefVal(init)) orelse | 23021 | break :blk ((try sema.resolveMaybeUndefVal(init)) orelse |
| 22465 | return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known"); | 23022 | return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known")).toIntern(); |
| 22466 | } else Value.initTag(.unreachable_value); | 23023 | } else .none; |
| 22467 | 23024 | ||
| 22468 | try sema.validateVarType(block, ty_src, var_ty, small.is_extern); | 23025 | try sema.validateVarType(block, ty_src, var_ty, small.is_extern); |
| 22469 | 23026 | ||
| 22470 | const new_var = try sema.gpa.create(Module.Var); | 23027 | return sema.addConstant(var_ty, (try mod.intern(.{ .variable = .{ |
| 22471 | errdefer sema.gpa.destroy(new_var); | 23028 | .ty = var_ty.toIntern(), |
| 22472 | |||
| 22473 | log.debug("created variable {*} owner_decl: {*} ({s})", .{ | ||
| 22474 | new_var, sema.owner_decl, sema.owner_decl.name, | ||
| 22475 | }); | ||
| 22476 | |||
| 22477 | new_var.* = .{ | ||
| 22478 | .owner_decl = sema.owner_decl_index, | ||
| 22479 | .init = init_val, | 23029 | .init = init_val, |
| 23030 | .decl = sema.owner_decl_index, | ||
| 23031 | .lib_name = if (lib_name) |lname| (try mod.intern_pool.getOrPutString( | ||
| 23032 | sema.gpa, | ||
| 23033 | try sema.handleExternLibName(block, ty_src, lname), | ||
| 23034 | )).toOptional() else .none, | ||
| 22480 | .is_extern = small.is_extern, | 23035 | .is_extern = small.is_extern, |
| 22481 | .is_mutable = true, | ||
| 22482 | .is_threadlocal = small.is_threadlocal, | 23036 | .is_threadlocal = small.is_threadlocal, |
| 22483 | .is_weak_linkage = false, | 23037 | } })).toValue()); |
| 22484 | .lib_name = null, | ||
| 22485 | }; | ||
| 22486 | |||
| 22487 | if (lib_name) |lname| { | ||
| 22488 | new_var.lib_name = try sema.handleExternLibName(block, ty_src, lname); | ||
| 22489 | } | ||
| 22490 | |||
| 22491 | const result = try sema.addConstant( | ||
| 22492 | var_ty, | ||
| 22493 | try Value.Tag.variable.create(sema.arena, new_var), | ||
| 22494 | ); | ||
| 22495 | return result; | ||
| 22496 | } | 23038 | } |
| 22497 | 23039 | ||
| 22498 | fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 23040 | fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 22499 | const tracy = trace(@src()); | 23041 | const tracy = trace(@src()); |
| 22500 | defer tracy.end(); | 23042 | defer tracy.end(); |
| 22501 | 23043 | ||
| 23044 | const mod = sema.mod; | ||
| 22502 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 23045 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 22503 | const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index); | 23046 | const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index); |
| 22504 | const target = sema.mod.getTarget(); | 23047 | const target = mod.getTarget(); |
| 22505 | 23048 | ||
| 22506 | const align_src: LazySrcLoc = .{ .node_offset_fn_type_align = inst_data.src_node }; | 23049 | const align_src: LazySrcLoc = .{ .node_offset_fn_type_align = inst_data.src_node }; |
| 22507 | const addrspace_src: LazySrcLoc = .{ .node_offset_fn_type_addrspace = inst_data.src_node }; | 23050 | const addrspace_src: LazySrcLoc = .{ .node_offset_fn_type_addrspace = inst_data.src_node }; |
| ... | @@ -22532,10 +23075,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -22532,10 +23075,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22532 | extra_index += body.len; | 23075 | extra_index += body.len; |
| 22533 | 23076 | ||
| 22534 | const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u29, "alignment must be comptime-known"); | 23077 | const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u29, "alignment must be comptime-known"); |
| 22535 | if (val.tag() == .generic_poison) { | 23078 | if (val.isGenericPoison()) { |
| 22536 | break :blk null; | 23079 | break :blk null; |
| 22537 | } | 23080 | } |
| 22538 | const alignment = @intCast(u32, val.toUnsignedInt(target)); | 23081 | const alignment = @intCast(u32, val.toUnsignedInt(mod)); |
| 22539 | try sema.validateAlign(block, align_src, alignment); | 23082 | try sema.validateAlign(block, align_src, alignment); |
| 22540 | if (alignment == target_util.defaultFunctionAlignment(target)) { | 23083 | if (alignment == target_util.defaultFunctionAlignment(target)) { |
| 22541 | break :blk 0; | 23084 | break :blk 0; |
| ... | @@ -22551,7 +23094,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -22551,7 +23094,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22551 | }, | 23094 | }, |
| 22552 | else => |e| return e, | 23095 | else => |e| return e, |
| 22553 | }; | 23096 | }; |
| 22554 | const alignment = @intCast(u32, align_tv.val.toUnsignedInt(target)); | 23097 | const alignment = @intCast(u32, align_tv.val.toUnsignedInt(mod)); |
| 22555 | try sema.validateAlign(block, align_src, alignment); | 23098 | try sema.validateAlign(block, align_src, alignment); |
| 22556 | if (alignment == target_util.defaultFunctionAlignment(target)) { | 23099 | if (alignment == target_util.defaultFunctionAlignment(target)) { |
| 22557 | break :blk 0; | 23100 | break :blk 0; |
| ... | @@ -22568,10 +23111,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -22568,10 +23111,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22568 | 23111 | ||
| 22569 | const addrspace_ty = try sema.getBuiltinType("AddressSpace"); | 23112 | const addrspace_ty = try sema.getBuiltinType("AddressSpace"); |
| 22570 | const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty, "addrespace must be comptime-known"); | 23113 | const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty, "addrespace must be comptime-known"); |
| 22571 | if (val.tag() == .generic_poison) { | 23114 | if (val.isGenericPoison()) { |
| 22572 | break :blk null; | 23115 | break :blk null; |
| 22573 | } | 23116 | } |
| 22574 | break :blk val.toEnum(std.builtin.AddressSpace); | 23117 | break :blk mod.toEnum(std.builtin.AddressSpace, val); |
| 22575 | } else if (extra.data.bits.has_addrspace_ref) blk: { | 23118 | } else if (extra.data.bits.has_addrspace_ref) blk: { |
| 22576 | const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 23119 | const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 22577 | extra_index += 1; | 23120 | extra_index += 1; |
| ... | @@ -22581,7 +23124,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -22581,7 +23124,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22581 | }, | 23124 | }, |
| 22582 | else => |e| return e, | 23125 | else => |e| return e, |
| 22583 | }; | 23126 | }; |
| 22584 | break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace); | 23127 | break :blk mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val); |
| 22585 | } else target_util.defaultAddressSpace(target, .function); | 23128 | } else target_util.defaultAddressSpace(target, .function); |
| 22586 | 23129 | ||
| 22587 | const @"linksection": FuncLinkSection = if (extra.data.bits.has_section_body) blk: { | 23130 | const @"linksection": FuncLinkSection = if (extra.data.bits.has_section_body) blk: { |
| ... | @@ -22590,16 +23133,16 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -22590,16 +23133,16 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22590 | const body = sema.code.extra[extra_index..][0..body_len]; | 23133 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 22591 | extra_index += body.len; | 23134 | extra_index += body.len; |
| 22592 | 23135 | ||
| 22593 | const ty = Type.initTag(.const_slice_u8); | 23136 | const ty = Type.slice_const_u8; |
| 22594 | const val = try sema.resolveGenericBody(block, section_src, body, inst, ty, "linksection must be comptime-known"); | 23137 | const val = try sema.resolveGenericBody(block, section_src, body, inst, ty, "linksection must be comptime-known"); |
| 22595 | if (val.tag() == .generic_poison) { | 23138 | if (val.isGenericPoison()) { |
| 22596 | break :blk FuncLinkSection{ .generic = {} }; | 23139 | break :blk FuncLinkSection{ .generic = {} }; |
| 22597 | } | 23140 | } |
| 22598 | break :blk FuncLinkSection{ .explicit = try val.toAllocatedBytes(ty, sema.arena, sema.mod) }; | 23141 | break :blk FuncLinkSection{ .explicit = try val.toIpString(ty, mod) }; |
| 22599 | } else if (extra.data.bits.has_section_ref) blk: { | 23142 | } else if (extra.data.bits.has_section_ref) blk: { |
| 22600 | const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 23143 | const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 22601 | extra_index += 1; | 23144 | extra_index += 1; |
| 22602 | const section_name = sema.resolveConstString(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) { | 23145 | const section_name = sema.resolveConstStringIntern(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) { |
| 22603 | error.GenericPoison => { | 23146 | error.GenericPoison => { |
| 22604 | break :blk FuncLinkSection{ .generic = {} }; | 23147 | break :blk FuncLinkSection{ .generic = {} }; |
| 22605 | }, | 23148 | }, |
| ... | @@ -22616,10 +23159,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -22616,10 +23159,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22616 | 23159 | ||
| 22617 | const cc_ty = try sema.getBuiltinType("CallingConvention"); | 23160 | const cc_ty = try sema.getBuiltinType("CallingConvention"); |
| 22618 | const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, "calling convention must be comptime-known"); | 23161 | const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, "calling convention must be comptime-known"); |
| 22619 | if (val.tag() == .generic_poison) { | 23162 | if (val.isGenericPoison()) { |
| 22620 | break :blk null; | 23163 | break :blk null; |
| 22621 | } | 23164 | } |
| 22622 | break :blk val.toEnum(std.builtin.CallingConvention); | 23165 | break :blk mod.toEnum(std.builtin.CallingConvention, val); |
| 22623 | } else if (extra.data.bits.has_cc_ref) blk: { | 23166 | } else if (extra.data.bits.has_cc_ref) blk: { |
| 22624 | const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 23167 | const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 22625 | extra_index += 1; | 23168 | extra_index += 1; |
| ... | @@ -22629,7 +23172,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -22629,7 +23172,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22629 | }, | 23172 | }, |
| 22630 | else => |e| return e, | 23173 | else => |e| return e, |
| 22631 | }; | 23174 | }; |
| 22632 | break :blk cc_tv.val.toEnum(std.builtin.CallingConvention); | 23175 | break :blk mod.toEnum(std.builtin.CallingConvention, cc_tv.val); |
| 22633 | } else if (sema.owner_decl.is_exported and has_body) | 23176 | } else if (sema.owner_decl.is_exported and has_body) |
| 22634 | .C | 23177 | .C |
| 22635 | else | 23178 | else |
| ... | @@ -22642,20 +23185,18 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -22642,20 +23185,18 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22642 | extra_index += body.len; | 23185 | extra_index += body.len; |
| 22643 | 23186 | ||
| 22644 | const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, "return type must be comptime-known"); | 23187 | const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, "return type must be comptime-known"); |
| 22645 | var buffer: Value.ToTypeBuffer = undefined; | 23188 | const ty = val.toType(); |
| 22646 | const ty = try val.toType(&buffer).copy(sema.arena); | ||
| 22647 | break :blk ty; | 23189 | break :blk ty; |
| 22648 | } else if (extra.data.bits.has_ret_ty_ref) blk: { | 23190 | } else if (extra.data.bits.has_ret_ty_ref) blk: { |
| 22649 | const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); | 23191 | const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); |
| 22650 | extra_index += 1; | 23192 | extra_index += 1; |
| 22651 | const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, "return type must be comptime-known") catch |err| switch (err) { | 23193 | const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, "return type must be comptime-known") catch |err| switch (err) { |
| 22652 | error.GenericPoison => { | 23194 | error.GenericPoison => { |
| 22653 | break :blk Type.initTag(.generic_poison); | 23195 | break :blk Type.generic_poison; |
| 22654 | }, | 23196 | }, |
| 22655 | else => |e| return e, | 23197 | else => |e| return e, |
| 22656 | }; | 23198 | }; |
| 22657 | var buffer: Value.ToTypeBuffer = undefined; | 23199 | const ty = ret_ty_tv.val.toType(); |
| 22658 | const ty = try ret_ty_tv.val.toType(&buffer).copy(sema.arena); | ||
| 22659 | break :blk ty; | 23200 | break :blk ty; |
| 22660 | } else Type.void; | 23201 | } else Type.void; |
| 22661 | 23202 | ||
| ... | @@ -22727,13 +23268,14 @@ fn zirCDefine( | ... | @@ -22727,13 +23268,14 @@ fn zirCDefine( |
| 22727 | block: *Block, | 23268 | block: *Block, |
| 22728 | extended: Zir.Inst.Extended.InstData, | 23269 | extended: Zir.Inst.Extended.InstData, |
| 22729 | ) CompileError!Air.Inst.Ref { | 23270 | ) CompileError!Air.Inst.Ref { |
| 23271 | const mod = sema.mod; | ||
| 22730 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | 23272 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 22731 | const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 23273 | const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 22732 | const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; | 23274 | const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; |
| 22733 | 23275 | ||
| 22734 | const name = try sema.resolveConstString(block, name_src, extra.lhs, "name of macro being undefined must be comptime-known"); | 23276 | const name = try sema.resolveConstString(block, name_src, extra.lhs, "name of macro being undefined must be comptime-known"); |
| 22735 | const rhs = try sema.resolveInst(extra.rhs); | 23277 | const rhs = try sema.resolveInst(extra.rhs); |
| 22736 | if (sema.typeOf(rhs).zigTypeTag() != .Void) { | 23278 | if (sema.typeOf(rhs).zigTypeTag(mod) != .Void) { |
| 22737 | const value = try sema.resolveConstString(block, val_src, extra.rhs, "value of macro being undefined must be comptime-known"); | 23279 | const value = try sema.resolveConstString(block, val_src, extra.rhs, "value of macro being undefined must be comptime-known"); |
| 22738 | try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); | 23280 | try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value }); |
| 22739 | } else { | 23281 | } else { |
| ... | @@ -22799,27 +23341,29 @@ fn resolvePrefetchOptions( | ... | @@ -22799,27 +23341,29 @@ fn resolvePrefetchOptions( |
| 22799 | src: LazySrcLoc, | 23341 | src: LazySrcLoc, |
| 22800 | zir_ref: Zir.Inst.Ref, | 23342 | zir_ref: Zir.Inst.Ref, |
| 22801 | ) CompileError!std.builtin.PrefetchOptions { | 23343 | ) CompileError!std.builtin.PrefetchOptions { |
| 23344 | const mod = sema.mod; | ||
| 23345 | const gpa = sema.gpa; | ||
| 23346 | const ip = &mod.intern_pool; | ||
| 22802 | const options_ty = try sema.getBuiltinType("PrefetchOptions"); | 23347 | const options_ty = try sema.getBuiltinType("PrefetchOptions"); |
| 22803 | const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src); | 23348 | const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src); |
| 22804 | const target = sema.mod.getTarget(); | ||
| 22805 | 23349 | ||
| 22806 | const rw_src = sema.maybeOptionsSrc(block, src, "rw"); | 23350 | const rw_src = sema.maybeOptionsSrc(block, src, "rw"); |
| 22807 | const locality_src = sema.maybeOptionsSrc(block, src, "locality"); | 23351 | const locality_src = sema.maybeOptionsSrc(block, src, "locality"); |
| 22808 | const cache_src = sema.maybeOptionsSrc(block, src, "cache"); | 23352 | const cache_src = sema.maybeOptionsSrc(block, src, "cache"); |
| 22809 | 23353 | ||
| 22810 | const rw = try sema.fieldVal(block, src, options, "rw", rw_src); | 23354 | const rw = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "rw"), rw_src); |
| 22811 | const rw_val = try sema.resolveConstValue(block, rw_src, rw, "prefetch read/write must be comptime-known"); | 23355 | const rw_val = try sema.resolveConstValue(block, rw_src, rw, "prefetch read/write must be comptime-known"); |
| 22812 | 23356 | ||
| 22813 | const locality = try sema.fieldVal(block, src, options, "locality", locality_src); | 23357 | const locality = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "locality"), locality_src); |
| 22814 | const locality_val = try sema.resolveConstValue(block, locality_src, locality, "prefetch locality must be comptime-known"); | 23358 | const locality_val = try sema.resolveConstValue(block, locality_src, locality, "prefetch locality must be comptime-known"); |
| 22815 | 23359 | ||
| 22816 | const cache = try sema.fieldVal(block, src, options, "cache", cache_src); | 23360 | const cache = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "cache"), cache_src); |
| 22817 | const cache_val = try sema.resolveConstValue(block, cache_src, cache, "prefetch cache must be comptime-known"); | 23361 | const cache_val = try sema.resolveConstValue(block, cache_src, cache, "prefetch cache must be comptime-known"); |
| 22818 | 23362 | ||
| 22819 | return std.builtin.PrefetchOptions{ | 23363 | return std.builtin.PrefetchOptions{ |
| 22820 | .rw = rw_val.toEnum(std.builtin.PrefetchOptions.Rw), | 23364 | .rw = mod.toEnum(std.builtin.PrefetchOptions.Rw, rw_val), |
| 22821 | .locality = @intCast(u2, locality_val.toUnsignedInt(target)), | 23365 | .locality = @intCast(u2, locality_val.toUnsignedInt(mod)), |
| 22822 | .cache = cache_val.toEnum(std.builtin.PrefetchOptions.Cache), | 23366 | .cache = mod.toEnum(std.builtin.PrefetchOptions.Cache, cache_val), |
| 22823 | }; | 23367 | }; |
| 22824 | } | 23368 | } |
| 22825 | 23369 | ||
| ... | @@ -22862,34 +23406,40 @@ fn resolveExternOptions( | ... | @@ -22862,34 +23406,40 @@ fn resolveExternOptions( |
| 22862 | block: *Block, | 23406 | block: *Block, |
| 22863 | src: LazySrcLoc, | 23407 | src: LazySrcLoc, |
| 22864 | zir_ref: Zir.Inst.Ref, | 23408 | zir_ref: Zir.Inst.Ref, |
| 22865 | ) CompileError!std.builtin.ExternOptions { | 23409 | ) CompileError!struct { |
| 23410 | name: InternPool.NullTerminatedString, | ||
| 23411 | library_name: InternPool.OptionalNullTerminatedString = .none, | ||
| 23412 | linkage: std.builtin.GlobalLinkage = .Strong, | ||
| 23413 | is_thread_local: bool = false, | ||
| 23414 | } { | ||
| 23415 | const mod = sema.mod; | ||
| 23416 | const gpa = sema.gpa; | ||
| 23417 | const ip = &mod.intern_pool; | ||
| 22866 | const options_inst = try sema.resolveInst(zir_ref); | 23418 | const options_inst = try sema.resolveInst(zir_ref); |
| 22867 | const extern_options_ty = try sema.getBuiltinType("ExternOptions"); | 23419 | const extern_options_ty = try sema.getBuiltinType("ExternOptions"); |
| 22868 | const options = try sema.coerce(block, extern_options_ty, options_inst, src); | 23420 | const options = try sema.coerce(block, extern_options_ty, options_inst, src); |
| 22869 | const mod = sema.mod; | ||
| 22870 | 23421 | ||
| 22871 | const name_src = sema.maybeOptionsSrc(block, src, "name"); | 23422 | const name_src = sema.maybeOptionsSrc(block, src, "name"); |
| 22872 | const library_src = sema.maybeOptionsSrc(block, src, "library"); | 23423 | const library_src = sema.maybeOptionsSrc(block, src, "library"); |
| 22873 | const linkage_src = sema.maybeOptionsSrc(block, src, "linkage"); | 23424 | const linkage_src = sema.maybeOptionsSrc(block, src, "linkage"); |
| 22874 | const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local"); | 23425 | const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local"); |
| 22875 | 23426 | ||
| 22876 | const name_ref = try sema.fieldVal(block, src, options, "name", name_src); | 23427 | const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src); |
| 22877 | const name_val = try sema.resolveConstValue(block, name_src, name_ref, "name of the extern symbol must be comptime-known"); | 23428 | const name_val = try sema.resolveConstValue(block, name_src, name_ref, "name of the extern symbol must be comptime-known"); |
| 22878 | const name = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod); | 23429 | const name = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); |
| 22879 | 23430 | ||
| 22880 | const library_name_inst = try sema.fieldVal(block, src, options, "library_name", library_src); | 23431 | const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name"), library_src); |
| 22881 | const library_name_val = try sema.resolveConstValue(block, library_src, library_name_inst, "library in which extern symbol is must be comptime-known"); | 23432 | const library_name_val = try sema.resolveConstValue(block, library_src, library_name_inst, "library in which extern symbol is must be comptime-known"); |
| 22882 | 23433 | ||
| 22883 | const linkage_ref = try sema.fieldVal(block, src, options, "linkage", linkage_src); | 23434 | const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src); |
| 22884 | const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_ref, "linkage of the extern symbol must be comptime-known"); | 23435 | const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_ref, "linkage of the extern symbol must be comptime-known"); |
| 22885 | const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage); | 23436 | const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val); |
| 22886 | 23437 | ||
| 22887 | const is_thread_local = try sema.fieldVal(block, src, options, "is_thread_local", thread_local_src); | 23438 | const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "is_thread_local"), thread_local_src); |
| 22888 | const is_thread_local_val = try sema.resolveConstValue(block, thread_local_src, is_thread_local, "threadlocality of the extern symbol must be comptime-known"); | 23439 | const is_thread_local_val = try sema.resolveConstValue(block, thread_local_src, is_thread_local, "threadlocality of the extern symbol must be comptime-known"); |
| 22889 | 23440 | ||
| 22890 | const library_name = if (!library_name_val.isNull()) blk: { | 23441 | const library_name = if (library_name_val.optionalValue(mod)) |payload| blk: { |
| 22891 | const payload = library_name_val.castTag(.opt_payload).?.data; | 23442 | const library_name = try payload.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); |
| 22892 | const library_name = try payload.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod); | ||
| 22893 | if (library_name.len == 0) { | 23443 | if (library_name.len == 0) { |
| 22894 | return sema.fail(block, library_src, "library name cannot be empty", .{}); | 23444 | return sema.fail(block, library_src, "library name cannot be empty", .{}); |
| 22895 | } | 23445 | } |
| ... | @@ -22904,9 +23454,9 @@ fn resolveExternOptions( | ... | @@ -22904,9 +23454,9 @@ fn resolveExternOptions( |
| 22904 | return sema.fail(block, linkage_src, "extern symbol must use strong or weak linkage", .{}); | 23454 | return sema.fail(block, linkage_src, "extern symbol must use strong or weak linkage", .{}); |
| 22905 | } | 23455 | } |
| 22906 | 23456 | ||
| 22907 | return std.builtin.ExternOptions{ | 23457 | return .{ |
| 22908 | .name = name, | 23458 | .name = try ip.getOrPutString(gpa, name), |
| 22909 | .library_name = library_name, | 23459 | .library_name = try ip.getOrPutStringOpt(gpa, library_name), |
| 22910 | .linkage = linkage, | 23460 | .linkage = linkage, |
| 22911 | .is_thread_local = is_thread_local_val.toBool(), | 23461 | .is_thread_local = is_thread_local_val.toBool(), |
| 22912 | }; | 23462 | }; |
| ... | @@ -22917,21 +23467,21 @@ fn zirBuiltinExtern( | ... | @@ -22917,21 +23467,21 @@ fn zirBuiltinExtern( |
| 22917 | block: *Block, | 23467 | block: *Block, |
| 22918 | extended: Zir.Inst.Extended.InstData, | 23468 | extended: Zir.Inst.Extended.InstData, |
| 22919 | ) CompileError!Air.Inst.Ref { | 23469 | ) CompileError!Air.Inst.Ref { |
| 23470 | const mod = sema.mod; | ||
| 22920 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | 23471 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 22921 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; | 23472 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 22922 | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; | 23473 | const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; |
| 22923 | 23474 | ||
| 22924 | var ty = try sema.resolveType(block, ty_src, extra.lhs); | 23475 | var ty = try sema.resolveType(block, ty_src, extra.lhs); |
| 22925 | if (!ty.isPtrAtRuntime()) { | 23476 | if (!ty.isPtrAtRuntime(mod)) { |
| 22926 | return sema.fail(block, ty_src, "expected (optional) pointer", .{}); | 23477 | return sema.fail(block, ty_src, "expected (optional) pointer", .{}); |
| 22927 | } | 23478 | } |
| 22928 | if (!try sema.validateExternType(ty.childType(), .other)) { | 23479 | if (!try sema.validateExternType(ty.childType(mod), .other)) { |
| 22929 | const msg = msg: { | 23480 | const msg = msg: { |
| 22930 | const mod = sema.mod; | ||
| 22931 | const msg = try sema.errMsg(block, ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(mod)}); | 23481 | const msg = try sema.errMsg(block, ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(mod)}); |
| 22932 | errdefer msg.destroy(sema.gpa); | 23482 | errdefer msg.destroy(sema.gpa); |
| 22933 | const src_decl = sema.mod.declPtr(block.src_decl); | 23483 | const src_decl = sema.mod.declPtr(block.src_decl); |
| 22934 | try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl), ty, .other); | 23484 | try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), ty, .other); |
| 22935 | break :msg msg; | 23485 | break :msg msg; |
| 22936 | }; | 23486 | }; |
| 22937 | return sema.failWithOwnedErrorMsg(msg); | 23487 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -22945,52 +23495,51 @@ fn zirBuiltinExtern( | ... | @@ -22945,52 +23495,51 @@ fn zirBuiltinExtern( |
| 22945 | else => |e| return e, | 23495 | else => |e| return e, |
| 22946 | }; | 23496 | }; |
| 22947 | 23497 | ||
| 22948 | if (options.linkage == .Weak and !ty.ptrAllowsZero()) { | 23498 | if (options.linkage == .Weak and !ty.ptrAllowsZero(mod)) { |
| 22949 | ty = try Type.optional(sema.arena, ty); | 23499 | ty = try Type.optional(sema.arena, ty, mod); |
| 22950 | } | 23500 | } |
| 22951 | 23501 | ||
| 22952 | // TODO check duplicate extern | 23502 | // TODO check duplicate extern |
| 22953 | 23503 | ||
| 22954 | const new_decl_index = try sema.mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null); | 23504 | const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null); |
| 22955 | errdefer sema.mod.destroyDecl(new_decl_index); | 23505 | errdefer mod.destroyDecl(new_decl_index); |
| 22956 | const new_decl = sema.mod.declPtr(new_decl_index); | 23506 | const new_decl = mod.declPtr(new_decl_index); |
| 22957 | new_decl.name = try sema.gpa.dupeZ(u8, options.name); | 23507 | new_decl.name = options.name; |
| 22958 | 23508 | ||
| 22959 | { | 23509 | { |
| 22960 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | 23510 | const new_var = try mod.intern(.{ .variable = .{ |
| 22961 | errdefer new_decl_arena.deinit(); | 23511 | .ty = ty.toIntern(), |
| 22962 | const new_decl_arena_allocator = new_decl_arena.allocator(); | 23512 | .init = .none, |
| 22963 | 23513 | .decl = sema.owner_decl_index, | |
| 22964 | const new_var = try new_decl_arena_allocator.create(Module.Var); | ||
| 22965 | new_var.* = .{ | ||
| 22966 | .owner_decl = sema.owner_decl_index, | ||
| 22967 | .init = Value.initTag(.unreachable_value), | ||
| 22968 | .is_extern = true, | 23514 | .is_extern = true, |
| 22969 | .is_mutable = false, | 23515 | .is_const = true, |
| 22970 | .is_threadlocal = options.is_thread_local, | 23516 | .is_threadlocal = options.is_thread_local, |
| 22971 | .is_weak_linkage = options.linkage == .Weak, | 23517 | .is_weak_linkage = options.linkage == .Weak, |
| 22972 | .lib_name = null, | 23518 | } }); |
| 22973 | }; | ||
| 22974 | 23519 | ||
| 22975 | new_decl.src_line = sema.owner_decl.src_line; | 23520 | new_decl.src_line = sema.owner_decl.src_line; |
| 22976 | // We only access this decl through the decl_ref with the correct type created | 23521 | // We only access this decl through the decl_ref with the correct type created |
| 22977 | // below, so this type doesn't matter | 23522 | // below, so this type doesn't matter |
| 22978 | new_decl.ty = Type.Tag.init(.anyopaque); | 23523 | new_decl.ty = ty; |
| 22979 | new_decl.val = try Value.Tag.variable.create(new_decl_arena_allocator, new_var); | 23524 | new_decl.val = new_var.toValue(); |
| 22980 | new_decl.@"align" = 0; | 23525 | new_decl.@"align" = 0; |
| 22981 | new_decl.@"linksection" = null; | 23526 | new_decl.@"linksection" = .none; |
| 22982 | new_decl.has_tv = true; | 23527 | new_decl.has_tv = true; |
| 22983 | new_decl.analysis = .complete; | 23528 | new_decl.analysis = .complete; |
| 22984 | new_decl.generation = sema.mod.generation; | 23529 | new_decl.generation = mod.generation; |
| 22985 | |||
| 22986 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 22987 | } | 23530 | } |
| 22988 | 23531 | ||
| 22989 | try sema.mod.declareDeclDependency(sema.owner_decl_index, new_decl_index); | 23532 | try mod.declareDeclDependency(sema.owner_decl_index, new_decl_index); |
| 22990 | try sema.ensureDeclAnalyzed(new_decl_index); | 23533 | try sema.ensureDeclAnalyzed(new_decl_index); |
| 22991 | 23534 | ||
| 22992 | const ref = try Value.Tag.decl_ref.create(sema.arena, new_decl_index); | 23535 | return sema.addConstant(ty, try mod.getCoerced((try mod.intern(.{ .ptr = .{ |
| 22993 | return sema.addConstant(ty, ref); | 23536 | .ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 23537 | .ptr_type => ty.toIntern(), | ||
| 23538 | .opt_type => |child_type| child_type, | ||
| 23539 | else => unreachable, | ||
| 23540 | }, | ||
| 23541 | .addr = .{ .decl = new_decl_index }, | ||
| 23542 | } })).toValue(), ty)); | ||
| 22994 | } | 23543 | } |
| 22995 | 23544 | ||
| 22996 | fn zirWorkItem( | 23545 | fn zirWorkItem( |
| ... | @@ -23073,7 +23622,7 @@ fn validateVarType( | ... | @@ -23073,7 +23622,7 @@ fn validateVarType( |
| 23073 | const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)}); | 23622 | const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)}); |
| 23074 | errdefer msg.destroy(sema.gpa); | 23623 | errdefer msg.destroy(sema.gpa); |
| 23075 | const src_decl = mod.declPtr(block.src_decl); | 23624 | const src_decl = mod.declPtr(block.src_decl); |
| 23076 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), var_ty, .other); | 23625 | try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), var_ty, .other); |
| 23077 | break :msg msg; | 23626 | break :msg msg; |
| 23078 | }; | 23627 | }; |
| 23079 | return sema.failWithOwnedErrorMsg(msg); | 23628 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -23086,8 +23635,8 @@ fn validateVarType( | ... | @@ -23086,8 +23635,8 @@ fn validateVarType( |
| 23086 | errdefer msg.destroy(sema.gpa); | 23635 | errdefer msg.destroy(sema.gpa); |
| 23087 | 23636 | ||
| 23088 | const src_decl = mod.declPtr(block.src_decl); | 23637 | const src_decl = mod.declPtr(block.src_decl); |
| 23089 | try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl), var_ty); | 23638 | try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), var_ty); |
| 23090 | if (var_ty.zigTypeTag() == .ComptimeInt or var_ty.zigTypeTag() == .ComptimeFloat) { | 23639 | if (var_ty.zigTypeTag(mod) == .ComptimeInt or var_ty.zigTypeTag(mod) == .ComptimeFloat) { |
| 23091 | try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{}); | 23640 | try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{}); |
| 23092 | } | 23641 | } |
| 23093 | 23642 | ||
| ... | @@ -23101,8 +23650,9 @@ fn validateRunTimeType( | ... | @@ -23101,8 +23650,9 @@ fn validateRunTimeType( |
| 23101 | var_ty: Type, | 23650 | var_ty: Type, |
| 23102 | is_extern: bool, | 23651 | is_extern: bool, |
| 23103 | ) CompileError!bool { | 23652 | ) CompileError!bool { |
| 23653 | const mod = sema.mod; | ||
| 23104 | var ty = var_ty; | 23654 | var ty = var_ty; |
| 23105 | while (true) switch (ty.zigTypeTag()) { | 23655 | while (true) switch (ty.zigTypeTag(mod)) { |
| 23106 | .Bool, | 23656 | .Bool, |
| 23107 | .Int, | 23657 | .Int, |
| 23108 | .Float, | 23658 | .Float, |
| ... | @@ -23125,23 +23675,22 @@ fn validateRunTimeType( | ... | @@ -23125,23 +23675,22 @@ fn validateRunTimeType( |
| 23125 | => return false, | 23675 | => return false, |
| 23126 | 23676 | ||
| 23127 | .Pointer => { | 23677 | .Pointer => { |
| 23128 | const elem_ty = ty.childType(); | 23678 | const elem_ty = ty.childType(mod); |
| 23129 | switch (elem_ty.zigTypeTag()) { | 23679 | switch (elem_ty.zigTypeTag(mod)) { |
| 23130 | .Opaque => return true, | 23680 | .Opaque => return true, |
| 23131 | .Fn => return elem_ty.isFnOrHasRuntimeBits(), | 23681 | .Fn => return elem_ty.isFnOrHasRuntimeBits(mod), |
| 23132 | else => ty = elem_ty, | 23682 | else => ty = elem_ty, |
| 23133 | } | 23683 | } |
| 23134 | }, | 23684 | }, |
| 23135 | .Opaque => return is_extern, | 23685 | .Opaque => return is_extern, |
| 23136 | 23686 | ||
| 23137 | .Optional => { | 23687 | .Optional => { |
| 23138 | var buf: Type.Payload.ElemType = undefined; | 23688 | const child_ty = ty.optionalChild(mod); |
| 23139 | const child_ty = ty.optionalChild(&buf); | ||
| 23140 | return sema.validateRunTimeType(child_ty, is_extern); | 23689 | return sema.validateRunTimeType(child_ty, is_extern); |
| 23141 | }, | 23690 | }, |
| 23142 | .Array, .Vector => ty = ty.elemType(), | 23691 | .Array, .Vector => ty = ty.childType(mod), |
| 23143 | 23692 | ||
| 23144 | .ErrorUnion => ty = ty.errorUnionPayload(), | 23693 | .ErrorUnion => ty = ty.errorUnionPayload(mod), |
| 23145 | 23694 | ||
| 23146 | .Struct, .Union => { | 23695 | .Struct, .Union => { |
| 23147 | const resolved_ty = try sema.resolveTypeFields(ty); | 23696 | const resolved_ty = try sema.resolveTypeFields(ty); |
| ... | @@ -23151,7 +23700,7 @@ fn validateRunTimeType( | ... | @@ -23151,7 +23700,7 @@ fn validateRunTimeType( |
| 23151 | }; | 23700 | }; |
| 23152 | } | 23701 | } |
| 23153 | 23702 | ||
| 23154 | const TypeSet = std.HashMapUnmanaged(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage); | 23703 | const TypeSet = std.AutoHashMapUnmanaged(InternPool.Index, void); |
| 23155 | 23704 | ||
| 23156 | fn explainWhyTypeIsComptime( | 23705 | fn explainWhyTypeIsComptime( |
| 23157 | sema: *Sema, | 23706 | sema: *Sema, |
| ... | @@ -23174,7 +23723,7 @@ fn explainWhyTypeIsComptimeInner( | ... | @@ -23174,7 +23723,7 @@ fn explainWhyTypeIsComptimeInner( |
| 23174 | type_set: *TypeSet, | 23723 | type_set: *TypeSet, |
| 23175 | ) CompileError!void { | 23724 | ) CompileError!void { |
| 23176 | const mod = sema.mod; | 23725 | const mod = sema.mod; |
| 23177 | switch (ty.zigTypeTag()) { | 23726 | switch (ty.zigTypeTag(mod)) { |
| 23178 | .Bool, | 23727 | .Bool, |
| 23179 | .Int, | 23728 | .Int, |
| 23180 | .Float, | 23729 | .Float, |
| ... | @@ -23208,12 +23757,12 @@ fn explainWhyTypeIsComptimeInner( | ... | @@ -23208,12 +23757,12 @@ fn explainWhyTypeIsComptimeInner( |
| 23208 | }, | 23757 | }, |
| 23209 | 23758 | ||
| 23210 | .Array, .Vector => { | 23759 | .Array, .Vector => { |
| 23211 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.elemType(), type_set); | 23760 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(mod), type_set); |
| 23212 | }, | 23761 | }, |
| 23213 | .Pointer => { | 23762 | .Pointer => { |
| 23214 | const elem_ty = ty.elemType2(); | 23763 | const elem_ty = ty.elemType2(mod); |
| 23215 | if (elem_ty.zigTypeTag() == .Fn) { | 23764 | if (elem_ty.zigTypeTag(mod) == .Fn) { |
| 23216 | const fn_info = elem_ty.fnInfo(); | 23765 | const fn_info = mod.typeToFunc(elem_ty).?; |
| 23217 | if (fn_info.is_generic) { | 23766 | if (fn_info.is_generic) { |
| 23218 | try mod.errNoteNonLazy(src_loc, msg, "function is generic", .{}); | 23767 | try mod.errNoteNonLazy(src_loc, msg, "function is generic", .{}); |
| 23219 | } | 23768 | } |
| ... | @@ -23221,29 +23770,27 @@ fn explainWhyTypeIsComptimeInner( | ... | @@ -23221,29 +23770,27 @@ fn explainWhyTypeIsComptimeInner( |
| 23221 | .Inline => try mod.errNoteNonLazy(src_loc, msg, "function has inline calling convention", .{}), | 23770 | .Inline => try mod.errNoteNonLazy(src_loc, msg, "function has inline calling convention", .{}), |
| 23222 | else => {}, | 23771 | else => {}, |
| 23223 | } | 23772 | } |
| 23224 | if (fn_info.return_type.comptimeOnly()) { | 23773 | if (fn_info.return_type.toType().comptimeOnly(mod)) { |
| 23225 | try mod.errNoteNonLazy(src_loc, msg, "function has a comptime-only return type", .{}); | 23774 | try mod.errNoteNonLazy(src_loc, msg, "function has a comptime-only return type", .{}); |
| 23226 | } | 23775 | } |
| 23227 | return; | 23776 | return; |
| 23228 | } | 23777 | } |
| 23229 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.elemType(), type_set); | 23778 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(mod), type_set); |
| 23230 | }, | 23779 | }, |
| 23231 | 23780 | ||
| 23232 | .Optional => { | 23781 | .Optional => { |
| 23233 | var buf: Type.Payload.ElemType = undefined; | 23782 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(mod), type_set); |
| 23234 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(&buf), type_set); | ||
| 23235 | }, | 23783 | }, |
| 23236 | .ErrorUnion => { | 23784 | .ErrorUnion => { |
| 23237 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.errorUnionPayload(), type_set); | 23785 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.errorUnionPayload(mod), type_set); |
| 23238 | }, | 23786 | }, |
| 23239 | 23787 | ||
| 23240 | .Struct => { | 23788 | .Struct => { |
| 23241 | if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return; | 23789 | if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return; |
| 23242 | 23790 | ||
| 23243 | if (ty.castTag(.@"struct")) |payload| { | 23791 | if (mod.typeToStruct(ty)) |struct_obj| { |
| 23244 | const struct_obj = payload.data; | ||
| 23245 | for (struct_obj.fields.values(), 0..) |field, i| { | 23792 | for (struct_obj.fields.values(), 0..) |field, i| { |
| 23246 | const field_src_loc = struct_obj.fieldSrcLoc(sema.mod, .{ | 23793 | const field_src_loc = mod.fieldSrcLoc(struct_obj.owner_decl, .{ |
| 23247 | .index = i, | 23794 | .index = i, |
| 23248 | .range = .type, | 23795 | .range = .type, |
| 23249 | }); | 23796 | }); |
| ... | @@ -23258,12 +23805,11 @@ fn explainWhyTypeIsComptimeInner( | ... | @@ -23258,12 +23805,11 @@ fn explainWhyTypeIsComptimeInner( |
| 23258 | }, | 23805 | }, |
| 23259 | 23806 | ||
| 23260 | .Union => { | 23807 | .Union => { |
| 23261 | if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return; | 23808 | if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return; |
| 23262 | 23809 | ||
| 23263 | if (ty.cast(Type.Payload.Union)) |payload| { | 23810 | if (mod.typeToUnion(ty)) |union_obj| { |
| 23264 | const union_obj = payload.data; | ||
| 23265 | for (union_obj.fields.values(), 0..) |field, i| { | 23811 | for (union_obj.fields.values(), 0..) |field, i| { |
| 23266 | const field_src_loc = union_obj.fieldSrcLoc(sema.mod, .{ | 23812 | const field_src_loc = mod.fieldSrcLoc(union_obj.owner_decl, .{ |
| 23267 | .index = i, | 23813 | .index = i, |
| 23268 | .range = .type, | 23814 | .range = .type, |
| 23269 | }); | 23815 | }); |
| ... | @@ -23295,7 +23841,8 @@ fn validateExternType( | ... | @@ -23295,7 +23841,8 @@ fn validateExternType( |
| 23295 | ty: Type, | 23841 | ty: Type, |
| 23296 | position: ExternPosition, | 23842 | position: ExternPosition, |
| 23297 | ) !bool { | 23843 | ) !bool { |
| 23298 | switch (ty.zigTypeTag()) { | 23844 | const mod = sema.mod; |
| 23845 | switch (ty.zigTypeTag(mod)) { | ||
| 23299 | .Type, | 23846 | .Type, |
| 23300 | .ComptimeFloat, | 23847 | .ComptimeFloat, |
| 23301 | .ComptimeInt, | 23848 | .ComptimeInt, |
| ... | @@ -23313,8 +23860,8 @@ fn validateExternType( | ... | @@ -23313,8 +23860,8 @@ fn validateExternType( |
| 23313 | .Float, | 23860 | .Float, |
| 23314 | .AnyFrame, | 23861 | .AnyFrame, |
| 23315 | => return true, | 23862 | => return true, |
| 23316 | .Pointer => return !(ty.isSlice() or try sema.typeRequiresComptime(ty)), | 23863 | .Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)), |
| 23317 | .Int => switch (ty.intInfo(sema.mod.getTarget()).bits) { | 23864 | .Int => switch (ty.intInfo(mod).bits) { |
| 23318 | 8, 16, 32, 64, 128 => return true, | 23865 | 8, 16, 32, 64, 128 => return true, |
| 23319 | else => return false, | 23866 | else => return false, |
| 23320 | }, | 23867 | }, |
| ... | @@ -23323,20 +23870,18 @@ fn validateExternType( | ... | @@ -23323,20 +23870,18 @@ fn validateExternType( |
| 23323 | const target = sema.mod.getTarget(); | 23870 | const target = sema.mod.getTarget(); |
| 23324 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. | 23871 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. |
| 23325 | // The goal is to experiment with more integrated CPU/GPU code. | 23872 | // The goal is to experiment with more integrated CPU/GPU code. |
| 23326 | if (ty.fnCallingConvention() == .Kernel and (target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64)) { | 23873 | if (ty.fnCallingConvention(mod) == .Kernel and (target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64)) { |
| 23327 | return true; | 23874 | return true; |
| 23328 | } | 23875 | } |
| 23329 | return !Type.fnCallingConventionAllowsZigTypes(target, ty.fnCallingConvention()); | 23876 | return !target_util.fnCallConvAllowsZigTypes(target, ty.fnCallingConvention(mod)); |
| 23330 | }, | 23877 | }, |
| 23331 | .Enum => { | 23878 | .Enum => { |
| 23332 | var buf: Type.Payload.Bits = undefined; | 23879 | return sema.validateExternType(ty.intTagType(mod), position); |
| 23333 | return sema.validateExternType(ty.intTagType(&buf), position); | ||
| 23334 | }, | 23880 | }, |
| 23335 | .Struct, .Union => switch (ty.containerLayout()) { | 23881 | .Struct, .Union => switch (ty.containerLayout(mod)) { |
| 23336 | .Extern => return true, | 23882 | .Extern => return true, |
| 23337 | .Packed => { | 23883 | .Packed => { |
| 23338 | const target = sema.mod.getTarget(); | 23884 | const bit_size = try ty.bitSizeAdvanced(mod, sema); |
| 23339 | const bit_size = try ty.bitSizeAdvanced(target, sema); | ||
| 23340 | switch (bit_size) { | 23885 | switch (bit_size) { |
| 23341 | 8, 16, 32, 64, 128 => return true, | 23886 | 8, 16, 32, 64, 128 => return true, |
| 23342 | else => return false, | 23887 | else => return false, |
| ... | @@ -23346,10 +23891,10 @@ fn validateExternType( | ... | @@ -23346,10 +23891,10 @@ fn validateExternType( |
| 23346 | }, | 23891 | }, |
| 23347 | .Array => { | 23892 | .Array => { |
| 23348 | if (position == .ret_ty or position == .param_ty) return false; | 23893 | if (position == .ret_ty or position == .param_ty) return false; |
| 23349 | return sema.validateExternType(ty.elemType2(), .element); | 23894 | return sema.validateExternType(ty.elemType2(mod), .element); |
| 23350 | }, | 23895 | }, |
| 23351 | .Vector => return sema.validateExternType(ty.elemType2(), .element), | 23896 | .Vector => return sema.validateExternType(ty.elemType2(mod), .element), |
| 23352 | .Optional => return ty.isPtrLikeOptional(), | 23897 | .Optional => return ty.isPtrLikeOptional(mod), |
| 23353 | } | 23898 | } |
| 23354 | } | 23899 | } |
| 23355 | 23900 | ||
| ... | @@ -23361,7 +23906,7 @@ fn explainWhyTypeIsNotExtern( | ... | @@ -23361,7 +23906,7 @@ fn explainWhyTypeIsNotExtern( |
| 23361 | position: ExternPosition, | 23906 | position: ExternPosition, |
| 23362 | ) CompileError!void { | 23907 | ) CompileError!void { |
| 23363 | const mod = sema.mod; | 23908 | const mod = sema.mod; |
| 23364 | switch (ty.zigTypeTag()) { | 23909 | switch (ty.zigTypeTag(mod)) { |
| 23365 | .Opaque, | 23910 | .Opaque, |
| 23366 | .Bool, | 23911 | .Bool, |
| 23367 | .Float, | 23912 | .Float, |
| ... | @@ -23380,17 +23925,17 @@ fn explainWhyTypeIsNotExtern( | ... | @@ -23380,17 +23925,17 @@ fn explainWhyTypeIsNotExtern( |
| 23380 | => return, | 23925 | => return, |
| 23381 | 23926 | ||
| 23382 | .Pointer => { | 23927 | .Pointer => { |
| 23383 | if (ty.isSlice()) { | 23928 | if (ty.isSlice(mod)) { |
| 23384 | try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); | 23929 | try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}); |
| 23385 | } else { | 23930 | } else { |
| 23386 | const pointee_ty = ty.childType(); | 23931 | const pointee_ty = ty.childType(mod); |
| 23387 | try mod.errNoteNonLazy(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(sema.mod)}); | 23932 | try mod.errNoteNonLazy(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(sema.mod)}); |
| 23388 | try sema.explainWhyTypeIsComptime(msg, src_loc, pointee_ty); | 23933 | try sema.explainWhyTypeIsComptime(msg, src_loc, pointee_ty); |
| 23389 | } | 23934 | } |
| 23390 | }, | 23935 | }, |
| 23391 | .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}), | 23936 | .Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}), |
| 23392 | .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), | 23937 | .NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), |
| 23393 | .Int => if (!std.math.isPowerOfTwo(ty.intInfo(sema.mod.getTarget()).bits)) { | 23938 | .Int => if (!std.math.isPowerOfTwo(ty.intInfo(mod).bits)) { |
| 23394 | try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{}); | 23939 | try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{}); |
| 23395 | } else { | 23940 | } else { |
| 23396 | try mod.errNoteNonLazy(src_loc, msg, "only integers with 8, 16, 32, 64 and 128 bits are extern compatible", .{}); | 23941 | try mod.errNoteNonLazy(src_loc, msg, "only integers with 8, 16, 32, 64 and 128 bits are extern compatible", .{}); |
| ... | @@ -23401,7 +23946,7 @@ fn explainWhyTypeIsNotExtern( | ... | @@ -23401,7 +23946,7 @@ fn explainWhyTypeIsNotExtern( |
| 23401 | try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{}); | 23946 | try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{}); |
| 23402 | return; | 23947 | return; |
| 23403 | } | 23948 | } |
| 23404 | switch (ty.fnCallingConvention()) { | 23949 | switch (ty.fnCallingConvention(mod)) { |
| 23405 | .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}), | 23950 | .Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}), |
| 23406 | .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}), | 23951 | .Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}), |
| 23407 | .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}), | 23952 | .Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}), |
| ... | @@ -23409,8 +23954,7 @@ fn explainWhyTypeIsNotExtern( | ... | @@ -23409,8 +23954,7 @@ fn explainWhyTypeIsNotExtern( |
| 23409 | } | 23954 | } |
| 23410 | }, | 23955 | }, |
| 23411 | .Enum => { | 23956 | .Enum => { |
| 23412 | var buf: Type.Payload.Bits = undefined; | 23957 | const tag_ty = ty.intTagType(mod); |
| 23413 | const tag_ty = ty.intTagType(&buf); | ||
| 23414 | try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)}); | 23958 | try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)}); |
| 23415 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); | 23959 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); |
| 23416 | }, | 23960 | }, |
| ... | @@ -23422,17 +23966,17 @@ fn explainWhyTypeIsNotExtern( | ... | @@ -23422,17 +23966,17 @@ fn explainWhyTypeIsNotExtern( |
| 23422 | } else if (position == .param_ty) { | 23966 | } else if (position == .param_ty) { |
| 23423 | return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{}); | 23967 | return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{}); |
| 23424 | } | 23968 | } |
| 23425 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), .element); | 23969 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(mod), .element); |
| 23426 | }, | 23970 | }, |
| 23427 | .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), .element), | 23971 | .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(mod), .element), |
| 23428 | .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}), | 23972 | .Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}), |
| 23429 | } | 23973 | } |
| 23430 | } | 23974 | } |
| 23431 | 23975 | ||
| 23432 | /// Returns true if `ty` is allowed in packed types. | 23976 | /// Returns true if `ty` is allowed in packed types. |
| 23433 | /// Does *NOT* require `ty` to be resolved in any way. | 23977 | /// Does *NOT* require `ty` to be resolved in any way. |
| 23434 | fn validatePackedType(ty: Type) bool { | 23978 | fn validatePackedType(ty: Type, mod: *Module) bool { |
| 23435 | switch (ty.zigTypeTag()) { | 23979 | switch (ty.zigTypeTag(mod)) { |
| 23436 | .Type, | 23980 | .Type, |
| 23437 | .ComptimeFloat, | 23981 | .ComptimeFloat, |
| 23438 | .ComptimeInt, | 23982 | .ComptimeInt, |
| ... | @@ -23448,7 +23992,7 @@ fn validatePackedType(ty: Type) bool { | ... | @@ -23448,7 +23992,7 @@ fn validatePackedType(ty: Type) bool { |
| 23448 | .Fn, | 23992 | .Fn, |
| 23449 | .Array, | 23993 | .Array, |
| 23450 | => return false, | 23994 | => return false, |
| 23451 | .Optional => return ty.isPtrLikeOptional(), | 23995 | .Optional => return ty.isPtrLikeOptional(mod), |
| 23452 | .Void, | 23996 | .Void, |
| 23453 | .Bool, | 23997 | .Bool, |
| 23454 | .Float, | 23998 | .Float, |
| ... | @@ -23456,8 +24000,8 @@ fn validatePackedType(ty: Type) bool { | ... | @@ -23456,8 +24000,8 @@ fn validatePackedType(ty: Type) bool { |
| 23456 | .Vector, | 24000 | .Vector, |
| 23457 | .Enum, | 24001 | .Enum, |
| 23458 | => return true, | 24002 | => return true, |
| 23459 | .Pointer => return !ty.isSlice(), | 24003 | .Pointer => return !ty.isSlice(mod), |
| 23460 | .Struct, .Union => return ty.containerLayout() == .Packed, | 24004 | .Struct, .Union => return ty.containerLayout(mod) == .Packed, |
| 23461 | } | 24005 | } |
| 23462 | } | 24006 | } |
| 23463 | 24007 | ||
| ... | @@ -23468,7 +24012,7 @@ fn explainWhyTypeIsNotPacked( | ... | @@ -23468,7 +24012,7 @@ fn explainWhyTypeIsNotPacked( |
| 23468 | ty: Type, | 24012 | ty: Type, |
| 23469 | ) CompileError!void { | 24013 | ) CompileError!void { |
| 23470 | const mod = sema.mod; | 24014 | const mod = sema.mod; |
| 23471 | switch (ty.zigTypeTag()) { | 24015 | switch (ty.zigTypeTag(mod)) { |
| 23472 | .Void, | 24016 | .Void, |
| 23473 | .Bool, | 24017 | .Bool, |
| 23474 | .Float, | 24018 | .Float, |
| ... | @@ -23616,7 +24160,6 @@ fn panicWithMsg( | ... | @@ -23616,7 +24160,6 @@ fn panicWithMsg( |
| 23616 | msg_inst: Air.Inst.Ref, | 24160 | msg_inst: Air.Inst.Ref, |
| 23617 | ) !void { | 24161 | ) !void { |
| 23618 | const mod = sema.mod; | 24162 | const mod = sema.mod; |
| 23619 | const arena = sema.arena; | ||
| 23620 | 24163 | ||
| 23621 | if (!mod.backendSupportsFeature(.panic_fn)) { | 24164 | if (!mod.backendSupportsFeature(.panic_fn)) { |
| 23622 | _ = try block.addNoOp(.trap); | 24165 | _ = try block.addNoOp(.trap); |
| ... | @@ -23626,16 +24169,24 @@ fn panicWithMsg( | ... | @@ -23626,16 +24169,24 @@ fn panicWithMsg( |
| 23626 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); | 24169 | const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); |
| 23627 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); | 24170 | const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); |
| 23628 | const target = mod.getTarget(); | 24171 | const target = mod.getTarget(); |
| 23629 | const ptr_stack_trace_ty = try Type.ptr(arena, mod, .{ | 24172 | const ptr_stack_trace_ty = try mod.ptrType(.{ |
| 23630 | .pointee_type = stack_trace_ty, | 24173 | .child = stack_trace_ty.toIntern(), |
| 23631 | .@"addrspace" = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic | 24174 | .flags = .{ |
| 24175 | .address_space = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic | ||
| 24176 | }, | ||
| 23632 | }); | 24177 | }); |
| 23633 | const null_stack_trace = try sema.addConstant( | 24178 | const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern()); |
| 23634 | try Type.optional(arena, ptr_stack_trace_ty), | 24179 | const null_stack_trace = try sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{ |
| 23635 | Value.null, | 24180 | .ty = opt_ptr_stack_trace_ty.toIntern(), |
| 23636 | ); | 24181 | .val = .none, |
| 23637 | const args: [3]Air.Inst.Ref = .{ msg_inst, null_stack_trace, .null_value }; | 24182 | } })).toValue()); |
| 23638 | try sema.callBuiltin(block, panic_fn, .auto, &args); | 24183 | |
| 24184 | const opt_usize_ty = try mod.optionalType(.usize_type); | ||
| 24185 | const null_ret_addr = try sema.addConstant(opt_usize_ty, (try mod.intern(.{ .opt = .{ | ||
| 24186 | .ty = opt_usize_ty.toIntern(), | ||
| 24187 | .val = .none, | ||
| 24188 | } })).toValue()); | ||
| 24189 | try sema.callBuiltin(block, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr }); | ||
| 23639 | } | 24190 | } |
| 23640 | 24191 | ||
| 23641 | fn panicUnwrapError( | 24192 | fn panicUnwrapError( |
| ... | @@ -23694,20 +24245,6 @@ fn panicIndexOutOfBounds( | ... | @@ -23694,20 +24245,6 @@ fn panicIndexOutOfBounds( |
| 23694 | try sema.safetyCheckFormatted(parent_block, ok, "panicOutOfBounds", &.{ index, len }); | 24245 | try sema.safetyCheckFormatted(parent_block, ok, "panicOutOfBounds", &.{ index, len }); |
| 23695 | } | 24246 | } |
| 23696 | 24247 | ||
| 23697 | fn panicStartGreaterThanEnd( | ||
| 23698 | sema: *Sema, | ||
| 23699 | parent_block: *Block, | ||
| 23700 | start: Air.Inst.Ref, | ||
| 23701 | end: Air.Inst.Ref, | ||
| 23702 | ) !void { | ||
| 23703 | assert(!parent_block.is_comptime); | ||
| 23704 | const ok = try parent_block.addBinOp(.cmp_lte, start, end); | ||
| 23705 | if (!sema.mod.comp.formatted_panics) { | ||
| 23706 | return sema.addSafetyCheck(parent_block, ok, .start_index_greater_than_end); | ||
| 23707 | } | ||
| 23708 | try sema.safetyCheckFormatted(parent_block, ok, "panicStartGreaterThanEnd", &.{ start, end }); | ||
| 23709 | } | ||
| 23710 | |||
| 23711 | fn panicInactiveUnionField( | 24248 | fn panicInactiveUnionField( |
| 23712 | sema: *Sema, | 24249 | sema: *Sema, |
| 23713 | parent_block: *Block, | 24250 | parent_block: *Block, |
| ... | @@ -23731,11 +24268,12 @@ fn panicSentinelMismatch( | ... | @@ -23731,11 +24268,12 @@ fn panicSentinelMismatch( |
| 23731 | sentinel_index: Air.Inst.Ref, | 24268 | sentinel_index: Air.Inst.Ref, |
| 23732 | ) !void { | 24269 | ) !void { |
| 23733 | assert(!parent_block.is_comptime); | 24270 | assert(!parent_block.is_comptime); |
| 24271 | const mod = sema.mod; | ||
| 23734 | const expected_sentinel_val = maybe_sentinel orelse return; | 24272 | const expected_sentinel_val = maybe_sentinel orelse return; |
| 23735 | const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val); | 24273 | const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val); |
| 23736 | 24274 | ||
| 23737 | const ptr_ty = sema.typeOf(ptr); | 24275 | const ptr_ty = sema.typeOf(ptr); |
| 23738 | const actual_sentinel = if (ptr_ty.isSlice()) | 24276 | const actual_sentinel = if (ptr_ty.isSlice(mod)) |
| 23739 | try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index) | 24277 | try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index) |
| 23740 | else blk: { | 24278 | else blk: { |
| 23741 | const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null); | 24279 | const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null); |
| ... | @@ -23743,7 +24281,7 @@ fn panicSentinelMismatch( | ... | @@ -23743,7 +24281,7 @@ fn panicSentinelMismatch( |
| 23743 | break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr); | 24281 | break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr); |
| 23744 | }; | 24282 | }; |
| 23745 | 24283 | ||
| 23746 | const ok = if (sentinel_ty.zigTypeTag() == .Vector) ok: { | 24284 | const ok = if (sentinel_ty.zigTypeTag(mod) == .Vector) ok: { |
| 23747 | const eql = | 24285 | const eql = |
| 23748 | try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq); | 24286 | try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq); |
| 23749 | break :ok try parent_block.addInst(.{ | 24287 | break :ok try parent_block.addInst(.{ |
| ... | @@ -23753,7 +24291,7 @@ fn panicSentinelMismatch( | ... | @@ -23753,7 +24291,7 @@ fn panicSentinelMismatch( |
| 23753 | .operation = .And, | 24291 | .operation = .And, |
| 23754 | } }, | 24292 | } }, |
| 23755 | }); | 24293 | }); |
| 23756 | } else if (sentinel_ty.isSelfComparable(true)) | 24294 | } else if (sentinel_ty.isSelfComparable(mod, true)) |
| 23757 | try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel) | 24295 | try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel) |
| 23758 | else { | 24296 | else { |
| 23759 | const panic_fn = try sema.getBuiltin("checkNonScalarSentinel"); | 24297 | const panic_fn = try sema.getBuiltin("checkNonScalarSentinel"); |
| ... | @@ -23805,12 +24343,14 @@ fn safetyPanic( | ... | @@ -23805,12 +24343,14 @@ fn safetyPanic( |
| 23805 | block: *Block, | 24343 | block: *Block, |
| 23806 | panic_id: PanicId, | 24344 | panic_id: PanicId, |
| 23807 | ) CompileError!void { | 24345 | ) CompileError!void { |
| 24346 | const mod = sema.mod; | ||
| 24347 | const gpa = sema.gpa; | ||
| 23808 | const panic_messages_ty = try sema.getBuiltinType("panic_messages"); | 24348 | const panic_messages_ty = try sema.getBuiltinType("panic_messages"); |
| 23809 | const msg_decl_index = (try sema.namespaceLookup( | 24349 | const msg_decl_index = (try sema.namespaceLookup( |
| 23810 | block, | 24350 | block, |
| 23811 | sema.src, | 24351 | sema.src, |
| 23812 | panic_messages_ty.getNamespace().?, | 24352 | panic_messages_ty.getNamespaceIndex(mod).unwrap().?, |
| 23813 | @tagName(panic_id), | 24353 | try mod.intern_pool.getOrPutString(gpa, @tagName(panic_id)), |
| 23814 | )).?; | 24354 | )).?; |
| 23815 | 24355 | ||
| 23816 | const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index); | 24356 | const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index); |
| ... | @@ -23842,37 +24382,38 @@ fn fieldVal( | ... | @@ -23842,37 +24382,38 @@ fn fieldVal( |
| 23842 | block: *Block, | 24382 | block: *Block, |
| 23843 | src: LazySrcLoc, | 24383 | src: LazySrcLoc, |
| 23844 | object: Air.Inst.Ref, | 24384 | object: Air.Inst.Ref, |
| 23845 | field_name: []const u8, | 24385 | field_name: InternPool.NullTerminatedString, |
| 23846 | field_name_src: LazySrcLoc, | 24386 | field_name_src: LazySrcLoc, |
| 23847 | ) CompileError!Air.Inst.Ref { | 24387 | ) CompileError!Air.Inst.Ref { |
| 23848 | // When editing this function, note that there is corresponding logic to be edited | 24388 | // When editing this function, note that there is corresponding logic to be edited |
| 23849 | // in `fieldPtr`. This function takes a value and returns a value. | 24389 | // in `fieldPtr`. This function takes a value and returns a value. |
| 23850 | 24390 | ||
| 23851 | const arena = sema.arena; | 24391 | const mod = sema.mod; |
| 24392 | const ip = &mod.intern_pool; | ||
| 23852 | const object_src = src; // TODO better source location | 24393 | const object_src = src; // TODO better source location |
| 23853 | const object_ty = sema.typeOf(object); | 24394 | const object_ty = sema.typeOf(object); |
| 23854 | 24395 | ||
| 23855 | // Zig allows dereferencing a single pointer during field lookup. Note that | 24396 | // Zig allows dereferencing a single pointer during field lookup. Note that |
| 23856 | // we don't actually need to generate the dereference some field lookups, like the | 24397 | // we don't actually need to generate the dereference some field lookups, like the |
| 23857 | // length of arrays and other comptime operations. | 24398 | // length of arrays and other comptime operations. |
| 23858 | const is_pointer_to = object_ty.isSinglePointer(); | 24399 | const is_pointer_to = object_ty.isSinglePointer(mod); |
| 23859 | 24400 | ||
| 23860 | const inner_ty = if (is_pointer_to) | 24401 | const inner_ty = if (is_pointer_to) |
| 23861 | object_ty.childType() | 24402 | object_ty.childType(mod) |
| 23862 | else | 24403 | else |
| 23863 | object_ty; | 24404 | object_ty; |
| 23864 | 24405 | ||
| 23865 | switch (inner_ty.zigTypeTag()) { | 24406 | switch (inner_ty.zigTypeTag(mod)) { |
| 23866 | .Array => { | 24407 | .Array => { |
| 23867 | if (mem.eql(u8, field_name, "len")) { | 24408 | if (ip.stringEqlSlice(field_name, "len")) { |
| 23868 | return sema.addConstant( | 24409 | return sema.addConstant( |
| 23869 | Type.usize, | 24410 | Type.usize, |
| 23870 | try Value.Tag.int_u64.create(arena, inner_ty.arrayLen()), | 24411 | try mod.intValue(Type.usize, inner_ty.arrayLen(mod)), |
| 23871 | ); | 24412 | ); |
| 23872 | } else if (mem.eql(u8, field_name, "ptr") and is_pointer_to) { | 24413 | } else if (ip.stringEqlSlice(field_name, "ptr") and is_pointer_to) { |
| 23873 | const ptr_info = object_ty.ptrInfo().data; | 24414 | const ptr_info = object_ty.ptrInfo(mod); |
| 23874 | const result_ty = try Type.ptr(sema.arena, sema.mod, .{ | 24415 | const result_ty = try Type.ptr(sema.arena, mod, .{ |
| 23875 | .pointee_type = ptr_info.pointee_type.childType(), | 24416 | .pointee_type = ptr_info.pointee_type.childType(mod), |
| 23876 | .sentinel = ptr_info.sentinel, | 24417 | .sentinel = ptr_info.sentinel, |
| 23877 | .@"align" = ptr_info.@"align", | 24418 | .@"align" = ptr_info.@"align", |
| 23878 | .@"addrspace" = ptr_info.@"addrspace", | 24419 | .@"addrspace" = ptr_info.@"addrspace", |
| ... | @@ -23889,21 +24430,21 @@ fn fieldVal( | ... | @@ -23889,21 +24430,21 @@ fn fieldVal( |
| 23889 | return sema.fail( | 24430 | return sema.fail( |
| 23890 | block, | 24431 | block, |
| 23891 | field_name_src, | 24432 | field_name_src, |
| 23892 | "no member named '{s}' in '{}'", | 24433 | "no member named '{}' in '{}'", |
| 23893 | .{ field_name, object_ty.fmt(sema.mod) }, | 24434 | .{ field_name.fmt(ip), object_ty.fmt(mod) }, |
| 23894 | ); | 24435 | ); |
| 23895 | } | 24436 | } |
| 23896 | }, | 24437 | }, |
| 23897 | .Pointer => { | 24438 | .Pointer => { |
| 23898 | const ptr_info = inner_ty.ptrInfo().data; | 24439 | const ptr_info = inner_ty.ptrInfo(mod); |
| 23899 | if (ptr_info.size == .Slice) { | 24440 | if (ptr_info.size == .Slice) { |
| 23900 | if (mem.eql(u8, field_name, "ptr")) { | 24441 | if (ip.stringEqlSlice(field_name, "ptr")) { |
| 23901 | const slice = if (is_pointer_to) | 24442 | const slice = if (is_pointer_to) |
| 23902 | try sema.analyzeLoad(block, src, object, object_src) | 24443 | try sema.analyzeLoad(block, src, object, object_src) |
| 23903 | else | 24444 | else |
| 23904 | object; | 24445 | object; |
| 23905 | return sema.analyzeSlicePtr(block, object_src, slice, inner_ty); | 24446 | return sema.analyzeSlicePtr(block, object_src, slice, inner_ty); |
| 23906 | } else if (mem.eql(u8, field_name, "len")) { | 24447 | } else if (ip.stringEqlSlice(field_name, "len")) { |
| 23907 | const slice = if (is_pointer_to) | 24448 | const slice = if (is_pointer_to) |
| 23908 | try sema.analyzeLoad(block, src, object, object_src) | 24449 | try sema.analyzeLoad(block, src, object, object_src) |
| 23909 | else | 24450 | else |
| ... | @@ -23913,8 +24454,8 @@ fn fieldVal( | ... | @@ -23913,8 +24454,8 @@ fn fieldVal( |
| 23913 | return sema.fail( | 24454 | return sema.fail( |
| 23914 | block, | 24455 | block, |
| 23915 | field_name_src, | 24456 | field_name_src, |
| 23916 | "no member named '{s}' in '{}'", | 24457 | "no member named '{}' in '{}'", |
| 23917 | .{ field_name, object_ty.fmt(sema.mod) }, | 24458 | .{ field_name.fmt(ip), object_ty.fmt(mod) }, |
| 23918 | ); | 24459 | ); |
| 23919 | } | 24460 | } |
| 23920 | } | 24461 | } |
| ... | @@ -23926,66 +24467,74 @@ fn fieldVal( | ... | @@ -23926,66 +24467,74 @@ fn fieldVal( |
| 23926 | object; | 24467 | object; |
| 23927 | 24468 | ||
| 23928 | const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; | 24469 | const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; |
| 23929 | var to_type_buffer: Value.ToTypeBuffer = undefined; | 24470 | const child_type = val.toType(); |
| 23930 | const child_type = val.toType(&to_type_buffer); | ||
| 23931 | 24471 | ||
| 23932 | switch (try child_type.zigTypeTagOrPoison()) { | 24472 | switch (try child_type.zigTypeTagOrPoison(mod)) { |
| 23933 | .ErrorSet => { | 24473 | .ErrorSet => { |
| 23934 | const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { | 24474 | switch (ip.indexToKey(child_type.toIntern())) { |
| 23935 | if (payload.data.names.getEntry(field_name)) |entry| { | 24475 | .error_set_type => |error_set_type| blk: { |
| 23936 | break :blk entry.key_ptr.*; | 24476 | if (error_set_type.nameIndex(ip, field_name) != null) break :blk; |
| 23937 | } | 24477 | const msg = msg: { |
| 23938 | const msg = msg: { | 24478 | const msg = try sema.errMsg(block, src, "no error named '{}' in '{}'", .{ |
| 23939 | const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{ | 24479 | field_name.fmt(ip), child_type.fmt(mod), |
| 23940 | field_name, child_type.fmt(sema.mod), | 24480 | }); |
| 23941 | }); | 24481 | errdefer msg.destroy(sema.gpa); |
| 23942 | errdefer msg.destroy(sema.gpa); | 24482 | try sema.addDeclaredHereNote(msg, child_type); |
| 23943 | try sema.addDeclaredHereNote(msg, child_type); | 24483 | break :msg msg; |
| 23944 | break :msg msg; | 24484 | }; |
| 23945 | }; | 24485 | return sema.failWithOwnedErrorMsg(msg); |
| 23946 | return sema.failWithOwnedErrorMsg(msg); | 24486 | }, |
| 23947 | } else (try sema.mod.getErrorValue(field_name)).key; | 24487 | .inferred_error_set_type => { |
| 24488 | return sema.fail(block, src, "TODO handle inferred error sets here", .{}); | ||
| 24489 | }, | ||
| 24490 | .simple_type => |t| { | ||
| 24491 | assert(t == .anyerror); | ||
| 24492 | _ = try mod.getErrorValue(field_name); | ||
| 24493 | }, | ||
| 24494 | else => unreachable, | ||
| 24495 | } | ||
| 23948 | 24496 | ||
| 23949 | return sema.addConstant( | 24497 | const error_set_type = if (!child_type.isAnyError(mod)) |
| 23950 | if (!child_type.isAnyError()) | 24498 | child_type |
| 23951 | try child_type.copy(arena) | 24499 | else |
| 23952 | else | 24500 | try mod.singleErrorSetType(field_name); |
| 23953 | try Type.Tag.error_set_single.create(arena, name), | 24501 | return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ |
| 23954 | try Value.Tag.@"error".create(arena, .{ .name = name }), | 24502 | .ty = error_set_type.toIntern(), |
| 23955 | ); | 24503 | .name = field_name, |
| 24504 | } })).toValue()); | ||
| 23956 | }, | 24505 | }, |
| 23957 | .Union => { | 24506 | .Union => { |
| 23958 | if (child_type.getNamespace()) |namespace| { | 24507 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { |
| 23959 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { | 24508 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { |
| 23960 | return inst; | 24509 | return inst; |
| 23961 | } | 24510 | } |
| 23962 | } | 24511 | } |
| 23963 | const union_ty = try sema.resolveTypeFields(child_type); | 24512 | const union_ty = try sema.resolveTypeFields(child_type); |
| 23964 | if (union_ty.unionTagType()) |enum_ty| { | 24513 | if (union_ty.unionTagType(mod)) |enum_ty| { |
| 23965 | if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| { | 24514 | if (enum_ty.enumFieldIndex(field_name, mod)) |field_index_usize| { |
| 23966 | const field_index = @intCast(u32, field_index_usize); | 24515 | const field_index = @intCast(u32, field_index_usize); |
| 23967 | return sema.addConstant( | 24516 | return sema.addConstant( |
| 23968 | enum_ty, | 24517 | enum_ty, |
| 23969 | try Value.Tag.enum_field_index.create(sema.arena, field_index), | 24518 | try mod.enumValueFieldIndex(enum_ty, field_index), |
| 23970 | ); | 24519 | ); |
| 23971 | } | 24520 | } |
| 23972 | } | 24521 | } |
| 23973 | return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name); | 24522 | return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name); |
| 23974 | }, | 24523 | }, |
| 23975 | .Enum => { | 24524 | .Enum => { |
| 23976 | if (child_type.getNamespace()) |namespace| { | 24525 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { |
| 23977 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { | 24526 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { |
| 23978 | return inst; | 24527 | return inst; |
| 23979 | } | 24528 | } |
| 23980 | } | 24529 | } |
| 23981 | const field_index_usize = child_type.enumFieldIndex(field_name) orelse | 24530 | const field_index_usize = child_type.enumFieldIndex(field_name, mod) orelse |
| 23982 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | 24531 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 23983 | const field_index = @intCast(u32, field_index_usize); | 24532 | const field_index = @intCast(u32, field_index_usize); |
| 23984 | const enum_val = try Value.Tag.enum_field_index.create(arena, field_index); | 24533 | const enum_val = try mod.enumValueFieldIndex(child_type, field_index); |
| 23985 | return sema.addConstant(try child_type.copy(arena), enum_val); | 24534 | return sema.addConstant(child_type, enum_val); |
| 23986 | }, | 24535 | }, |
| 23987 | .Struct, .Opaque => { | 24536 | .Struct, .Opaque => { |
| 23988 | if (child_type.getNamespace()) |namespace| { | 24537 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { |
| 23989 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { | 24538 | if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| { |
| 23990 | return inst; | 24539 | return inst; |
| 23991 | } | 24540 | } |
| ... | @@ -23994,10 +24543,10 @@ fn fieldVal( | ... | @@ -23994,10 +24543,10 @@ fn fieldVal( |
| 23994 | }, | 24543 | }, |
| 23995 | else => { | 24544 | else => { |
| 23996 | const msg = msg: { | 24545 | const msg = msg: { |
| 23997 | const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)}); | 24546 | const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(mod)}); |
| 23998 | errdefer msg.destroy(sema.gpa); | 24547 | errdefer msg.destroy(sema.gpa); |
| 23999 | if (child_type.isSlice()) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{}); | 24548 | if (child_type.isSlice(mod)) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{}); |
| 24000 | if (child_type.zigTypeTag() == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{}); | 24549 | if (child_type.zigTypeTag(mod) == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{}); |
| 24001 | break :msg msg; | 24550 | break :msg msg; |
| 24002 | }; | 24551 | }; |
| 24003 | return sema.failWithOwnedErrorMsg(msg); | 24552 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -24028,50 +24577,52 @@ fn fieldPtr( | ... | @@ -24028,50 +24577,52 @@ fn fieldPtr( |
| 24028 | block: *Block, | 24577 | block: *Block, |
| 24029 | src: LazySrcLoc, | 24578 | src: LazySrcLoc, |
| 24030 | object_ptr: Air.Inst.Ref, | 24579 | object_ptr: Air.Inst.Ref, |
| 24031 | field_name: []const u8, | 24580 | field_name: InternPool.NullTerminatedString, |
| 24032 | field_name_src: LazySrcLoc, | 24581 | field_name_src: LazySrcLoc, |
| 24033 | initializing: bool, | 24582 | initializing: bool, |
| 24034 | ) CompileError!Air.Inst.Ref { | 24583 | ) CompileError!Air.Inst.Ref { |
| 24035 | // When editing this function, note that there is corresponding logic to be edited | 24584 | // When editing this function, note that there is corresponding logic to be edited |
| 24036 | // in `fieldVal`. This function takes a pointer and returns a pointer. | 24585 | // in `fieldVal`. This function takes a pointer and returns a pointer. |
| 24037 | 24586 | ||
| 24587 | const mod = sema.mod; | ||
| 24588 | const ip = &mod.intern_pool; | ||
| 24038 | const object_ptr_src = src; // TODO better source location | 24589 | const object_ptr_src = src; // TODO better source location |
| 24039 | const object_ptr_ty = sema.typeOf(object_ptr); | 24590 | const object_ptr_ty = sema.typeOf(object_ptr); |
| 24040 | const object_ty = switch (object_ptr_ty.zigTypeTag()) { | 24591 | const object_ty = switch (object_ptr_ty.zigTypeTag(mod)) { |
| 24041 | .Pointer => object_ptr_ty.elemType(), | 24592 | .Pointer => object_ptr_ty.childType(mod), |
| 24042 | else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(sema.mod)}), | 24593 | else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(mod)}), |
| 24043 | }; | 24594 | }; |
| 24044 | 24595 | ||
| 24045 | // Zig allows dereferencing a single pointer during field lookup. Note that | 24596 | // Zig allows dereferencing a single pointer during field lookup. Note that |
| 24046 | // we don't actually need to generate the dereference some field lookups, like the | 24597 | // we don't actually need to generate the dereference some field lookups, like the |
| 24047 | // length of arrays and other comptime operations. | 24598 | // length of arrays and other comptime operations. |
| 24048 | const is_pointer_to = object_ty.isSinglePointer(); | 24599 | const is_pointer_to = object_ty.isSinglePointer(mod); |
| 24049 | 24600 | ||
| 24050 | const inner_ty = if (is_pointer_to) | 24601 | const inner_ty = if (is_pointer_to) |
| 24051 | object_ty.childType() | 24602 | object_ty.childType(mod) |
| 24052 | else | 24603 | else |
| 24053 | object_ty; | 24604 | object_ty; |
| 24054 | 24605 | ||
| 24055 | switch (inner_ty.zigTypeTag()) { | 24606 | switch (inner_ty.zigTypeTag(mod)) { |
| 24056 | .Array => { | 24607 | .Array => { |
| 24057 | if (mem.eql(u8, field_name, "len")) { | 24608 | if (ip.stringEqlSlice(field_name, "len")) { |
| 24058 | var anon_decl = try block.startAnonDecl(); | 24609 | var anon_decl = try block.startAnonDecl(); |
| 24059 | defer anon_decl.deinit(); | 24610 | defer anon_decl.deinit(); |
| 24060 | return sema.analyzeDeclRef(try anon_decl.finish( | 24611 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 24061 | Type.usize, | 24612 | Type.usize, |
| 24062 | try Value.Tag.int_u64.create(anon_decl.arena(), inner_ty.arrayLen()), | 24613 | try mod.intValue(Type.usize, inner_ty.arrayLen(mod)), |
| 24063 | 0, // default alignment | 24614 | 0, // default alignment |
| 24064 | )); | 24615 | )); |
| 24065 | } else { | 24616 | } else { |
| 24066 | return sema.fail( | 24617 | return sema.fail( |
| 24067 | block, | 24618 | block, |
| 24068 | field_name_src, | 24619 | field_name_src, |
| 24069 | "no member named '{s}' in '{}'", | 24620 | "no member named '{}' in '{}'", |
| 24070 | .{ field_name, object_ty.fmt(sema.mod) }, | 24621 | .{ field_name.fmt(ip), object_ty.fmt(mod) }, |
| 24071 | ); | 24622 | ); |
| 24072 | } | 24623 | } |
| 24073 | }, | 24624 | }, |
| 24074 | .Pointer => if (inner_ty.isSlice()) { | 24625 | .Pointer => if (inner_ty.isSlice(mod)) { |
| 24075 | const inner_ptr = if (is_pointer_to) | 24626 | const inner_ptr = if (is_pointer_to) |
| 24076 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) | 24627 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) |
| 24077 | else | 24628 | else |
| ... | @@ -24079,47 +24630,44 @@ fn fieldPtr( | ... | @@ -24079,47 +24630,44 @@ fn fieldPtr( |
| 24079 | 24630 | ||
| 24080 | const attr_ptr_ty = if (is_pointer_to) object_ty else object_ptr_ty; | 24631 | const attr_ptr_ty = if (is_pointer_to) object_ty else object_ptr_ty; |
| 24081 | 24632 | ||
| 24082 | if (mem.eql(u8, field_name, "ptr")) { | 24633 | if (ip.stringEqlSlice(field_name, "ptr")) { |
| 24083 | const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer); | 24634 | const slice_ptr_ty = inner_ty.slicePtrFieldType(mod); |
| 24084 | const slice_ptr_ty = inner_ty.slicePtrFieldType(buf); | ||
| 24085 | 24635 | ||
| 24086 | const result_ty = try Type.ptr(sema.arena, sema.mod, .{ | 24636 | const result_ty = try Type.ptr(sema.arena, mod, .{ |
| 24087 | .pointee_type = slice_ptr_ty, | 24637 | .pointee_type = slice_ptr_ty, |
| 24088 | .mutable = attr_ptr_ty.ptrIsMutable(), | 24638 | .mutable = attr_ptr_ty.ptrIsMutable(mod), |
| 24089 | .@"volatile" = attr_ptr_ty.isVolatilePtr(), | 24639 | .@"volatile" = attr_ptr_ty.isVolatilePtr(mod), |
| 24090 | .@"addrspace" = attr_ptr_ty.ptrAddressSpace(), | 24640 | .@"addrspace" = attr_ptr_ty.ptrAddressSpace(mod), |
| 24091 | }); | 24641 | }); |
| 24092 | 24642 | ||
| 24093 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { | 24643 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { |
| 24094 | return sema.addConstant( | 24644 | return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{ |
| 24095 | result_ty, | 24645 | .ty = result_ty.toIntern(), |
| 24096 | try Value.Tag.field_ptr.create(sema.arena, .{ | 24646 | .addr = .{ .field = .{ |
| 24097 | .container_ptr = val, | 24647 | .base = val.toIntern(), |
| 24098 | .container_ty = inner_ty, | 24648 | .index = Value.slice_ptr_index, |
| 24099 | .field_index = Value.Payload.Slice.ptr_index, | 24649 | } }, |
| 24100 | }), | 24650 | } })).toValue()); |
| 24101 | ); | ||
| 24102 | } | 24651 | } |
| 24103 | try sema.requireRuntimeBlock(block, src, null); | 24652 | try sema.requireRuntimeBlock(block, src, null); |
| 24104 | 24653 | ||
| 24105 | return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr); | 24654 | return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr); |
| 24106 | } else if (mem.eql(u8, field_name, "len")) { | 24655 | } else if (ip.stringEqlSlice(field_name, "len")) { |
| 24107 | const result_ty = try Type.ptr(sema.arena, sema.mod, .{ | 24656 | const result_ty = try Type.ptr(sema.arena, mod, .{ |
| 24108 | .pointee_type = Type.usize, | 24657 | .pointee_type = Type.usize, |
| 24109 | .mutable = attr_ptr_ty.ptrIsMutable(), | 24658 | .mutable = attr_ptr_ty.ptrIsMutable(mod), |
| 24110 | .@"volatile" = attr_ptr_ty.isVolatilePtr(), | 24659 | .@"volatile" = attr_ptr_ty.isVolatilePtr(mod), |
| 24111 | .@"addrspace" = attr_ptr_ty.ptrAddressSpace(), | 24660 | .@"addrspace" = attr_ptr_ty.ptrAddressSpace(mod), |
| 24112 | }); | 24661 | }); |
| 24113 | 24662 | ||
| 24114 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { | 24663 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { |
| 24115 | return sema.addConstant( | 24664 | return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{ |
| 24116 | result_ty, | 24665 | .ty = result_ty.toIntern(), |
| 24117 | try Value.Tag.field_ptr.create(sema.arena, .{ | 24666 | .addr = .{ .field = .{ |
| 24118 | .container_ptr = val, | 24667 | .base = val.toIntern(), |
| 24119 | .container_ty = inner_ty, | 24668 | .index = Value.slice_len_index, |
| 24120 | .field_index = Value.Payload.Slice.len_index, | 24669 | } }, |
| 24121 | }), | 24670 | } })).toValue()); |
| 24122 | ); | ||
| 24123 | } | 24671 | } |
| 24124 | try sema.requireRuntimeBlock(block, src, null); | 24672 | try sema.requireRuntimeBlock(block, src, null); |
| 24125 | 24673 | ||
| ... | @@ -24128,8 +24676,8 @@ fn fieldPtr( | ... | @@ -24128,8 +24676,8 @@ fn fieldPtr( |
| 24128 | return sema.fail( | 24676 | return sema.fail( |
| 24129 | block, | 24677 | block, |
| 24130 | field_name_src, | 24678 | field_name_src, |
| 24131 | "no member named '{s}' in '{}'", | 24679 | "no member named '{}' in '{}'", |
| 24132 | .{ field_name, object_ty.fmt(sema.mod) }, | 24680 | .{ field_name.fmt(ip), object_ty.fmt(mod) }, |
| 24133 | ); | 24681 | ); |
| 24134 | } | 24682 | } |
| 24135 | }, | 24683 | }, |
| ... | @@ -24142,47 +24690,59 @@ fn fieldPtr( | ... | @@ -24142,47 +24690,59 @@ fn fieldPtr( |
| 24142 | result; | 24690 | result; |
| 24143 | 24691 | ||
| 24144 | const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?; | 24692 | const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?; |
| 24145 | var to_type_buffer: Value.ToTypeBuffer = undefined; | 24693 | const child_type = val.toType(); |
| 24146 | const child_type = val.toType(&to_type_buffer); | ||
| 24147 | 24694 | ||
| 24148 | switch (child_type.zigTypeTag()) { | 24695 | switch (child_type.zigTypeTag(mod)) { |
| 24149 | .ErrorSet => { | 24696 | .ErrorSet => { |
| 24150 | // TODO resolve inferred error sets | 24697 | switch (ip.indexToKey(child_type.toIntern())) { |
| 24151 | const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: { | 24698 | .error_set_type => |error_set_type| blk: { |
| 24152 | if (payload.data.names.getEntry(field_name)) |entry| { | 24699 | if (error_set_type.nameIndex(ip, field_name) != null) { |
| 24153 | break :blk entry.key_ptr.*; | 24700 | break :blk; |
| 24154 | } | 24701 | } |
| 24155 | return sema.fail(block, src, "no error named '{s}' in '{}'", .{ | 24702 | return sema.fail(block, src, "no error named '{}' in '{}'", .{ |
| 24156 | field_name, child_type.fmt(sema.mod), | 24703 | field_name.fmt(ip), child_type.fmt(mod), |
| 24157 | }); | 24704 | }); |
| 24158 | } else (try sema.mod.getErrorValue(field_name)).key; | 24705 | }, |
| 24706 | .inferred_error_set_type => { | ||
| 24707 | return sema.fail(block, src, "TODO handle inferred error sets here", .{}); | ||
| 24708 | }, | ||
| 24709 | .simple_type => |t| { | ||
| 24710 | assert(t == .anyerror); | ||
| 24711 | _ = try mod.getErrorValue(field_name); | ||
| 24712 | }, | ||
| 24713 | else => unreachable, | ||
| 24714 | } | ||
| 24159 | 24715 | ||
| 24160 | var anon_decl = try block.startAnonDecl(); | 24716 | var anon_decl = try block.startAnonDecl(); |
| 24161 | defer anon_decl.deinit(); | 24717 | defer anon_decl.deinit(); |
| 24718 | const error_set_type = if (!child_type.isAnyError(mod)) | ||
| 24719 | child_type | ||
| 24720 | else | ||
| 24721 | try mod.singleErrorSetType(field_name); | ||
| 24162 | return sema.analyzeDeclRef(try anon_decl.finish( | 24722 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 24163 | if (!child_type.isAnyError()) | 24723 | error_set_type, |
| 24164 | try child_type.copy(anon_decl.arena()) | 24724 | (try mod.intern(.{ .err = .{ |
| 24165 | else | 24725 | .ty = error_set_type.toIntern(), |
| 24166 | try Type.Tag.error_set_single.create(anon_decl.arena(), name), | 24726 | .name = field_name, |
| 24167 | try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }), | 24727 | } })).toValue(), |
| 24168 | 0, // default alignment | 24728 | 0, // default alignment |
| 24169 | )); | 24729 | )); |
| 24170 | }, | 24730 | }, |
| 24171 | .Union => { | 24731 | .Union => { |
| 24172 | if (child_type.getNamespace()) |namespace| { | 24732 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { |
| 24173 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { | 24733 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { |
| 24174 | return inst; | 24734 | return inst; |
| 24175 | } | 24735 | } |
| 24176 | } | 24736 | } |
| 24177 | const union_ty = try sema.resolveTypeFields(child_type); | 24737 | const union_ty = try sema.resolveTypeFields(child_type); |
| 24178 | if (union_ty.unionTagType()) |enum_ty| { | 24738 | if (union_ty.unionTagType(mod)) |enum_ty| { |
| 24179 | if (enum_ty.enumFieldIndex(field_name)) |field_index| { | 24739 | if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| { |
| 24180 | const field_index_u32 = @intCast(u32, field_index); | 24740 | const field_index_u32 = @intCast(u32, field_index); |
| 24181 | var anon_decl = try block.startAnonDecl(); | 24741 | var anon_decl = try block.startAnonDecl(); |
| 24182 | defer anon_decl.deinit(); | 24742 | defer anon_decl.deinit(); |
| 24183 | return sema.analyzeDeclRef(try anon_decl.finish( | 24743 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 24184 | try enum_ty.copy(anon_decl.arena()), | 24744 | enum_ty, |
| 24185 | try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), | 24745 | try mod.enumValueFieldIndex(enum_ty, field_index_u32), |
| 24186 | 0, // default alignment | 24746 | 0, // default alignment |
| 24187 | )); | 24747 | )); |
| 24188 | } | 24748 | } |
| ... | @@ -24190,32 +24750,32 @@ fn fieldPtr( | ... | @@ -24190,32 +24750,32 @@ fn fieldPtr( |
| 24190 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | 24750 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 24191 | }, | 24751 | }, |
| 24192 | .Enum => { | 24752 | .Enum => { |
| 24193 | if (child_type.getNamespace()) |namespace| { | 24753 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { |
| 24194 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { | 24754 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { |
| 24195 | return inst; | 24755 | return inst; |
| 24196 | } | 24756 | } |
| 24197 | } | 24757 | } |
| 24198 | const field_index = child_type.enumFieldIndex(field_name) orelse { | 24758 | const field_index = child_type.enumFieldIndex(field_name, mod) orelse { |
| 24199 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | 24759 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 24200 | }; | 24760 | }; |
| 24201 | const field_index_u32 = @intCast(u32, field_index); | 24761 | const field_index_u32 = @intCast(u32, field_index); |
| 24202 | var anon_decl = try block.startAnonDecl(); | 24762 | var anon_decl = try block.startAnonDecl(); |
| 24203 | defer anon_decl.deinit(); | 24763 | defer anon_decl.deinit(); |
| 24204 | return sema.analyzeDeclRef(try anon_decl.finish( | 24764 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 24205 | try child_type.copy(anon_decl.arena()), | 24765 | child_type, |
| 24206 | try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32), | 24766 | try mod.enumValueFieldIndex(child_type, field_index_u32), |
| 24207 | 0, // default alignment | 24767 | 0, // default alignment |
| 24208 | )); | 24768 | )); |
| 24209 | }, | 24769 | }, |
| 24210 | .Struct, .Opaque => { | 24770 | .Struct, .Opaque => { |
| 24211 | if (child_type.getNamespace()) |namespace| { | 24771 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { |
| 24212 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { | 24772 | if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| { |
| 24213 | return inst; | 24773 | return inst; |
| 24214 | } | 24774 | } |
| 24215 | } | 24775 | } |
| 24216 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); | 24776 | return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name); |
| 24217 | }, | 24777 | }, |
| 24218 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)}), | 24778 | else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(mod)}), |
| 24219 | } | 24779 | } |
| 24220 | }, | 24780 | }, |
| 24221 | .Struct => { | 24781 | .Struct => { |
| ... | @@ -24252,22 +24812,24 @@ fn fieldCallBind( | ... | @@ -24252,22 +24812,24 @@ fn fieldCallBind( |
| 24252 | block: *Block, | 24812 | block: *Block, |
| 24253 | src: LazySrcLoc, | 24813 | src: LazySrcLoc, |
| 24254 | raw_ptr: Air.Inst.Ref, | 24814 | raw_ptr: Air.Inst.Ref, |
| 24255 | field_name: []const u8, | 24815 | field_name: InternPool.NullTerminatedString, |
| 24256 | field_name_src: LazySrcLoc, | 24816 | field_name_src: LazySrcLoc, |
| 24257 | ) CompileError!ResolvedFieldCallee { | 24817 | ) CompileError!ResolvedFieldCallee { |
| 24258 | // When editing this function, note that there is corresponding logic to be edited | 24818 | // When editing this function, note that there is corresponding logic to be edited |
| 24259 | // in `fieldVal`. This function takes a pointer and returns a pointer. | 24819 | // in `fieldVal`. This function takes a pointer and returns a pointer. |
| 24260 | 24820 | ||
| 24821 | const mod = sema.mod; | ||
| 24822 | const ip = &mod.intern_pool; | ||
| 24261 | const raw_ptr_src = src; // TODO better source location | 24823 | const raw_ptr_src = src; // TODO better source location |
| 24262 | const raw_ptr_ty = sema.typeOf(raw_ptr); | 24824 | const raw_ptr_ty = sema.typeOf(raw_ptr); |
| 24263 | const inner_ty = if (raw_ptr_ty.zigTypeTag() == .Pointer and (raw_ptr_ty.ptrSize() == .One or raw_ptr_ty.ptrSize() == .C)) | 24825 | const inner_ty = if (raw_ptr_ty.zigTypeTag(mod) == .Pointer and (raw_ptr_ty.ptrSize(mod) == .One or raw_ptr_ty.ptrSize(mod) == .C)) |
| 24264 | raw_ptr_ty.childType() | 24826 | raw_ptr_ty.childType(mod) |
| 24265 | else | 24827 | else |
| 24266 | return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(sema.mod)}); | 24828 | return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(mod)}); |
| 24267 | 24829 | ||
| 24268 | // Optionally dereference a second pointer to get the concrete type. | 24830 | // Optionally dereference a second pointer to get the concrete type. |
| 24269 | const is_double_ptr = inner_ty.zigTypeTag() == .Pointer and inner_ty.ptrSize() == .One; | 24831 | const is_double_ptr = inner_ty.zigTypeTag(mod) == .Pointer and inner_ty.ptrSize(mod) == .One; |
| 24270 | const concrete_ty = if (is_double_ptr) inner_ty.childType() else inner_ty; | 24832 | const concrete_ty = if (is_double_ptr) inner_ty.childType(mod) else inner_ty; |
| 24271 | const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty; | 24833 | const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty; |
| 24272 | const object_ptr = if (is_double_ptr) | 24834 | const object_ptr = if (is_double_ptr) |
| 24273 | try sema.analyzeLoad(block, src, raw_ptr, src) | 24835 | try sema.analyzeLoad(block, src, raw_ptr, src) |
| ... | @@ -24275,37 +24837,37 @@ fn fieldCallBind( | ... | @@ -24275,37 +24837,37 @@ fn fieldCallBind( |
| 24275 | raw_ptr; | 24837 | raw_ptr; |
| 24276 | 24838 | ||
| 24277 | find_field: { | 24839 | find_field: { |
| 24278 | switch (concrete_ty.zigTypeTag()) { | 24840 | switch (concrete_ty.zigTypeTag(mod)) { |
| 24279 | .Struct => { | 24841 | .Struct => { |
| 24280 | const struct_ty = try sema.resolveTypeFields(concrete_ty); | 24842 | const struct_ty = try sema.resolveTypeFields(concrete_ty); |
| 24281 | if (struct_ty.castTag(.@"struct")) |struct_obj| { | 24843 | if (mod.typeToStruct(struct_ty)) |struct_obj| { |
| 24282 | const field_index_usize = struct_obj.data.fields.getIndex(field_name) orelse | 24844 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse |
| 24283 | break :find_field; | 24845 | break :find_field; |
| 24284 | const field_index = @intCast(u32, field_index_usize); | 24846 | const field_index = @intCast(u32, field_index_usize); |
| 24285 | const field = struct_obj.data.fields.values()[field_index]; | 24847 | const field = struct_obj.fields.values()[field_index]; |
| 24286 | 24848 | ||
| 24287 | return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr); | 24849 | return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr); |
| 24288 | } else if (struct_ty.isTuple()) { | 24850 | } else if (struct_ty.isTuple(mod)) { |
| 24289 | if (mem.eql(u8, field_name, "len")) { | 24851 | if (ip.stringEqlSlice(field_name, "len")) { |
| 24290 | return .{ .direct = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount()) }; | 24852 | return .{ .direct = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod)) }; |
| 24853 | } | ||
| 24854 | if (field_name.toUnsigned(ip)) |field_index| { | ||
| 24855 | if (field_index >= struct_ty.structFieldCount(mod)) break :find_field; | ||
| 24856 | return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(field_index, mod), field_index, object_ptr); | ||
| 24291 | } | 24857 | } |
| 24292 | if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { | ||
| 24293 | if (field_index >= struct_ty.structFieldCount()) break :find_field; | ||
| 24294 | return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(field_index), field_index, object_ptr); | ||
| 24295 | } else |_| {} | ||
| 24296 | } else { | 24858 | } else { |
| 24297 | const max = struct_ty.structFieldCount(); | 24859 | const max = struct_ty.structFieldCount(mod); |
| 24298 | var i: u32 = 0; | 24860 | for (0..max) |i_usize| { |
| 24299 | while (i < max) : (i += 1) { | 24861 | const i = @intCast(u32, i_usize); |
| 24300 | if (mem.eql(u8, struct_ty.structFieldName(i), field_name)) { | 24862 | if (field_name == struct_ty.structFieldName(i, mod)) { |
| 24301 | return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(i), i, object_ptr); | 24863 | return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(i, mod), i, object_ptr); |
| 24302 | } | 24864 | } |
| 24303 | } | 24865 | } |
| 24304 | } | 24866 | } |
| 24305 | }, | 24867 | }, |
| 24306 | .Union => { | 24868 | .Union => { |
| 24307 | const union_ty = try sema.resolveTypeFields(concrete_ty); | 24869 | const union_ty = try sema.resolveTypeFields(concrete_ty); |
| 24308 | const fields = union_ty.unionFields(); | 24870 | const fields = union_ty.unionFields(mod); |
| 24309 | const field_index_usize = fields.getIndex(field_name) orelse break :find_field; | 24871 | const field_index_usize = fields.getIndex(field_name) orelse break :find_field; |
| 24310 | const field_index = @intCast(u32, field_index_usize); | 24872 | const field_index = @intCast(u32, field_index_usize); |
| 24311 | const field = fields.values()[field_index]; | 24873 | const field = fields.values()[field_index]; |
| ... | @@ -24321,24 +24883,23 @@ fn fieldCallBind( | ... | @@ -24321,24 +24883,23 @@ fn fieldCallBind( |
| 24321 | } | 24883 | } |
| 24322 | 24884 | ||
| 24323 | // If we get here, we need to look for a decl in the struct type instead. | 24885 | // If we get here, we need to look for a decl in the struct type instead. |
| 24324 | const found_decl = switch (concrete_ty.zigTypeTag()) { | 24886 | const found_decl = switch (concrete_ty.zigTypeTag(mod)) { |
| 24325 | .Struct, .Opaque, .Union, .Enum => found_decl: { | 24887 | .Struct, .Opaque, .Union, .Enum => found_decl: { |
| 24326 | if (concrete_ty.getNamespace()) |namespace| { | 24888 | if (concrete_ty.getNamespaceIndex(mod).unwrap()) |namespace| { |
| 24327 | if (try sema.namespaceLookup(block, src, namespace, field_name)) |decl_idx| { | 24889 | if (try sema.namespaceLookup(block, src, namespace, field_name)) |decl_idx| { |
| 24328 | try sema.addReferencedBy(block, src, decl_idx); | 24890 | try sema.addReferencedBy(block, src, decl_idx); |
| 24329 | const decl_val = try sema.analyzeDeclVal(block, src, decl_idx); | 24891 | const decl_val = try sema.analyzeDeclVal(block, src, decl_idx); |
| 24330 | const decl_type = sema.typeOf(decl_val); | 24892 | const decl_type = sema.typeOf(decl_val); |
| 24331 | if (decl_type.zigTypeTag() == .Fn and | 24893 | if (mod.typeToFunc(decl_type)) |func_type| f: { |
| 24332 | decl_type.fnParamLen() >= 1) | 24894 | if (func_type.param_types.len == 0) break :f; |
| 24333 | { | 24895 | |
| 24334 | const first_param_type = decl_type.fnParamType(0); | 24896 | const first_param_type = func_type.param_types[0].toType(); |
| 24335 | const first_param_tag = first_param_type.tag(); | ||
| 24336 | // zig fmt: off | 24897 | // zig fmt: off |
| 24337 | if (first_param_tag == .generic_poison or ( | 24898 | if (first_param_type.isGenericPoison() or ( |
| 24338 | first_param_type.zigTypeTag() == .Pointer and | 24899 | first_param_type.zigTypeTag(mod) == .Pointer and |
| 24339 | (first_param_type.ptrSize() == .One or | 24900 | (first_param_type.ptrSize(mod) == .One or |
| 24340 | first_param_type.ptrSize() == .C) and | 24901 | first_param_type.ptrSize(mod) == .C) and |
| 24341 | first_param_type.childType().eql(concrete_ty, sema.mod))) | 24902 | first_param_type.childType(mod).eql(concrete_ty, mod))) |
| 24342 | { | 24903 | { |
| 24343 | // zig fmt: on | 24904 | // zig fmt: on |
| 24344 | // Note that if the param type is generic poison, we know that it must | 24905 | // Note that if the param type is generic poison, we know that it must |
| ... | @@ -24350,32 +24911,31 @@ fn fieldCallBind( | ... | @@ -24350,32 +24911,31 @@ fn fieldCallBind( |
| 24350 | .func_inst = decl_val, | 24911 | .func_inst = decl_val, |
| 24351 | .arg0_inst = object_ptr, | 24912 | .arg0_inst = object_ptr, |
| 24352 | } }; | 24913 | } }; |
| 24353 | } else if (first_param_type.eql(concrete_ty, sema.mod)) { | 24914 | } else if (first_param_type.eql(concrete_ty, mod)) { |
| 24354 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); | 24915 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); |
| 24355 | return .{ .method = .{ | 24916 | return .{ .method = .{ |
| 24356 | .func_inst = decl_val, | 24917 | .func_inst = decl_val, |
| 24357 | .arg0_inst = deref, | 24918 | .arg0_inst = deref, |
| 24358 | } }; | 24919 | } }; |
| 24359 | } else if (first_param_type.zigTypeTag() == .Optional) { | 24920 | } else if (first_param_type.zigTypeTag(mod) == .Optional) { |
| 24360 | var opt_buf: Type.Payload.ElemType = undefined; | 24921 | const child = first_param_type.optionalChild(mod); |
| 24361 | const child = first_param_type.optionalChild(&opt_buf); | 24922 | if (child.eql(concrete_ty, mod)) { |
| 24362 | if (child.eql(concrete_ty, sema.mod)) { | ||
| 24363 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); | 24923 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); |
| 24364 | return .{ .method = .{ | 24924 | return .{ .method = .{ |
| 24365 | .func_inst = decl_val, | 24925 | .func_inst = decl_val, |
| 24366 | .arg0_inst = deref, | 24926 | .arg0_inst = deref, |
| 24367 | } }; | 24927 | } }; |
| 24368 | } else if (child.zigTypeTag() == .Pointer and | 24928 | } else if (child.zigTypeTag(mod) == .Pointer and |
| 24369 | child.ptrSize() == .One and | 24929 | child.ptrSize(mod) == .One and |
| 24370 | child.childType().eql(concrete_ty, sema.mod)) | 24930 | child.childType(mod).eql(concrete_ty, mod)) |
| 24371 | { | 24931 | { |
| 24372 | return .{ .method = .{ | 24932 | return .{ .method = .{ |
| 24373 | .func_inst = decl_val, | 24933 | .func_inst = decl_val, |
| 24374 | .arg0_inst = object_ptr, | 24934 | .arg0_inst = object_ptr, |
| 24375 | } }; | 24935 | } }; |
| 24376 | } | 24936 | } |
| 24377 | } else if (first_param_type.zigTypeTag() == .ErrorUnion and | 24937 | } else if (first_param_type.zigTypeTag(mod) == .ErrorUnion and |
| 24378 | first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod)) | 24938 | first_param_type.errorUnionPayload(mod).eql(concrete_ty, mod)) |
| 24379 | { | 24939 | { |
| 24380 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); | 24940 | const deref = try sema.analyzeLoad(block, src, object_ptr, src); |
| 24381 | return .{ .method = .{ | 24941 | return .{ .method = .{ |
| ... | @@ -24393,12 +24953,15 @@ fn fieldCallBind( | ... | @@ -24393,12 +24953,15 @@ fn fieldCallBind( |
| 24393 | }; | 24953 | }; |
| 24394 | 24954 | ||
| 24395 | const msg = msg: { | 24955 | const msg = msg: { |
| 24396 | const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ field_name, concrete_ty.fmt(sema.mod) }); | 24956 | const msg = try sema.errMsg(block, src, "no field or member function named '{}' in '{}'", .{ |
| 24957 | field_name.fmt(ip), | ||
| 24958 | concrete_ty.fmt(mod), | ||
| 24959 | }); | ||
| 24397 | errdefer msg.destroy(sema.gpa); | 24960 | errdefer msg.destroy(sema.gpa); |
| 24398 | try sema.addDeclaredHereNote(msg, concrete_ty); | 24961 | try sema.addDeclaredHereNote(msg, concrete_ty); |
| 24399 | if (found_decl) |decl_idx| { | 24962 | if (found_decl) |decl_idx| { |
| 24400 | const decl = sema.mod.declPtr(decl_idx); | 24963 | const decl = mod.declPtr(decl_idx); |
| 24401 | try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "'{s}' is not a member function", .{field_name}); | 24964 | try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "'{}' is not a member function", .{field_name.fmt(ip)}); |
| 24402 | } | 24965 | } |
| 24403 | break :msg msg; | 24966 | break :msg msg; |
| 24404 | }; | 24967 | }; |
| ... | @@ -24414,29 +24977,29 @@ fn finishFieldCallBind( | ... | @@ -24414,29 +24977,29 @@ fn finishFieldCallBind( |
| 24414 | field_index: u32, | 24977 | field_index: u32, |
| 24415 | object_ptr: Air.Inst.Ref, | 24978 | object_ptr: Air.Inst.Ref, |
| 24416 | ) CompileError!ResolvedFieldCallee { | 24979 | ) CompileError!ResolvedFieldCallee { |
| 24980 | const mod = sema.mod; | ||
| 24417 | const arena = sema.arena; | 24981 | const arena = sema.arena; |
| 24418 | const ptr_field_ty = try Type.ptr(arena, sema.mod, .{ | 24982 | const ptr_field_ty = try Type.ptr(arena, mod, .{ |
| 24419 | .pointee_type = field_ty, | 24983 | .pointee_type = field_ty, |
| 24420 | .mutable = ptr_ty.ptrIsMutable(), | 24984 | .mutable = ptr_ty.ptrIsMutable(mod), |
| 24421 | .@"addrspace" = ptr_ty.ptrAddressSpace(), | 24985 | .@"addrspace" = ptr_ty.ptrAddressSpace(mod), |
| 24422 | }); | 24986 | }); |
| 24423 | 24987 | ||
| 24424 | const container_ty = ptr_ty.childType(); | 24988 | const container_ty = ptr_ty.childType(mod); |
| 24425 | if (container_ty.zigTypeTag() == .Struct) { | 24989 | if (container_ty.zigTypeTag(mod) == .Struct) { |
| 24426 | if (container_ty.structFieldValueComptime(field_index)) |default_val| { | 24990 | if (try container_ty.structFieldValueComptime(mod, field_index)) |default_val| { |
| 24427 | return .{ .direct = try sema.addConstant(field_ty, default_val) }; | 24991 | return .{ .direct = try sema.addConstant(field_ty, default_val) }; |
| 24428 | } | 24992 | } |
| 24429 | } | 24993 | } |
| 24430 | 24994 | ||
| 24431 | if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| { | 24995 | if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| { |
| 24432 | const pointer = try sema.addConstant( | 24996 | const pointer = try sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ |
| 24433 | ptr_field_ty, | 24997 | .ty = ptr_field_ty.toIntern(), |
| 24434 | try Value.Tag.field_ptr.create(arena, .{ | 24998 | .addr = .{ .field = .{ |
| 24435 | .container_ptr = struct_ptr_val, | 24999 | .base = struct_ptr_val.toIntern(), |
| 24436 | .container_ty = container_ty, | 25000 | .index = field_index, |
| 24437 | .field_index = field_index, | 25001 | } }, |
| 24438 | }), | 25002 | } })).toValue()); |
| 24439 | ); | ||
| 24440 | return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) }; | 25003 | return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) }; |
| 24441 | } | 25004 | } |
| 24442 | 25005 | ||
| ... | @@ -24449,19 +25012,20 @@ fn namespaceLookup( | ... | @@ -24449,19 +25012,20 @@ fn namespaceLookup( |
| 24449 | sema: *Sema, | 25012 | sema: *Sema, |
| 24450 | block: *Block, | 25013 | block: *Block, |
| 24451 | src: LazySrcLoc, | 25014 | src: LazySrcLoc, |
| 24452 | namespace: *Namespace, | 25015 | namespace: Namespace.Index, |
| 24453 | decl_name: []const u8, | 25016 | decl_name: InternPool.NullTerminatedString, |
| 24454 | ) CompileError!?Decl.Index { | 25017 | ) CompileError!?Decl.Index { |
| 25018 | const mod = sema.mod; | ||
| 24455 | const gpa = sema.gpa; | 25019 | const gpa = sema.gpa; |
| 24456 | if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { | 25020 | if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| { |
| 24457 | const decl = sema.mod.declPtr(decl_index); | 25021 | const decl = mod.declPtr(decl_index); |
| 24458 | if (!decl.is_pub and decl.getFileScope() != block.getFileScope()) { | 25022 | if (!decl.is_pub and decl.getFileScope(mod) != block.getFileScope(mod)) { |
| 24459 | const msg = msg: { | 25023 | const msg = msg: { |
| 24460 | const msg = try sema.errMsg(block, src, "'{s}' is not marked 'pub'", .{ | 25024 | const msg = try sema.errMsg(block, src, "'{}' is not marked 'pub'", .{ |
| 24461 | decl_name, | 25025 | decl_name.fmt(&mod.intern_pool), |
| 24462 | }); | 25026 | }); |
| 24463 | errdefer msg.destroy(gpa); | 25027 | errdefer msg.destroy(gpa); |
| 24464 | try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "declared here", .{}); | 25028 | try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "declared here", .{}); |
| 24465 | break :msg msg; | 25029 | break :msg msg; |
| 24466 | }; | 25030 | }; |
| 24467 | return sema.failWithOwnedErrorMsg(msg); | 25031 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -24475,8 +25039,8 @@ fn namespaceLookupRef( | ... | @@ -24475,8 +25039,8 @@ fn namespaceLookupRef( |
| 24475 | sema: *Sema, | 25039 | sema: *Sema, |
| 24476 | block: *Block, | 25040 | block: *Block, |
| 24477 | src: LazySrcLoc, | 25041 | src: LazySrcLoc, |
| 24478 | namespace: *Namespace, | 25042 | namespace: Namespace.Index, |
| 24479 | decl_name: []const u8, | 25043 | decl_name: InternPool.NullTerminatedString, |
| 24480 | ) CompileError!?Air.Inst.Ref { | 25044 | ) CompileError!?Air.Inst.Ref { |
| 24481 | const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; | 25045 | const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; |
| 24482 | try sema.addReferencedBy(block, src, decl); | 25046 | try sema.addReferencedBy(block, src, decl); |
| ... | @@ -24487,8 +25051,8 @@ fn namespaceLookupVal( | ... | @@ -24487,8 +25051,8 @@ fn namespaceLookupVal( |
| 24487 | sema: *Sema, | 25051 | sema: *Sema, |
| 24488 | block: *Block, | 25052 | block: *Block, |
| 24489 | src: LazySrcLoc, | 25053 | src: LazySrcLoc, |
| 24490 | namespace: *Namespace, | 25054 | namespace: Namespace.Index, |
| 24491 | decl_name: []const u8, | 25055 | decl_name: InternPool.NullTerminatedString, |
| 24492 | ) CompileError!?Air.Inst.Ref { | 25056 | ) CompileError!?Air.Inst.Ref { |
| 24493 | const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; | 25057 | const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; |
| 24494 | return try sema.analyzeDeclVal(block, src, decl); | 25058 | return try sema.analyzeDeclVal(block, src, decl); |
| ... | @@ -24499,29 +25063,30 @@ fn structFieldPtr( | ... | @@ -24499,29 +25063,30 @@ fn structFieldPtr( |
| 24499 | block: *Block, | 25063 | block: *Block, |
| 24500 | src: LazySrcLoc, | 25064 | src: LazySrcLoc, |
| 24501 | struct_ptr: Air.Inst.Ref, | 25065 | struct_ptr: Air.Inst.Ref, |
| 24502 | field_name: []const u8, | 25066 | field_name: InternPool.NullTerminatedString, |
| 24503 | field_name_src: LazySrcLoc, | 25067 | field_name_src: LazySrcLoc, |
| 24504 | unresolved_struct_ty: Type, | 25068 | unresolved_struct_ty: Type, |
| 24505 | initializing: bool, | 25069 | initializing: bool, |
| 24506 | ) CompileError!Air.Inst.Ref { | 25070 | ) CompileError!Air.Inst.Ref { |
| 24507 | assert(unresolved_struct_ty.zigTypeTag() == .Struct); | 25071 | const mod = sema.mod; |
| 25072 | assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); | ||
| 24508 | 25073 | ||
| 24509 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); | 25074 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); |
| 24510 | try sema.resolveStructLayout(struct_ty); | 25075 | try sema.resolveStructLayout(struct_ty); |
| 24511 | 25076 | ||
| 24512 | if (struct_ty.isTuple()) { | 25077 | if (struct_ty.isTuple(mod)) { |
| 24513 | if (mem.eql(u8, field_name, "len")) { | 25078 | if (mod.intern_pool.stringEqlSlice(field_name, "len")) { |
| 24514 | const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount()); | 25079 | const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod)); |
| 24515 | return sema.analyzeRef(block, src, len_inst); | 25080 | return sema.analyzeRef(block, src, len_inst); |
| 24516 | } | 25081 | } |
| 24517 | const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); | 25082 | const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src); |
| 24518 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); | 25083 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); |
| 24519 | } else if (struct_ty.isAnonStruct()) { | 25084 | } else if (struct_ty.isAnonStruct(mod)) { |
| 24520 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); | 25085 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); |
| 24521 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); | 25086 | return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing); |
| 24522 | } | 25087 | } |
| 24523 | 25088 | ||
| 24524 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 25089 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| 24525 | 25090 | ||
| 24526 | const field_index_big = struct_obj.fields.getIndex(field_name) orelse | 25091 | const field_index_big = struct_obj.fields.getIndex(field_name) orelse |
| 24527 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); | 25092 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name); |
| ... | @@ -24540,14 +25105,15 @@ fn structFieldPtrByIndex( | ... | @@ -24540,14 +25105,15 @@ fn structFieldPtrByIndex( |
| 24540 | struct_ty: Type, | 25105 | struct_ty: Type, |
| 24541 | initializing: bool, | 25106 | initializing: bool, |
| 24542 | ) CompileError!Air.Inst.Ref { | 25107 | ) CompileError!Air.Inst.Ref { |
| 24543 | if (struct_ty.isAnonStruct()) { | 25108 | const mod = sema.mod; |
| 25109 | if (struct_ty.isAnonStruct(mod)) { | ||
| 24544 | return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing); | 25110 | return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing); |
| 24545 | } | 25111 | } |
| 24546 | 25112 | ||
| 24547 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 25113 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| 24548 | const field = struct_obj.fields.values()[field_index]; | 25114 | const field = struct_obj.fields.values()[field_index]; |
| 24549 | const struct_ptr_ty = sema.typeOf(struct_ptr); | 25115 | const struct_ptr_ty = sema.typeOf(struct_ptr); |
| 24550 | const struct_ptr_ty_info = struct_ptr_ty.ptrInfo().data; | 25116 | const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod); |
| 24551 | 25117 | ||
| 24552 | var ptr_ty_data: Type.Payload.Pointer.Data = .{ | 25118 | var ptr_ty_data: Type.Payload.Pointer.Data = .{ |
| 24553 | .pointee_type = field.ty, | 25119 | .pointee_type = field.ty, |
| ... | @@ -24556,7 +25122,7 @@ fn structFieldPtrByIndex( | ... | @@ -24556,7 +25122,7 @@ fn structFieldPtrByIndex( |
| 24556 | .@"addrspace" = struct_ptr_ty_info.@"addrspace", | 25122 | .@"addrspace" = struct_ptr_ty_info.@"addrspace", |
| 24557 | }; | 25123 | }; |
| 24558 | 25124 | ||
| 24559 | const target = sema.mod.getTarget(); | 25125 | const target = mod.getTarget(); |
| 24560 | 25126 | ||
| 24561 | if (struct_obj.layout == .Packed) { | 25127 | if (struct_obj.layout == .Packed) { |
| 24562 | comptime assert(Type.packed_struct_layout_version == 2); | 25128 | comptime assert(Type.packed_struct_layout_version == 2); |
| ... | @@ -24568,7 +25134,7 @@ fn structFieldPtrByIndex( | ... | @@ -24568,7 +25134,7 @@ fn structFieldPtrByIndex( |
| 24568 | if (i == field_index) { | 25134 | if (i == field_index) { |
| 24569 | ptr_ty_data.bit_offset = running_bits; | 25135 | ptr_ty_data.bit_offset = running_bits; |
| 24570 | } | 25136 | } |
| 24571 | running_bits += @intCast(u16, f.ty.bitSize(target)); | 25137 | running_bits += @intCast(u16, f.ty.bitSize(mod)); |
| 24572 | } | 25138 | } |
| 24573 | ptr_ty_data.host_size = (running_bits + 7) / 8; | 25139 | ptr_ty_data.host_size = (running_bits + 7) / 8; |
| 24574 | 25140 | ||
| ... | @@ -24582,7 +25148,7 @@ fn structFieldPtrByIndex( | ... | @@ -24582,7 +25148,7 @@ fn structFieldPtrByIndex( |
| 24582 | const parent_align = if (struct_ptr_ty_info.@"align" != 0) | 25148 | const parent_align = if (struct_ptr_ty_info.@"align" != 0) |
| 24583 | struct_ptr_ty_info.@"align" | 25149 | struct_ptr_ty_info.@"align" |
| 24584 | else | 25150 | else |
| 24585 | struct_ptr_ty_info.pointee_type.abiAlignment(target); | 25151 | struct_ptr_ty_info.pointee_type.abiAlignment(mod); |
| 24586 | ptr_ty_data.@"align" = parent_align; | 25152 | ptr_ty_data.@"align" = parent_align; |
| 24587 | 25153 | ||
| 24588 | // If the field happens to be byte-aligned, simplify the pointer type. | 25154 | // If the field happens to be byte-aligned, simplify the pointer type. |
| ... | @@ -24596,8 +25162,8 @@ fn structFieldPtrByIndex( | ... | @@ -24596,8 +25162,8 @@ fn structFieldPtrByIndex( |
| 24596 | if (parent_align != 0 and ptr_ty_data.bit_offset % 8 == 0 and | 25162 | if (parent_align != 0 and ptr_ty_data.bit_offset % 8 == 0 and |
| 24597 | target.cpu.arch.endian() == .Little) | 25163 | target.cpu.arch.endian() == .Little) |
| 24598 | { | 25164 | { |
| 24599 | const elem_size_bytes = ptr_ty_data.pointee_type.abiSize(target); | 25165 | const elem_size_bytes = ptr_ty_data.pointee_type.abiSize(mod); |
| 24600 | const elem_size_bits = ptr_ty_data.pointee_type.bitSize(target); | 25166 | const elem_size_bits = ptr_ty_data.pointee_type.bitSize(mod); |
| 24601 | if (elem_size_bytes * 8 == elem_size_bits) { | 25167 | if (elem_size_bytes * 8 == elem_size_bits) { |
| 24602 | const byte_offset = ptr_ty_data.bit_offset / 8; | 25168 | const byte_offset = ptr_ty_data.bit_offset / 8; |
| 24603 | const new_align = @as(u32, 1) << @intCast(u5, @ctz(byte_offset | parent_align)); | 25169 | const new_align = @as(u32, 1) << @intCast(u5, @ctz(byte_offset | parent_align)); |
| ... | @@ -24610,25 +25176,25 @@ fn structFieldPtrByIndex( | ... | @@ -24610,25 +25176,25 @@ fn structFieldPtrByIndex( |
| 24610 | ptr_ty_data.@"align" = field.abi_align; | 25176 | ptr_ty_data.@"align" = field.abi_align; |
| 24611 | } | 25177 | } |
| 24612 | 25178 | ||
| 24613 | const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); | 25179 | const ptr_field_ty = try Type.ptr(sema.arena, mod, ptr_ty_data); |
| 24614 | 25180 | ||
| 24615 | if (field.is_comptime) { | 25181 | if (field.is_comptime) { |
| 24616 | const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{ | 25182 | const val = try mod.intern(.{ .ptr = .{ |
| 24617 | .field_ty = try field.ty.copy(sema.arena), | 25183 | .ty = ptr_field_ty.toIntern(), |
| 24618 | .field_val = try field.default_val.copy(sema.arena), | 25184 | .addr = .{ .comptime_field = field.default_val }, |
| 24619 | }); | 25185 | } }); |
| 24620 | return sema.addConstant(ptr_field_ty, val); | 25186 | return sema.addConstant(ptr_field_ty, val.toValue()); |
| 24621 | } | 25187 | } |
| 24622 | 25188 | ||
| 24623 | if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { | 25189 | if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { |
| 24624 | return sema.addConstant( | 25190 | const val = try mod.intern(.{ .ptr = .{ |
| 24625 | ptr_field_ty, | 25191 | .ty = ptr_field_ty.toIntern(), |
| 24626 | try Value.Tag.field_ptr.create(sema.arena, .{ | 25192 | .addr = .{ .field = .{ |
| 24627 | .container_ptr = struct_ptr_val, | 25193 | .base = try struct_ptr_val.intern(struct_ptr_ty, mod), |
| 24628 | .container_ty = struct_ptr_ty.childType(), | 25194 | .index = field_index, |
| 24629 | .field_index = field_index, | 25195 | } }, |
| 24630 | }), | 25196 | } }); |
| 24631 | ); | 25197 | return sema.addConstant(ptr_field_ty, val.toValue()); |
| 24632 | } | 25198 | } |
| 24633 | 25199 | ||
| 24634 | try sema.requireRuntimeBlock(block, src, null); | 25200 | try sema.requireRuntimeBlock(block, src, null); |
| ... | @@ -24640,21 +25206,17 @@ fn structFieldVal( | ... | @@ -24640,21 +25206,17 @@ fn structFieldVal( |
| 24640 | block: *Block, | 25206 | block: *Block, |
| 24641 | src: LazySrcLoc, | 25207 | src: LazySrcLoc, |
| 24642 | struct_byval: Air.Inst.Ref, | 25208 | struct_byval: Air.Inst.Ref, |
| 24643 | field_name: []const u8, | 25209 | field_name: InternPool.NullTerminatedString, |
| 24644 | field_name_src: LazySrcLoc, | 25210 | field_name_src: LazySrcLoc, |
| 24645 | unresolved_struct_ty: Type, | 25211 | unresolved_struct_ty: Type, |
| 24646 | ) CompileError!Air.Inst.Ref { | 25212 | ) CompileError!Air.Inst.Ref { |
| 24647 | assert(unresolved_struct_ty.zigTypeTag() == .Struct); | 25213 | const mod = sema.mod; |
| 25214 | assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct); | ||
| 24648 | 25215 | ||
| 24649 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); | 25216 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); |
| 24650 | switch (struct_ty.tag()) { | 25217 | switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { |
| 24651 | .tuple, .empty_struct_literal => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty), | 25218 | .struct_type => |struct_type| { |
| 24652 | .anon_struct => { | 25219 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 24653 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); | ||
| 24654 | return sema.tupleFieldValByIndex(block, src, struct_byval, field_index, struct_ty); | ||
| 24655 | }, | ||
| 24656 | .@"struct" => { | ||
| 24657 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | ||
| 24658 | if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); | 25220 | if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); |
| 24659 | 25221 | ||
| 24660 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | 25222 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse |
| ... | @@ -24663,22 +25225,28 @@ fn structFieldVal( | ... | @@ -24663,22 +25225,28 @@ fn structFieldVal( |
| 24663 | const field = struct_obj.fields.values()[field_index]; | 25225 | const field = struct_obj.fields.values()[field_index]; |
| 24664 | 25226 | ||
| 24665 | if (field.is_comptime) { | 25227 | if (field.is_comptime) { |
| 24666 | return sema.addConstant(field.ty, field.default_val); | 25228 | return sema.addConstant(field.ty, field.default_val.toValue()); |
| 24667 | } | 25229 | } |
| 24668 | 25230 | ||
| 24669 | if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { | 25231 | if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { |
| 24670 | if (struct_val.isUndef()) return sema.addConstUndef(field.ty); | 25232 | if (struct_val.isUndef(mod)) return sema.addConstUndef(field.ty); |
| 24671 | if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { | 25233 | if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { |
| 24672 | return sema.addConstant(field.ty, opv); | 25234 | return sema.addConstant(field.ty, opv); |
| 24673 | } | 25235 | } |
| 24674 | 25236 | return sema.addConstant(field.ty, try struct_val.fieldValue(mod, field_index)); | |
| 24675 | const field_values = struct_val.castTag(.aggregate).?.data; | ||
| 24676 | return sema.addConstant(field.ty, field_values[field_index]); | ||
| 24677 | } | 25237 | } |
| 24678 | 25238 | ||
| 24679 | try sema.requireRuntimeBlock(block, src, null); | 25239 | try sema.requireRuntimeBlock(block, src, null); |
| 24680 | return block.addStructFieldVal(struct_byval, field_index, field.ty); | 25240 | return block.addStructFieldVal(struct_byval, field_index, field.ty); |
| 24681 | }, | 25241 | }, |
| 25242 | .anon_struct_type => |anon_struct| { | ||
| 25243 | if (anon_struct.names.len == 0) { | ||
| 25244 | return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty); | ||
| 25245 | } else { | ||
| 25246 | const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src); | ||
| 25247 | return sema.tupleFieldValByIndex(block, src, struct_byval, field_index, struct_ty); | ||
| 25248 | } | ||
| 25249 | }, | ||
| 24682 | else => unreachable, | 25250 | else => unreachable, |
| 24683 | } | 25251 | } |
| 24684 | } | 25252 | } |
| ... | @@ -24688,12 +25256,13 @@ fn tupleFieldVal( | ... | @@ -24688,12 +25256,13 @@ fn tupleFieldVal( |
| 24688 | block: *Block, | 25256 | block: *Block, |
| 24689 | src: LazySrcLoc, | 25257 | src: LazySrcLoc, |
| 24690 | tuple_byval: Air.Inst.Ref, | 25258 | tuple_byval: Air.Inst.Ref, |
| 24691 | field_name: []const u8, | 25259 | field_name: InternPool.NullTerminatedString, |
| 24692 | field_name_src: LazySrcLoc, | 25260 | field_name_src: LazySrcLoc, |
| 24693 | tuple_ty: Type, | 25261 | tuple_ty: Type, |
| 24694 | ) CompileError!Air.Inst.Ref { | 25262 | ) CompileError!Air.Inst.Ref { |
| 24695 | if (mem.eql(u8, field_name, "len")) { | 25263 | const mod = sema.mod; |
| 24696 | return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount()); | 25264 | if (mod.intern_pool.stringEqlSlice(field_name, "len")) { |
| 25265 | return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount(mod)); | ||
| 24697 | } | 25266 | } |
| 24698 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src); | 25267 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src); |
| 24699 | return sema.tupleFieldValByIndex(block, src, tuple_byval, field_index, tuple_ty); | 25268 | return sema.tupleFieldValByIndex(block, src, tuple_byval, field_index, tuple_ty); |
| ... | @@ -24704,19 +25273,20 @@ fn tupleFieldIndex( | ... | @@ -24704,19 +25273,20 @@ fn tupleFieldIndex( |
| 24704 | sema: *Sema, | 25273 | sema: *Sema, |
| 24705 | block: *Block, | 25274 | block: *Block, |
| 24706 | tuple_ty: Type, | 25275 | tuple_ty: Type, |
| 24707 | field_name: []const u8, | 25276 | field_name: InternPool.NullTerminatedString, |
| 24708 | field_name_src: LazySrcLoc, | 25277 | field_name_src: LazySrcLoc, |
| 24709 | ) CompileError!u32 { | 25278 | ) CompileError!u32 { |
| 24710 | assert(!std.mem.eql(u8, field_name, "len")); | 25279 | const mod = sema.mod; |
| 24711 | if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { | 25280 | assert(!mod.intern_pool.stringEqlSlice(field_name, "len")); |
| 24712 | if (field_index < tuple_ty.structFieldCount()) return field_index; | 25281 | if (field_name.toUnsigned(&mod.intern_pool)) |field_index| { |
| 24713 | return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{ | 25282 | if (field_index < tuple_ty.structFieldCount(mod)) return field_index; |
| 24714 | field_name, tuple_ty.fmt(sema.mod), | 25283 | return sema.fail(block, field_name_src, "index '{}' out of bounds of tuple '{}'", .{ |
| 25284 | field_name.fmt(&mod.intern_pool), tuple_ty.fmt(mod), | ||
| 24715 | }); | 25285 | }); |
| 24716 | } else |_| {} | 25286 | } |
| 24717 | 25287 | ||
| 24718 | return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{ | 25288 | return sema.fail(block, field_name_src, "no field named '{}' in tuple '{}'", .{ |
| 24719 | field_name, tuple_ty.fmt(sema.mod), | 25289 | field_name.fmt(&mod.intern_pool), tuple_ty.fmt(mod), |
| 24720 | }); | 25290 | }); |
| 24721 | } | 25291 | } |
| 24722 | 25292 | ||
| ... | @@ -24728,22 +25298,29 @@ fn tupleFieldValByIndex( | ... | @@ -24728,22 +25298,29 @@ fn tupleFieldValByIndex( |
| 24728 | field_index: u32, | 25298 | field_index: u32, |
| 24729 | tuple_ty: Type, | 25299 | tuple_ty: Type, |
| 24730 | ) CompileError!Air.Inst.Ref { | 25300 | ) CompileError!Air.Inst.Ref { |
| 24731 | const field_ty = tuple_ty.structFieldType(field_index); | 25301 | const mod = sema.mod; |
| 25302 | const field_ty = tuple_ty.structFieldType(field_index, mod); | ||
| 24732 | 25303 | ||
| 24733 | if (tuple_ty.structFieldValueComptime(field_index)) |default_value| { | 25304 | if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| { |
| 24734 | return sema.addConstant(field_ty, default_value); | 25305 | return sema.addConstant(field_ty, default_value); |
| 24735 | } | 25306 | } |
| 24736 | 25307 | ||
| 24737 | if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| { | 25308 | if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| { |
| 24738 | if (tuple_val.isUndef()) return sema.addConstUndef(field_ty); | ||
| 24739 | if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| { | 25309 | if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| { |
| 24740 | return sema.addConstant(field_ty, opv); | 25310 | return sema.addConstant(field_ty, opv); |
| 24741 | } | 25311 | } |
| 24742 | const field_values = tuple_val.castTag(.aggregate).?.data; | 25312 | return switch (mod.intern_pool.indexToKey(tuple_val.toIntern())) { |
| 24743 | return sema.addConstant(field_ty, field_values[field_index]); | 25313 | .undef => sema.addConstUndef(field_ty), |
| 25314 | .aggregate => |aggregate| sema.addConstant(field_ty, switch (aggregate.storage) { | ||
| 25315 | .bytes => |bytes| try mod.intValue(Type.u8, bytes[0]), | ||
| 25316 | .elems => |elems| elems[field_index].toValue(), | ||
| 25317 | .repeated_elem => |elem| elem.toValue(), | ||
| 25318 | }), | ||
| 25319 | else => unreachable, | ||
| 25320 | }; | ||
| 24744 | } | 25321 | } |
| 24745 | 25322 | ||
| 24746 | if (tuple_ty.structFieldValueComptime(field_index)) |default_val| { | 25323 | if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| { |
| 24747 | return sema.addConstant(field_ty, default_val); | 25324 | return sema.addConstant(field_ty, default_val); |
| 24748 | } | 25325 | } |
| 24749 | 25326 | ||
| ... | @@ -24756,33 +25333,38 @@ fn unionFieldPtr( | ... | @@ -24756,33 +25333,38 @@ fn unionFieldPtr( |
| 24756 | block: *Block, | 25333 | block: *Block, |
| 24757 | src: LazySrcLoc, | 25334 | src: LazySrcLoc, |
| 24758 | union_ptr: Air.Inst.Ref, | 25335 | union_ptr: Air.Inst.Ref, |
| 24759 | field_name: []const u8, | 25336 | field_name: InternPool.NullTerminatedString, |
| 24760 | field_name_src: LazySrcLoc, | 25337 | field_name_src: LazySrcLoc, |
| 24761 | unresolved_union_ty: Type, | 25338 | unresolved_union_ty: Type, |
| 24762 | initializing: bool, | 25339 | initializing: bool, |
| 24763 | ) CompileError!Air.Inst.Ref { | 25340 | ) CompileError!Air.Inst.Ref { |
| 24764 | const arena = sema.arena; | 25341 | const arena = sema.arena; |
| 24765 | assert(unresolved_union_ty.zigTypeTag() == .Union); | 25342 | const mod = sema.mod; |
| 25343 | const ip = &mod.intern_pool; | ||
| 25344 | |||
| 25345 | assert(unresolved_union_ty.zigTypeTag(mod) == .Union); | ||
| 24766 | 25346 | ||
| 24767 | const union_ptr_ty = sema.typeOf(union_ptr); | 25347 | const union_ptr_ty = sema.typeOf(union_ptr); |
| 24768 | const union_ty = try sema.resolveTypeFields(unresolved_union_ty); | 25348 | const union_ty = try sema.resolveTypeFields(unresolved_union_ty); |
| 24769 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 25349 | const union_obj = mod.typeToUnion(union_ty).?; |
| 24770 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); | 25350 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 24771 | const field = union_obj.fields.values()[field_index]; | 25351 | const field = union_obj.fields.values()[field_index]; |
| 24772 | const ptr_field_ty = try Type.ptr(arena, sema.mod, .{ | 25352 | const ptr_field_ty = try Type.ptr(arena, mod, .{ |
| 24773 | .pointee_type = field.ty, | 25353 | .pointee_type = field.ty, |
| 24774 | .mutable = union_ptr_ty.ptrIsMutable(), | 25354 | .mutable = union_ptr_ty.ptrIsMutable(mod), |
| 24775 | .@"volatile" = union_ptr_ty.isVolatilePtr(), | 25355 | .@"volatile" = union_ptr_ty.isVolatilePtr(mod), |
| 24776 | .@"addrspace" = union_ptr_ty.ptrAddressSpace(), | 25356 | .@"addrspace" = union_ptr_ty.ptrAddressSpace(mod), |
| 24777 | }); | 25357 | }); |
| 24778 | const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?); | 25358 | const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name, mod).?); |
| 24779 | 25359 | ||
| 24780 | if (initializing and field.ty.zigTypeTag() == .NoReturn) { | 25360 | if (initializing and field.ty.zigTypeTag(mod) == .NoReturn) { |
| 24781 | const msg = msg: { | 25361 | const msg = msg: { |
| 24782 | const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{}); | 25362 | const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{}); |
| 24783 | errdefer msg.destroy(sema.gpa); | 25363 | errdefer msg.destroy(sema.gpa); |
| 24784 | 25364 | ||
| 24785 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); | 25365 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{ |
| 25366 | field_name.fmt(ip), | ||
| 25367 | }); | ||
| 24786 | try sema.addDeclaredHereNote(msg, union_ty); | 25368 | try sema.addDeclaredHereNote(msg, union_ty); |
| 24787 | break :msg msg; | 25369 | break :msg msg; |
| 24788 | }; | 25370 | }; |
| ... | @@ -24794,21 +25376,20 @@ fn unionFieldPtr( | ... | @@ -24794,21 +25376,20 @@ fn unionFieldPtr( |
| 24794 | .Auto => if (!initializing) { | 25376 | .Auto => if (!initializing) { |
| 24795 | const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse | 25377 | const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse |
| 24796 | break :ct; | 25378 | break :ct; |
| 24797 | if (union_val.isUndef()) { | 25379 | if (union_val.isUndef(mod)) { |
| 24798 | return sema.failWithUseOfUndef(block, src); | 25380 | return sema.failWithUseOfUndef(block, src); |
| 24799 | } | 25381 | } |
| 24800 | const tag_and_val = union_val.castTag(.@"union").?.data; | 25382 | const un = ip.indexToKey(union_val.toIntern()).un; |
| 24801 | var field_tag_buf: Value.Payload.U32 = .{ | 25383 | const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); |
| 24802 | .base = .{ .tag = .enum_field_index }, | 25384 | const tag_matches = un.tag == field_tag.toIntern(); |
| 24803 | .data = enum_field_index, | ||
| 24804 | }; | ||
| 24805 | const field_tag = Value.initPayload(&field_tag_buf.base); | ||
| 24806 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); | ||
| 24807 | if (!tag_matches) { | 25385 | if (!tag_matches) { |
| 24808 | const msg = msg: { | 25386 | const msg = msg: { |
| 24809 | const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; | 25387 | const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?; |
| 24810 | const active_field_name = union_obj.tag_ty.enumFieldName(active_index); | 25388 | const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod); |
| 24811 | const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); | 25389 | const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{ |
| 25390 | field_name.fmt(ip), | ||
| 25391 | active_field_name.fmt(ip), | ||
| 25392 | }); | ||
| 24812 | errdefer msg.destroy(sema.gpa); | 25393 | errdefer msg.destroy(sema.gpa); |
| 24813 | try sema.addDeclaredHereNote(msg, union_ty); | 25394 | try sema.addDeclaredHereNote(msg, union_ty); |
| 24814 | break :msg msg; | 25395 | break :msg msg; |
| ... | @@ -24818,28 +25399,27 @@ fn unionFieldPtr( | ... | @@ -24818,28 +25399,27 @@ fn unionFieldPtr( |
| 24818 | }, | 25399 | }, |
| 24819 | .Packed, .Extern => {}, | 25400 | .Packed, .Extern => {}, |
| 24820 | } | 25401 | } |
| 24821 | return sema.addConstant( | 25402 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ |
| 24822 | ptr_field_ty, | 25403 | .ty = ptr_field_ty.toIntern(), |
| 24823 | try Value.Tag.field_ptr.create(arena, .{ | 25404 | .addr = .{ .field = .{ |
| 24824 | .container_ptr = union_ptr_val, | 25405 | .base = union_ptr_val.toIntern(), |
| 24825 | .container_ty = union_ty, | 25406 | .index = field_index, |
| 24826 | .field_index = field_index, | 25407 | } }, |
| 24827 | }), | 25408 | } })).toValue()); |
| 24828 | ); | ||
| 24829 | } | 25409 | } |
| 24830 | 25410 | ||
| 24831 | try sema.requireRuntimeBlock(block, src, null); | 25411 | try sema.requireRuntimeBlock(block, src, null); |
| 24832 | if (!initializing and union_obj.layout == .Auto and block.wantSafety() and | 25412 | if (!initializing and union_obj.layout == .Auto and block.wantSafety() and |
| 24833 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) | 25413 | union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1) |
| 24834 | { | 25414 | { |
| 24835 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); | 25415 | const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); |
| 24836 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); | 25416 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); |
| 24837 | // TODO would it be better if get_union_tag supported pointers to unions? | 25417 | // TODO would it be better if get_union_tag supported pointers to unions? |
| 24838 | const union_val = try block.addTyOp(.load, union_ty, union_ptr); | 25418 | const union_val = try block.addTyOp(.load, union_ty, union_ptr); |
| 24839 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val); | 25419 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val); |
| 24840 | try sema.panicInactiveUnionField(block, active_tag, wanted_tag); | 25420 | try sema.panicInactiveUnionField(block, active_tag, wanted_tag); |
| 24841 | } | 25421 | } |
| 24842 | if (field.ty.zigTypeTag() == .NoReturn) { | 25422 | if (field.ty.zigTypeTag(mod) == .NoReturn) { |
| 24843 | _ = try block.addNoOp(.unreach); | 25423 | _ = try block.addNoOp(.unreach); |
| 24844 | return Air.Inst.Ref.unreachable_value; | 25424 | return Air.Inst.Ref.unreachable_value; |
| 24845 | } | 25425 | } |
| ... | @@ -24851,37 +25431,37 @@ fn unionFieldVal( | ... | @@ -24851,37 +25431,37 @@ fn unionFieldVal( |
| 24851 | block: *Block, | 25431 | block: *Block, |
| 24852 | src: LazySrcLoc, | 25432 | src: LazySrcLoc, |
| 24853 | union_byval: Air.Inst.Ref, | 25433 | union_byval: Air.Inst.Ref, |
| 24854 | field_name: []const u8, | 25434 | field_name: InternPool.NullTerminatedString, |
| 24855 | field_name_src: LazySrcLoc, | 25435 | field_name_src: LazySrcLoc, |
| 24856 | unresolved_union_ty: Type, | 25436 | unresolved_union_ty: Type, |
| 24857 | ) CompileError!Air.Inst.Ref { | 25437 | ) CompileError!Air.Inst.Ref { |
| 24858 | assert(unresolved_union_ty.zigTypeTag() == .Union); | 25438 | const mod = sema.mod; |
| 25439 | const ip = &mod.intern_pool; | ||
| 25440 | assert(unresolved_union_ty.zigTypeTag(mod) == .Union); | ||
| 24859 | 25441 | ||
| 24860 | const union_ty = try sema.resolveTypeFields(unresolved_union_ty); | 25442 | const union_ty = try sema.resolveTypeFields(unresolved_union_ty); |
| 24861 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 25443 | const union_obj = mod.typeToUnion(union_ty).?; |
| 24862 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); | 25444 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 24863 | const field = union_obj.fields.values()[field_index]; | 25445 | const field = union_obj.fields.values()[field_index]; |
| 24864 | const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?); | 25446 | const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name, mod).?); |
| 24865 | 25447 | ||
| 24866 | if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| { | 25448 | if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| { |
| 24867 | if (union_val.isUndef()) return sema.addConstUndef(field.ty); | 25449 | if (union_val.isUndef(mod)) return sema.addConstUndef(field.ty); |
| 24868 | 25450 | ||
| 24869 | const tag_and_val = union_val.castTag(.@"union").?.data; | 25451 | const un = ip.indexToKey(union_val.toIntern()).un; |
| 24870 | var field_tag_buf: Value.Payload.U32 = .{ | 25452 | const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); |
| 24871 | .base = .{ .tag = .enum_field_index }, | 25453 | const tag_matches = un.tag == field_tag.toIntern(); |
| 24872 | .data = enum_field_index, | ||
| 24873 | }; | ||
| 24874 | const field_tag = Value.initPayload(&field_tag_buf.base); | ||
| 24875 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod); | ||
| 24876 | switch (union_obj.layout) { | 25454 | switch (union_obj.layout) { |
| 24877 | .Auto => { | 25455 | .Auto => { |
| 24878 | if (tag_matches) { | 25456 | if (tag_matches) { |
| 24879 | return sema.addConstant(field.ty, tag_and_val.val); | 25457 | return sema.addConstant(field.ty, un.val.toValue()); |
| 24880 | } else { | 25458 | } else { |
| 24881 | const msg = msg: { | 25459 | const msg = msg: { |
| 24882 | const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data; | 25460 | const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?; |
| 24883 | const active_field_name = union_obj.tag_ty.enumFieldName(active_index); | 25461 | const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod); |
| 24884 | const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); | 25462 | const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{ |
| 25463 | field_name.fmt(ip), active_field_name.fmt(ip), | ||
| 25464 | }); | ||
| 24885 | errdefer msg.destroy(sema.gpa); | 25465 | errdefer msg.destroy(sema.gpa); |
| 24886 | try sema.addDeclaredHereNote(msg, union_ty); | 25466 | try sema.addDeclaredHereNote(msg, union_ty); |
| 24887 | break :msg msg; | 25467 | break :msg msg; |
| ... | @@ -24891,10 +25471,10 @@ fn unionFieldVal( | ... | @@ -24891,10 +25471,10 @@ fn unionFieldVal( |
| 24891 | }, | 25471 | }, |
| 24892 | .Packed, .Extern => { | 25472 | .Packed, .Extern => { |
| 24893 | if (tag_matches) { | 25473 | if (tag_matches) { |
| 24894 | return sema.addConstant(field.ty, tag_and_val.val); | 25474 | return sema.addConstant(field.ty, un.val.toValue()); |
| 24895 | } else { | 25475 | } else { |
| 24896 | const old_ty = union_ty.unionFieldType(tag_and_val.tag, sema.mod); | 25476 | const old_ty = union_ty.unionFieldType(un.tag.toValue(), mod); |
| 24897 | if (try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0)) |new_val| { | 25477 | if (try sema.bitCastVal(block, src, un.val.toValue(), old_ty, field.ty, 0)) |new_val| { |
| 24898 | return sema.addConstant(field.ty, new_val); | 25478 | return sema.addConstant(field.ty, new_val); |
| 24899 | } | 25479 | } |
| 24900 | } | 25480 | } |
| ... | @@ -24904,14 +25484,14 @@ fn unionFieldVal( | ... | @@ -24904,14 +25484,14 @@ fn unionFieldVal( |
| 24904 | 25484 | ||
| 24905 | try sema.requireRuntimeBlock(block, src, null); | 25485 | try sema.requireRuntimeBlock(block, src, null); |
| 24906 | if (union_obj.layout == .Auto and block.wantSafety() and | 25486 | if (union_obj.layout == .Auto and block.wantSafety() and |
| 24907 | union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1) | 25487 | union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1) |
| 24908 | { | 25488 | { |
| 24909 | const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index); | 25489 | const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); |
| 24910 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); | 25490 | const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val); |
| 24911 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval); | 25491 | const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval); |
| 24912 | try sema.panicInactiveUnionField(block, active_tag, wanted_tag); | 25492 | try sema.panicInactiveUnionField(block, active_tag, wanted_tag); |
| 24913 | } | 25493 | } |
| 24914 | if (field.ty.zigTypeTag() == .NoReturn) { | 25494 | if (field.ty.zigTypeTag(mod) == .NoReturn) { |
| 24915 | _ = try block.addNoOp(.unreach); | 25495 | _ = try block.addNoOp(.unreach); |
| 24916 | return Air.Inst.Ref.unreachable_value; | 25496 | return Air.Inst.Ref.unreachable_value; |
| 24917 | } | 25497 | } |
| ... | @@ -24928,22 +25508,22 @@ fn elemPtr( | ... | @@ -24928,22 +25508,22 @@ fn elemPtr( |
| 24928 | init: bool, | 25508 | init: bool, |
| 24929 | oob_safety: bool, | 25509 | oob_safety: bool, |
| 24930 | ) CompileError!Air.Inst.Ref { | 25510 | ) CompileError!Air.Inst.Ref { |
| 25511 | const mod = sema.mod; | ||
| 24931 | const indexable_ptr_src = src; // TODO better source location | 25512 | const indexable_ptr_src = src; // TODO better source location |
| 24932 | const indexable_ptr_ty = sema.typeOf(indexable_ptr); | 25513 | const indexable_ptr_ty = sema.typeOf(indexable_ptr); |
| 24933 | const target = sema.mod.getTarget(); | ||
| 24934 | 25514 | ||
| 24935 | const indexable_ty = switch (indexable_ptr_ty.zigTypeTag()) { | 25515 | const indexable_ty = switch (indexable_ptr_ty.zigTypeTag(mod)) { |
| 24936 | .Pointer => indexable_ptr_ty.elemType(), | 25516 | .Pointer => indexable_ptr_ty.childType(mod), |
| 24937 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(sema.mod)}), | 25517 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(mod)}), |
| 24938 | }; | 25518 | }; |
| 24939 | try checkIndexable(sema, block, src, indexable_ty); | 25519 | try checkIndexable(sema, block, src, indexable_ty); |
| 24940 | 25520 | ||
| 24941 | switch (indexable_ty.zigTypeTag()) { | 25521 | switch (indexable_ty.zigTypeTag(mod)) { |
| 24942 | .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), | 25522 | .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), |
| 24943 | .Struct => { | 25523 | .Struct => { |
| 24944 | // Tuple field access. | 25524 | // Tuple field access. |
| 24945 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known"); | 25525 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known"); |
| 24946 | const index = @intCast(u32, index_val.toUnsignedInt(target)); | 25526 | const index = @intCast(u32, index_val.toUnsignedInt(mod)); |
| 24947 | return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); | 25527 | return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); |
| 24948 | }, | 25528 | }, |
| 24949 | else => { | 25529 | else => { |
| ... | @@ -24966,11 +25546,11 @@ fn elemPtrOneLayerOnly( | ... | @@ -24966,11 +25546,11 @@ fn elemPtrOneLayerOnly( |
| 24966 | ) CompileError!Air.Inst.Ref { | 25546 | ) CompileError!Air.Inst.Ref { |
| 24967 | const indexable_src = src; // TODO better source location | 25547 | const indexable_src = src; // TODO better source location |
| 24968 | const indexable_ty = sema.typeOf(indexable); | 25548 | const indexable_ty = sema.typeOf(indexable); |
| 24969 | const target = sema.mod.getTarget(); | 25549 | const mod = sema.mod; |
| 24970 | 25550 | ||
| 24971 | try checkIndexable(sema, block, src, indexable_ty); | 25551 | try checkIndexable(sema, block, src, indexable_ty); |
| 24972 | 25552 | ||
| 24973 | switch (indexable_ty.ptrSize()) { | 25553 | switch (indexable_ty.ptrSize(mod)) { |
| 24974 | .Slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), | 25554 | .Slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), |
| 24975 | .Many, .C => { | 25555 | .Many, .C => { |
| 24976 | const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable); | 25556 | const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable); |
| ... | @@ -24978,9 +25558,9 @@ fn elemPtrOneLayerOnly( | ... | @@ -24978,9 +25558,9 @@ fn elemPtrOneLayerOnly( |
| 24978 | const runtime_src = rs: { | 25558 | const runtime_src = rs: { |
| 24979 | const ptr_val = maybe_ptr_val orelse break :rs indexable_src; | 25559 | const ptr_val = maybe_ptr_val orelse break :rs indexable_src; |
| 24980 | const index_val = maybe_index_val orelse break :rs elem_index_src; | 25560 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 24981 | const index = @intCast(usize, index_val.toUnsignedInt(target)); | 25561 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); |
| 24982 | const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); | ||
| 24983 | const result_ty = try sema.elemPtrType(indexable_ty, index); | 25562 | const result_ty = try sema.elemPtrType(indexable_ty, index); |
| 25563 | const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod); | ||
| 24984 | return sema.addConstant(result_ty, elem_ptr); | 25564 | return sema.addConstant(result_ty, elem_ptr); |
| 24985 | }; | 25565 | }; |
| 24986 | const result_ty = try sema.elemPtrType(indexable_ty, null); | 25566 | const result_ty = try sema.elemPtrType(indexable_ty, null); |
| ... | @@ -24989,7 +25569,7 @@ fn elemPtrOneLayerOnly( | ... | @@ -24989,7 +25569,7 @@ fn elemPtrOneLayerOnly( |
| 24989 | return block.addPtrElemPtr(indexable, elem_index, result_ty); | 25569 | return block.addPtrElemPtr(indexable, elem_index, result_ty); |
| 24990 | }, | 25570 | }, |
| 24991 | .One => { | 25571 | .One => { |
| 24992 | assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by checkIndexable | 25572 | assert(indexable_ty.childType(mod).zigTypeTag(mod) == .Array); // Guaranteed by checkIndexable |
| 24993 | return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety); | 25573 | return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety); |
| 24994 | }, | 25574 | }, |
| 24995 | } | 25575 | } |
| ... | @@ -25006,7 +25586,7 @@ fn elemVal( | ... | @@ -25006,7 +25586,7 @@ fn elemVal( |
| 25006 | ) CompileError!Air.Inst.Ref { | 25586 | ) CompileError!Air.Inst.Ref { |
| 25007 | const indexable_src = src; // TODO better source location | 25587 | const indexable_src = src; // TODO better source location |
| 25008 | const indexable_ty = sema.typeOf(indexable); | 25588 | const indexable_ty = sema.typeOf(indexable); |
| 25009 | const target = sema.mod.getTarget(); | 25589 | const mod = sema.mod; |
| 25010 | 25590 | ||
| 25011 | try checkIndexable(sema, block, src, indexable_ty); | 25591 | try checkIndexable(sema, block, src, indexable_ty); |
| 25012 | 25592 | ||
| ... | @@ -25014,8 +25594,8 @@ fn elemVal( | ... | @@ -25014,8 +25594,8 @@ fn elemVal( |
| 25014 | // index is a scalar or vector instead of unconditionally casting to usize. | 25594 | // index is a scalar or vector instead of unconditionally casting to usize. |
| 25015 | const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src); | 25595 | const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src); |
| 25016 | 25596 | ||
| 25017 | switch (indexable_ty.zigTypeTag()) { | 25597 | switch (indexable_ty.zigTypeTag(mod)) { |
| 25018 | .Pointer => switch (indexable_ty.ptrSize()) { | 25598 | .Pointer => switch (indexable_ty.ptrSize(mod)) { |
| 25019 | .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), | 25599 | .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), |
| 25020 | .Many, .C => { | 25600 | .Many, .C => { |
| 25021 | const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable); | 25601 | const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable); |
| ... | @@ -25024,10 +25604,14 @@ fn elemVal( | ... | @@ -25024,10 +25604,14 @@ fn elemVal( |
| 25024 | const runtime_src = rs: { | 25604 | const runtime_src = rs: { |
| 25025 | const indexable_val = maybe_indexable_val orelse break :rs indexable_src; | 25605 | const indexable_val = maybe_indexable_val orelse break :rs indexable_src; |
| 25026 | const index_val = maybe_index_val orelse break :rs elem_index_src; | 25606 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 25027 | const index = @intCast(usize, index_val.toUnsignedInt(target)); | 25607 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); |
| 25028 | const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, sema.arena, index, sema.mod); | 25608 | const elem_ty = indexable_ty.elemType2(mod); |
| 25029 | if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| { | 25609 | const many_ptr_ty = try mod.manyConstPtrType(elem_ty); |
| 25030 | return sema.addConstant(indexable_ty.elemType2(), elem_val); | 25610 | const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty); |
| 25611 | const elem_ptr_ty = try mod.singleConstPtrType(elem_ty); | ||
| 25612 | const elem_ptr_val = try many_ptr_val.elemPtr(elem_ptr_ty, index, mod); | ||
| 25613 | if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { | ||
| 25614 | return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty)); | ||
| 25031 | } | 25615 | } |
| 25032 | break :rs indexable_src; | 25616 | break :rs indexable_src; |
| 25033 | }; | 25617 | }; |
| ... | @@ -25036,7 +25620,19 @@ fn elemVal( | ... | @@ -25036,7 +25620,19 @@ fn elemVal( |
| 25036 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); | 25620 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); |
| 25037 | }, | 25621 | }, |
| 25038 | .One => { | 25622 | .One => { |
| 25039 | assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by checkIndexable | 25623 | const array_ty = indexable_ty.childType(mod); // Guaranteed by checkIndexable |
| 25624 | assert(array_ty.zigTypeTag(mod) == .Array); | ||
| 25625 | |||
| 25626 | if (array_ty.sentinel(mod)) |sentinel| { | ||
| 25627 | // index must be defined since it can access out of bounds | ||
| 25628 | if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| { | ||
| 25629 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); | ||
| 25630 | if (index == array_ty.arrayLen(mod)) { | ||
| 25631 | return sema.addConstant(array_ty.childType(mod), sentinel); | ||
| 25632 | } | ||
| 25633 | } | ||
| 25634 | } | ||
| 25635 | |||
| 25040 | const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety); | 25636 | const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety); |
| 25041 | return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src); | 25637 | return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src); |
| 25042 | }, | 25638 | }, |
| ... | @@ -25049,7 +25645,7 @@ fn elemVal( | ... | @@ -25049,7 +25645,7 @@ fn elemVal( |
| 25049 | .Struct => { | 25645 | .Struct => { |
| 25050 | // Tuple field access. | 25646 | // Tuple field access. |
| 25051 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known"); | 25647 | const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known"); |
| 25052 | const index = @intCast(u32, index_val.toUnsignedInt(target)); | 25648 | const index = @intCast(u32, index_val.toUnsignedInt(mod)); |
| 25053 | return sema.tupleField(block, indexable_src, indexable, elem_index_src, index); | 25649 | return sema.tupleField(block, indexable_src, indexable, elem_index_src, index); |
| 25054 | }, | 25650 | }, |
| 25055 | else => unreachable, | 25651 | else => unreachable, |
| ... | @@ -25064,6 +25660,7 @@ fn validateRuntimeElemAccess( | ... | @@ -25064,6 +25660,7 @@ fn validateRuntimeElemAccess( |
| 25064 | parent_ty: Type, | 25660 | parent_ty: Type, |
| 25065 | parent_src: LazySrcLoc, | 25661 | parent_src: LazySrcLoc, |
| 25066 | ) CompileError!void { | 25662 | ) CompileError!void { |
| 25663 | const mod = sema.mod; | ||
| 25067 | const valid_rt = try sema.validateRunTimeType(elem_ty, false); | 25664 | const valid_rt = try sema.validateRunTimeType(elem_ty, false); |
| 25068 | if (!valid_rt) { | 25665 | if (!valid_rt) { |
| 25069 | const msg = msg: { | 25666 | const msg = msg: { |
| ... | @@ -25071,12 +25668,12 @@ fn validateRuntimeElemAccess( | ... | @@ -25071,12 +25668,12 @@ fn validateRuntimeElemAccess( |
| 25071 | block, | 25668 | block, |
| 25072 | elem_index_src, | 25669 | elem_index_src, |
| 25073 | "values of type '{}' must be comptime-known, but index value is runtime-known", | 25670 | "values of type '{}' must be comptime-known, but index value is runtime-known", |
| 25074 | .{parent_ty.fmt(sema.mod)}, | 25671 | .{parent_ty.fmt(mod)}, |
| 25075 | ); | 25672 | ); |
| 25076 | errdefer msg.destroy(sema.gpa); | 25673 | errdefer msg.destroy(sema.gpa); |
| 25077 | 25674 | ||
| 25078 | const src_decl = sema.mod.declPtr(block.src_decl); | 25675 | const src_decl = mod.declPtr(block.src_decl); |
| 25079 | try sema.explainWhyTypeIsComptime(msg, parent_src.toSrcLoc(src_decl), parent_ty); | 25676 | try sema.explainWhyTypeIsComptime(msg, parent_src.toSrcLoc(src_decl, mod), parent_ty); |
| 25080 | 25677 | ||
| 25081 | break :msg msg; | 25678 | break :msg msg; |
| 25082 | }; | 25679 | }; |
| ... | @@ -25093,10 +25690,11 @@ fn tupleFieldPtr( | ... | @@ -25093,10 +25690,11 @@ fn tupleFieldPtr( |
| 25093 | field_index: u32, | 25690 | field_index: u32, |
| 25094 | init: bool, | 25691 | init: bool, |
| 25095 | ) CompileError!Air.Inst.Ref { | 25692 | ) CompileError!Air.Inst.Ref { |
| 25693 | const mod = sema.mod; | ||
| 25096 | const tuple_ptr_ty = sema.typeOf(tuple_ptr); | 25694 | const tuple_ptr_ty = sema.typeOf(tuple_ptr); |
| 25097 | const tuple_ty = tuple_ptr_ty.childType(); | 25695 | const tuple_ty = tuple_ptr_ty.childType(mod); |
| 25098 | _ = try sema.resolveTypeFields(tuple_ty); | 25696 | _ = try sema.resolveTypeFields(tuple_ty); |
| 25099 | const field_count = tuple_ty.structFieldCount(); | 25697 | const field_count = tuple_ty.structFieldCount(mod); |
| 25100 | 25698 | ||
| 25101 | if (field_count == 0) { | 25699 | if (field_count == 0) { |
| 25102 | return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{}); | 25700 | return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{}); |
| ... | @@ -25108,31 +25706,29 @@ fn tupleFieldPtr( | ... | @@ -25108,31 +25706,29 @@ fn tupleFieldPtr( |
| 25108 | }); | 25706 | }); |
| 25109 | } | 25707 | } |
| 25110 | 25708 | ||
| 25111 | const field_ty = tuple_ty.structFieldType(field_index); | 25709 | const field_ty = tuple_ty.structFieldType(field_index, mod); |
| 25112 | const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{ | 25710 | const ptr_field_ty = try Type.ptr(sema.arena, mod, .{ |
| 25113 | .pointee_type = field_ty, | 25711 | .pointee_type = field_ty, |
| 25114 | .mutable = tuple_ptr_ty.ptrIsMutable(), | 25712 | .mutable = tuple_ptr_ty.ptrIsMutable(mod), |
| 25115 | .@"volatile" = tuple_ptr_ty.isVolatilePtr(), | 25713 | .@"volatile" = tuple_ptr_ty.isVolatilePtr(mod), |
| 25116 | .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(), | 25714 | .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(mod), |
| 25117 | }); | 25715 | }); |
| 25118 | 25716 | ||
| 25119 | if (tuple_ty.structFieldValueComptime(field_index)) |default_val| { | 25717 | if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| { |
| 25120 | const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{ | 25718 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ |
| 25121 | .field_ty = field_ty, | 25719 | .ty = ptr_field_ty.toIntern(), |
| 25122 | .field_val = default_val, | 25720 | .addr = .{ .comptime_field = default_val.toIntern() }, |
| 25123 | }); | 25721 | } })).toValue()); |
| 25124 | return sema.addConstant(ptr_field_ty, val); | ||
| 25125 | } | 25722 | } |
| 25126 | 25723 | ||
| 25127 | if (try sema.resolveMaybeUndefVal(tuple_ptr)) |tuple_ptr_val| { | 25724 | if (try sema.resolveMaybeUndefVal(tuple_ptr)) |tuple_ptr_val| { |
| 25128 | return sema.addConstant( | 25725 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ |
| 25129 | ptr_field_ty, | 25726 | .ty = ptr_field_ty.toIntern(), |
| 25130 | try Value.Tag.field_ptr.create(sema.arena, .{ | 25727 | .addr = .{ .field = .{ |
| 25131 | .container_ptr = tuple_ptr_val, | 25728 | .base = tuple_ptr_val.toIntern(), |
| 25132 | .container_ty = tuple_ty, | 25729 | .index = field_index, |
| 25133 | .field_index = field_index, | 25730 | } }, |
| 25134 | }), | 25731 | } })).toValue()); |
| 25135 | ); | ||
| 25136 | } | 25732 | } |
| 25137 | 25733 | ||
| 25138 | if (!init) { | 25734 | if (!init) { |
| ... | @@ -25151,8 +25747,9 @@ fn tupleField( | ... | @@ -25151,8 +25747,9 @@ fn tupleField( |
| 25151 | field_index_src: LazySrcLoc, | 25747 | field_index_src: LazySrcLoc, |
| 25152 | field_index: u32, | 25748 | field_index: u32, |
| 25153 | ) CompileError!Air.Inst.Ref { | 25749 | ) CompileError!Air.Inst.Ref { |
| 25750 | const mod = sema.mod; | ||
| 25154 | const tuple_ty = try sema.resolveTypeFields(sema.typeOf(tuple)); | 25751 | const tuple_ty = try sema.resolveTypeFields(sema.typeOf(tuple)); |
| 25155 | const field_count = tuple_ty.structFieldCount(); | 25752 | const field_count = tuple_ty.structFieldCount(mod); |
| 25156 | 25753 | ||
| 25157 | if (field_count == 0) { | 25754 | if (field_count == 0) { |
| 25158 | return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{}); | 25755 | return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{}); |
| ... | @@ -25164,15 +25761,15 @@ fn tupleField( | ... | @@ -25164,15 +25761,15 @@ fn tupleField( |
| 25164 | }); | 25761 | }); |
| 25165 | } | 25762 | } |
| 25166 | 25763 | ||
| 25167 | const field_ty = tuple_ty.structFieldType(field_index); | 25764 | const field_ty = tuple_ty.structFieldType(field_index, mod); |
| 25168 | 25765 | ||
| 25169 | if (tuple_ty.structFieldValueComptime(field_index)) |default_value| { | 25766 | if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| { |
| 25170 | return sema.addConstant(field_ty, default_value); // comptime field | 25767 | return sema.addConstant(field_ty, default_value); // comptime field |
| 25171 | } | 25768 | } |
| 25172 | 25769 | ||
| 25173 | if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| { | 25770 | if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| { |
| 25174 | if (tuple_val.isUndef()) return sema.addConstUndef(field_ty); | 25771 | if (tuple_val.isUndef(mod)) return sema.addConstUndef(field_ty); |
| 25175 | return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index)); | 25772 | return sema.addConstant(field_ty, try tuple_val.fieldValue(mod, field_index)); |
| 25176 | } | 25773 | } |
| 25177 | 25774 | ||
| 25178 | try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); | 25775 | try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); |
| ... | @@ -25191,11 +25788,12 @@ fn elemValArray( | ... | @@ -25191,11 +25788,12 @@ fn elemValArray( |
| 25191 | elem_index: Air.Inst.Ref, | 25788 | elem_index: Air.Inst.Ref, |
| 25192 | oob_safety: bool, | 25789 | oob_safety: bool, |
| 25193 | ) CompileError!Air.Inst.Ref { | 25790 | ) CompileError!Air.Inst.Ref { |
| 25791 | const mod = sema.mod; | ||
| 25194 | const array_ty = sema.typeOf(array); | 25792 | const array_ty = sema.typeOf(array); |
| 25195 | const array_sent = array_ty.sentinel(); | 25793 | const array_sent = array_ty.sentinel(mod); |
| 25196 | const array_len = array_ty.arrayLen(); | 25794 | const array_len = array_ty.arrayLen(mod); |
| 25197 | const array_len_s = array_len + @boolToInt(array_sent != null); | 25795 | const array_len_s = array_len + @boolToInt(array_sent != null); |
| 25198 | const elem_ty = array_ty.childType(); | 25796 | const elem_ty = array_ty.childType(mod); |
| 25199 | 25797 | ||
| 25200 | if (array_len_s == 0) { | 25798 | if (array_len_s == 0) { |
| 25201 | return sema.fail(block, array_src, "indexing into empty array is not allowed", .{}); | 25799 | return sema.fail(block, array_src, "indexing into empty array is not allowed", .{}); |
| ... | @@ -25204,10 +25802,9 @@ fn elemValArray( | ... | @@ -25204,10 +25802,9 @@ fn elemValArray( |
| 25204 | const maybe_undef_array_val = try sema.resolveMaybeUndefVal(array); | 25802 | const maybe_undef_array_val = try sema.resolveMaybeUndefVal(array); |
| 25205 | // index must be defined since it can access out of bounds | 25803 | // index must be defined since it can access out of bounds |
| 25206 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); | 25804 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 25207 | const target = sema.mod.getTarget(); | ||
| 25208 | 25805 | ||
| 25209 | if (maybe_index_val) |index_val| { | 25806 | if (maybe_index_val) |index_val| { |
| 25210 | const index = @intCast(usize, index_val.toUnsignedInt(target)); | 25807 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); |
| 25211 | if (array_sent) |s| { | 25808 | if (array_sent) |s| { |
| 25212 | if (index == array_len) { | 25809 | if (index == array_len) { |
| 25213 | return sema.addConstant(elem_ty, s); | 25810 | return sema.addConstant(elem_ty, s); |
| ... | @@ -25219,12 +25816,12 @@ fn elemValArray( | ... | @@ -25219,12 +25816,12 @@ fn elemValArray( |
| 25219 | } | 25816 | } |
| 25220 | } | 25817 | } |
| 25221 | if (maybe_undef_array_val) |array_val| { | 25818 | if (maybe_undef_array_val) |array_val| { |
| 25222 | if (array_val.isUndef()) { | 25819 | if (array_val.isUndef(mod)) { |
| 25223 | return sema.addConstUndef(elem_ty); | 25820 | return sema.addConstUndef(elem_ty); |
| 25224 | } | 25821 | } |
| 25225 | if (maybe_index_val) |index_val| { | 25822 | if (maybe_index_val) |index_val| { |
| 25226 | const index = @intCast(usize, index_val.toUnsignedInt(target)); | 25823 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); |
| 25227 | const elem_val = try array_val.elemValue(sema.mod, sema.arena, index); | 25824 | const elem_val = try array_val.elemValue(mod, index); |
| 25228 | return sema.addConstant(elem_ty, elem_val); | 25825 | return sema.addConstant(elem_ty, elem_val); |
| 25229 | } | 25826 | } |
| 25230 | } | 25827 | } |
| ... | @@ -25255,11 +25852,11 @@ fn elemPtrArray( | ... | @@ -25255,11 +25852,11 @@ fn elemPtrArray( |
| 25255 | init: bool, | 25852 | init: bool, |
| 25256 | oob_safety: bool, | 25853 | oob_safety: bool, |
| 25257 | ) CompileError!Air.Inst.Ref { | 25854 | ) CompileError!Air.Inst.Ref { |
| 25258 | const target = sema.mod.getTarget(); | 25855 | const mod = sema.mod; |
| 25259 | const array_ptr_ty = sema.typeOf(array_ptr); | 25856 | const array_ptr_ty = sema.typeOf(array_ptr); |
| 25260 | const array_ty = array_ptr_ty.childType(); | 25857 | const array_ty = array_ptr_ty.childType(mod); |
| 25261 | const array_sent = array_ty.sentinel() != null; | 25858 | const array_sent = array_ty.sentinel(mod) != null; |
| 25262 | const array_len = array_ty.arrayLen(); | 25859 | const array_len = array_ty.arrayLen(mod); |
| 25263 | const array_len_s = array_len + @boolToInt(array_sent); | 25860 | const array_len_s = array_len + @boolToInt(array_sent); |
| 25264 | 25861 | ||
| 25265 | if (array_len_s == 0) { | 25862 | if (array_len_s == 0) { |
| ... | @@ -25269,7 +25866,7 @@ fn elemPtrArray( | ... | @@ -25269,7 +25866,7 @@ fn elemPtrArray( |
| 25269 | const maybe_undef_array_ptr_val = try sema.resolveMaybeUndefVal(array_ptr); | 25866 | const maybe_undef_array_ptr_val = try sema.resolveMaybeUndefVal(array_ptr); |
| 25270 | // The index must not be undefined since it can be out of bounds. | 25867 | // The index must not be undefined since it can be out of bounds. |
| 25271 | const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { | 25868 | const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { |
| 25272 | const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(target)); | 25869 | const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(mod)); |
| 25273 | if (index >= array_len_s) { | 25870 | if (index >= array_len_s) { |
| 25274 | const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; | 25871 | const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; |
| 25275 | return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); | 25872 | return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); |
| ... | @@ -25280,17 +25877,17 @@ fn elemPtrArray( | ... | @@ -25280,17 +25877,17 @@ fn elemPtrArray( |
| 25280 | const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset); | 25877 | const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset); |
| 25281 | 25878 | ||
| 25282 | if (maybe_undef_array_ptr_val) |array_ptr_val| { | 25879 | if (maybe_undef_array_ptr_val) |array_ptr_val| { |
| 25283 | if (array_ptr_val.isUndef()) { | 25880 | if (array_ptr_val.isUndef(mod)) { |
| 25284 | return sema.addConstUndef(elem_ptr_ty); | 25881 | return sema.addConstUndef(elem_ptr_ty); |
| 25285 | } | 25882 | } |
| 25286 | if (offset) |index| { | 25883 | if (offset) |index| { |
| 25287 | const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, index, sema.mod); | 25884 | const elem_ptr = try array_ptr_val.elemPtr(elem_ptr_ty, index, mod); |
| 25288 | return sema.addConstant(elem_ptr_ty, elem_ptr); | 25885 | return sema.addConstant(elem_ptr_ty, elem_ptr); |
| 25289 | } | 25886 | } |
| 25290 | } | 25887 | } |
| 25291 | 25888 | ||
| 25292 | if (!init) { | 25889 | if (!init) { |
| 25293 | try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(), array_ty, array_ptr_src); | 25890 | try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(mod), array_ty, array_ptr_src); |
| 25294 | } | 25891 | } |
| 25295 | 25892 | ||
| 25296 | const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src; | 25893 | const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src; |
| ... | @@ -25316,32 +25913,33 @@ fn elemValSlice( | ... | @@ -25316,32 +25913,33 @@ fn elemValSlice( |
| 25316 | elem_index: Air.Inst.Ref, | 25913 | elem_index: Air.Inst.Ref, |
| 25317 | oob_safety: bool, | 25914 | oob_safety: bool, |
| 25318 | ) CompileError!Air.Inst.Ref { | 25915 | ) CompileError!Air.Inst.Ref { |
| 25916 | const mod = sema.mod; | ||
| 25319 | const slice_ty = sema.typeOf(slice); | 25917 | const slice_ty = sema.typeOf(slice); |
| 25320 | const slice_sent = slice_ty.sentinel() != null; | 25918 | const slice_sent = slice_ty.sentinel(mod) != null; |
| 25321 | const elem_ty = slice_ty.elemType2(); | 25919 | const elem_ty = slice_ty.elemType2(mod); |
| 25322 | var runtime_src = slice_src; | 25920 | var runtime_src = slice_src; |
| 25323 | 25921 | ||
| 25324 | // slice must be defined since it can dereferenced as null | 25922 | // slice must be defined since it can dereferenced as null |
| 25325 | const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice); | 25923 | const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice); |
| 25326 | // index must be defined since it can index out of bounds | 25924 | // index must be defined since it can index out of bounds |
| 25327 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); | 25925 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 25328 | const target = sema.mod.getTarget(); | ||
| 25329 | 25926 | ||
| 25330 | if (maybe_slice_val) |slice_val| { | 25927 | if (maybe_slice_val) |slice_val| { |
| 25331 | runtime_src = elem_index_src; | 25928 | runtime_src = elem_index_src; |
| 25332 | const slice_len = slice_val.sliceLen(sema.mod); | 25929 | const slice_len = slice_val.sliceLen(mod); |
| 25333 | const slice_len_s = slice_len + @boolToInt(slice_sent); | 25930 | const slice_len_s = slice_len + @boolToInt(slice_sent); |
| 25334 | if (slice_len_s == 0) { | 25931 | if (slice_len_s == 0) { |
| 25335 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); | 25932 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| 25336 | } | 25933 | } |
| 25337 | if (maybe_index_val) |index_val| { | 25934 | if (maybe_index_val) |index_val| { |
| 25338 | const index = @intCast(usize, index_val.toUnsignedInt(target)); | 25935 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); |
| 25339 | if (index >= slice_len_s) { | 25936 | if (index >= slice_len_s) { |
| 25340 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; | 25937 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 25341 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); | 25938 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| 25342 | } | 25939 | } |
| 25343 | const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, sema.mod); | 25940 | const elem_ptr_ty = try sema.elemPtrType(slice_ty, index); |
| 25344 | if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| { | 25941 | const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod); |
| 25942 | if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { | ||
| 25345 | return sema.addConstant(elem_ty, elem_val); | 25943 | return sema.addConstant(elem_ty, elem_val); |
| 25346 | } | 25944 | } |
| 25347 | runtime_src = slice_src; | 25945 | runtime_src = slice_src; |
| ... | @@ -25353,7 +25951,7 @@ fn elemValSlice( | ... | @@ -25353,7 +25951,7 @@ fn elemValSlice( |
| 25353 | try sema.requireRuntimeBlock(block, src, runtime_src); | 25951 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 25354 | if (oob_safety and block.wantSafety()) { | 25952 | if (oob_safety and block.wantSafety()) { |
| 25355 | const len_inst = if (maybe_slice_val) |slice_val| | 25953 | const len_inst = if (maybe_slice_val) |slice_val| |
| 25356 | try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)) | 25954 | try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod)) |
| 25357 | else | 25955 | else |
| 25358 | try block.addTyOp(.slice_len, Type.usize, slice); | 25956 | try block.addTyOp(.slice_len, Type.usize, slice); |
| 25359 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; | 25957 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| ... | @@ -25373,24 +25971,24 @@ fn elemPtrSlice( | ... | @@ -25373,24 +25971,24 @@ fn elemPtrSlice( |
| 25373 | elem_index: Air.Inst.Ref, | 25971 | elem_index: Air.Inst.Ref, |
| 25374 | oob_safety: bool, | 25972 | oob_safety: bool, |
| 25375 | ) CompileError!Air.Inst.Ref { | 25973 | ) CompileError!Air.Inst.Ref { |
| 25376 | const target = sema.mod.getTarget(); | 25974 | const mod = sema.mod; |
| 25377 | const slice_ty = sema.typeOf(slice); | 25975 | const slice_ty = sema.typeOf(slice); |
| 25378 | const slice_sent = slice_ty.sentinel() != null; | 25976 | const slice_sent = slice_ty.sentinel(mod) != null; |
| 25379 | 25977 | ||
| 25380 | const maybe_undef_slice_val = try sema.resolveMaybeUndefVal(slice); | 25978 | const maybe_undef_slice_val = try sema.resolveMaybeUndefVal(slice); |
| 25381 | // The index must not be undefined since it can be out of bounds. | 25979 | // The index must not be undefined since it can be out of bounds. |
| 25382 | const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { | 25980 | const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { |
| 25383 | const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(target)); | 25981 | const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(mod)); |
| 25384 | break :o index; | 25982 | break :o index; |
| 25385 | } else null; | 25983 | } else null; |
| 25386 | 25984 | ||
| 25387 | const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset); | 25985 | const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset); |
| 25388 | 25986 | ||
| 25389 | if (maybe_undef_slice_val) |slice_val| { | 25987 | if (maybe_undef_slice_val) |slice_val| { |
| 25390 | if (slice_val.isUndef()) { | 25988 | if (slice_val.isUndef(mod)) { |
| 25391 | return sema.addConstUndef(elem_ptr_ty); | 25989 | return sema.addConstUndef(elem_ptr_ty); |
| 25392 | } | 25990 | } |
| 25393 | const slice_len = slice_val.sliceLen(sema.mod); | 25991 | const slice_len = slice_val.sliceLen(mod); |
| 25394 | const slice_len_s = slice_len + @boolToInt(slice_sent); | 25992 | const slice_len_s = slice_len + @boolToInt(slice_sent); |
| 25395 | if (slice_len_s == 0) { | 25993 | if (slice_len_s == 0) { |
| 25396 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); | 25994 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| ... | @@ -25400,7 +25998,7 @@ fn elemPtrSlice( | ... | @@ -25400,7 +25998,7 @@ fn elemPtrSlice( |
| 25400 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; | 25998 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 25401 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); | 25999 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| 25402 | } | 26000 | } |
| 25403 | const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, sema.mod); | 26001 | const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod); |
| 25404 | return sema.addConstant(elem_ptr_ty, elem_ptr_val); | 26002 | return sema.addConstant(elem_ptr_ty, elem_ptr_val); |
| 25405 | } | 26003 | } |
| 25406 | } | 26004 | } |
| ... | @@ -25412,8 +26010,8 @@ fn elemPtrSlice( | ... | @@ -25412,8 +26010,8 @@ fn elemPtrSlice( |
| 25412 | if (oob_safety and block.wantSafety()) { | 26010 | if (oob_safety and block.wantSafety()) { |
| 25413 | const len_inst = len: { | 26011 | const len_inst = len: { |
| 25414 | if (maybe_undef_slice_val) |slice_val| | 26012 | if (maybe_undef_slice_val) |slice_val| |
| 25415 | if (!slice_val.isUndef()) | 26013 | if (!slice_val.isUndef(mod)) |
| 25416 | break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)); | 26014 | break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod)); |
| 25417 | break :len try block.addTyOp(.slice_len, Type.usize, slice); | 26015 | break :len try block.addTyOp(.slice_len, Type.usize, slice); |
| 25418 | }; | 26016 | }; |
| 25419 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; | 26017 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| ... | @@ -25455,16 +26053,17 @@ const CoerceOpts = struct { | ... | @@ -25455,16 +26053,17 @@ const CoerceOpts = struct { |
| 25455 | 26053 | ||
| 25456 | fn get(info: @This(), sema: *Sema) !?Module.SrcLoc { | 26054 | fn get(info: @This(), sema: *Sema) !?Module.SrcLoc { |
| 25457 | if (info.func_inst == .none) return null; | 26055 | if (info.func_inst == .none) return null; |
| 26056 | const mod = sema.mod; | ||
| 25458 | const fn_decl = (try sema.funcDeclSrc(info.func_inst)) orelse return null; | 26057 | const fn_decl = (try sema.funcDeclSrc(info.func_inst)) orelse return null; |
| 25459 | const param_src = Module.paramSrc(0, sema.gpa, fn_decl, info.param_i); | 26058 | const param_src = Module.paramSrc(0, mod, fn_decl, info.param_i); |
| 25460 | if (param_src == .node_offset_param) { | 26059 | if (param_src == .node_offset_param) { |
| 25461 | return Module.SrcLoc{ | 26060 | return Module.SrcLoc{ |
| 25462 | .file_scope = fn_decl.getFileScope(), | 26061 | .file_scope = fn_decl.getFileScope(mod), |
| 25463 | .parent_decl_node = fn_decl.src_node, | 26062 | .parent_decl_node = fn_decl.src_node, |
| 25464 | .lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param), | 26063 | .lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param), |
| 25465 | }; | 26064 | }; |
| 25466 | } | 26065 | } |
| 25467 | return param_src.toSrcLoc(fn_decl); | 26066 | return param_src.toSrcLoc(fn_decl, mod); |
| 25468 | } | 26067 | } |
| 25469 | } = .{}, | 26068 | } = .{}, |
| 25470 | }; | 26069 | }; |
| ... | @@ -25477,34 +26076,30 @@ fn coerceExtra( | ... | @@ -25477,34 +26076,30 @@ fn coerceExtra( |
| 25477 | inst_src: LazySrcLoc, | 26076 | inst_src: LazySrcLoc, |
| 25478 | opts: CoerceOpts, | 26077 | opts: CoerceOpts, |
| 25479 | ) CoersionError!Air.Inst.Ref { | 26078 | ) CoersionError!Air.Inst.Ref { |
| 25480 | switch (dest_ty_unresolved.tag()) { | 26079 | if (dest_ty_unresolved.isGenericPoison()) return inst; |
| 25481 | .generic_poison => return inst, | 26080 | const mod = sema.mod; |
| 25482 | else => {}, | ||
| 25483 | } | ||
| 25484 | const dest_ty_src = inst_src; // TODO better source location | 26081 | const dest_ty_src = inst_src; // TODO better source location |
| 25485 | const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); | 26082 | const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); |
| 25486 | const inst_ty = try sema.resolveTypeFields(sema.typeOf(inst)); | 26083 | const inst_ty = try sema.resolveTypeFields(sema.typeOf(inst)); |
| 25487 | const target = sema.mod.getTarget(); | 26084 | const target = mod.getTarget(); |
| 25488 | // If the types are the same, we can return the operand. | 26085 | // If the types are the same, we can return the operand. |
| 25489 | if (dest_ty.eql(inst_ty, sema.mod)) | 26086 | if (dest_ty.eql(inst_ty, mod)) |
| 25490 | return inst; | 26087 | return inst; |
| 25491 | 26088 | ||
| 25492 | const arena = sema.arena; | ||
| 25493 | const maybe_inst_val = try sema.resolveMaybeUndefVal(inst); | 26089 | const maybe_inst_val = try sema.resolveMaybeUndefVal(inst); |
| 25494 | 26090 | ||
| 25495 | var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); | 26091 | var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src); |
| 25496 | if (in_memory_result == .ok) { | 26092 | if (in_memory_result == .ok) { |
| 25497 | if (maybe_inst_val) |val| { | 26093 | if (maybe_inst_val) |val| { |
| 25498 | // Keep the comptime Value representation; take the new type. | 26094 | return sema.coerceInMemory(block, val, inst_ty, dest_ty, dest_ty_src); |
| 25499 | return sema.addConstant(dest_ty, val); | ||
| 25500 | } | 26095 | } |
| 25501 | try sema.requireRuntimeBlock(block, inst_src, null); | 26096 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 25502 | return block.addBitCast(dest_ty, inst); | 26097 | return block.addBitCast(dest_ty, inst); |
| 25503 | } | 26098 | } |
| 25504 | 26099 | ||
| 25505 | const is_undef = inst_ty.zigTypeTag() == .Undefined; | 26100 | const is_undef = inst_ty.zigTypeTag(mod) == .Undefined; |
| 25506 | 26101 | ||
| 25507 | switch (dest_ty.zigTypeTag()) { | 26102 | switch (dest_ty.zigTypeTag(mod)) { |
| 25508 | .Optional => optional: { | 26103 | .Optional => optional: { |
| 25509 | // undefined sets the optional bit also to undefined. | 26104 | // undefined sets the optional bit also to undefined. |
| 25510 | if (is_undef) { | 26105 | if (is_undef) { |
| ... | @@ -25512,18 +26107,22 @@ fn coerceExtra( | ... | @@ -25512,18 +26107,22 @@ fn coerceExtra( |
| 25512 | } | 26107 | } |
| 25513 | 26108 | ||
| 25514 | // null to ?T | 26109 | // null to ?T |
| 25515 | if (inst_ty.zigTypeTag() == .Null) { | 26110 | if (inst_ty.zigTypeTag(mod) == .Null) { |
| 25516 | return sema.addConstant(dest_ty, Value.null); | 26111 | return sema.addConstant(dest_ty, (try mod.intern(.{ .opt = .{ |
| 26112 | .ty = dest_ty.toIntern(), | ||
| 26113 | .val = .none, | ||
| 26114 | } })).toValue()); | ||
| 25517 | } | 26115 | } |
| 25518 | 26116 | ||
| 25519 | // cast from ?*T and ?[*]T to ?*anyopaque | 26117 | // cast from ?*T and ?[*]T to ?*anyopaque |
| 25520 | // but don't do it if the source type is a double pointer | 26118 | // but don't do it if the source type is a double pointer |
| 25521 | if (dest_ty.isPtrLikeOptional() and dest_ty.elemType2().tag() == .anyopaque and | 26119 | if (dest_ty.isPtrLikeOptional(mod) and |
| 25522 | inst_ty.isPtrAtRuntime()) | 26120 | dest_ty.elemType2(mod).toIntern() == .anyopaque_type and |
| 26121 | inst_ty.isPtrAtRuntime(mod)) | ||
| 25523 | anyopaque_check: { | 26122 | anyopaque_check: { |
| 25524 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional; | 26123 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional; |
| 25525 | const elem_ty = inst_ty.elemType2(); | 26124 | const elem_ty = inst_ty.elemType2(mod); |
| 25526 | if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) { | 26125 | if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) { |
| 25527 | in_memory_result = .{ .double_ptr_to_anyopaque = .{ | 26126 | in_memory_result = .{ .double_ptr_to_anyopaque = .{ |
| 25528 | .actual = inst_ty, | 26127 | .actual = inst_ty, |
| 25529 | .wanted = dest_ty, | 26128 | .wanted = dest_ty, |
| ... | @@ -25532,12 +26131,12 @@ fn coerceExtra( | ... | @@ -25532,12 +26131,12 @@ fn coerceExtra( |
| 25532 | } | 26131 | } |
| 25533 | // Let the logic below handle wrapping the optional now that | 26132 | // Let the logic below handle wrapping the optional now that |
| 25534 | // it has been checked to correctly coerce. | 26133 | // it has been checked to correctly coerce. |
| 25535 | if (!inst_ty.isPtrLikeOptional()) break :anyopaque_check; | 26134 | if (!inst_ty.isPtrLikeOptional(mod)) break :anyopaque_check; |
| 25536 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); | 26135 | return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src); |
| 25537 | } | 26136 | } |
| 25538 | 26137 | ||
| 25539 | // T to ?T | 26138 | // T to ?T |
| 25540 | const child_type = try dest_ty.optionalChildAlloc(sema.arena); | 26139 | const child_type = dest_ty.optionalChild(mod); |
| 25541 | const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { | 26140 | const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { |
| 25542 | error.NotCoercible => { | 26141 | error.NotCoercible => { |
| 25543 | if (in_memory_result == .no_match) { | 26142 | if (in_memory_result == .no_match) { |
| ... | @@ -25551,12 +26150,12 @@ fn coerceExtra( | ... | @@ -25551,12 +26150,12 @@ fn coerceExtra( |
| 25551 | return try sema.wrapOptional(block, dest_ty, intermediate, inst_src); | 26150 | return try sema.wrapOptional(block, dest_ty, intermediate, inst_src); |
| 25552 | }, | 26151 | }, |
| 25553 | .Pointer => pointer: { | 26152 | .Pointer => pointer: { |
| 25554 | const dest_info = dest_ty.ptrInfo().data; | 26153 | const dest_info = dest_ty.ptrInfo(mod); |
| 25555 | 26154 | ||
| 25556 | // Function body to function pointer. | 26155 | // Function body to function pointer. |
| 25557 | if (inst_ty.zigTypeTag() == .Fn) { | 26156 | if (inst_ty.zigTypeTag(mod) == .Fn) { |
| 25558 | const fn_val = try sema.resolveConstValue(block, .unneeded, inst, ""); | 26157 | const fn_val = try sema.resolveConstValue(block, .unneeded, inst, ""); |
| 25559 | const fn_decl = fn_val.pointerDecl().?; | 26158 | const fn_decl = fn_val.pointerDecl(mod).?; |
| 25560 | const inst_as_ptr = try sema.analyzeDeclRef(fn_decl); | 26159 | const inst_as_ptr = try sema.analyzeDeclRef(fn_decl); |
| 25561 | return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); | 26160 | return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); |
| 25562 | } | 26161 | } |
| ... | @@ -25564,13 +26163,13 @@ fn coerceExtra( | ... | @@ -25564,13 +26163,13 @@ fn coerceExtra( |
| 25564 | // *T to *[1]T | 26163 | // *T to *[1]T |
| 25565 | single_item: { | 26164 | single_item: { |
| 25566 | if (dest_info.size != .One) break :single_item; | 26165 | if (dest_info.size != .One) break :single_item; |
| 25567 | if (!inst_ty.isSinglePointer()) break :single_item; | 26166 | if (!inst_ty.isSinglePointer(mod)) break :single_item; |
| 25568 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; | 26167 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; |
| 25569 | const ptr_elem_ty = inst_ty.childType(); | 26168 | const ptr_elem_ty = inst_ty.childType(mod); |
| 25570 | const array_ty = dest_info.pointee_type; | 26169 | const array_ty = dest_info.pointee_type; |
| 25571 | if (array_ty.zigTypeTag() != .Array) break :single_item; | 26170 | if (array_ty.zigTypeTag(mod) != .Array) break :single_item; |
| 25572 | const array_elem_ty = array_ty.childType(); | 26171 | const array_elem_ty = array_ty.childType(mod); |
| 25573 | if (array_ty.arrayLen() != 1) break :single_item; | 26172 | if (array_ty.arrayLen(mod) != 1) break :single_item; |
| 25574 | const dest_is_mut = dest_info.mutable; | 26173 | const dest_is_mut = dest_info.mutable; |
| 25575 | switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { | 26174 | switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { |
| 25576 | .ok => {}, | 26175 | .ok => {}, |
| ... | @@ -25581,11 +26180,11 @@ fn coerceExtra( | ... | @@ -25581,11 +26180,11 @@ fn coerceExtra( |
| 25581 | 26180 | ||
| 25582 | // Coercions where the source is a single pointer to an array. | 26181 | // Coercions where the source is a single pointer to an array. |
| 25583 | src_array_ptr: { | 26182 | src_array_ptr: { |
| 25584 | if (!inst_ty.isSinglePointer()) break :src_array_ptr; | 26183 | if (!inst_ty.isSinglePointer(mod)) break :src_array_ptr; |
| 25585 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; | 26184 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; |
| 25586 | const array_ty = inst_ty.childType(); | 26185 | const array_ty = inst_ty.childType(mod); |
| 25587 | if (array_ty.zigTypeTag() != .Array) break :src_array_ptr; | 26186 | if (array_ty.zigTypeTag(mod) != .Array) break :src_array_ptr; |
| 25588 | const array_elem_type = array_ty.childType(); | 26187 | const array_elem_type = array_ty.childType(mod); |
| 25589 | const dest_is_mut = dest_info.mutable; | 26188 | const dest_is_mut = dest_info.mutable; |
| 25590 | 26189 | ||
| 25591 | const dst_elem_type = dest_info.pointee_type; | 26190 | const dst_elem_type = dest_info.pointee_type; |
| ... | @@ -25603,8 +26202,8 @@ fn coerceExtra( | ... | @@ -25603,8 +26202,8 @@ fn coerceExtra( |
| 25603 | } | 26202 | } |
| 25604 | 26203 | ||
| 25605 | if (dest_info.sentinel) |dest_sent| { | 26204 | if (dest_info.sentinel) |dest_sent| { |
| 25606 | if (array_ty.sentinel()) |inst_sent| { | 26205 | if (array_ty.sentinel(mod)) |inst_sent| { |
| 25607 | if (!dest_sent.eql(inst_sent, dst_elem_type, sema.mod)) { | 26206 | if (!dest_sent.eql(inst_sent, dst_elem_type, mod)) { |
| 25608 | in_memory_result = .{ .ptr_sentinel = .{ | 26207 | in_memory_result = .{ .ptr_sentinel = .{ |
| 25609 | .actual = inst_sent, | 26208 | .actual = inst_sent, |
| 25610 | .wanted = dest_sent, | 26209 | .wanted = dest_sent, |
| ... | @@ -25614,7 +26213,7 @@ fn coerceExtra( | ... | @@ -25614,7 +26213,7 @@ fn coerceExtra( |
| 25614 | } | 26213 | } |
| 25615 | } else { | 26214 | } else { |
| 25616 | in_memory_result = .{ .ptr_sentinel = .{ | 26215 | in_memory_result = .{ .ptr_sentinel = .{ |
| 25617 | .actual = Value.initTag(.unreachable_value), | 26216 | .actual = Value.@"unreachable", |
| 25618 | .wanted = dest_sent, | 26217 | .wanted = dest_sent, |
| 25619 | .ty = dst_elem_type, | 26218 | .ty = dst_elem_type, |
| 25620 | } }; | 26219 | } }; |
| ... | @@ -25640,11 +26239,11 @@ fn coerceExtra( | ... | @@ -25640,11 +26239,11 @@ fn coerceExtra( |
| 25640 | } | 26239 | } |
| 25641 | 26240 | ||
| 25642 | // coercion from C pointer | 26241 | // coercion from C pointer |
| 25643 | if (inst_ty.isCPtr()) src_c_ptr: { | 26242 | if (inst_ty.isCPtr(mod)) src_c_ptr: { |
| 25644 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr; | 26243 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr; |
| 25645 | // In this case we must add a safety check because the C pointer | 26244 | // In this case we must add a safety check because the C pointer |
| 25646 | // could be null. | 26245 | // could be null. |
| 25647 | const src_elem_ty = inst_ty.childType(); | 26246 | const src_elem_ty = inst_ty.childType(mod); |
| 25648 | const dest_is_mut = dest_info.mutable; | 26247 | const dest_is_mut = dest_info.mutable; |
| 25649 | const dst_elem_type = dest_info.pointee_type; | 26248 | const dst_elem_type = dest_info.pointee_type; |
| 25650 | switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { | 26249 | switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) { |
| ... | @@ -25656,18 +26255,18 @@ fn coerceExtra( | ... | @@ -25656,18 +26255,18 @@ fn coerceExtra( |
| 25656 | 26255 | ||
| 25657 | // cast from *T and [*]T to *anyopaque | 26256 | // cast from *T and [*]T to *anyopaque |
| 25658 | // but don't do it if the source type is a double pointer | 26257 | // but don't do it if the source type is a double pointer |
| 25659 | if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer) to_anyopaque: { | 26258 | if (dest_info.pointee_type.toIntern() == .anyopaque_type and inst_ty.zigTypeTag(mod) == .Pointer) to_anyopaque: { |
| 25660 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; | 26259 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; |
| 25661 | const elem_ty = inst_ty.elemType2(); | 26260 | const elem_ty = inst_ty.elemType2(mod); |
| 25662 | if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) { | 26261 | if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) { |
| 25663 | in_memory_result = .{ .double_ptr_to_anyopaque = .{ | 26262 | in_memory_result = .{ .double_ptr_to_anyopaque = .{ |
| 25664 | .actual = inst_ty, | 26263 | .actual = inst_ty, |
| 25665 | .wanted = dest_ty, | 26264 | .wanted = dest_ty, |
| 25666 | } }; | 26265 | } }; |
| 25667 | break :pointer; | 26266 | break :pointer; |
| 25668 | } | 26267 | } |
| 25669 | if (dest_ty.isSlice()) break :to_anyopaque; | 26268 | if (dest_ty.isSlice(mod)) break :to_anyopaque; |
| 25670 | if (inst_ty.isSlice()) { | 26269 | if (inst_ty.isSlice(mod)) { |
| 25671 | in_memory_result = .{ .slice_to_anyopaque = .{ | 26270 | in_memory_result = .{ .slice_to_anyopaque = .{ |
| 25672 | .actual = inst_ty, | 26271 | .actual = inst_ty, |
| 25673 | .wanted = dest_ty, | 26272 | .wanted = dest_ty, |
| ... | @@ -25679,9 +26278,9 @@ fn coerceExtra( | ... | @@ -25679,9 +26278,9 @@ fn coerceExtra( |
| 25679 | 26278 | ||
| 25680 | switch (dest_info.size) { | 26279 | switch (dest_info.size) { |
| 25681 | // coercion to C pointer | 26280 | // coercion to C pointer |
| 25682 | .C => switch (inst_ty.zigTypeTag()) { | 26281 | .C => switch (inst_ty.zigTypeTag(mod)) { |
| 25683 | .Null => { | 26282 | .Null => { |
| 25684 | return sema.addConstant(dest_ty, Value.null); | 26283 | return sema.addConstant(dest_ty, try mod.getCoerced(Value.null, dest_ty)); |
| 25685 | }, | 26284 | }, |
| 25686 | .ComptimeInt => { | 26285 | .ComptimeInt => { |
| 25687 | const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { | 26286 | const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) { |
| ... | @@ -25691,7 +26290,7 @@ fn coerceExtra( | ... | @@ -25691,7 +26290,7 @@ fn coerceExtra( |
| 25691 | return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); | 26290 | return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src); |
| 25692 | }, | 26291 | }, |
| 25693 | .Int => { | 26292 | .Int => { |
| 25694 | const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) { | 26293 | const ptr_size_ty = switch (inst_ty.intInfo(mod).signedness) { |
| 25695 | .signed => Type.isize, | 26294 | .signed => Type.isize, |
| 25696 | .unsigned => Type.usize, | 26295 | .unsigned => Type.usize, |
| 25697 | }; | 26296 | }; |
| ... | @@ -25707,7 +26306,7 @@ fn coerceExtra( | ... | @@ -25707,7 +26306,7 @@ fn coerceExtra( |
| 25707 | }, | 26306 | }, |
| 25708 | .Pointer => p: { | 26307 | .Pointer => p: { |
| 25709 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p; | 26308 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p; |
| 25710 | const inst_info = inst_ty.ptrInfo().data; | 26309 | const inst_info = inst_ty.ptrInfo(mod); |
| 25711 | switch (try sema.coerceInMemoryAllowed( | 26310 | switch (try sema.coerceInMemoryAllowed( |
| 25712 | block, | 26311 | block, |
| 25713 | dest_info.pointee_type, | 26312 | dest_info.pointee_type, |
| ... | @@ -25723,7 +26322,7 @@ fn coerceExtra( | ... | @@ -25723,7 +26322,7 @@ fn coerceExtra( |
| 25723 | if (inst_info.size == .Slice) { | 26322 | if (inst_info.size == .Slice) { |
| 25724 | assert(dest_info.sentinel == null); | 26323 | assert(dest_info.sentinel == null); |
| 25725 | if (inst_info.sentinel == null or | 26324 | if (inst_info.sentinel == null or |
| 25726 | !inst_info.sentinel.?.eql(Value.zero, dest_info.pointee_type, sema.mod)) | 26325 | !inst_info.sentinel.?.eql(try mod.intValue(dest_info.pointee_type, 0), dest_info.pointee_type, mod)) |
| 25727 | break :p; | 26326 | break :p; |
| 25728 | 26327 | ||
| 25729 | const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); | 26328 | const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); |
| ... | @@ -25733,11 +26332,11 @@ fn coerceExtra( | ... | @@ -25733,11 +26332,11 @@ fn coerceExtra( |
| 25733 | }, | 26332 | }, |
| 25734 | else => {}, | 26333 | else => {}, |
| 25735 | }, | 26334 | }, |
| 25736 | .One => switch (dest_info.pointee_type.zigTypeTag()) { | 26335 | .One => switch (dest_info.pointee_type.zigTypeTag(mod)) { |
| 25737 | .Union => { | 26336 | .Union => { |
| 25738 | // pointer to anonymous struct to pointer to union | 26337 | // pointer to anonymous struct to pointer to union |
| 25739 | if (inst_ty.isSinglePointer() and | 26338 | if (inst_ty.isSinglePointer(mod) and |
| 25740 | inst_ty.childType().isAnonStruct() and | 26339 | inst_ty.childType(mod).isAnonStruct(mod) and |
| 25741 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) | 26340 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) |
| 25742 | { | 26341 | { |
| 25743 | return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src); | 26342 | return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src); |
| ... | @@ -25745,8 +26344,8 @@ fn coerceExtra( | ... | @@ -25745,8 +26344,8 @@ fn coerceExtra( |
| 25745 | }, | 26344 | }, |
| 25746 | .Struct => { | 26345 | .Struct => { |
| 25747 | // pointer to anonymous struct to pointer to struct | 26346 | // pointer to anonymous struct to pointer to struct |
| 25748 | if (inst_ty.isSinglePointer() and | 26347 | if (inst_ty.isSinglePointer(mod) and |
| 25749 | inst_ty.childType().isAnonStruct() and | 26348 | inst_ty.childType(mod).isAnonStruct(mod) and |
| 25750 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) | 26349 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) |
| 25751 | { | 26350 | { |
| 25752 | return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) { | 26351 | return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) { |
| ... | @@ -25757,8 +26356,8 @@ fn coerceExtra( | ... | @@ -25757,8 +26356,8 @@ fn coerceExtra( |
| 25757 | }, | 26356 | }, |
| 25758 | .Array => { | 26357 | .Array => { |
| 25759 | // pointer to tuple to pointer to array | 26358 | // pointer to tuple to pointer to array |
| 25760 | if (inst_ty.isSinglePointer() and | 26359 | if (inst_ty.isSinglePointer(mod) and |
| 25761 | inst_ty.childType().isTuple() and | 26360 | inst_ty.childType(mod).isTuple(mod) and |
| 25762 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) | 26361 | sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) |
| 25763 | { | 26362 | { |
| 25764 | return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src); | 26363 | return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src); |
| ... | @@ -25767,38 +26366,38 @@ fn coerceExtra( | ... | @@ -25767,38 +26366,38 @@ fn coerceExtra( |
| 25767 | else => {}, | 26366 | else => {}, |
| 25768 | }, | 26367 | }, |
| 25769 | .Slice => to_slice: { | 26368 | .Slice => to_slice: { |
| 25770 | if (inst_ty.zigTypeTag() == .Array) { | 26369 | if (inst_ty.zigTypeTag(mod) == .Array) { |
| 25771 | return sema.fail( | 26370 | return sema.fail( |
| 25772 | block, | 26371 | block, |
| 25773 | inst_src, | 26372 | inst_src, |
| 25774 | "array literal requires address-of operator (&) to coerce to slice type '{}'", | 26373 | "array literal requires address-of operator (&) to coerce to slice type '{}'", |
| 25775 | .{dest_ty.fmt(sema.mod)}, | 26374 | .{dest_ty.fmt(mod)}, |
| 25776 | ); | 26375 | ); |
| 25777 | } | 26376 | } |
| 25778 | 26377 | ||
| 25779 | if (!inst_ty.isSinglePointer()) break :to_slice; | 26378 | if (!inst_ty.isSinglePointer(mod)) break :to_slice; |
| 25780 | const inst_child_ty = inst_ty.childType(); | 26379 | const inst_child_ty = inst_ty.childType(mod); |
| 25781 | if (!inst_child_ty.isTuple()) break :to_slice; | 26380 | if (!inst_child_ty.isTuple(mod)) break :to_slice; |
| 25782 | 26381 | ||
| 25783 | // empty tuple to zero-length slice | 26382 | // empty tuple to zero-length slice |
| 25784 | // note that this allows coercing to a mutable slice. | 26383 | // note that this allows coercing to a mutable slice. |
| 25785 | if (inst_child_ty.structFieldCount() == 0) { | 26384 | if (inst_child_ty.structFieldCount(mod) == 0) { |
| 25786 | // Optional slice is represented with a null pointer so | 26385 | // Optional slice is represented with a null pointer so |
| 25787 | // we use a dummy pointer value with the required alignment. | 26386 | // we use a dummy pointer value with the required alignment. |
| 25788 | const slice_val = try Value.Tag.slice.create(sema.arena, .{ | 26387 | return sema.addConstant(dest_ty, (try mod.intern(.{ .ptr = .{ |
| 25789 | .ptr = if (dest_info.@"align" != 0) | 26388 | .ty = dest_ty.toIntern(), |
| 25790 | try Value.Tag.int_u64.create(sema.arena, dest_info.@"align") | 26389 | .addr = .{ .int = (if (dest_info.@"align" != 0) |
| 26390 | try mod.intValue(Type.usize, dest_info.@"align") | ||
| 25791 | else | 26391 | else |
| 25792 | try dest_info.pointee_type.lazyAbiAlignment(target, sema.arena), | 26392 | try mod.getCoerced(try dest_info.pointee_type.lazyAbiAlignment(mod), Type.usize)).toIntern() }, |
| 25793 | .len = Value.zero, | 26393 | .len = (try mod.intValue(Type.usize, 0)).toIntern(), |
| 25794 | }); | 26394 | } })).toValue()); |
| 25795 | return sema.addConstant(dest_ty, slice_val); | ||
| 25796 | } | 26395 | } |
| 25797 | 26396 | ||
| 25798 | // pointer to tuple to slice | 26397 | // pointer to tuple to slice |
| 25799 | if (dest_info.mutable) { | 26398 | if (dest_info.mutable) { |
| 25800 | const err_msg = err_msg: { | 26399 | const err_msg = err_msg: { |
| 25801 | const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(sema.mod)}); | 26400 | const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(mod)}); |
| 25802 | errdefer err_msg.deinit(sema.gpa); | 26401 | errdefer err_msg.deinit(sema.gpa); |
| 25803 | try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{}); | 26402 | try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{}); |
| 25804 | break :err_msg err_msg; | 26403 | break :err_msg err_msg; |
| ... | @@ -25808,9 +26407,9 @@ fn coerceExtra( | ... | @@ -25808,9 +26407,9 @@ fn coerceExtra( |
| 25808 | return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src); | 26407 | return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src); |
| 25809 | }, | 26408 | }, |
| 25810 | .Many => p: { | 26409 | .Many => p: { |
| 25811 | if (!inst_ty.isSlice()) break :p; | 26410 | if (!inst_ty.isSlice(mod)) break :p; |
| 25812 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p; | 26411 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p; |
| 25813 | const inst_info = inst_ty.ptrInfo().data; | 26412 | const inst_info = inst_ty.ptrInfo(mod); |
| 25814 | 26413 | ||
| 25815 | switch (try sema.coerceInMemoryAllowed( | 26414 | switch (try sema.coerceInMemoryAllowed( |
| 25816 | block, | 26415 | block, |
| ... | @@ -25826,7 +26425,11 @@ fn coerceExtra( | ... | @@ -25826,7 +26425,11 @@ fn coerceExtra( |
| 25826 | } | 26425 | } |
| 25827 | 26426 | ||
| 25828 | if (dest_info.sentinel == null or inst_info.sentinel == null or | 26427 | if (dest_info.sentinel == null or inst_info.sentinel == null or |
| 25829 | !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type, sema.mod)) | 26428 | !dest_info.sentinel.?.eql( |
| 26429 | try mod.getCoerced(inst_info.sentinel.?, dest_info.pointee_type), | ||
| 26430 | dest_info.pointee_type, | ||
| 26431 | mod, | ||
| 26432 | )) | ||
| 25830 | break :p; | 26433 | break :p; |
| 25831 | 26434 | ||
| 25832 | const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); | 26435 | const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty); |
| ... | @@ -25834,25 +26437,25 @@ fn coerceExtra( | ... | @@ -25834,25 +26437,25 @@ fn coerceExtra( |
| 25834 | }, | 26437 | }, |
| 25835 | } | 26438 | } |
| 25836 | }, | 26439 | }, |
| 25837 | .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) { | 26440 | .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) { |
| 25838 | .Float, .ComptimeFloat => float: { | 26441 | .Float, .ComptimeFloat => float: { |
| 25839 | if (is_undef) { | 26442 | if (is_undef) { |
| 25840 | return sema.addConstUndef(dest_ty); | 26443 | return sema.addConstUndef(dest_ty); |
| 25841 | } | 26444 | } |
| 25842 | const val = (try sema.resolveMaybeUndefVal(inst)) orelse { | 26445 | const val = (try sema.resolveMaybeUndefVal(inst)) orelse { |
| 25843 | if (dest_ty.zigTypeTag() == .ComptimeInt) { | 26446 | if (dest_ty.zigTypeTag(mod) == .ComptimeInt) { |
| 25844 | if (!opts.report_err) return error.NotCoercible; | 26447 | if (!opts.report_err) return error.NotCoercible; |
| 25845 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known"); | 26448 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known"); |
| 25846 | } | 26449 | } |
| 25847 | break :float; | 26450 | break :float; |
| 25848 | }; | 26451 | }; |
| 25849 | 26452 | ||
| 25850 | if (val.floatHasFraction()) { | 26453 | if (val.floatHasFraction(mod)) { |
| 25851 | return sema.fail( | 26454 | return sema.fail( |
| 25852 | block, | 26455 | block, |
| 25853 | inst_src, | 26456 | inst_src, |
| 25854 | "fractional component prevents float value '{}' from coercion to type '{}'", | 26457 | "fractional component prevents float value '{}' from coercion to type '{}'", |
| 25855 | .{ val.fmtValue(inst_ty, sema.mod), dest_ty.fmt(sema.mod) }, | 26458 | .{ val.fmtValue(inst_ty, mod), dest_ty.fmt(mod) }, |
| 25856 | ); | 26459 | ); |
| 25857 | } | 26460 | } |
| 25858 | const result_val = try sema.floatToInt(block, inst_src, val, inst_ty, dest_ty); | 26461 | const result_val = try sema.floatToInt(block, inst_src, val, inst_ty, dest_ty); |
| ... | @@ -25866,19 +26469,19 @@ fn coerceExtra( | ... | @@ -25866,19 +26469,19 @@ fn coerceExtra( |
| 25866 | // comptime-known integer to other number | 26469 | // comptime-known integer to other number |
| 25867 | if (!(try sema.intFitsInType(val, dest_ty, null))) { | 26470 | if (!(try sema.intFitsInType(val, dest_ty, null))) { |
| 25868 | if (!opts.report_err) return error.NotCoercible; | 26471 | if (!opts.report_err) return error.NotCoercible; |
| 25869 | return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }); | 26472 | return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) }); |
| 25870 | } | 26473 | } |
| 25871 | return try sema.addConstant(dest_ty, val); | 26474 | return try sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty)); |
| 25872 | } | 26475 | } |
| 25873 | if (dest_ty.zigTypeTag() == .ComptimeInt) { | 26476 | if (dest_ty.zigTypeTag(mod) == .ComptimeInt) { |
| 25874 | if (!opts.report_err) return error.NotCoercible; | 26477 | if (!opts.report_err) return error.NotCoercible; |
| 25875 | if (opts.no_cast_to_comptime_int) return inst; | 26478 | if (opts.no_cast_to_comptime_int) return inst; |
| 25876 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known"); | 26479 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known"); |
| 25877 | } | 26480 | } |
| 25878 | 26481 | ||
| 25879 | // integer widening | 26482 | // integer widening |
| 25880 | const dst_info = dest_ty.intInfo(target); | 26483 | const dst_info = dest_ty.intInfo(mod); |
| 25881 | const src_info = inst_ty.intInfo(target); | 26484 | const src_info = inst_ty.intInfo(mod); |
| 25882 | if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or | 26485 | if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or |
| 25883 | // small enough unsigned ints can get casted to large enough signed ints | 26486 | // small enough unsigned ints can get casted to large enough signed ints |
| 25884 | (dst_info.signedness == .signed and dst_info.bits > src_info.bits)) | 26487 | (dst_info.signedness == .signed and dst_info.bits > src_info.bits)) |
| ... | @@ -25892,10 +26495,10 @@ fn coerceExtra( | ... | @@ -25892,10 +26495,10 @@ fn coerceExtra( |
| 25892 | }, | 26495 | }, |
| 25893 | else => {}, | 26496 | else => {}, |
| 25894 | }, | 26497 | }, |
| 25895 | .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) { | 26498 | .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) { |
| 25896 | .ComptimeFloat => { | 26499 | .ComptimeFloat => { |
| 25897 | const val = try sema.resolveConstValue(block, .unneeded, inst, ""); | 26500 | const val = try sema.resolveConstValue(block, .unneeded, inst, ""); |
| 25898 | const result_val = try val.floatCast(sema.arena, dest_ty, target); | 26501 | const result_val = try val.floatCast(dest_ty, mod); |
| 25899 | return try sema.addConstant(dest_ty, result_val); | 26502 | return try sema.addConstant(dest_ty, result_val); |
| 25900 | }, | 26503 | }, |
| 25901 | .Float => { | 26504 | .Float => { |
| ... | @@ -25903,17 +26506,17 @@ fn coerceExtra( | ... | @@ -25903,17 +26506,17 @@ fn coerceExtra( |
| 25903 | return sema.addConstUndef(dest_ty); | 26506 | return sema.addConstUndef(dest_ty); |
| 25904 | } | 26507 | } |
| 25905 | if (try sema.resolveMaybeUndefVal(inst)) |val| { | 26508 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 25906 | const result_val = try val.floatCast(sema.arena, dest_ty, target); | 26509 | const result_val = try val.floatCast(dest_ty, mod); |
| 25907 | if (!val.eql(result_val, inst_ty, sema.mod)) { | 26510 | if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) { |
| 25908 | return sema.fail( | 26511 | return sema.fail( |
| 25909 | block, | 26512 | block, |
| 25910 | inst_src, | 26513 | inst_src, |
| 25911 | "type '{}' cannot represent float value '{}'", | 26514 | "type '{}' cannot represent float value '{}'", |
| 25912 | .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) }, | 26515 | .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) }, |
| 25913 | ); | 26516 | ); |
| 25914 | } | 26517 | } |
| 25915 | return try sema.addConstant(dest_ty, result_val); | 26518 | return try sema.addConstant(dest_ty, result_val); |
| 25916 | } else if (dest_ty.zigTypeTag() == .ComptimeFloat) { | 26519 | } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) { |
| 25917 | if (!opts.report_err) return error.NotCoercible; | 26520 | if (!opts.report_err) return error.NotCoercible; |
| 25918 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known"); | 26521 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known"); |
| 25919 | } | 26522 | } |
| ... | @@ -25931,13 +26534,13 @@ fn coerceExtra( | ... | @@ -25931,13 +26534,13 @@ fn coerceExtra( |
| 25931 | return sema.addConstUndef(dest_ty); | 26534 | return sema.addConstUndef(dest_ty); |
| 25932 | } | 26535 | } |
| 25933 | const val = (try sema.resolveMaybeUndefVal(inst)) orelse { | 26536 | const val = (try sema.resolveMaybeUndefVal(inst)) orelse { |
| 25934 | if (dest_ty.zigTypeTag() == .ComptimeFloat) { | 26537 | if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) { |
| 25935 | if (!opts.report_err) return error.NotCoercible; | 26538 | if (!opts.report_err) return error.NotCoercible; |
| 25936 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known"); | 26539 | return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known"); |
| 25937 | } | 26540 | } |
| 25938 | break :int; | 26541 | break :int; |
| 25939 | }; | 26542 | }; |
| 25940 | const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, sema.mod, sema); | 26543 | const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, mod, sema); |
| 25941 | // TODO implement this compile error | 26544 | // TODO implement this compile error |
| 25942 | //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); | 26545 | //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); |
| 25943 | //if (!int_again_val.eql(val, inst_ty, mod)) { | 26546 | //if (!int_again_val.eql(val, inst_ty, mod)) { |
| ... | @@ -25945,7 +26548,7 @@ fn coerceExtra( | ... | @@ -25945,7 +26548,7 @@ fn coerceExtra( |
| 25945 | // block, | 26548 | // block, |
| 25946 | // inst_src, | 26549 | // inst_src, |
| 25947 | // "type '{}' cannot represent integer value '{}'", | 26550 | // "type '{}' cannot represent integer value '{}'", |
| 25948 | // .{ dest_ty.fmt(sema.mod), val }, | 26551 | // .{ dest_ty.fmt(mod), val }, |
| 25949 | // ); | 26552 | // ); |
| 25950 | //} | 26553 | //} |
| 25951 | return try sema.addConstant(dest_ty, result_val); | 26554 | return try sema.addConstant(dest_ty, result_val); |
| ... | @@ -25955,18 +26558,18 @@ fn coerceExtra( | ... | @@ -25955,18 +26558,18 @@ fn coerceExtra( |
| 25955 | }, | 26558 | }, |
| 25956 | else => {}, | 26559 | else => {}, |
| 25957 | }, | 26560 | }, |
| 25958 | .Enum => switch (inst_ty.zigTypeTag()) { | 26561 | .Enum => switch (inst_ty.zigTypeTag(mod)) { |
| 25959 | .EnumLiteral => { | 26562 | .EnumLiteral => { |
| 25960 | // enum literal to enum | 26563 | // enum literal to enum |
| 25961 | const val = try sema.resolveConstValue(block, .unneeded, inst, ""); | 26564 | const val = try sema.resolveConstValue(block, .unneeded, inst, ""); |
| 25962 | const bytes = val.castTag(.enum_literal).?.data; | 26565 | const string = mod.intern_pool.indexToKey(val.toIntern()).enum_literal; |
| 25963 | const field_index = dest_ty.enumFieldIndex(bytes) orelse { | 26566 | const field_index = dest_ty.enumFieldIndex(string, mod) orelse { |
| 25964 | const msg = msg: { | 26567 | const msg = msg: { |
| 25965 | const msg = try sema.errMsg( | 26568 | const msg = try sema.errMsg( |
| 25966 | block, | 26569 | block, |
| 25967 | inst_src, | 26570 | inst_src, |
| 25968 | "no field named '{s}' in enum '{}'", | 26571 | "no field named '{}' in enum '{}'", |
| 25969 | .{ bytes, dest_ty.fmt(sema.mod) }, | 26572 | .{ string.fmt(&mod.intern_pool), dest_ty.fmt(mod) }, |
| 25970 | ); | 26573 | ); |
| 25971 | errdefer msg.destroy(sema.gpa); | 26574 | errdefer msg.destroy(sema.gpa); |
| 25972 | try sema.addDeclaredHereNote(msg, dest_ty); | 26575 | try sema.addDeclaredHereNote(msg, dest_ty); |
| ... | @@ -25976,13 +26579,13 @@ fn coerceExtra( | ... | @@ -25976,13 +26579,13 @@ fn coerceExtra( |
| 25976 | }; | 26579 | }; |
| 25977 | return sema.addConstant( | 26580 | return sema.addConstant( |
| 25978 | dest_ty, | 26581 | dest_ty, |
| 25979 | try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)), | 26582 | try mod.enumValueFieldIndex(dest_ty, @intCast(u32, field_index)), |
| 25980 | ); | 26583 | ); |
| 25981 | }, | 26584 | }, |
| 25982 | .Union => blk: { | 26585 | .Union => blk: { |
| 25983 | // union to its own tag type | 26586 | // union to its own tag type |
| 25984 | const union_tag_ty = inst_ty.unionTagType() orelse break :blk; | 26587 | const union_tag_ty = inst_ty.unionTagType(mod) orelse break :blk; |
| 25985 | if (union_tag_ty.eql(dest_ty, sema.mod)) { | 26588 | if (union_tag_ty.eql(dest_ty, mod)) { |
| 25986 | return sema.unionToTag(block, dest_ty, inst, inst_src); | 26589 | return sema.unionToTag(block, dest_ty, inst, inst_src); |
| 25987 | } | 26590 | } |
| 25988 | }, | 26591 | }, |
| ... | @@ -25991,27 +26594,33 @@ fn coerceExtra( | ... | @@ -25991,27 +26594,33 @@ fn coerceExtra( |
| 25991 | }, | 26594 | }, |
| 25992 | else => {}, | 26595 | else => {}, |
| 25993 | }, | 26596 | }, |
| 25994 | .ErrorUnion => switch (inst_ty.zigTypeTag()) { | 26597 | .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) { |
| 25995 | .ErrorUnion => eu: { | 26598 | .ErrorUnion => eu: { |
| 25996 | if (maybe_inst_val) |inst_val| { | 26599 | if (maybe_inst_val) |inst_val| { |
| 25997 | switch (inst_val.tag()) { | 26600 | switch (inst_val.toIntern()) { |
| 25998 | .undef => return sema.addConstUndef(dest_ty), | 26601 | .undef => return sema.addConstUndef(dest_ty), |
| 25999 | .eu_payload => { | 26602 | else => switch (mod.intern_pool.indexToKey(inst_val.toIntern())) { |
| 26000 | const payload = try sema.addConstant( | 26603 | .error_union => |error_union| switch (error_union.val) { |
| 26001 | inst_ty.errorUnionPayload(), | 26604 | .err_name => |err_name| { |
| 26002 | inst_val.castTag(.eu_payload).?.data, | 26605 | const error_set_ty = inst_ty.errorUnionSet(mod); |
| 26003 | ); | 26606 | const error_set_val = try sema.addConstant(error_set_ty, (try mod.intern(.{ .err = .{ |
| 26004 | return sema.wrapErrorUnionPayload(block, dest_ty, payload, inst_src) catch |err| switch (err) { | 26607 | .ty = error_set_ty.toIntern(), |
| 26005 | error.NotCoercible => break :eu, | 26608 | .name = err_name, |
| 26006 | else => |e| return e, | 26609 | } })).toValue()); |
| 26007 | }; | 26610 | return sema.wrapErrorUnionSet(block, dest_ty, error_set_val, inst_src); |
| 26008 | }, | 26611 | }, |
| 26009 | else => { | 26612 | .payload => |payload| { |
| 26010 | const error_set = try sema.addConstant( | 26613 | const payload_val = try sema.addConstant( |
| 26011 | inst_ty.errorUnionSet(), | 26614 | inst_ty.errorUnionPayload(mod), |
| 26012 | inst_val, | 26615 | payload.toValue(), |
| 26013 | ); | 26616 | ); |
| 26014 | return sema.wrapErrorUnionSet(block, dest_ty, error_set, inst_src); | 26617 | return sema.wrapErrorUnionPayload(block, dest_ty, payload_val, inst_src) catch |err| switch (err) { |
| 26618 | error.NotCoercible => break :eu, | ||
| 26619 | else => |e| return e, | ||
| 26620 | }; | ||
| 26621 | }, | ||
| 26622 | }, | ||
| 26623 | else => unreachable, | ||
| 26015 | }, | 26624 | }, |
| 26016 | } | 26625 | } |
| 26017 | } | 26626 | } |
| ... | @@ -26031,10 +26640,10 @@ fn coerceExtra( | ... | @@ -26031,10 +26640,10 @@ fn coerceExtra( |
| 26031 | }; | 26640 | }; |
| 26032 | }, | 26641 | }, |
| 26033 | }, | 26642 | }, |
| 26034 | .Union => switch (inst_ty.zigTypeTag()) { | 26643 | .Union => switch (inst_ty.zigTypeTag(mod)) { |
| 26035 | .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src), | 26644 | .Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src), |
| 26036 | .Struct => { | 26645 | .Struct => { |
| 26037 | if (inst_ty.isAnonStruct()) { | 26646 | if (inst_ty.isAnonStruct(mod)) { |
| 26038 | return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src); | 26647 | return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src); |
| 26039 | } | 26648 | } |
| 26040 | }, | 26649 | }, |
| ... | @@ -26043,13 +26652,13 @@ fn coerceExtra( | ... | @@ -26043,13 +26652,13 @@ fn coerceExtra( |
| 26043 | }, | 26652 | }, |
| 26044 | else => {}, | 26653 | else => {}, |
| 26045 | }, | 26654 | }, |
| 26046 | .Array => switch (inst_ty.zigTypeTag()) { | 26655 | .Array => switch (inst_ty.zigTypeTag(mod)) { |
| 26047 | .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src), | 26656 | .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src), |
| 26048 | .Struct => { | 26657 | .Struct => { |
| 26049 | if (inst == .empty_struct) { | 26658 | if (inst == .empty_struct) { |
| 26050 | return sema.arrayInitEmpty(block, inst_src, dest_ty); | 26659 | return sema.arrayInitEmpty(block, inst_src, dest_ty); |
| 26051 | } | 26660 | } |
| 26052 | if (inst_ty.isTuple()) { | 26661 | if (inst_ty.isTuple(mod)) { |
| 26053 | return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src); | 26662 | return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src); |
| 26054 | } | 26663 | } |
| 26055 | }, | 26664 | }, |
| ... | @@ -26058,10 +26667,10 @@ fn coerceExtra( | ... | @@ -26058,10 +26667,10 @@ fn coerceExtra( |
| 26058 | }, | 26667 | }, |
| 26059 | else => {}, | 26668 | else => {}, |
| 26060 | }, | 26669 | }, |
| 26061 | .Vector => switch (inst_ty.zigTypeTag()) { | 26670 | .Vector => switch (inst_ty.zigTypeTag(mod)) { |
| 26062 | .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src), | 26671 | .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src), |
| 26063 | .Struct => { | 26672 | .Struct => { |
| 26064 | if (inst_ty.isTuple()) { | 26673 | if (inst_ty.isTuple(mod)) { |
| 26065 | return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src); | 26674 | return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src); |
| 26066 | } | 26675 | } |
| 26067 | }, | 26676 | }, |
| ... | @@ -26074,7 +26683,7 @@ fn coerceExtra( | ... | @@ -26074,7 +26683,7 @@ fn coerceExtra( |
| 26074 | if (inst == .empty_struct) { | 26683 | if (inst == .empty_struct) { |
| 26075 | return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src); | 26684 | return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src); |
| 26076 | } | 26685 | } |
| 26077 | if (inst_ty.isTupleOrAnonStruct()) { | 26686 | if (inst_ty.isTupleOrAnonStruct(mod)) { |
| 26078 | return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) { | 26687 | return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) { |
| 26079 | error.NotCoercible => break :blk, | 26688 | error.NotCoercible => break :blk, |
| 26080 | else => |e| return e, | 26689 | else => |e| return e, |
| ... | @@ -26093,35 +26702,34 @@ fn coerceExtra( | ... | @@ -26093,35 +26702,34 @@ fn coerceExtra( |
| 26093 | 26702 | ||
| 26094 | if (!opts.report_err) return error.NotCoercible; | 26703 | if (!opts.report_err) return error.NotCoercible; |
| 26095 | 26704 | ||
| 26096 | if (opts.is_ret and dest_ty.zigTypeTag() == .NoReturn) { | 26705 | if (opts.is_ret and dest_ty.zigTypeTag(mod) == .NoReturn) { |
| 26097 | const msg = msg: { | 26706 | const msg = msg: { |
| 26098 | const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{}); | 26707 | const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{}); |
| 26099 | errdefer msg.destroy(sema.gpa); | 26708 | errdefer msg.destroy(sema.gpa); |
| 26100 | 26709 | ||
| 26101 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; | 26710 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 26102 | const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); | 26711 | const src_decl = mod.declPtr(sema.func.?.owner_decl); |
| 26103 | try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "'noreturn' declared here", .{}); | 26712 | try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "'noreturn' declared here", .{}); |
| 26104 | break :msg msg; | 26713 | break :msg msg; |
| 26105 | }; | 26714 | }; |
| 26106 | return sema.failWithOwnedErrorMsg(msg); | 26715 | return sema.failWithOwnedErrorMsg(msg); |
| 26107 | } | 26716 | } |
| 26108 | 26717 | ||
| 26109 | const msg = msg: { | 26718 | const msg = msg: { |
| 26110 | const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) }); | 26719 | const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(mod), inst_ty.fmt(mod) }); |
| 26111 | errdefer msg.destroy(sema.gpa); | 26720 | errdefer msg.destroy(sema.gpa); |
| 26112 | 26721 | ||
| 26113 | // E!T to T | 26722 | // E!T to T |
| 26114 | if (inst_ty.zigTypeTag() == .ErrorUnion and | 26723 | if (inst_ty.zigTypeTag(mod) == .ErrorUnion and |
| 26115 | (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) | 26724 | (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) |
| 26116 | { | 26725 | { |
| 26117 | try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{}); | 26726 | try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{}); |
| 26118 | try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{}); | 26727 | try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{}); |
| 26119 | } | 26728 | } |
| 26120 | 26729 | ||
| 26121 | // ?T to T | 26730 | // ?T to T |
| 26122 | var buf: Type.Payload.ElemType = undefined; | 26731 | if (inst_ty.zigTypeTag(mod) == .Optional and |
| 26123 | if (inst_ty.zigTypeTag() == .Optional and | 26732 | (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) |
| 26124 | (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok) | ||
| 26125 | { | 26733 | { |
| 26126 | try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{}); | 26734 | try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{}); |
| 26127 | try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{}); | 26735 | try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{}); |
| ... | @@ -26130,18 +26738,18 @@ fn coerceExtra( | ... | @@ -26130,18 +26738,18 @@ fn coerceExtra( |
| 26130 | try in_memory_result.report(sema, block, inst_src, msg); | 26738 | try in_memory_result.report(sema, block, inst_src, msg); |
| 26131 | 26739 | ||
| 26132 | // Add notes about function return type | 26740 | // Add notes about function return type |
| 26133 | if (opts.is_ret and sema.mod.test_functions.get(sema.func.?.owner_decl) == null) { | 26741 | if (opts.is_ret and mod.test_functions.get(sema.func.?.owner_decl) == null) { |
| 26134 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; | 26742 | const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 }; |
| 26135 | const src_decl = sema.mod.declPtr(sema.func.?.owner_decl); | 26743 | const src_decl = mod.declPtr(sema.func.?.owner_decl); |
| 26136 | if (inst_ty.isError() and !dest_ty.isError()) { | 26744 | if (inst_ty.isError(mod) and !dest_ty.isError(mod)) { |
| 26137 | try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function cannot return an error", .{}); | 26745 | try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function cannot return an error", .{}); |
| 26138 | } else { | 26746 | } else { |
| 26139 | try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function return type declared here", .{}); | 26747 | try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function return type declared here", .{}); |
| 26140 | } | 26748 | } |
| 26141 | } | 26749 | } |
| 26142 | 26750 | ||
| 26143 | if (try opts.param_src.get(sema)) |param_src| { | 26751 | if (try opts.param_src.get(sema)) |param_src| { |
| 26144 | try sema.mod.errNoteNonLazy(param_src, msg, "parameter type declared here", .{}); | 26752 | try mod.errNoteNonLazy(param_src, msg, "parameter type declared here", .{}); |
| 26145 | } | 26753 | } |
| 26146 | 26754 | ||
| 26147 | // TODO maybe add "cannot store an error in type '{}'" note | 26755 | // TODO maybe add "cannot store an error in type '{}'" note |
| ... | @@ -26151,6 +26759,84 @@ fn coerceExtra( | ... | @@ -26151,6 +26759,84 @@ fn coerceExtra( |
| 26151 | return sema.failWithOwnedErrorMsg(msg); | 26759 | return sema.failWithOwnedErrorMsg(msg); |
| 26152 | } | 26760 | } |
| 26153 | 26761 | ||
| 26762 | fn coerceValueInMemory( | ||
| 26763 | sema: *Sema, | ||
| 26764 | block: *Block, | ||
| 26765 | val: Value, | ||
| 26766 | src_ty: Type, | ||
| 26767 | dst_ty: Type, | ||
| 26768 | dst_ty_src: LazySrcLoc, | ||
| 26769 | ) CompileError!Value { | ||
| 26770 | const mod = sema.mod; | ||
| 26771 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | ||
| 26772 | .aggregate => |aggregate| { | ||
| 26773 | const dst_ty_key = mod.intern_pool.indexToKey(dst_ty.toIntern()); | ||
| 26774 | const dest_len = try sema.usizeCast( | ||
| 26775 | block, | ||
| 26776 | dst_ty_src, | ||
| 26777 | mod.intern_pool.aggregateTypeLen(dst_ty.toIntern()), | ||
| 26778 | ); | ||
| 26779 | direct: { | ||
| 26780 | const src_ty_child = switch (mod.intern_pool.indexToKey(src_ty.toIntern())) { | ||
| 26781 | inline .array_type, .vector_type => |seq_type| seq_type.child, | ||
| 26782 | .anon_struct_type, .struct_type => break :direct, | ||
| 26783 | else => unreachable, | ||
| 26784 | }; | ||
| 26785 | const dst_ty_child = switch (dst_ty_key) { | ||
| 26786 | inline .array_type, .vector_type => |seq_type| seq_type.child, | ||
| 26787 | .anon_struct_type, .struct_type => break :direct, | ||
| 26788 | else => unreachable, | ||
| 26789 | }; | ||
| 26790 | if (src_ty_child != dst_ty_child) break :direct; | ||
| 26791 | // TODO: write something like getCoercedInts to avoid needing to dupe | ||
| 26792 | return (try mod.intern(.{ .aggregate = .{ | ||
| 26793 | .ty = dst_ty.toIntern(), | ||
| 26794 | .storage = switch (aggregate.storage) { | ||
| 26795 | .bytes => |bytes| .{ .bytes = try sema.arena.dupe(u8, bytes[0..dest_len]) }, | ||
| 26796 | .elems => |elems| .{ .elems = try sema.arena.dupe(InternPool.Index, elems[0..dest_len]) }, | ||
| 26797 | .repeated_elem => |elem| .{ .repeated_elem = elem }, | ||
| 26798 | }, | ||
| 26799 | } })).toValue(); | ||
| 26800 | } | ||
| 26801 | const dest_elems = try sema.arena.alloc(InternPool.Index, dest_len); | ||
| 26802 | for (dest_elems, 0..) |*dest_elem, i| { | ||
| 26803 | const elem_ty = switch (dst_ty_key) { | ||
| 26804 | inline .array_type, .vector_type => |seq_type| seq_type.child, | ||
| 26805 | .anon_struct_type => |anon_struct_type| anon_struct_type.types[i], | ||
| 26806 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).? | ||
| 26807 | .fields.values()[i].ty.toIntern(), | ||
| 26808 | else => unreachable, | ||
| 26809 | }; | ||
| 26810 | dest_elem.* = try mod.intern_pool.getCoerced(mod.gpa, switch (aggregate.storage) { | ||
| 26811 | .bytes => |bytes| (try mod.intValue(Type.u8, bytes[i])).toIntern(), | ||
| 26812 | .elems => |elems| elems[i], | ||
| 26813 | .repeated_elem => |elem| elem, | ||
| 26814 | }, elem_ty); | ||
| 26815 | } | ||
| 26816 | return (try mod.intern(.{ .aggregate = .{ | ||
| 26817 | .ty = dst_ty.toIntern(), | ||
| 26818 | .storage = .{ .elems = dest_elems }, | ||
| 26819 | } })).toValue(); | ||
| 26820 | }, | ||
| 26821 | .float => |float| (try mod.intern(.{ .float = .{ | ||
| 26822 | .ty = dst_ty.toIntern(), | ||
| 26823 | .storage = float.storage, | ||
| 26824 | } })).toValue(), | ||
| 26825 | else => try mod.getCoerced(val, dst_ty), | ||
| 26826 | }; | ||
| 26827 | } | ||
| 26828 | |||
| 26829 | fn coerceInMemory( | ||
| 26830 | sema: *Sema, | ||
| 26831 | block: *Block, | ||
| 26832 | val: Value, | ||
| 26833 | src_ty: Type, | ||
| 26834 | dst_ty: Type, | ||
| 26835 | dst_ty_src: LazySrcLoc, | ||
| 26836 | ) CompileError!Air.Inst.Ref { | ||
| 26837 | return sema.addConstant(dst_ty, try sema.coerceValueInMemory(block, val, src_ty, dst_ty, dst_ty_src)); | ||
| 26838 | } | ||
| 26839 | |||
| 26154 | const InMemoryCoercionResult = union(enum) { | 26840 | const InMemoryCoercionResult = union(enum) { |
| 26155 | ok, | 26841 | ok, |
| 26156 | no_match: Pair, | 26842 | no_match: Pair, |
| ... | @@ -26164,7 +26850,7 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26164,7 +26850,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26164 | optional_shape: Pair, | 26850 | optional_shape: Pair, |
| 26165 | optional_child: PairAndChild, | 26851 | optional_child: PairAndChild, |
| 26166 | from_anyerror, | 26852 | from_anyerror, |
| 26167 | missing_error: []const []const u8, | 26853 | missing_error: []const InternPool.NullTerminatedString, |
| 26168 | /// true if wanted is var args | 26854 | /// true if wanted is var args |
| 26169 | fn_var_args: bool, | 26855 | fn_var_args: bool, |
| 26170 | /// true if wanted is generic | 26856 | /// true if wanted is generic |
| ... | @@ -26264,6 +26950,7 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26264,6 +26950,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26264 | } | 26950 | } |
| 26265 | 26951 | ||
| 26266 | fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void { | 26952 | fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void { |
| 26953 | const mod = sema.mod; | ||
| 26267 | var cur = res; | 26954 | var cur = res; |
| 26268 | while (true) switch (cur.*) { | 26955 | while (true) switch (cur.*) { |
| 26269 | .ok => unreachable, | 26956 | .ok => unreachable, |
| ... | @@ -26280,7 +26967,7 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26280,7 +26967,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26280 | }, | 26967 | }, |
| 26281 | .error_union_payload => |pair| { | 26968 | .error_union_payload => |pair| { |
| 26282 | try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{ | 26969 | try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{ |
| 26283 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 26970 | pair.actual.fmt(mod), pair.wanted.fmt(mod), |
| 26284 | }); | 26971 | }); |
| 26285 | cur = pair.child; | 26972 | cur = pair.child; |
| 26286 | }, | 26973 | }, |
| ... | @@ -26291,20 +26978,20 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26291,20 +26978,20 @@ const InMemoryCoercionResult = union(enum) { |
| 26291 | break; | 26978 | break; |
| 26292 | }, | 26979 | }, |
| 26293 | .array_sentinel => |sentinel| { | 26980 | .array_sentinel => |sentinel| { |
| 26294 | if (sentinel.actual.tag() != .unreachable_value) { | 26981 | if (sentinel.actual.toIntern() != .unreachable_value) { |
| 26295 | try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ | 26982 | try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{ |
| 26296 | sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), | 26983 | sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod), |
| 26297 | }); | 26984 | }); |
| 26298 | } else { | 26985 | } else { |
| 26299 | try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{ | 26986 | try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{ |
| 26300 | sentinel.wanted.fmtValue(sentinel.ty, sema.mod), | 26987 | sentinel.wanted.fmtValue(sentinel.ty, mod), |
| 26301 | }); | 26988 | }); |
| 26302 | } | 26989 | } |
| 26303 | break; | 26990 | break; |
| 26304 | }, | 26991 | }, |
| 26305 | .array_elem => |pair| { | 26992 | .array_elem => |pair| { |
| 26306 | try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{ | 26993 | try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{ |
| 26307 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 26994 | pair.actual.fmt(mod), pair.wanted.fmt(mod), |
| 26308 | }); | 26995 | }); |
| 26309 | cur = pair.child; | 26996 | cur = pair.child; |
| 26310 | }, | 26997 | }, |
| ... | @@ -26316,21 +27003,19 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26316,21 +27003,19 @@ const InMemoryCoercionResult = union(enum) { |
| 26316 | }, | 27003 | }, |
| 26317 | .vector_elem => |pair| { | 27004 | .vector_elem => |pair| { |
| 26318 | try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{ | 27005 | try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{ |
| 26319 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 27006 | pair.actual.fmt(mod), pair.wanted.fmt(mod), |
| 26320 | }); | 27007 | }); |
| 26321 | cur = pair.child; | 27008 | cur = pair.child; |
| 26322 | }, | 27009 | }, |
| 26323 | .optional_shape => |pair| { | 27010 | .optional_shape => |pair| { |
| 26324 | var buf_actual: Type.Payload.ElemType = undefined; | ||
| 26325 | var buf_wanted: Type.Payload.ElemType = undefined; | ||
| 26326 | try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ | 27011 | try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ |
| 26327 | pair.actual.optionalChild(&buf_actual).fmt(sema.mod), pair.wanted.optionalChild(&buf_wanted).fmt(sema.mod), | 27012 | pair.actual.optionalChild(mod).fmt(mod), pair.wanted.optionalChild(mod).fmt(mod), |
| 26328 | }); | 27013 | }); |
| 26329 | break; | 27014 | break; |
| 26330 | }, | 27015 | }, |
| 26331 | .optional_child => |pair| { | 27016 | .optional_child => |pair| { |
| 26332 | try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ | 27017 | try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{ |
| 26333 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 27018 | pair.actual.fmt(mod), pair.wanted.fmt(mod), |
| 26334 | }); | 27019 | }); |
| 26335 | cur = pair.child; | 27020 | cur = pair.child; |
| 26336 | }, | 27021 | }, |
| ... | @@ -26340,7 +27025,7 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26340,7 +27025,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26340 | }, | 27025 | }, |
| 26341 | .missing_error => |missing_errors| { | 27026 | .missing_error => |missing_errors| { |
| 26342 | for (missing_errors) |err| { | 27027 | for (missing_errors) |err| { |
| 26343 | try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err}); | 27028 | try sema.errNote(block, src, msg, "'error.{}' not a member of destination error set", .{err.fmt(&mod.intern_pool)}); |
| 26344 | } | 27029 | } |
| 26345 | break; | 27030 | break; |
| 26346 | }, | 27031 | }, |
| ... | @@ -26394,7 +27079,7 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26394,7 +27079,7 @@ const InMemoryCoercionResult = union(enum) { |
| 26394 | }, | 27079 | }, |
| 26395 | .fn_param => |param| { | 27080 | .fn_param => |param| { |
| 26396 | try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{ | 27081 | try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{ |
| 26397 | param.index, param.actual.fmt(sema.mod), param.wanted.fmt(sema.mod), | 27082 | param.index, param.actual.fmt(mod), param.wanted.fmt(mod), |
| 26398 | }); | 27083 | }); |
| 26399 | cur = param.child; | 27084 | cur = param.child; |
| 26400 | }, | 27085 | }, |
| ... | @@ -26404,13 +27089,13 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26404,13 +27089,13 @@ const InMemoryCoercionResult = union(enum) { |
| 26404 | }, | 27089 | }, |
| 26405 | .fn_return_type => |pair| { | 27090 | .fn_return_type => |pair| { |
| 26406 | try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{ | 27091 | try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{ |
| 26407 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 27092 | pair.actual.fmt(mod), pair.wanted.fmt(mod), |
| 26408 | }); | 27093 | }); |
| 26409 | cur = pair.child; | 27094 | cur = pair.child; |
| 26410 | }, | 27095 | }, |
| 26411 | .ptr_child => |pair| { | 27096 | .ptr_child => |pair| { |
| 26412 | try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{ | 27097 | try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{ |
| 26413 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 27098 | pair.actual.fmt(mod), pair.wanted.fmt(mod), |
| 26414 | }); | 27099 | }); |
| 26415 | cur = pair.child; | 27100 | cur = pair.child; |
| 26416 | }, | 27101 | }, |
| ... | @@ -26419,13 +27104,13 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26419,13 +27104,13 @@ const InMemoryCoercionResult = union(enum) { |
| 26419 | break; | 27104 | break; |
| 26420 | }, | 27105 | }, |
| 26421 | .ptr_sentinel => |sentinel| { | 27106 | .ptr_sentinel => |sentinel| { |
| 26422 | if (sentinel.actual.tag() != .unreachable_value) { | 27107 | if (sentinel.actual.toIntern() != .unreachable_value) { |
| 26423 | try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ | 27108 | try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{ |
| 26424 | sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod), | 27109 | sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod), |
| 26425 | }); | 27110 | }); |
| 26426 | } else { | 27111 | } else { |
| 26427 | try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{ | 27112 | try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{ |
| 26428 | sentinel.wanted.fmtValue(sentinel.ty, sema.mod), | 27113 | sentinel.wanted.fmtValue(sentinel.ty, mod), |
| 26429 | }); | 27114 | }); |
| 26430 | } | 27115 | } |
| 26431 | break; | 27116 | break; |
| ... | @@ -26445,15 +27130,15 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26445,15 +27130,15 @@ const InMemoryCoercionResult = union(enum) { |
| 26445 | break; | 27130 | break; |
| 26446 | }, | 27131 | }, |
| 26447 | .ptr_allowzero => |pair| { | 27132 | .ptr_allowzero => |pair| { |
| 26448 | const wanted_allow_zero = pair.wanted.ptrAllowsZero(); | 27133 | const wanted_allow_zero = pair.wanted.ptrAllowsZero(mod); |
| 26449 | const actual_allow_zero = pair.actual.ptrAllowsZero(); | 27134 | const actual_allow_zero = pair.actual.ptrAllowsZero(mod); |
| 26450 | if (actual_allow_zero and !wanted_allow_zero) { | 27135 | if (actual_allow_zero and !wanted_allow_zero) { |
| 26451 | try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{ | 27136 | try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{ |
| 26452 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 27137 | pair.actual.fmt(mod), pair.wanted.fmt(mod), |
| 26453 | }); | 27138 | }); |
| 26454 | } else { | 27139 | } else { |
| 26455 | try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{ | 27140 | try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{ |
| 26456 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 27141 | pair.actual.fmt(mod), pair.wanted.fmt(mod), |
| 26457 | }); | 27142 | }); |
| 26458 | } | 27143 | } |
| 26459 | break; | 27144 | break; |
| ... | @@ -26479,13 +27164,13 @@ const InMemoryCoercionResult = union(enum) { | ... | @@ -26479,13 +27164,13 @@ const InMemoryCoercionResult = union(enum) { |
| 26479 | }, | 27164 | }, |
| 26480 | .double_ptr_to_anyopaque => |pair| { | 27165 | .double_ptr_to_anyopaque => |pair| { |
| 26481 | try sema.errNote(block, src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{ | 27166 | try sema.errNote(block, src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{ |
| 26482 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 27167 | pair.actual.fmt(mod), pair.wanted.fmt(mod), |
| 26483 | }); | 27168 | }); |
| 26484 | break; | 27169 | break; |
| 26485 | }, | 27170 | }, |
| 26486 | .slice_to_anyopaque => |pair| { | 27171 | .slice_to_anyopaque => |pair| { |
| 26487 | try sema.errNote(block, src, msg, "cannot implicitly cast slice '{}' to anyopaque pointer '{}'", .{ | 27172 | try sema.errNote(block, src, msg, "cannot implicitly cast slice '{}' to anyopaque pointer '{}'", .{ |
| 26488 | pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod), | 27173 | pair.actual.fmt(mod), pair.wanted.fmt(mod), |
| 26489 | }); | 27174 | }); |
| 26490 | try sema.errNote(block, src, msg, "consider using '.ptr'", .{}); | 27175 | try sema.errNote(block, src, msg, "consider using '.ptr'", .{}); |
| 26491 | break; | 27176 | break; |
| ... | @@ -26522,13 +27207,18 @@ fn coerceInMemoryAllowed( | ... | @@ -26522,13 +27207,18 @@ fn coerceInMemoryAllowed( |
| 26522 | dest_src: LazySrcLoc, | 27207 | dest_src: LazySrcLoc, |
| 26523 | src_src: LazySrcLoc, | 27208 | src_src: LazySrcLoc, |
| 26524 | ) CompileError!InMemoryCoercionResult { | 27209 | ) CompileError!InMemoryCoercionResult { |
| 26525 | if (dest_ty.eql(src_ty, sema.mod)) | 27210 | const mod = sema.mod; |
| 27211 | |||
| 27212 | if (dest_ty.eql(src_ty, mod)) | ||
| 26526 | return .ok; | 27213 | return .ok; |
| 26527 | 27214 | ||
| 27215 | const dest_tag = dest_ty.zigTypeTag(mod); | ||
| 27216 | const src_tag = src_ty.zigTypeTag(mod); | ||
| 27217 | |||
| 26528 | // Differently-named integers with the same number of bits. | 27218 | // Differently-named integers with the same number of bits. |
| 26529 | if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) { | 27219 | if (dest_tag == .Int and src_tag == .Int) { |
| 26530 | const dest_info = dest_ty.intInfo(target); | 27220 | const dest_info = dest_ty.intInfo(mod); |
| 26531 | const src_info = src_ty.intInfo(target); | 27221 | const src_info = src_ty.intInfo(mod); |
| 26532 | 27222 | ||
| 26533 | if (dest_info.signedness == src_info.signedness and | 27223 | if (dest_info.signedness == src_info.signedness and |
| 26534 | dest_info.bits == src_info.bits) | 27224 | dest_info.bits == src_info.bits) |
| ... | @@ -26551,7 +27241,7 @@ fn coerceInMemoryAllowed( | ... | @@ -26551,7 +27241,7 @@ fn coerceInMemoryAllowed( |
| 26551 | } | 27241 | } |
| 26552 | 27242 | ||
| 26553 | // Differently-named floats with the same number of bits. | 27243 | // Differently-named floats with the same number of bits. |
| 26554 | if (dest_ty.zigTypeTag() == .Float and src_ty.zigTypeTag() == .Float) { | 27244 | if (dest_tag == .Float and src_tag == .Float) { |
| 26555 | const dest_bits = dest_ty.floatBits(target); | 27245 | const dest_bits = dest_ty.floatBits(target); |
| 26556 | const src_bits = src_ty.floatBits(target); | 27246 | const src_bits = src_ty.floatBits(target); |
| 26557 | if (dest_bits == src_bits) { | 27247 | if (dest_bits == src_bits) { |
| ... | @@ -26560,10 +27250,8 @@ fn coerceInMemoryAllowed( | ... | @@ -26560,10 +27250,8 @@ fn coerceInMemoryAllowed( |
| 26560 | } | 27250 | } |
| 26561 | 27251 | ||
| 26562 | // Pointers / Pointer-like Optionals | 27252 | // Pointers / Pointer-like Optionals |
| 26563 | var dest_buf: Type.Payload.ElemType = undefined; | 27253 | const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(dest_ty); |
| 26564 | var src_buf: Type.Payload.ElemType = undefined; | 27254 | const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty); |
| 26565 | const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(dest_ty, &dest_buf); | ||
| 26566 | const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty, &src_buf); | ||
| 26567 | if (maybe_dest_ptr_ty) |dest_ptr_ty| { | 27255 | if (maybe_dest_ptr_ty) |dest_ptr_ty| { |
| 26568 | if (maybe_src_ptr_ty) |src_ptr_ty| { | 27256 | if (maybe_src_ptr_ty) |src_ptr_ty| { |
| 26569 | return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src); | 27257 | return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src); |
| ... | @@ -26571,13 +27259,10 @@ fn coerceInMemoryAllowed( | ... | @@ -26571,13 +27259,10 @@ fn coerceInMemoryAllowed( |
| 26571 | } | 27259 | } |
| 26572 | 27260 | ||
| 26573 | // Slices | 27261 | // Slices |
| 26574 | if (dest_ty.isSlice() and src_ty.isSlice()) { | 27262 | if (dest_ty.isSlice(mod) and src_ty.isSlice(mod)) { |
| 26575 | return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src); | 27263 | return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src); |
| 26576 | } | 27264 | } |
| 26577 | 27265 | ||
| 26578 | const dest_tag = dest_ty.zigTypeTag(); | ||
| 26579 | const src_tag = src_ty.zigTypeTag(); | ||
| 26580 | |||
| 26581 | // Functions | 27266 | // Functions |
| 26582 | if (dest_tag == .Fn and src_tag == .Fn) { | 27267 | if (dest_tag == .Fn and src_tag == .Fn) { |
| 26583 | return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src); | 27268 | return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src); |
| ... | @@ -26585,8 +27270,8 @@ fn coerceInMemoryAllowed( | ... | @@ -26585,8 +27270,8 @@ fn coerceInMemoryAllowed( |
| 26585 | 27270 | ||
| 26586 | // Error Unions | 27271 | // Error Unions |
| 26587 | if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { | 27272 | if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) { |
| 26588 | const dest_payload = dest_ty.errorUnionPayload(); | 27273 | const dest_payload = dest_ty.errorUnionPayload(mod); |
| 26589 | const src_payload = src_ty.errorUnionPayload(); | 27274 | const src_payload = src_ty.errorUnionPayload(mod); |
| 26590 | const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src); | 27275 | const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src); |
| 26591 | if (child != .ok) { | 27276 | if (child != .ok) { |
| 26592 | return InMemoryCoercionResult{ .error_union_payload = .{ | 27277 | return InMemoryCoercionResult{ .error_union_payload = .{ |
| ... | @@ -26595,7 +27280,7 @@ fn coerceInMemoryAllowed( | ... | @@ -26595,7 +27280,7 @@ fn coerceInMemoryAllowed( |
| 26595 | .wanted = dest_payload, | 27280 | .wanted = dest_payload, |
| 26596 | } }; | 27281 | } }; |
| 26597 | } | 27282 | } |
| 26598 | return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src); | 27283 | return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(mod), src_ty.errorUnionSet(mod), dest_is_mut, target, dest_src, src_src); |
| 26599 | } | 27284 | } |
| 26600 | 27285 | ||
| 26601 | // Error Sets | 27286 | // Error Sets |
| ... | @@ -26605,8 +27290,8 @@ fn coerceInMemoryAllowed( | ... | @@ -26605,8 +27290,8 @@ fn coerceInMemoryAllowed( |
| 26605 | 27290 | ||
| 26606 | // Arrays | 27291 | // Arrays |
| 26607 | if (dest_tag == .Array and src_tag == .Array) { | 27292 | if (dest_tag == .Array and src_tag == .Array) { |
| 26608 | const dest_info = dest_ty.arrayInfo(); | 27293 | const dest_info = dest_ty.arrayInfo(mod); |
| 26609 | const src_info = src_ty.arrayInfo(); | 27294 | const src_info = src_ty.arrayInfo(mod); |
| 26610 | if (dest_info.len != src_info.len) { | 27295 | if (dest_info.len != src_info.len) { |
| 26611 | return InMemoryCoercionResult{ .array_len = .{ | 27296 | return InMemoryCoercionResult{ .array_len = .{ |
| 26612 | .actual = src_info.len, | 27297 | .actual = src_info.len, |
| ... | @@ -26624,11 +27309,15 @@ fn coerceInMemoryAllowed( | ... | @@ -26624,11 +27309,15 @@ fn coerceInMemoryAllowed( |
| 26624 | } | 27309 | } |
| 26625 | const ok_sent = dest_info.sentinel == null or | 27310 | const ok_sent = dest_info.sentinel == null or |
| 26626 | (src_info.sentinel != null and | 27311 | (src_info.sentinel != null and |
| 26627 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod)); | 27312 | dest_info.sentinel.?.eql( |
| 27313 | try mod.getCoerced(src_info.sentinel.?, dest_info.elem_type), | ||
| 27314 | dest_info.elem_type, | ||
| 27315 | mod, | ||
| 27316 | )); | ||
| 26628 | if (!ok_sent) { | 27317 | if (!ok_sent) { |
| 26629 | return InMemoryCoercionResult{ .array_sentinel = .{ | 27318 | return InMemoryCoercionResult{ .array_sentinel = .{ |
| 26630 | .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), | 27319 | .actual = src_info.sentinel orelse Value.@"unreachable", |
| 26631 | .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), | 27320 | .wanted = dest_info.sentinel orelse Value.@"unreachable", |
| 26632 | .ty = dest_info.elem_type, | 27321 | .ty = dest_info.elem_type, |
| 26633 | } }; | 27322 | } }; |
| 26634 | } | 27323 | } |
| ... | @@ -26637,8 +27326,8 @@ fn coerceInMemoryAllowed( | ... | @@ -26637,8 +27326,8 @@ fn coerceInMemoryAllowed( |
| 26637 | 27326 | ||
| 26638 | // Vectors | 27327 | // Vectors |
| 26639 | if (dest_tag == .Vector and src_tag == .Vector) { | 27328 | if (dest_tag == .Vector and src_tag == .Vector) { |
| 26640 | const dest_len = dest_ty.vectorLen(); | 27329 | const dest_len = dest_ty.vectorLen(mod); |
| 26641 | const src_len = src_ty.vectorLen(); | 27330 | const src_len = src_ty.vectorLen(mod); |
| 26642 | if (dest_len != src_len) { | 27331 | if (dest_len != src_len) { |
| 26643 | return InMemoryCoercionResult{ .vector_len = .{ | 27332 | return InMemoryCoercionResult{ .vector_len = .{ |
| 26644 | .actual = src_len, | 27333 | .actual = src_len, |
| ... | @@ -26646,8 +27335,8 @@ fn coerceInMemoryAllowed( | ... | @@ -26646,8 +27335,8 @@ fn coerceInMemoryAllowed( |
| 26646 | } }; | 27335 | } }; |
| 26647 | } | 27336 | } |
| 26648 | 27337 | ||
| 26649 | const dest_elem_ty = dest_ty.scalarType(); | 27338 | const dest_elem_ty = dest_ty.scalarType(mod); |
| 26650 | const src_elem_ty = src_ty.scalarType(); | 27339 | const src_elem_ty = src_ty.scalarType(mod); |
| 26651 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src); | 27340 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src); |
| 26652 | if (child != .ok) { | 27341 | if (child != .ok) { |
| 26653 | return InMemoryCoercionResult{ .vector_elem = .{ | 27342 | return InMemoryCoercionResult{ .vector_elem = .{ |
| ... | @@ -26668,15 +27357,15 @@ fn coerceInMemoryAllowed( | ... | @@ -26668,15 +27357,15 @@ fn coerceInMemoryAllowed( |
| 26668 | .wanted = dest_ty, | 27357 | .wanted = dest_ty, |
| 26669 | } }; | 27358 | } }; |
| 26670 | } | 27359 | } |
| 26671 | const dest_child_type = dest_ty.optionalChild(&dest_buf); | 27360 | const dest_child_type = dest_ty.optionalChild(mod); |
| 26672 | const src_child_type = src_ty.optionalChild(&src_buf); | 27361 | const src_child_type = src_ty.optionalChild(mod); |
| 26673 | 27362 | ||
| 26674 | const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src); | 27363 | const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src); |
| 26675 | if (child != .ok) { | 27364 | if (child != .ok) { |
| 26676 | return InMemoryCoercionResult{ .optional_child = .{ | 27365 | return InMemoryCoercionResult{ .optional_child = .{ |
| 26677 | .child = try child.dupe(sema.arena), | 27366 | .child = try child.dupe(sema.arena), |
| 26678 | .actual = try src_child_type.copy(sema.arena), | 27367 | .actual = src_child_type, |
| 26679 | .wanted = try dest_child_type.copy(sema.arena), | 27368 | .wanted = dest_child_type, |
| 26680 | } }; | 27369 | } }; |
| 26681 | } | 27370 | } |
| 26682 | 27371 | ||
| ... | @@ -26697,138 +27386,108 @@ fn coerceInMemoryAllowedErrorSets( | ... | @@ -26697,138 +27386,108 @@ fn coerceInMemoryAllowedErrorSets( |
| 26697 | dest_src: LazySrcLoc, | 27386 | dest_src: LazySrcLoc, |
| 26698 | src_src: LazySrcLoc, | 27387 | src_src: LazySrcLoc, |
| 26699 | ) !InMemoryCoercionResult { | 27388 | ) !InMemoryCoercionResult { |
| 27389 | const mod = sema.mod; | ||
| 27390 | const gpa = sema.gpa; | ||
| 27391 | const ip = &mod.intern_pool; | ||
| 27392 | |||
| 26700 | // Coercion to `anyerror`. Note that this check can return false negatives | 27393 | // Coercion to `anyerror`. Note that this check can return false negatives |
| 26701 | // in case the error sets did not get resolved. | 27394 | // in case the error sets did not get resolved. |
| 26702 | if (dest_ty.isAnyError()) { | 27395 | if (dest_ty.isAnyError(mod)) { |
| 26703 | return .ok; | 27396 | return .ok; |
| 26704 | } | 27397 | } |
| 26705 | 27398 | ||
| 26706 | if (dest_ty.castTag(.error_set_inferred)) |dst_payload| { | 27399 | if (mod.typeToInferredErrorSetIndex(dest_ty).unwrap()) |dst_ies_index| { |
| 26707 | const dst_ies = dst_payload.data; | 27400 | const dst_ies = mod.inferredErrorSetPtr(dst_ies_index); |
| 26708 | // We will make an effort to return `ok` without resolving either error set, to | 27401 | // We will make an effort to return `ok` without resolving either error set, to |
| 26709 | // avoid unnecessary "unable to resolve error set" dependency loop errors. | 27402 | // avoid unnecessary "unable to resolve error set" dependency loop errors. |
| 26710 | switch (src_ty.tag()) { | 27403 | switch (src_ty.toIntern()) { |
| 26711 | .error_set_inferred => { | 27404 | .anyerror_type => {}, |
| 26712 | // If both are inferred error sets of functions, and | 27405 | else => switch (ip.indexToKey(src_ty.toIntern())) { |
| 26713 | // the dest includes the source function, the coercion is OK. | 27406 | .inferred_error_set_type => |src_index| { |
| 26714 | // This check is important because it works without forcing a full resolution | 27407 | // If both are inferred error sets of functions, and |
| 26715 | // of inferred error sets. | 27408 | // the dest includes the source function, the coercion is OK. |
| 26716 | const src_ies = src_ty.castTag(.error_set_inferred).?.data; | 27409 | // This check is important because it works without forcing a full resolution |
| 26717 | 27410 | // of inferred error sets. | |
| 26718 | if (dst_ies.inferred_error_sets.contains(src_ies)) { | 27411 | if (dst_ies.inferred_error_sets.contains(src_index)) { |
| 26719 | return .ok; | 27412 | return .ok; |
| 26720 | } | 27413 | } |
| 26721 | }, | 27414 | }, |
| 26722 | .error_set_single => { | 27415 | .error_set_type => |error_set_type| { |
| 26723 | const name = src_ty.castTag(.error_set_single).?.data; | 27416 | for (error_set_type.names) |name| { |
| 26724 | if (dst_ies.errors.contains(name)) return .ok; | 27417 | if (!dst_ies.errors.contains(name)) break; |
| 26725 | }, | 27418 | } else return .ok; |
| 26726 | .error_set_merged => { | 27419 | }, |
| 26727 | const names = src_ty.castTag(.error_set_merged).?.data.keys(); | 27420 | else => unreachable, |
| 26728 | for (names) |name| { | 27421 | }, |
| 26729 | if (!dst_ies.errors.contains(name)) break; | ||
| 26730 | } else return .ok; | ||
| 26731 | }, | ||
| 26732 | .error_set => { | ||
| 26733 | const names = src_ty.castTag(.error_set).?.data.names.keys(); | ||
| 26734 | for (names) |name| { | ||
| 26735 | if (!dst_ies.errors.contains(name)) break; | ||
| 26736 | } else return .ok; | ||
| 26737 | }, | ||
| 26738 | .anyerror => {}, | ||
| 26739 | else => unreachable, | ||
| 26740 | } | 27422 | } |
| 26741 | 27423 | ||
| 26742 | if (dst_ies.func == sema.owner_func) { | 27424 | if (dst_ies.func == sema.owner_func_index.unwrap()) { |
| 26743 | // We are trying to coerce an error set to the current function's | 27425 | // We are trying to coerce an error set to the current function's |
| 26744 | // inferred error set. | 27426 | // inferred error set. |
| 26745 | try dst_ies.addErrorSet(sema.gpa, src_ty); | 27427 | try dst_ies.addErrorSet(src_ty, ip, gpa); |
| 26746 | return .ok; | 27428 | return .ok; |
| 26747 | } | 27429 | } |
| 26748 | 27430 | ||
| 26749 | try sema.resolveInferredErrorSet(block, dest_src, dst_payload.data); | 27431 | try sema.resolveInferredErrorSet(block, dest_src, dst_ies_index); |
| 26750 | // isAnyError might have changed from a false negative to a true positive after resolution. | 27432 | // isAnyError might have changed from a false negative to a true positive after resolution. |
| 26751 | if (dest_ty.isAnyError()) { | 27433 | if (dest_ty.isAnyError(mod)) { |
| 26752 | return .ok; | 27434 | return .ok; |
| 26753 | } | 27435 | } |
| 26754 | } | 27436 | } |
| 26755 | 27437 | ||
| 26756 | var missing_error_buf = std.ArrayList([]const u8).init(sema.gpa); | 27438 | var missing_error_buf = std.ArrayList(InternPool.NullTerminatedString).init(gpa); |
| 26757 | defer missing_error_buf.deinit(); | 27439 | defer missing_error_buf.deinit(); |
| 26758 | 27440 | ||
| 26759 | switch (src_ty.tag()) { | 27441 | switch (src_ty.toIntern()) { |
| 26760 | .error_set_inferred => { | 27442 | .anyerror_type => switch (ip.indexToKey(dest_ty.toIntern())) { |
| 26761 | const src_data = src_ty.castTag(.error_set_inferred).?.data; | 27443 | .inferred_error_set_type => unreachable, // Caught by dest_ty.isAnyError(mod) above. |
| 27444 | .simple_type => unreachable, // filtered out above | ||
| 27445 | .error_set_type => return .from_anyerror, | ||
| 27446 | else => unreachable, | ||
| 27447 | }, | ||
| 27448 | |||
| 27449 | else => switch (ip.indexToKey(src_ty.toIntern())) { | ||
| 27450 | .inferred_error_set_type => |src_index| { | ||
| 27451 | const src_data = mod.inferredErrorSetPtr(src_index); | ||
| 26762 | 27452 | ||
| 26763 | try sema.resolveInferredErrorSet(block, src_src, src_data); | 27453 | try sema.resolveInferredErrorSet(block, src_src, src_index); |
| 26764 | // src anyerror status might have changed after the resolution. | 27454 | // src anyerror status might have changed after the resolution. |
| 26765 | if (src_ty.isAnyError()) { | 27455 | if (src_ty.isAnyError(mod)) { |
| 26766 | // dest_ty.isAnyError() == true is already checked for at this point. | 27456 | // dest_ty.isAnyError(mod) == true is already checked for at this point. |
| 26767 | return .from_anyerror; | 27457 | return .from_anyerror; |
| 26768 | } | 27458 | } |
| 26769 | 27459 | ||
| 26770 | for (src_data.errors.keys()) |key| { | 27460 | for (src_data.errors.keys()) |key| { |
| 26771 | if (!dest_ty.errorSetHasField(key)) { | 27461 | if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), key)) { |
| 26772 | try missing_error_buf.append(key); | 27462 | try missing_error_buf.append(key); |
| 27463 | } | ||
| 26773 | } | 27464 | } |
| 26774 | } | ||
| 26775 | 27465 | ||
| 26776 | if (missing_error_buf.items.len != 0) { | 27466 | if (missing_error_buf.items.len != 0) { |
| 26777 | return InMemoryCoercionResult{ | 27467 | return InMemoryCoercionResult{ |
| 26778 | .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), | 27468 | .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items), |
| 26779 | }; | 27469 | }; |
| 26780 | } | 27470 | } |
| 26781 | 27471 | ||
| 26782 | return .ok; | ||
| 26783 | }, | ||
| 26784 | .error_set_single => { | ||
| 26785 | const name = src_ty.castTag(.error_set_single).?.data; | ||
| 26786 | if (dest_ty.errorSetHasField(name)) { | ||
| 26787 | return .ok; | 27472 | return .ok; |
| 26788 | } | 27473 | }, |
| 26789 | const list = try sema.arena.alloc([]const u8, 1); | 27474 | .error_set_type => |error_set_type| { |
| 26790 | list[0] = name; | 27475 | for (error_set_type.names) |name| { |
| 26791 | return InMemoryCoercionResult{ .missing_error = list }; | 27476 | if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), name)) { |
| 26792 | }, | 27477 | try missing_error_buf.append(name); |
| 26793 | .error_set_merged => { | 27478 | } |
| 26794 | const names = src_ty.castTag(.error_set_merged).?.data.keys(); | ||
| 26795 | for (names) |name| { | ||
| 26796 | if (!dest_ty.errorSetHasField(name)) { | ||
| 26797 | try missing_error_buf.append(name); | ||
| 26798 | } | 27479 | } |
| 26799 | } | ||
| 26800 | |||
| 26801 | if (missing_error_buf.items.len != 0) { | ||
| 26802 | return InMemoryCoercionResult{ | ||
| 26803 | .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), | ||
| 26804 | }; | ||
| 26805 | } | ||
| 26806 | 27480 | ||
| 26807 | return .ok; | 27481 | if (missing_error_buf.items.len != 0) { |
| 26808 | }, | 27482 | return InMemoryCoercionResult{ |
| 26809 | .error_set => { | 27483 | .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items), |
| 26810 | const names = src_ty.castTag(.error_set).?.data.names.keys(); | 27484 | }; |
| 26811 | for (names) |name| { | ||
| 26812 | if (!dest_ty.errorSetHasField(name)) { | ||
| 26813 | try missing_error_buf.append(name); | ||
| 26814 | } | 27485 | } |
| 26815 | } | ||
| 26816 | 27486 | ||
| 26817 | if (missing_error_buf.items.len != 0) { | 27487 | return .ok; |
| 26818 | return InMemoryCoercionResult{ | 27488 | }, |
| 26819 | .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items), | ||
| 26820 | }; | ||
| 26821 | } | ||
| 26822 | |||
| 26823 | return .ok; | ||
| 26824 | }, | ||
| 26825 | .anyerror => switch (dest_ty.tag()) { | ||
| 26826 | .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above. | ||
| 26827 | .error_set_single, .error_set_merged, .error_set => return .from_anyerror, | ||
| 26828 | .anyerror => unreachable, // Filtered out above. | ||
| 26829 | else => unreachable, | 27489 | else => unreachable, |
| 26830 | }, | 27490 | }, |
| 26831 | else => unreachable, | ||
| 26832 | } | 27491 | } |
| 26833 | 27492 | ||
| 26834 | unreachable; | 27493 | unreachable; |
| ... | @@ -26843,69 +27502,95 @@ fn coerceInMemoryAllowedFns( | ... | @@ -26843,69 +27502,95 @@ fn coerceInMemoryAllowedFns( |
| 26843 | dest_src: LazySrcLoc, | 27502 | dest_src: LazySrcLoc, |
| 26844 | src_src: LazySrcLoc, | 27503 | src_src: LazySrcLoc, |
| 26845 | ) !InMemoryCoercionResult { | 27504 | ) !InMemoryCoercionResult { |
| 26846 | const dest_info = dest_ty.fnInfo(); | 27505 | const mod = sema.mod; |
| 26847 | const src_info = src_ty.fnInfo(); | ||
| 26848 | 27506 | ||
| 26849 | if (dest_info.is_var_args != src_info.is_var_args) { | 27507 | { |
| 26850 | return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args }; | 27508 | const dest_info = mod.typeToFunc(dest_ty).?; |
| 26851 | } | 27509 | const src_info = mod.typeToFunc(src_ty).?; |
| 26852 | 27510 | ||
| 26853 | if (dest_info.is_generic != src_info.is_generic) { | 27511 | if (dest_info.is_var_args != src_info.is_var_args) { |
| 26854 | return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; | 27512 | return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args }; |
| 26855 | } | 27513 | } |
| 26856 | 27514 | ||
| 26857 | if (dest_info.cc != src_info.cc) { | 27515 | if (dest_info.is_generic != src_info.is_generic) { |
| 26858 | return InMemoryCoercionResult{ .fn_cc = .{ | 27516 | return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; |
| 26859 | .actual = src_info.cc, | 27517 | } |
| 26860 | .wanted = dest_info.cc, | ||
| 26861 | } }; | ||
| 26862 | } | ||
| 26863 | 27518 | ||
| 26864 | if (!src_info.return_type.isNoReturn()) { | 27519 | if (dest_info.cc != src_info.cc) { |
| 26865 | const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src); | 27520 | return InMemoryCoercionResult{ .fn_cc = .{ |
| 26866 | if (rt != .ok) { | 27521 | .actual = src_info.cc, |
| 26867 | return InMemoryCoercionResult{ .fn_return_type = .{ | 27522 | .wanted = dest_info.cc, |
| 26868 | .child = try rt.dupe(sema.arena), | ||
| 26869 | .actual = src_info.return_type, | ||
| 26870 | .wanted = dest_info.return_type, | ||
| 26871 | } }; | 27523 | } }; |
| 26872 | } | 27524 | } |
| 26873 | } | ||
| 26874 | 27525 | ||
| 26875 | if (dest_info.param_types.len != src_info.param_types.len) { | 27526 | switch (src_info.return_type) { |
| 26876 | return InMemoryCoercionResult{ .fn_param_count = .{ | 27527 | .noreturn_type, .generic_poison_type => {}, |
| 26877 | .actual = src_info.param_types.len, | 27528 | else => { |
| 26878 | .wanted = dest_info.param_types.len, | 27529 | const dest_return_type = dest_info.return_type.toType(); |
| 26879 | } }; | 27530 | const src_return_type = src_info.return_type.toType(); |
| 27531 | const rt = try sema.coerceInMemoryAllowed(block, dest_return_type, src_return_type, false, target, dest_src, src_src); | ||
| 27532 | if (rt != .ok) { | ||
| 27533 | return InMemoryCoercionResult{ .fn_return_type = .{ | ||
| 27534 | .child = try rt.dupe(sema.arena), | ||
| 27535 | .actual = src_return_type, | ||
| 27536 | .wanted = dest_return_type, | ||
| 27537 | } }; | ||
| 27538 | } | ||
| 27539 | }, | ||
| 27540 | } | ||
| 26880 | } | 27541 | } |
| 26881 | 27542 | ||
| 26882 | if (dest_info.noalias_bits != src_info.noalias_bits) { | 27543 | const params_len = params_len: { |
| 26883 | return InMemoryCoercionResult{ .fn_param_noalias = .{ | 27544 | const dest_info = mod.typeToFunc(dest_ty).?; |
| 26884 | .actual = src_info.noalias_bits, | 27545 | const src_info = mod.typeToFunc(src_ty).?; |
| 26885 | .wanted = dest_info.noalias_bits, | ||
| 26886 | } }; | ||
| 26887 | } | ||
| 26888 | 27546 | ||
| 26889 | for (dest_info.param_types, 0..) |dest_param_ty, i| { | 27547 | if (dest_info.param_types.len != src_info.param_types.len) { |
| 26890 | const src_param_ty = src_info.param_types[i]; | 27548 | return InMemoryCoercionResult{ .fn_param_count = .{ |
| 27549 | .actual = src_info.param_types.len, | ||
| 27550 | .wanted = dest_info.param_types.len, | ||
| 27551 | } }; | ||
| 27552 | } | ||
| 26891 | 27553 | ||
| 26892 | if (dest_info.comptime_params[i] != src_info.comptime_params[i]) { | 27554 | if (dest_info.noalias_bits != src_info.noalias_bits) { |
| 26893 | return InMemoryCoercionResult{ .fn_param_comptime = .{ | 27555 | return InMemoryCoercionResult{ .fn_param_noalias = .{ |
| 26894 | .index = i, | 27556 | .actual = src_info.noalias_bits, |
| 26895 | .wanted = dest_info.comptime_params[i], | 27557 | .wanted = dest_info.noalias_bits, |
| 26896 | } }; | 27558 | } }; |
| 26897 | } | 27559 | } |
| 26898 | 27560 | ||
| 26899 | // Note: Cast direction is reversed here. | 27561 | break :params_len dest_info.param_types.len; |
| 26900 | const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src); | 27562 | }; |
| 26901 | if (param != .ok) { | 27563 | |
| 26902 | return InMemoryCoercionResult{ .fn_param = .{ | 27564 | for (0..params_len) |param_i| { |
| 26903 | .child = try param.dupe(sema.arena), | 27565 | const dest_info = mod.typeToFunc(dest_ty).?; |
| 26904 | .actual = src_param_ty, | 27566 | const src_info = mod.typeToFunc(src_ty).?; |
| 26905 | .wanted = dest_param_ty, | 27567 | |
| 26906 | .index = i, | 27568 | const dest_param_ty = dest_info.param_types[param_i].toType(); |
| 27569 | const src_param_ty = src_info.param_types[param_i].toType(); | ||
| 27570 | |||
| 27571 | const param_i_small = @intCast(u5, param_i); | ||
| 27572 | if (dest_info.paramIsComptime(param_i_small) != src_info.paramIsComptime(param_i_small)) { | ||
| 27573 | return InMemoryCoercionResult{ .fn_param_comptime = .{ | ||
| 27574 | .index = param_i, | ||
| 27575 | .wanted = dest_info.paramIsComptime(param_i_small), | ||
| 26907 | } }; | 27576 | } }; |
| 26908 | } | 27577 | } |
| 27578 | |||
| 27579 | switch (src_param_ty.toIntern()) { | ||
| 27580 | .generic_poison_type => {}, | ||
| 27581 | else => { | ||
| 27582 | // Note: Cast direction is reversed here. | ||
| 27583 | const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src); | ||
| 27584 | if (param != .ok) { | ||
| 27585 | return InMemoryCoercionResult{ .fn_param = .{ | ||
| 27586 | .child = try param.dupe(sema.arena), | ||
| 27587 | .actual = src_param_ty, | ||
| 27588 | .wanted = dest_param_ty, | ||
| 27589 | .index = param_i, | ||
| 27590 | } }; | ||
| 27591 | } | ||
| 27592 | }, | ||
| 27593 | } | ||
| 26909 | } | 27594 | } |
| 26910 | 27595 | ||
| 26911 | return .ok; | 27596 | return .ok; |
| ... | @@ -26923,8 +27608,9 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -26923,8 +27608,9 @@ fn coerceInMemoryAllowedPtrs( |
| 26923 | dest_src: LazySrcLoc, | 27608 | dest_src: LazySrcLoc, |
| 26924 | src_src: LazySrcLoc, | 27609 | src_src: LazySrcLoc, |
| 26925 | ) !InMemoryCoercionResult { | 27610 | ) !InMemoryCoercionResult { |
| 26926 | const dest_info = dest_ptr_ty.ptrInfo().data; | 27611 | const mod = sema.mod; |
| 26927 | const src_info = src_ptr_ty.ptrInfo().data; | 27612 | const dest_info = dest_ptr_ty.ptrInfo(mod); |
| 27613 | const src_info = src_ptr_ty.ptrInfo(mod); | ||
| 26928 | 27614 | ||
| 26929 | const ok_ptr_size = src_info.size == dest_info.size or | 27615 | const ok_ptr_size = src_info.size == dest_info.size or |
| 26930 | src_info.size == .C or dest_info.size == .C; | 27616 | src_info.size == .C or dest_info.size == .C; |
| ... | @@ -26964,8 +27650,8 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -26964,8 +27650,8 @@ fn coerceInMemoryAllowedPtrs( |
| 26964 | } }; | 27650 | } }; |
| 26965 | } | 27651 | } |
| 26966 | 27652 | ||
| 26967 | const dest_allow_zero = dest_ty.ptrAllowsZero(); | 27653 | const dest_allow_zero = dest_ty.ptrAllowsZero(mod); |
| 26968 | const src_allow_zero = src_ty.ptrAllowsZero(); | 27654 | const src_allow_zero = src_ty.ptrAllowsZero(mod); |
| 26969 | 27655 | ||
| 26970 | const ok_allows_zero = (dest_allow_zero and | 27656 | const ok_allows_zero = (dest_allow_zero and |
| 26971 | (src_allow_zero or !dest_is_mut)) or | 27657 | (src_allow_zero or !dest_is_mut)) or |
| ... | @@ -26989,12 +27675,15 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -26989,12 +27675,15 @@ fn coerceInMemoryAllowedPtrs( |
| 26989 | } | 27675 | } |
| 26990 | 27676 | ||
| 26991 | const ok_sent = dest_info.sentinel == null or src_info.size == .C or | 27677 | const ok_sent = dest_info.sentinel == null or src_info.size == .C or |
| 26992 | (src_info.sentinel != null and | 27678 | (src_info.sentinel != null and dest_info.sentinel.?.eql( |
| 26993 | dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod)); | 27679 | try mod.getCoerced(src_info.sentinel.?, dest_info.pointee_type), |
| 27680 | dest_info.pointee_type, | ||
| 27681 | sema.mod, | ||
| 27682 | )); | ||
| 26994 | if (!ok_sent) { | 27683 | if (!ok_sent) { |
| 26995 | return InMemoryCoercionResult{ .ptr_sentinel = .{ | 27684 | return InMemoryCoercionResult{ .ptr_sentinel = .{ |
| 26996 | .actual = src_info.sentinel orelse Value.initTag(.unreachable_value), | 27685 | .actual = src_info.sentinel orelse Value.@"unreachable", |
| 26997 | .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value), | 27686 | .wanted = dest_info.sentinel orelse Value.@"unreachable", |
| 26998 | .ty = dest_info.pointee_type, | 27687 | .ty = dest_info.pointee_type, |
| 26999 | } }; | 27688 | } }; |
| 27000 | } | 27689 | } |
| ... | @@ -27013,12 +27702,12 @@ fn coerceInMemoryAllowedPtrs( | ... | @@ -27013,12 +27702,12 @@ fn coerceInMemoryAllowedPtrs( |
| 27013 | const src_align = if (src_info.@"align" != 0) | 27702 | const src_align = if (src_info.@"align" != 0) |
| 27014 | src_info.@"align" | 27703 | src_info.@"align" |
| 27015 | else | 27704 | else |
| 27016 | src_info.pointee_type.abiAlignment(target); | 27705 | src_info.pointee_type.abiAlignment(mod); |
| 27017 | 27706 | ||
| 27018 | const dest_align = if (dest_info.@"align" != 0) | 27707 | const dest_align = if (dest_info.@"align" != 0) |
| 27019 | dest_info.@"align" | 27708 | dest_info.@"align" |
| 27020 | else | 27709 | else |
| 27021 | dest_info.pointee_type.abiAlignment(target); | 27710 | dest_info.pointee_type.abiAlignment(mod); |
| 27022 | 27711 | ||
| 27023 | if (dest_align > src_align) { | 27712 | if (dest_align > src_align) { |
| 27024 | return InMemoryCoercionResult{ .ptr_alignment = .{ | 27713 | return InMemoryCoercionResult{ .ptr_alignment = .{ |
| ... | @@ -27041,8 +27730,9 @@ fn coerceVarArgParam( | ... | @@ -27041,8 +27730,9 @@ fn coerceVarArgParam( |
| 27041 | ) !Air.Inst.Ref { | 27730 | ) !Air.Inst.Ref { |
| 27042 | if (block.is_typeof) return inst; | 27731 | if (block.is_typeof) return inst; |
| 27043 | 27732 | ||
| 27733 | const mod = sema.mod; | ||
| 27044 | const uncasted_ty = sema.typeOf(inst); | 27734 | const uncasted_ty = sema.typeOf(inst); |
| 27045 | const coerced = switch (uncasted_ty.zigTypeTag()) { | 27735 | const coerced = switch (uncasted_ty.zigTypeTag(mod)) { |
| 27046 | // TODO consider casting to c_int/f64 if they fit | 27736 | // TODO consider casting to c_int/f64 if they fit |
| 27047 | .ComptimeInt, .ComptimeFloat => return sema.fail( | 27737 | .ComptimeInt, .ComptimeFloat => return sema.fail( |
| 27048 | block, | 27738 | block, |
| ... | @@ -27052,7 +27742,7 @@ fn coerceVarArgParam( | ... | @@ -27052,7 +27742,7 @@ fn coerceVarArgParam( |
| 27052 | ), | 27742 | ), |
| 27053 | .Fn => blk: { | 27743 | .Fn => blk: { |
| 27054 | const fn_val = try sema.resolveConstValue(block, .unneeded, inst, ""); | 27744 | const fn_val = try sema.resolveConstValue(block, .unneeded, inst, ""); |
| 27055 | const fn_decl = fn_val.pointerDecl().?; | 27745 | const fn_decl = fn_val.pointerDecl(mod).?; |
| 27056 | break :blk try sema.analyzeDeclRef(fn_decl); | 27746 | break :blk try sema.analyzeDeclRef(fn_decl); |
| 27057 | }, | 27747 | }, |
| 27058 | .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), | 27748 | .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), |
| ... | @@ -27077,7 +27767,7 @@ fn coerceVarArgParam( | ... | @@ -27077,7 +27767,7 @@ fn coerceVarArgParam( |
| 27077 | errdefer msg.destroy(sema.gpa); | 27767 | errdefer msg.destroy(sema.gpa); |
| 27078 | 27768 | ||
| 27079 | const src_decl = sema.mod.declPtr(block.src_decl); | 27769 | const src_decl = sema.mod.declPtr(block.src_decl); |
| 27080 | try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .param_ty); | 27770 | try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl, mod), coerced_ty, .param_ty); |
| 27081 | 27771 | ||
| 27082 | try sema.addDeclaredHereNote(msg, coerced_ty); | 27772 | try sema.addDeclaredHereNote(msg, coerced_ty); |
| 27083 | break :msg msg; | 27773 | break :msg msg; |
| ... | @@ -27109,11 +27799,12 @@ fn storePtr2( | ... | @@ -27109,11 +27799,12 @@ fn storePtr2( |
| 27109 | operand_src: LazySrcLoc, | 27799 | operand_src: LazySrcLoc, |
| 27110 | air_tag: Air.Inst.Tag, | 27800 | air_tag: Air.Inst.Tag, |
| 27111 | ) CompileError!void { | 27801 | ) CompileError!void { |
| 27802 | const mod = sema.mod; | ||
| 27112 | const ptr_ty = sema.typeOf(ptr); | 27803 | const ptr_ty = sema.typeOf(ptr); |
| 27113 | if (ptr_ty.isConstPtr()) | 27804 | if (ptr_ty.isConstPtr(mod)) |
| 27114 | return sema.fail(block, ptr_src, "cannot assign to constant", .{}); | 27805 | return sema.fail(block, ptr_src, "cannot assign to constant", .{}); |
| 27115 | 27806 | ||
| 27116 | const elem_ty = ptr_ty.childType(); | 27807 | const elem_ty = ptr_ty.childType(mod); |
| 27117 | 27808 | ||
| 27118 | // To generate better code for tuples, we detect a tuple operand here, and | 27809 | // To generate better code for tuples, we detect a tuple operand here, and |
| 27119 | // analyze field loads and stores directly. This avoids an extra allocation + memcpy | 27810 | // analyze field loads and stores directly. This avoids an extra allocation + memcpy |
| ... | @@ -27124,8 +27815,8 @@ fn storePtr2( | ... | @@ -27124,8 +27815,8 @@ fn storePtr2( |
| 27124 | // this code does not handle tuple-to-struct coercion which requires dealing with missing | 27815 | // this code does not handle tuple-to-struct coercion which requires dealing with missing |
| 27125 | // fields. | 27816 | // fields. |
| 27126 | const operand_ty = sema.typeOf(uncasted_operand); | 27817 | const operand_ty = sema.typeOf(uncasted_operand); |
| 27127 | if (operand_ty.isTuple() and elem_ty.zigTypeTag() == .Array) { | 27818 | if (operand_ty.isTuple(mod) and elem_ty.zigTypeTag(mod) == .Array) { |
| 27128 | const field_count = operand_ty.structFieldCount(); | 27819 | const field_count = operand_ty.structFieldCount(mod); |
| 27129 | var i: u32 = 0; | 27820 | var i: u32 = 0; |
| 27130 | while (i < field_count) : (i += 1) { | 27821 | while (i < field_count) : (i += 1) { |
| 27131 | const elem_src = operand_src; // TODO better source location | 27822 | const elem_src = operand_src; // TODO better source location |
| ... | @@ -27149,7 +27840,7 @@ fn storePtr2( | ... | @@ -27149,7 +27840,7 @@ fn storePtr2( |
| 27149 | // as well as working around an LLVM bug: | 27840 | // as well as working around an LLVM bug: |
| 27150 | // https://github.com/ziglang/zig/issues/11154 | 27841 | // https://github.com/ziglang/zig/issues/11154 |
| 27151 | if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { | 27842 | if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| { |
| 27152 | const vector_ty = sema.typeOf(vector_ptr).childType(); | 27843 | const vector_ty = sema.typeOf(vector_ptr).childType(mod); |
| 27153 | const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { | 27844 | const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) { |
| 27154 | error.NotCoercible => unreachable, | 27845 | error.NotCoercible => unreachable, |
| 27155 | else => |e| return e, | 27846 | else => |e| return e, |
| ... | @@ -27169,7 +27860,7 @@ fn storePtr2( | ... | @@ -27169,7 +27860,7 @@ fn storePtr2( |
| 27169 | try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); | 27860 | try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); |
| 27170 | break :rs operand_src; | 27861 | break :rs operand_src; |
| 27171 | }; | 27862 | }; |
| 27172 | if (ptr_val.isComptimeMutablePtr()) { | 27863 | if (ptr_val.isComptimeMutablePtr(mod)) { |
| 27173 | try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty); | 27864 | try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty); |
| 27174 | return; | 27865 | return; |
| 27175 | } else break :rs ptr_src; | 27866 | } else break :rs ptr_src; |
| ... | @@ -27190,7 +27881,7 @@ fn storePtr2( | ... | @@ -27190,7 +27881,7 @@ fn storePtr2( |
| 27190 | try sema.requireRuntimeBlock(block, src, runtime_src); | 27881 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 27191 | try sema.queueFullTypeResolution(elem_ty); | 27882 | try sema.queueFullTypeResolution(elem_ty); |
| 27192 | 27883 | ||
| 27193 | if (ptr_ty.ptrInfo().data.vector_index == .runtime) { | 27884 | if (ptr_ty.ptrInfo(mod).vector_index == .runtime) { |
| 27194 | const ptr_inst = Air.refToIndex(ptr).?; | 27885 | const ptr_inst = Air.refToIndex(ptr).?; |
| 27195 | const air_tags = sema.air_instructions.items(.tag); | 27886 | const air_tags = sema.air_instructions.items(.tag); |
| 27196 | if (air_tags[ptr_inst] == .ptr_elem_ptr) { | 27887 | if (air_tags[ptr_inst] == .ptr_elem_ptr) { |
| ... | @@ -27224,30 +27915,27 @@ fn storePtr2( | ... | @@ -27224,30 +27915,27 @@ fn storePtr2( |
| 27224 | /// pointer. Only if the final element type matches the vector element type, and the | 27915 | /// pointer. Only if the final element type matches the vector element type, and the |
| 27225 | /// lengths match. | 27916 | /// lengths match. |
| 27226 | fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref { | 27917 | fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref { |
| 27227 | const array_ty = sema.typeOf(ptr).childType(); | 27918 | const mod = sema.mod; |
| 27228 | if (array_ty.zigTypeTag() != .Array) return null; | 27919 | const array_ty = sema.typeOf(ptr).childType(mod); |
| 27229 | var ptr_inst = Air.refToIndex(ptr) orelse return null; | 27920 | if (array_ty.zigTypeTag(mod) != .Array) return null; |
| 27921 | var ptr_ref = ptr; | ||
| 27922 | var ptr_inst = Air.refToIndex(ptr_ref) orelse return null; | ||
| 27230 | const air_datas = sema.air_instructions.items(.data); | 27923 | const air_datas = sema.air_instructions.items(.data); |
| 27231 | const air_tags = sema.air_instructions.items(.tag); | 27924 | const air_tags = sema.air_instructions.items(.tag); |
| 27232 | const prev_ptr = while (air_tags[ptr_inst] == .bitcast) { | 27925 | const vector_ty = while (air_tags[ptr_inst] == .bitcast) { |
| 27233 | const prev_ptr = air_datas[ptr_inst].ty_op.operand; | 27926 | ptr_ref = air_datas[ptr_inst].ty_op.operand; |
| 27234 | const prev_ptr_ty = sema.typeOf(prev_ptr); | 27927 | if (!sema.isKnownZigType(ptr_ref, .Pointer)) return null; |
| 27235 | const prev_ptr_child_ty = switch (prev_ptr_ty.tag()) { | 27928 | const child_ty = sema.typeOf(ptr_ref).childType(mod); |
| 27236 | .single_mut_pointer => prev_ptr_ty.castTag(.single_mut_pointer).?.data, | 27929 | if (child_ty.zigTypeTag(mod) == .Vector) break child_ty; |
| 27237 | .pointer => prev_ptr_ty.castTag(.pointer).?.data.pointee_type, | 27930 | ptr_inst = Air.refToIndex(ptr_ref) orelse return null; |
| 27238 | else => return null, | ||
| 27239 | }; | ||
| 27240 | if (prev_ptr_child_ty.zigTypeTag() == .Vector) break prev_ptr; | ||
| 27241 | ptr_inst = Air.refToIndex(prev_ptr) orelse return null; | ||
| 27242 | } else return null; | 27931 | } else return null; |
| 27243 | 27932 | ||
| 27244 | // We have a pointer-to-array and a pointer-to-vector. If the elements and | 27933 | // We have a pointer-to-array and a pointer-to-vector. If the elements and |
| 27245 | // lengths match, return the result. | 27934 | // lengths match, return the result. |
| 27246 | const vector_ty = sema.typeOf(prev_ptr).childType(); | 27935 | if (array_ty.childType(mod).eql(vector_ty.childType(mod), sema.mod) and |
| 27247 | if (array_ty.childType().eql(vector_ty.childType(), sema.mod) and | 27936 | array_ty.arrayLen(mod) == vector_ty.vectorLen(mod)) |
| 27248 | array_ty.arrayLen() == vector_ty.vectorLen()) | ||
| 27249 | { | 27937 | { |
| 27250 | return prev_ptr; | 27938 | return ptr_ref; |
| 27251 | } else { | 27939 | } else { |
| 27252 | return null; | 27940 | return null; |
| 27253 | } | 27941 | } |
| ... | @@ -27263,54 +27951,55 @@ fn storePtrVal( | ... | @@ -27263,54 +27951,55 @@ fn storePtrVal( |
| 27263 | operand_val: Value, | 27951 | operand_val: Value, |
| 27264 | operand_ty: Type, | 27952 | operand_ty: Type, |
| 27265 | ) !void { | 27953 | ) !void { |
| 27954 | const mod = sema.mod; | ||
| 27266 | var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty); | 27955 | var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty); |
| 27267 | try sema.checkComptimeVarStore(block, src, mut_kit.decl_ref_mut); | 27956 | try sema.checkComptimeVarStore(block, src, mut_kit.mut_decl); |
| 27268 | 27957 | ||
| 27269 | switch (mut_kit.pointee) { | 27958 | switch (mut_kit.pointee) { |
| 27270 | .direct => |val_ptr| { | 27959 | .direct => |val_ptr| { |
| 27271 | if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) { | 27960 | if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) { |
| 27272 | if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) { | 27961 | if (!operand_val.eql(val_ptr.*, operand_ty, mod)) { |
| 27273 | // TODO use failWithInvalidComptimeFieldStore | 27962 | // TODO use failWithInvalidComptimeFieldStore |
| 27274 | return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); | 27963 | return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{}); |
| 27275 | } | 27964 | } |
| 27276 | return; | 27965 | return; |
| 27277 | } | 27966 | } |
| 27278 | const arena = mut_kit.beginArena(sema.mod); | 27967 | val_ptr.* = (try operand_val.intern(operand_ty, mod)).toValue(); |
| 27279 | defer mut_kit.finishArena(sema.mod); | ||
| 27280 | |||
| 27281 | val_ptr.* = try operand_val.copy(arena); | ||
| 27282 | }, | 27968 | }, |
| 27283 | .reinterpret => |reinterpret| { | 27969 | .reinterpret => |reinterpret| { |
| 27284 | const target = sema.mod.getTarget(); | 27970 | const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod)); |
| 27285 | const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(target)); | ||
| 27286 | const buffer = try sema.gpa.alloc(u8, abi_size); | 27971 | const buffer = try sema.gpa.alloc(u8, abi_size); |
| 27287 | defer sema.gpa.free(buffer); | 27972 | defer sema.gpa.free(buffer); |
| 27288 | reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer) catch |err| switch (err) { | 27973 | reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) { |
| 27974 | error.OutOfMemory => return error.OutOfMemory, | ||
| 27289 | error.ReinterpretDeclRef => unreachable, | 27975 | error.ReinterpretDeclRef => unreachable, |
| 27290 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already | 27976 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already |
| 27291 | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(sema.mod)}), | 27977 | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}), |
| 27292 | }; | 27978 | }; |
| 27293 | operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) { | 27979 | operand_val.writeToMemory(operand_ty, mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) { |
| 27980 | error.OutOfMemory => return error.OutOfMemory, | ||
| 27294 | error.ReinterpretDeclRef => unreachable, | 27981 | error.ReinterpretDeclRef => unreachable, |
| 27295 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already | 27982 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already |
| 27296 | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(sema.mod)}), | 27983 | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}), |
| 27297 | }; | 27984 | }; |
| 27298 | 27985 | ||
| 27299 | const arena = mut_kit.beginArena(sema.mod); | 27986 | reinterpret.val_ptr.* = (try (try Value.readFromMemory(mut_kit.ty, mod, buffer, sema.arena)).intern(mut_kit.ty, mod)).toValue(); |
| 27300 | defer mut_kit.finishArena(sema.mod); | ||
| 27301 | |||
| 27302 | reinterpret.val_ptr.* = try Value.readFromMemory(mut_kit.ty, sema.mod, buffer, arena); | ||
| 27303 | }, | 27987 | }, |
| 27304 | .bad_decl_ty, .bad_ptr_ty => { | 27988 | .bad_decl_ty, .bad_ptr_ty => { |
| 27305 | // TODO show the decl declaration site in a note and explain whether the decl | 27989 | // TODO show the decl declaration site in a note and explain whether the decl |
| 27306 | // or the pointer is the problematic type | 27990 | // or the pointer is the problematic type |
| 27307 | return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(sema.mod)}); | 27991 | return sema.fail( |
| 27992 | block, | ||
| 27993 | src, | ||
| 27994 | "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", | ||
| 27995 | .{mut_kit.ty.fmt(mod)}, | ||
| 27996 | ); | ||
| 27308 | }, | 27997 | }, |
| 27309 | } | 27998 | } |
| 27310 | } | 27999 | } |
| 27311 | 28000 | ||
| 27312 | const ComptimePtrMutationKit = struct { | 28001 | const ComptimePtrMutationKit = struct { |
| 27313 | decl_ref_mut: Value.Payload.DeclRefMut.Data, | 28002 | mut_decl: InternPool.Key.Ptr.Addr.MutDecl, |
| 27314 | pointee: union(enum) { | 28003 | pointee: union(enum) { |
| 27315 | /// The pointer type matches the actual comptime Value so a direct | 28004 | /// The pointer type matches the actual comptime Value so a direct |
| 27316 | /// modification is possible. | 28005 | /// modification is possible. |
| ... | @@ -27333,18 +28022,6 @@ const ComptimePtrMutationKit = struct { | ... | @@ -27333,18 +28022,6 @@ const ComptimePtrMutationKit = struct { |
| 27333 | bad_ptr_ty, | 28022 | bad_ptr_ty, |
| 27334 | }, | 28023 | }, |
| 27335 | ty: Type, | 28024 | ty: Type, |
| 27336 | decl_arena: std.heap.ArenaAllocator = undefined, | ||
| 27337 | |||
| 27338 | fn beginArena(self: *ComptimePtrMutationKit, mod: *Module) Allocator { | ||
| 27339 | const decl = mod.declPtr(self.decl_ref_mut.decl_index); | ||
| 27340 | return decl.value_arena.?.acquire(mod.gpa, &self.decl_arena); | ||
| 27341 | } | ||
| 27342 | |||
| 27343 | fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void { | ||
| 27344 | const decl = mod.declPtr(self.decl_ref_mut.decl_index); | ||
| 27345 | decl.value_arena.?.release(&self.decl_arena); | ||
| 27346 | self.decl_arena = undefined; | ||
| 27347 | } | ||
| 27348 | }; | 28025 | }; |
| 27349 | 28026 | ||
| 27350 | fn beginComptimePtrMutation( | 28027 | fn beginComptimePtrMutation( |
| ... | @@ -27354,201 +28031,251 @@ fn beginComptimePtrMutation( | ... | @@ -27354,201 +28031,251 @@ fn beginComptimePtrMutation( |
| 27354 | ptr_val: Value, | 28031 | ptr_val: Value, |
| 27355 | ptr_elem_ty: Type, | 28032 | ptr_elem_ty: Type, |
| 27356 | ) CompileError!ComptimePtrMutationKit { | 28033 | ) CompileError!ComptimePtrMutationKit { |
| 27357 | const target = sema.mod.getTarget(); | 28034 | const mod = sema.mod; |
| 27358 | switch (ptr_val.tag()) { | 28035 | const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr; |
| 27359 | .decl_ref_mut => { | 28036 | switch (ptr.addr) { |
| 27360 | const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data; | 28037 | .decl, .int => unreachable, // isComptimeMutablePtr has been checked already |
| 27361 | const decl = sema.mod.declPtr(decl_ref_mut.decl_index); | 28038 | .mut_decl => |mut_decl| { |
| 27362 | return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, decl_ref_mut); | 28039 | const decl = mod.declPtr(mut_decl.decl); |
| 27363 | }, | 28040 | return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl); |
| 27364 | .comptime_field_ptr => { | 28041 | }, |
| 27365 | const payload = ptr_val.castTag(.comptime_field_ptr).?.data; | 28042 | .comptime_field => |comptime_field| { |
| 27366 | const duped = try sema.arena.create(Value); | 28043 | const duped = try sema.arena.create(Value); |
| 27367 | duped.* = payload.field_val; | 28044 | duped.* = comptime_field.toValue(); |
| 27368 | return sema.beginComptimePtrMutationInner(block, src, payload.field_ty, duped, ptr_elem_ty, .{ | 28045 | return sema.beginComptimePtrMutationInner(block, src, mod.intern_pool.typeOf(comptime_field).toType(), duped, ptr_elem_ty, .{ |
| 27369 | .decl_index = @intToEnum(Module.Decl.Index, 0), | 28046 | .decl = undefined, |
| 27370 | .runtime_index = .comptime_field_ptr, | 28047 | .runtime_index = .comptime_field_ptr, |
| 27371 | }); | 28048 | }); |
| 27372 | }, | 28049 | }, |
| 27373 | .elem_ptr => { | 28050 | .eu_payload => |eu_ptr| { |
| 27374 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | 28051 | const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); |
| 27375 | var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.array_ptr, elem_ptr.elem_ty); | 28052 | var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.toValue(), eu_ty); |
| 28053 | switch (parent.pointee) { | ||
| 28054 | .direct => |val_ptr| { | ||
| 28055 | const payload_ty = parent.ty.errorUnionPayload(mod); | ||
| 28056 | if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) { | ||
| 28057 | return ComptimePtrMutationKit{ | ||
| 28058 | .mut_decl = parent.mut_decl, | ||
| 28059 | .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, | ||
| 28060 | .ty = payload_ty, | ||
| 28061 | }; | ||
| 28062 | } else { | ||
| 28063 | // An error union has been initialized to undefined at comptime and now we | ||
| 28064 | // are for the first time setting the payload. We must change the | ||
| 28065 | // representation of the error union from `undef` to `opt_payload`. | ||
| 28066 | |||
| 28067 | const payload = try sema.arena.create(Value.Payload.SubValue); | ||
| 28068 | payload.* = .{ | ||
| 28069 | .base = .{ .tag = .eu_payload }, | ||
| 28070 | .data = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(), | ||
| 28071 | }; | ||
| 28072 | |||
| 28073 | val_ptr.* = Value.initPayload(&payload.base); | ||
| 28074 | |||
| 28075 | return ComptimePtrMutationKit{ | ||
| 28076 | .mut_decl = parent.mut_decl, | ||
| 28077 | .pointee = .{ .direct = &payload.data }, | ||
| 28078 | .ty = payload_ty, | ||
| 28079 | }; | ||
| 28080 | } | ||
| 28081 | }, | ||
| 28082 | .bad_decl_ty, .bad_ptr_ty => return parent, | ||
| 28083 | // Even though the parent value type has well-defined memory layout, our | ||
| 28084 | // pointer type does not. | ||
| 28085 | .reinterpret => return ComptimePtrMutationKit{ | ||
| 28086 | .mut_decl = parent.mut_decl, | ||
| 28087 | .pointee = .bad_ptr_ty, | ||
| 28088 | .ty = eu_ty, | ||
| 28089 | }, | ||
| 28090 | } | ||
| 28091 | }, | ||
| 28092 | .opt_payload => |opt_ptr| { | ||
| 28093 | const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod); | ||
| 28094 | var parent = try sema.beginComptimePtrMutation(block, src, opt_ptr.toValue(), opt_ty); | ||
| 28095 | switch (parent.pointee) { | ||
| 28096 | .direct => |val_ptr| { | ||
| 28097 | const payload_ty = parent.ty.optionalChild(mod); | ||
| 28098 | switch (val_ptr.ip_index) { | ||
| 28099 | .none => return ComptimePtrMutationKit{ | ||
| 28100 | .mut_decl = parent.mut_decl, | ||
| 28101 | .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, | ||
| 28102 | .ty = payload_ty, | ||
| 28103 | }, | ||
| 28104 | else => { | ||
| 28105 | const payload_val = switch (mod.intern_pool.indexToKey(val_ptr.ip_index)) { | ||
| 28106 | .undef => try mod.intern(.{ .undef = payload_ty.toIntern() }), | ||
| 28107 | .opt => |opt| switch (opt.val) { | ||
| 28108 | .none => try mod.intern(.{ .undef = payload_ty.toIntern() }), | ||
| 28109 | else => |payload| payload, | ||
| 28110 | }, | ||
| 28111 | else => unreachable, | ||
| 28112 | }; | ||
| 28113 | |||
| 28114 | // An optional has been initialized to undefined at comptime and now we | ||
| 28115 | // are for the first time setting the payload. We must change the | ||
| 28116 | // representation of the optional from `undef` to `opt_payload`. | ||
| 28117 | |||
| 28118 | const payload = try sema.arena.create(Value.Payload.SubValue); | ||
| 28119 | payload.* = .{ | ||
| 28120 | .base = .{ .tag = .opt_payload }, | ||
| 28121 | .data = payload_val.toValue(), | ||
| 28122 | }; | ||
| 28123 | |||
| 28124 | val_ptr.* = Value.initPayload(&payload.base); | ||
| 28125 | |||
| 28126 | return ComptimePtrMutationKit{ | ||
| 28127 | .mut_decl = parent.mut_decl, | ||
| 28128 | .pointee = .{ .direct = &payload.data }, | ||
| 28129 | .ty = payload_ty, | ||
| 28130 | }; | ||
| 28131 | }, | ||
| 28132 | } | ||
| 28133 | }, | ||
| 28134 | .bad_decl_ty, .bad_ptr_ty => return parent, | ||
| 28135 | // Even though the parent value type has well-defined memory layout, our | ||
| 28136 | // pointer type does not. | ||
| 28137 | .reinterpret => return ComptimePtrMutationKit{ | ||
| 28138 | .mut_decl = parent.mut_decl, | ||
| 28139 | .pointee = .bad_ptr_ty, | ||
| 28140 | .ty = opt_ty, | ||
| 28141 | }, | ||
| 28142 | } | ||
| 28143 | }, | ||
| 28144 | .elem => |elem_ptr| { | ||
| 28145 | const base_elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod); | ||
| 28146 | var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.base.toValue(), base_elem_ty); | ||
| 27376 | 28147 | ||
| 27377 | switch (parent.pointee) { | 28148 | switch (parent.pointee) { |
| 27378 | .direct => |val_ptr| switch (parent.ty.zigTypeTag()) { | 28149 | .direct => |val_ptr| switch (parent.ty.zigTypeTag(mod)) { |
| 27379 | .Array, .Vector => { | 28150 | .Array, .Vector => { |
| 27380 | const check_len = parent.ty.arrayLenIncludingSentinel(); | 28151 | const check_len = parent.ty.arrayLenIncludingSentinel(mod); |
| 27381 | if (elem_ptr.index >= check_len) { | 28152 | if (elem_ptr.index >= check_len) { |
| 27382 | // TODO have the parent include the decl so we can say "declared here" | 28153 | // TODO have the parent include the decl so we can say "declared here" |
| 27383 | return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{ | 28154 | return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{ |
| 27384 | elem_ptr.index, check_len, | 28155 | elem_ptr.index, check_len, |
| 27385 | }); | 28156 | }); |
| 27386 | } | 28157 | } |
| 27387 | const elem_ty = parent.ty.childType(); | 28158 | const elem_ty = parent.ty.childType(mod); |
| 27388 | 28159 | ||
| 27389 | // We might have a pointer to multiple elements of the array (e.g. a pointer | 28160 | // We might have a pointer to multiple elements of the array (e.g. a pointer |
| 27390 | // to a sub-array). In this case, we just have to reinterpret the relevant | 28161 | // to a sub-array). In this case, we just have to reinterpret the relevant |
| 27391 | // bytes of the whole array rather than any single element. | 28162 | // bytes of the whole array rather than any single element. |
| 27392 | const elem_abi_size_u64 = try sema.typeAbiSize(elem_ptr.elem_ty); | 28163 | const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty); |
| 27393 | if (elem_abi_size_u64 < try sema.typeAbiSize(ptr_elem_ty)) { | 28164 | if (elem_abi_size_u64 < try sema.typeAbiSize(ptr_elem_ty)) { |
| 27394 | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); | 28165 | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); |
| 28166 | const elem_idx = try sema.usizeCast(block, src, elem_ptr.index); | ||
| 27395 | return .{ | 28167 | return .{ |
| 27396 | .decl_ref_mut = parent.decl_ref_mut, | 28168 | .mut_decl = parent.mut_decl, |
| 27397 | .pointee = .{ .reinterpret = .{ | 28169 | .pointee = .{ .reinterpret = .{ |
| 27398 | .val_ptr = val_ptr, | 28170 | .val_ptr = val_ptr, |
| 27399 | .byte_offset = elem_abi_size * elem_ptr.index, | 28171 | .byte_offset = elem_abi_size * elem_idx, |
| 27400 | } }, | 28172 | } }, |
| 27401 | .ty = parent.ty, | 28173 | .ty = parent.ty, |
| 27402 | }; | 28174 | }; |
| 27403 | } | 28175 | } |
| 27404 | 28176 | ||
| 27405 | switch (val_ptr.tag()) { | 28177 | switch (val_ptr.ip_index) { |
| 27406 | .undef => { | 28178 | .none => switch (val_ptr.tag()) { |
| 27407 | // An array has been initialized to undefined at comptime and now we | 28179 | .bytes => { |
| 27408 | // are for the first time setting an element. We must change the representation | 28180 | // An array is memory-optimized to store a slice of bytes, but we are about |
| 27409 | // of the array from `undef` to `array`. | 28181 | // to modify an individual field and the representation has to change. |
| 27410 | const arena = parent.beginArena(sema.mod); | 28182 | // If we wanted to avoid this, there would need to be special detection |
| 27411 | defer parent.finishArena(sema.mod); | 28183 | // elsewhere to identify when writing a value to an array element that is stored |
| 28184 | // using the `bytes` tag, and handle it without making a call to this function. | ||
| 28185 | const arena = sema.arena; | ||
| 28186 | |||
| 28187 | const bytes = val_ptr.castTag(.bytes).?.data; | ||
| 28188 | const dest_len = parent.ty.arrayLenIncludingSentinel(mod); | ||
| 28189 | // bytes.len may be one greater than dest_len because of the case when | ||
| 28190 | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. | ||
| 28191 | assert(bytes.len >= dest_len); | ||
| 28192 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); | ||
| 28193 | for (elems, 0..) |*elem, i| { | ||
| 28194 | elem.* = try mod.intValue(elem_ty, bytes[i]); | ||
| 28195 | } | ||
| 27412 | 28196 | ||
| 27413 | const array_len_including_sentinel = | 28197 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 27414 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); | ||
| 27415 | const elems = try arena.alloc(Value, array_len_including_sentinel); | ||
| 27416 | @memset(elems, Value.undef); | ||
| 27417 | 28198 | ||
| 27418 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | 28199 | return beginComptimePtrMutationInner( |
| 28200 | sema, | ||
| 28201 | block, | ||
| 28202 | src, | ||
| 28203 | elem_ty, | ||
| 28204 | &elems[@intCast(usize, elem_ptr.index)], | ||
| 28205 | ptr_elem_ty, | ||
| 28206 | parent.mut_decl, | ||
| 28207 | ); | ||
| 28208 | }, | ||
| 28209 | .repeated => { | ||
| 28210 | // An array is memory-optimized to store only a single element value, and | ||
| 28211 | // that value is understood to be the same for the entire length of the array. | ||
| 28212 | // However, now we want to modify an individual field and so the | ||
| 28213 | // representation has to change. If we wanted to avoid this, there would | ||
| 28214 | // need to be special detection elsewhere to identify when writing a value to an | ||
| 28215 | // array element that is stored using the `repeated` tag, and handle it | ||
| 28216 | // without making a call to this function. | ||
| 28217 | const arena = sema.arena; | ||
| 28218 | |||
| 28219 | const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena); | ||
| 28220 | const array_len_including_sentinel = | ||
| 28221 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); | ||
| 28222 | const elems = try arena.alloc(Value, array_len_including_sentinel); | ||
| 28223 | if (elems.len > 0) elems[0] = repeated_val; | ||
| 28224 | for (elems[1..]) |*elem| { | ||
| 28225 | elem.* = try repeated_val.copy(arena); | ||
| 28226 | } | ||
| 27419 | 28227 | ||
| 27420 | return beginComptimePtrMutationInner( | 28228 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 27421 | sema, | ||
| 27422 | block, | ||
| 27423 | src, | ||
| 27424 | elem_ty, | ||
| 27425 | &elems[elem_ptr.index], | ||
| 27426 | ptr_elem_ty, | ||
| 27427 | parent.decl_ref_mut, | ||
| 27428 | ); | ||
| 27429 | }, | ||
| 27430 | .bytes => { | ||
| 27431 | // An array is memory-optimized to store a slice of bytes, but we are about | ||
| 27432 | // to modify an individual field and the representation has to change. | ||
| 27433 | // If we wanted to avoid this, there would need to be special detection | ||
| 27434 | // elsewhere to identify when writing a value to an array element that is stored | ||
| 27435 | // using the `bytes` tag, and handle it without making a call to this function. | ||
| 27436 | const arena = parent.beginArena(sema.mod); | ||
| 27437 | defer parent.finishArena(sema.mod); | ||
| 27438 | |||
| 27439 | const bytes = val_ptr.castTag(.bytes).?.data; | ||
| 27440 | const dest_len = parent.ty.arrayLenIncludingSentinel(); | ||
| 27441 | // bytes.len may be one greater than dest_len because of the case when | ||
| 27442 | // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted. | ||
| 27443 | assert(bytes.len >= dest_len); | ||
| 27444 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); | ||
| 27445 | for (elems, 0..) |*elem, i| { | ||
| 27446 | elem.* = try Value.Tag.int_u64.create(arena, bytes[i]); | ||
| 27447 | } | ||
| 27448 | 28229 | ||
| 27449 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | 28230 | return beginComptimePtrMutationInner( |
| 28231 | sema, | ||
| 28232 | block, | ||
| 28233 | src, | ||
| 28234 | elem_ty, | ||
| 28235 | &elems[@intCast(usize, elem_ptr.index)], | ||
| 28236 | ptr_elem_ty, | ||
| 28237 | parent.mut_decl, | ||
| 28238 | ); | ||
| 28239 | }, | ||
| 27450 | 28240 | ||
| 27451 | return beginComptimePtrMutationInner( | 28241 | .aggregate => return beginComptimePtrMutationInner( |
| 27452 | sema, | 28242 | sema, |
| 27453 | block, | 28243 | block, |
| 27454 | src, | 28244 | src, |
| 27455 | elem_ty, | 28245 | elem_ty, |
| 27456 | &elems[elem_ptr.index], | 28246 | &val_ptr.castTag(.aggregate).?.data[@intCast(usize, elem_ptr.index)], |
| 27457 | ptr_elem_ty, | 28247 | ptr_elem_ty, |
| 27458 | parent.decl_ref_mut, | 28248 | parent.mut_decl, |
| 27459 | ); | 28249 | ), |
| 27460 | }, | ||
| 27461 | .str_lit => { | ||
| 27462 | // An array is memory-optimized to store a slice of bytes, but we are about | ||
| 27463 | // to modify an individual field and the representation has to change. | ||
| 27464 | // If we wanted to avoid this, there would need to be special detection | ||
| 27465 | // elsewhere to identify when writing a value to an array element that is stored | ||
| 27466 | // using the `str_lit` tag, and handle it without making a call to this function. | ||
| 27467 | const arena = parent.beginArena(sema.mod); | ||
| 27468 | defer parent.finishArena(sema.mod); | ||
| 27469 | |||
| 27470 | const str_lit = val_ptr.castTag(.str_lit).?.data; | ||
| 27471 | const dest_len = parent.ty.arrayLenIncludingSentinel(); | ||
| 27472 | const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | ||
| 27473 | const elems = try arena.alloc(Value, @intCast(usize, dest_len)); | ||
| 27474 | for (bytes, 0..) |byte, i| { | ||
| 27475 | elems[i] = try Value.Tag.int_u64.create(arena, byte); | ||
| 27476 | } | ||
| 27477 | if (parent.ty.sentinel()) |sent_val| { | ||
| 27478 | assert(elems.len == bytes.len + 1); | ||
| 27479 | elems[bytes.len] = sent_val; | ||
| 27480 | } | ||
| 27481 | |||
| 27482 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | ||
| 27483 | 28250 | ||
| 27484 | return beginComptimePtrMutationInner( | 28251 | else => unreachable, |
| 27485 | sema, | ||
| 27486 | block, | ||
| 27487 | src, | ||
| 27488 | elem_ty, | ||
| 27489 | &elems[elem_ptr.index], | ||
| 27490 | ptr_elem_ty, | ||
| 27491 | parent.decl_ref_mut, | ||
| 27492 | ); | ||
| 27493 | }, | 28252 | }, |
| 27494 | .repeated => { | 28253 | else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) { |
| 27495 | // An array is memory-optimized to store only a single element value, and | 28254 | .undef => { |
| 27496 | // that value is understood to be the same for the entire length of the array. | 28255 | // An array has been initialized to undefined at comptime and now we |
| 27497 | // However, now we want to modify an individual field and so the | 28256 | // are for the first time setting an element. We must change the representation |
| 27498 | // representation has to change. If we wanted to avoid this, there would | 28257 | // of the array from `undef` to `array`. |
| 27499 | // need to be special detection elsewhere to identify when writing a value to an | 28258 | const arena = sema.arena; |
| 27500 | // array element that is stored using the `repeated` tag, and handle it | ||
| 27501 | // without making a call to this function. | ||
| 27502 | const arena = parent.beginArena(sema.mod); | ||
| 27503 | defer parent.finishArena(sema.mod); | ||
| 27504 | |||
| 27505 | const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena); | ||
| 27506 | const array_len_including_sentinel = | ||
| 27507 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel()); | ||
| 27508 | const elems = try arena.alloc(Value, array_len_including_sentinel); | ||
| 27509 | if (elems.len > 0) elems[0] = repeated_val; | ||
| 27510 | for (elems[1..]) |*elem| { | ||
| 27511 | elem.* = try repeated_val.copy(arena); | ||
| 27512 | } | ||
| 27513 | 28259 | ||
| 27514 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); | 28260 | const array_len_including_sentinel = |
| 28261 | try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); | ||
| 28262 | const elems = try arena.alloc(Value, array_len_including_sentinel); | ||
| 28263 | @memset(elems, (try mod.intern(.{ .undef = elem_ty.toIntern() })).toValue()); | ||
| 27515 | 28264 | ||
| 27516 | return beginComptimePtrMutationInner( | 28265 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 27517 | sema, | ||
| 27518 | block, | ||
| 27519 | src, | ||
| 27520 | elem_ty, | ||
| 27521 | &elems[elem_ptr.index], | ||
| 27522 | ptr_elem_ty, | ||
| 27523 | parent.decl_ref_mut, | ||
| 27524 | ); | ||
| 27525 | }, | ||
| 27526 | 28266 | ||
| 27527 | .aggregate => return beginComptimePtrMutationInner( | 28267 | return beginComptimePtrMutationInner( |
| 27528 | sema, | 28268 | sema, |
| 27529 | block, | 28269 | block, |
| 27530 | src, | 28270 | src, |
| 27531 | elem_ty, | 28271 | elem_ty, |
| 27532 | &val_ptr.castTag(.aggregate).?.data[elem_ptr.index], | 28272 | &elems[@intCast(usize, elem_ptr.index)], |
| 27533 | ptr_elem_ty, | 28273 | ptr_elem_ty, |
| 27534 | parent.decl_ref_mut, | 28274 | parent.mut_decl, |
| 27535 | ), | 28275 | ); |
| 27536 | 28276 | }, | |
| 27537 | .the_only_possible_value => { | 28277 | else => unreachable, |
| 27538 | const duped = try sema.arena.create(Value); | ||
| 27539 | duped.* = Value.initTag(.the_only_possible_value); | ||
| 27540 | return beginComptimePtrMutationInner( | ||
| 27541 | sema, | ||
| 27542 | block, | ||
| 27543 | src, | ||
| 27544 | elem_ty, | ||
| 27545 | duped, | ||
| 27546 | ptr_elem_ty, | ||
| 27547 | parent.decl_ref_mut, | ||
| 27548 | ); | ||
| 27549 | }, | 28278 | }, |
| 27550 | |||
| 27551 | else => unreachable, | ||
| 27552 | } | 28279 | } |
| 27553 | }, | 28280 | }, |
| 27554 | else => { | 28281 | else => { |
| ... | @@ -27565,28 +28292,29 @@ fn beginComptimePtrMutation( | ... | @@ -27565,28 +28292,29 @@ fn beginComptimePtrMutation( |
| 27565 | parent.ty, | 28292 | parent.ty, |
| 27566 | val_ptr, | 28293 | val_ptr, |
| 27567 | ptr_elem_ty, | 28294 | ptr_elem_ty, |
| 27568 | parent.decl_ref_mut, | 28295 | parent.mut_decl, |
| 27569 | ); | 28296 | ); |
| 27570 | }, | 28297 | }, |
| 27571 | }, | 28298 | }, |
| 27572 | .reinterpret => |reinterpret| { | 28299 | .reinterpret => |reinterpret| { |
| 27573 | if (!elem_ptr.elem_ty.hasWellDefinedLayout()) { | 28300 | if (!base_elem_ty.hasWellDefinedLayout(mod)) { |
| 27574 | // Even though the parent value type has well-defined memory layout, our | 28301 | // Even though the parent value type has well-defined memory layout, our |
| 27575 | // pointer type does not. | 28302 | // pointer type does not. |
| 27576 | return ComptimePtrMutationKit{ | 28303 | return ComptimePtrMutationKit{ |
| 27577 | .decl_ref_mut = parent.decl_ref_mut, | 28304 | .mut_decl = parent.mut_decl, |
| 27578 | .pointee = .bad_ptr_ty, | 28305 | .pointee = .bad_ptr_ty, |
| 27579 | .ty = elem_ptr.elem_ty, | 28306 | .ty = base_elem_ty, |
| 27580 | }; | 28307 | }; |
| 27581 | } | 28308 | } |
| 27582 | 28309 | ||
| 27583 | const elem_abi_size_u64 = try sema.typeAbiSize(elem_ptr.elem_ty); | 28310 | const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty); |
| 27584 | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); | 28311 | const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64); |
| 28312 | const elem_idx = try sema.usizeCast(block, src, elem_ptr.index); | ||
| 27585 | return ComptimePtrMutationKit{ | 28313 | return ComptimePtrMutationKit{ |
| 27586 | .decl_ref_mut = parent.decl_ref_mut, | 28314 | .mut_decl = parent.mut_decl, |
| 27587 | .pointee = .{ .reinterpret = .{ | 28315 | .pointee = .{ .reinterpret = .{ |
| 27588 | .val_ptr = reinterpret.val_ptr, | 28316 | .val_ptr = reinterpret.val_ptr, |
| 27589 | .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index, | 28317 | .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_idx, |
| 27590 | } }, | 28318 | } }, |
| 27591 | .ty = parent.ty, | 28319 | .ty = parent.ty, |
| 27592 | }; | 28320 | }; |
| ... | @@ -27594,162 +28322,184 @@ fn beginComptimePtrMutation( | ... | @@ -27594,162 +28322,184 @@ fn beginComptimePtrMutation( |
| 27594 | .bad_decl_ty, .bad_ptr_ty => return parent, | 28322 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 27595 | } | 28323 | } |
| 27596 | }, | 28324 | }, |
| 27597 | .field_ptr => { | 28325 | .field => |field_ptr| { |
| 27598 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | 28326 | const base_child_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); |
| 27599 | const field_index = @intCast(u32, field_ptr.field_index); | 28327 | const field_index = @intCast(u32, field_ptr.index); |
| 27600 | 28328 | ||
| 27601 | var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.container_ptr, field_ptr.container_ty); | 28329 | var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.base.toValue(), base_child_ty); |
| 27602 | switch (parent.pointee) { | 28330 | switch (parent.pointee) { |
| 27603 | .direct => |val_ptr| switch (val_ptr.tag()) { | 28331 | .direct => |val_ptr| switch (val_ptr.ip_index) { |
| 27604 | .undef => { | 28332 | .empty_struct => { |
| 27605 | // A struct or union has been initialized to undefined at comptime and now we | 28333 | const duped = try sema.arena.create(Value); |
| 27606 | // are for the first time setting a field. We must change the representation | 28334 | duped.* = val_ptr.*; |
| 27607 | // of the struct/union from `undef` to `struct`/`union`. | ||
| 27608 | const arena = parent.beginArena(sema.mod); | ||
| 27609 | defer parent.finishArena(sema.mod); | ||
| 27610 | |||
| 27611 | switch (parent.ty.zigTypeTag()) { | ||
| 27612 | .Struct => { | ||
| 27613 | const fields = try arena.alloc(Value, parent.ty.structFieldCount()); | ||
| 27614 | @memset(fields, Value.undef); | ||
| 27615 | |||
| 27616 | val_ptr.* = try Value.Tag.aggregate.create(arena, fields); | ||
| 27617 | |||
| 27618 | return beginComptimePtrMutationInner( | ||
| 27619 | sema, | ||
| 27620 | block, | ||
| 27621 | src, | ||
| 27622 | parent.ty.structFieldType(field_index), | ||
| 27623 | &fields[field_index], | ||
| 27624 | ptr_elem_ty, | ||
| 27625 | parent.decl_ref_mut, | ||
| 27626 | ); | ||
| 27627 | }, | ||
| 27628 | .Union => { | ||
| 27629 | const payload = try arena.create(Value.Payload.Union); | ||
| 27630 | payload.* = .{ .data = .{ | ||
| 27631 | .tag = try Value.Tag.enum_field_index.create(arena, field_index), | ||
| 27632 | .val = Value.undef, | ||
| 27633 | } }; | ||
| 27634 | |||
| 27635 | val_ptr.* = Value.initPayload(&payload.base); | ||
| 27636 | |||
| 27637 | return beginComptimePtrMutationInner( | ||
| 27638 | sema, | ||
| 27639 | block, | ||
| 27640 | src, | ||
| 27641 | parent.ty.structFieldType(field_index), | ||
| 27642 | &payload.data.val, | ||
| 27643 | ptr_elem_ty, | ||
| 27644 | parent.decl_ref_mut, | ||
| 27645 | ); | ||
| 27646 | }, | ||
| 27647 | .Pointer => { | ||
| 27648 | assert(parent.ty.isSlice()); | ||
| 27649 | val_ptr.* = try Value.Tag.slice.create(arena, .{ | ||
| 27650 | .ptr = Value.undef, | ||
| 27651 | .len = Value.undef, | ||
| 27652 | }); | ||
| 27653 | |||
| 27654 | switch (field_index) { | ||
| 27655 | Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( | ||
| 27656 | sema, | ||
| 27657 | block, | ||
| 27658 | src, | ||
| 27659 | parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | ||
| 27660 | &val_ptr.castTag(.slice).?.data.ptr, | ||
| 27661 | ptr_elem_ty, | ||
| 27662 | parent.decl_ref_mut, | ||
| 27663 | ), | ||
| 27664 | Value.Payload.Slice.len_index => return beginComptimePtrMutationInner( | ||
| 27665 | sema, | ||
| 27666 | block, | ||
| 27667 | src, | ||
| 27668 | Type.usize, | ||
| 27669 | &val_ptr.castTag(.slice).?.data.len, | ||
| 27670 | ptr_elem_ty, | ||
| 27671 | parent.decl_ref_mut, | ||
| 27672 | ), | ||
| 27673 | |||
| 27674 | else => unreachable, | ||
| 27675 | } | ||
| 27676 | }, | ||
| 27677 | else => unreachable, | ||
| 27678 | } | ||
| 27679 | }, | ||
| 27680 | .aggregate => return beginComptimePtrMutationInner( | ||
| 27681 | sema, | ||
| 27682 | block, | ||
| 27683 | src, | ||
| 27684 | parent.ty.structFieldType(field_index), | ||
| 27685 | &val_ptr.castTag(.aggregate).?.data[field_index], | ||
| 27686 | ptr_elem_ty, | ||
| 27687 | parent.decl_ref_mut, | ||
| 27688 | ), | ||
| 27689 | |||
| 27690 | .@"union" => { | ||
| 27691 | // We need to set the active field of the union. | ||
| 27692 | const arena = parent.beginArena(sema.mod); | ||
| 27693 | defer parent.finishArena(sema.mod); | ||
| 27694 | |||
| 27695 | const payload = &val_ptr.castTag(.@"union").?.data; | ||
| 27696 | payload.tag = try Value.Tag.enum_field_index.create(arena, field_index); | ||
| 27697 | |||
| 27698 | return beginComptimePtrMutationInner( | 28335 | return beginComptimePtrMutationInner( |
| 27699 | sema, | 28336 | sema, |
| 27700 | block, | 28337 | block, |
| 27701 | src, | 28338 | src, |
| 27702 | parent.ty.structFieldType(field_index), | 28339 | parent.ty.structFieldType(field_index, mod), |
| 27703 | &payload.val, | 28340 | duped, |
| 27704 | ptr_elem_ty, | 28341 | ptr_elem_ty, |
| 27705 | parent.decl_ref_mut, | 28342 | parent.mut_decl, |
| 27706 | ); | 28343 | ); |
| 27707 | }, | 28344 | }, |
| 27708 | .slice => switch (field_index) { | 28345 | .none => switch (val_ptr.tag()) { |
| 27709 | Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner( | 28346 | .aggregate => return beginComptimePtrMutationInner( |
| 27710 | sema, | 28347 | sema, |
| 27711 | block, | 28348 | block, |
| 27712 | src, | 28349 | src, |
| 27713 | parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | 28350 | parent.ty.structFieldType(field_index, mod), |
| 27714 | &val_ptr.castTag(.slice).?.data.ptr, | 28351 | &val_ptr.castTag(.aggregate).?.data[field_index], |
| 27715 | ptr_elem_ty, | 28352 | ptr_elem_ty, |
| 27716 | parent.decl_ref_mut, | 28353 | parent.mut_decl, |
| 27717 | ), | 28354 | ), |
| 28355 | .repeated => { | ||
| 28356 | const arena = sema.arena; | ||
| 27718 | 28357 | ||
| 27719 | Value.Payload.Slice.len_index => return beginComptimePtrMutationInner( | 28358 | const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod)); |
| 27720 | sema, | 28359 | @memset(elems, val_ptr.castTag(.repeated).?.data); |
| 27721 | block, | 28360 | val_ptr.* = try Value.Tag.aggregate.create(arena, elems); |
| 27722 | src, | 28361 | |
| 27723 | Type.usize, | 28362 | return beginComptimePtrMutationInner( |
| 27724 | &val_ptr.castTag(.slice).?.data.len, | 28363 | sema, |
| 27725 | ptr_elem_ty, | 28364 | block, |
| 27726 | parent.decl_ref_mut, | 28365 | src, |
| 27727 | ), | 28366 | parent.ty.structFieldType(field_index, mod), |
| 28367 | &elems[field_index], | ||
| 28368 | ptr_elem_ty, | ||
| 28369 | parent.mut_decl, | ||
| 28370 | ); | ||
| 28371 | }, | ||
| 28372 | .@"union" => { | ||
| 28373 | // We need to set the active field of the union. | ||
| 28374 | const union_tag_ty = base_child_ty.unionTagTypeHypothetical(mod); | ||
| 27728 | 28375 | ||
| 28376 | const payload = &val_ptr.castTag(.@"union").?.data; | ||
| 28377 | payload.tag = try mod.enumValueFieldIndex(union_tag_ty, field_index); | ||
| 28378 | |||
| 28379 | return beginComptimePtrMutationInner( | ||
| 28380 | sema, | ||
| 28381 | block, | ||
| 28382 | src, | ||
| 28383 | parent.ty.structFieldType(field_index, mod), | ||
| 28384 | &payload.val, | ||
| 28385 | ptr_elem_ty, | ||
| 28386 | parent.mut_decl, | ||
| 28387 | ); | ||
| 28388 | }, | ||
| 28389 | .slice => switch (field_index) { | ||
| 28390 | Value.slice_ptr_index => return beginComptimePtrMutationInner( | ||
| 28391 | sema, | ||
| 28392 | block, | ||
| 28393 | src, | ||
| 28394 | parent.ty.slicePtrFieldType(mod), | ||
| 28395 | &val_ptr.castTag(.slice).?.data.ptr, | ||
| 28396 | ptr_elem_ty, | ||
| 28397 | parent.mut_decl, | ||
| 28398 | ), | ||
| 28399 | |||
| 28400 | Value.slice_len_index => return beginComptimePtrMutationInner( | ||
| 28401 | sema, | ||
| 28402 | block, | ||
| 28403 | src, | ||
| 28404 | Type.usize, | ||
| 28405 | &val_ptr.castTag(.slice).?.data.len, | ||
| 28406 | ptr_elem_ty, | ||
| 28407 | parent.mut_decl, | ||
| 28408 | ), | ||
| 28409 | |||
| 28410 | else => unreachable, | ||
| 28411 | }, | ||
| 27729 | else => unreachable, | 28412 | else => unreachable, |
| 27730 | }, | 28413 | }, |
| 27731 | 28414 | else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) { | |
| 27732 | .empty_struct_value => { | 28415 | .undef => { |
| 27733 | const duped = try sema.arena.create(Value); | 28416 | // A struct or union has been initialized to undefined at comptime and now we |
| 27734 | duped.* = Value.initTag(.the_only_possible_value); | 28417 | // are for the first time setting a field. We must change the representation |
| 27735 | return beginComptimePtrMutationInner( | 28418 | // of the struct/union from `undef` to `struct`/`union`. |
| 27736 | sema, | 28419 | const arena = sema.arena; |
| 27737 | block, | 28420 | |
| 27738 | src, | 28421 | switch (parent.ty.zigTypeTag(mod)) { |
| 27739 | parent.ty.structFieldType(field_index), | 28422 | .Struct => { |
| 27740 | duped, | 28423 | const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod)); |
| 27741 | ptr_elem_ty, | 28424 | for (fields, 0..) |*field, i| field.* = (try mod.intern(.{ |
| 27742 | parent.decl_ref_mut, | 28425 | .undef = parent.ty.structFieldType(i, mod).toIntern(), |
| 27743 | ); | 28426 | })).toValue(); |
| 28427 | |||
| 28428 | val_ptr.* = try Value.Tag.aggregate.create(arena, fields); | ||
| 28429 | |||
| 28430 | return beginComptimePtrMutationInner( | ||
| 28431 | sema, | ||
| 28432 | block, | ||
| 28433 | src, | ||
| 28434 | parent.ty.structFieldType(field_index, mod), | ||
| 28435 | &fields[field_index], | ||
| 28436 | ptr_elem_ty, | ||
| 28437 | parent.mut_decl, | ||
| 28438 | ); | ||
| 28439 | }, | ||
| 28440 | .Union => { | ||
| 28441 | const payload = try arena.create(Value.Payload.Union); | ||
| 28442 | const tag_ty = parent.ty.unionTagTypeHypothetical(mod); | ||
| 28443 | const payload_ty = parent.ty.structFieldType(field_index, mod); | ||
| 28444 | payload.* = .{ .data = .{ | ||
| 28445 | .tag = try mod.enumValueFieldIndex(tag_ty, field_index), | ||
| 28446 | .val = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(), | ||
| 28447 | } }; | ||
| 28448 | |||
| 28449 | val_ptr.* = Value.initPayload(&payload.base); | ||
| 28450 | |||
| 28451 | return beginComptimePtrMutationInner( | ||
| 28452 | sema, | ||
| 28453 | block, | ||
| 28454 | src, | ||
| 28455 | payload_ty, | ||
| 28456 | &payload.data.val, | ||
| 28457 | ptr_elem_ty, | ||
| 28458 | parent.mut_decl, | ||
| 28459 | ); | ||
| 28460 | }, | ||
| 28461 | .Pointer => { | ||
| 28462 | assert(parent.ty.isSlice(mod)); | ||
| 28463 | const ptr_ty = parent.ty.slicePtrFieldType(mod); | ||
| 28464 | val_ptr.* = try Value.Tag.slice.create(arena, .{ | ||
| 28465 | .ptr = (try mod.intern(.{ .undef = ptr_ty.toIntern() })).toValue(), | ||
| 28466 | .len = (try mod.intern(.{ .undef = .usize_type })).toValue(), | ||
| 28467 | }); | ||
| 28468 | |||
| 28469 | switch (field_index) { | ||
| 28470 | Value.slice_ptr_index => return beginComptimePtrMutationInner( | ||
| 28471 | sema, | ||
| 28472 | block, | ||
| 28473 | src, | ||
| 28474 | ptr_ty, | ||
| 28475 | &val_ptr.castTag(.slice).?.data.ptr, | ||
| 28476 | ptr_elem_ty, | ||
| 28477 | parent.mut_decl, | ||
| 28478 | ), | ||
| 28479 | Value.slice_len_index => return beginComptimePtrMutationInner( | ||
| 28480 | sema, | ||
| 28481 | block, | ||
| 28482 | src, | ||
| 28483 | Type.usize, | ||
| 28484 | &val_ptr.castTag(.slice).?.data.len, | ||
| 28485 | ptr_elem_ty, | ||
| 28486 | parent.mut_decl, | ||
| 28487 | ), | ||
| 28488 | |||
| 28489 | else => unreachable, | ||
| 28490 | } | ||
| 28491 | }, | ||
| 28492 | else => unreachable, | ||
| 28493 | } | ||
| 28494 | }, | ||
| 28495 | else => unreachable, | ||
| 27744 | }, | 28496 | }, |
| 27745 | |||
| 27746 | else => unreachable, | ||
| 27747 | }, | 28497 | }, |
| 27748 | .reinterpret => |reinterpret| { | 28498 | .reinterpret => |reinterpret| { |
| 27749 | const field_offset_u64 = field_ptr.container_ty.structFieldOffset(field_index, target); | 28499 | const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod); |
| 27750 | const field_offset = try sema.usizeCast(block, src, field_offset_u64); | 28500 | const field_offset = try sema.usizeCast(block, src, field_offset_u64); |
| 27751 | return ComptimePtrMutationKit{ | 28501 | return ComptimePtrMutationKit{ |
| 27752 | .decl_ref_mut = parent.decl_ref_mut, | 28502 | .mut_decl = parent.mut_decl, |
| 27753 | .pointee = .{ .reinterpret = .{ | 28503 | .pointee = .{ .reinterpret = .{ |
| 27754 | .val_ptr = reinterpret.val_ptr, | 28504 | .val_ptr = reinterpret.val_ptr, |
| 27755 | .byte_offset = reinterpret.byte_offset + field_offset, | 28505 | .byte_offset = reinterpret.byte_offset + field_offset, |
| ... | @@ -27760,106 +28510,6 @@ fn beginComptimePtrMutation( | ... | @@ -27760,106 +28510,6 @@ fn beginComptimePtrMutation( |
| 27760 | .bad_decl_ty, .bad_ptr_ty => return parent, | 28510 | .bad_decl_ty, .bad_ptr_ty => return parent, |
| 27761 | } | 28511 | } |
| 27762 | }, | 28512 | }, |
| 27763 | .eu_payload_ptr => { | ||
| 27764 | const eu_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; | ||
| 27765 | var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.container_ptr, eu_ptr.container_ty); | ||
| 27766 | switch (parent.pointee) { | ||
| 27767 | .direct => |val_ptr| { | ||
| 27768 | const payload_ty = parent.ty.errorUnionPayload(); | ||
| 27769 | switch (val_ptr.tag()) { | ||
| 27770 | else => { | ||
| 27771 | // An error union has been initialized to undefined at comptime and now we | ||
| 27772 | // are for the first time setting the payload. We must change the | ||
| 27773 | // representation of the error union from `undef` to `opt_payload`. | ||
| 27774 | const arena = parent.beginArena(sema.mod); | ||
| 27775 | defer parent.finishArena(sema.mod); | ||
| 27776 | |||
| 27777 | const payload = try arena.create(Value.Payload.SubValue); | ||
| 27778 | payload.* = .{ | ||
| 27779 | .base = .{ .tag = .eu_payload }, | ||
| 27780 | .data = Value.undef, | ||
| 27781 | }; | ||
| 27782 | |||
| 27783 | val_ptr.* = Value.initPayload(&payload.base); | ||
| 27784 | |||
| 27785 | return ComptimePtrMutationKit{ | ||
| 27786 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 27787 | .pointee = .{ .direct = &payload.data }, | ||
| 27788 | .ty = payload_ty, | ||
| 27789 | }; | ||
| 27790 | }, | ||
| 27791 | .eu_payload => return ComptimePtrMutationKit{ | ||
| 27792 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 27793 | .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data }, | ||
| 27794 | .ty = payload_ty, | ||
| 27795 | }, | ||
| 27796 | } | ||
| 27797 | }, | ||
| 27798 | .bad_decl_ty, .bad_ptr_ty => return parent, | ||
| 27799 | // Even though the parent value type has well-defined memory layout, our | ||
| 27800 | // pointer type does not. | ||
| 27801 | .reinterpret => return ComptimePtrMutationKit{ | ||
| 27802 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 27803 | .pointee = .bad_ptr_ty, | ||
| 27804 | .ty = eu_ptr.container_ty, | ||
| 27805 | }, | ||
| 27806 | } | ||
| 27807 | }, | ||
| 27808 | .opt_payload_ptr => { | ||
| 27809 | const opt_ptr = if (ptr_val.castTag(.opt_payload_ptr)) |some| some.data else { | ||
| 27810 | return sema.beginComptimePtrMutation(block, src, ptr_val, try ptr_elem_ty.optionalChildAlloc(sema.arena)); | ||
| 27811 | }; | ||
| 27812 | var parent = try sema.beginComptimePtrMutation(block, src, opt_ptr.container_ptr, opt_ptr.container_ty); | ||
| 27813 | switch (parent.pointee) { | ||
| 27814 | .direct => |val_ptr| { | ||
| 27815 | const payload_ty = try parent.ty.optionalChildAlloc(sema.arena); | ||
| 27816 | switch (val_ptr.tag()) { | ||
| 27817 | .undef, .null_value => { | ||
| 27818 | // An optional has been initialized to undefined at comptime and now we | ||
| 27819 | // are for the first time setting the payload. We must change the | ||
| 27820 | // representation of the optional from `undef` to `opt_payload`. | ||
| 27821 | const arena = parent.beginArena(sema.mod); | ||
| 27822 | defer parent.finishArena(sema.mod); | ||
| 27823 | |||
| 27824 | const payload = try arena.create(Value.Payload.SubValue); | ||
| 27825 | payload.* = .{ | ||
| 27826 | .base = .{ .tag = .opt_payload }, | ||
| 27827 | .data = Value.undef, | ||
| 27828 | }; | ||
| 27829 | |||
| 27830 | val_ptr.* = Value.initPayload(&payload.base); | ||
| 27831 | |||
| 27832 | return ComptimePtrMutationKit{ | ||
| 27833 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 27834 | .pointee = .{ .direct = &payload.data }, | ||
| 27835 | .ty = payload_ty, | ||
| 27836 | }; | ||
| 27837 | }, | ||
| 27838 | .opt_payload => return ComptimePtrMutationKit{ | ||
| 27839 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 27840 | .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data }, | ||
| 27841 | .ty = payload_ty, | ||
| 27842 | }, | ||
| 27843 | |||
| 27844 | else => return ComptimePtrMutationKit{ | ||
| 27845 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 27846 | .pointee = .{ .direct = val_ptr }, | ||
| 27847 | .ty = payload_ty, | ||
| 27848 | }, | ||
| 27849 | } | ||
| 27850 | }, | ||
| 27851 | .bad_decl_ty, .bad_ptr_ty => return parent, | ||
| 27852 | // Even though the parent value type has well-defined memory layout, our | ||
| 27853 | // pointer type does not. | ||
| 27854 | .reinterpret => return ComptimePtrMutationKit{ | ||
| 27855 | .decl_ref_mut = parent.decl_ref_mut, | ||
| 27856 | .pointee = .bad_ptr_ty, | ||
| 27857 | .ty = opt_ptr.container_ty, | ||
| 27858 | }, | ||
| 27859 | } | ||
| 27860 | }, | ||
| 27861 | .decl_ref => unreachable, // isComptimeMutablePtr() has been checked already | ||
| 27862 | else => unreachable, | ||
| 27863 | } | 28513 | } |
| 27864 | } | 28514 | } |
| 27865 | 28515 | ||
| ... | @@ -27870,46 +28520,50 @@ fn beginComptimePtrMutationInner( | ... | @@ -27870,46 +28520,50 @@ fn beginComptimePtrMutationInner( |
| 27870 | decl_ty: Type, | 28520 | decl_ty: Type, |
| 27871 | decl_val: *Value, | 28521 | decl_val: *Value, |
| 27872 | ptr_elem_ty: Type, | 28522 | ptr_elem_ty: Type, |
| 27873 | decl_ref_mut: Value.Payload.DeclRefMut.Data, | 28523 | mut_decl: InternPool.Key.Ptr.Addr.MutDecl, |
| 27874 | ) CompileError!ComptimePtrMutationKit { | 28524 | ) CompileError!ComptimePtrMutationKit { |
| 27875 | const target = sema.mod.getTarget(); | 28525 | const mod = sema.mod; |
| 28526 | const target = mod.getTarget(); | ||
| 27876 | const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok; | 28527 | const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok; |
| 28528 | |||
| 28529 | decl_val.* = try decl_val.unintern(sema.arena, mod); | ||
| 28530 | |||
| 27877 | if (coerce_ok) { | 28531 | if (coerce_ok) { |
| 27878 | return ComptimePtrMutationKit{ | 28532 | return ComptimePtrMutationKit{ |
| 27879 | .decl_ref_mut = decl_ref_mut, | 28533 | .mut_decl = mut_decl, |
| 27880 | .pointee = .{ .direct = decl_val }, | 28534 | .pointee = .{ .direct = decl_val }, |
| 27881 | .ty = decl_ty, | 28535 | .ty = decl_ty, |
| 27882 | }; | 28536 | }; |
| 27883 | } | 28537 | } |
| 27884 | 28538 | ||
| 27885 | // Handle the case that the decl is an array and we're actually trying to point to an element. | 28539 | // Handle the case that the decl is an array and we're actually trying to point to an element. |
| 27886 | if (decl_ty.isArrayOrVector()) { | 28540 | if (decl_ty.isArrayOrVector(mod)) { |
| 27887 | const decl_elem_ty = decl_ty.childType(); | 28541 | const decl_elem_ty = decl_ty.childType(mod); |
| 27888 | if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) { | 28542 | if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) { |
| 27889 | return ComptimePtrMutationKit{ | 28543 | return ComptimePtrMutationKit{ |
| 27890 | .decl_ref_mut = decl_ref_mut, | 28544 | .mut_decl = mut_decl, |
| 27891 | .pointee = .{ .direct = decl_val }, | 28545 | .pointee = .{ .direct = decl_val }, |
| 27892 | .ty = decl_ty, | 28546 | .ty = decl_ty, |
| 27893 | }; | 28547 | }; |
| 27894 | } | 28548 | } |
| 27895 | } | 28549 | } |
| 27896 | 28550 | ||
| 27897 | if (!decl_ty.hasWellDefinedLayout()) { | 28551 | if (!decl_ty.hasWellDefinedLayout(mod)) { |
| 27898 | return ComptimePtrMutationKit{ | 28552 | return ComptimePtrMutationKit{ |
| 27899 | .decl_ref_mut = decl_ref_mut, | 28553 | .mut_decl = mut_decl, |
| 27900 | .pointee = .{ .bad_decl_ty = {} }, | 28554 | .pointee = .bad_decl_ty, |
| 27901 | .ty = decl_ty, | 28555 | .ty = decl_ty, |
| 27902 | }; | 28556 | }; |
| 27903 | } | 28557 | } |
| 27904 | if (!ptr_elem_ty.hasWellDefinedLayout()) { | 28558 | if (!ptr_elem_ty.hasWellDefinedLayout(mod)) { |
| 27905 | return ComptimePtrMutationKit{ | 28559 | return ComptimePtrMutationKit{ |
| 27906 | .decl_ref_mut = decl_ref_mut, | 28560 | .mut_decl = mut_decl, |
| 27907 | .pointee = .{ .bad_ptr_ty = {} }, | 28561 | .pointee = .bad_ptr_ty, |
| 27908 | .ty = ptr_elem_ty, | 28562 | .ty = ptr_elem_ty, |
| 27909 | }; | 28563 | }; |
| 27910 | } | 28564 | } |
| 27911 | return ComptimePtrMutationKit{ | 28565 | return ComptimePtrMutationKit{ |
| 27912 | .decl_ref_mut = decl_ref_mut, | 28566 | .mut_decl = mut_decl, |
| 27913 | .pointee = .{ .reinterpret = .{ | 28567 | .pointee = .{ .reinterpret = .{ |
| 27914 | .val_ptr = decl_val, | 28568 | .val_ptr = decl_val, |
| 27915 | .byte_offset = 0, | 28569 | .byte_offset = 0, |
| ... | @@ -27951,237 +28605,227 @@ fn beginComptimePtrLoad( | ... | @@ -27951,237 +28605,227 @@ fn beginComptimePtrLoad( |
| 27951 | ptr_val: Value, | 28605 | ptr_val: Value, |
| 27952 | maybe_array_ty: ?Type, | 28606 | maybe_array_ty: ?Type, |
| 27953 | ) ComptimePtrLoadError!ComptimePtrLoadKit { | 28607 | ) ComptimePtrLoadError!ComptimePtrLoadKit { |
| 27954 | const target = sema.mod.getTarget(); | 28608 | const mod = sema.mod; |
| 27955 | var deref: ComptimePtrLoadKit = switch (ptr_val.tag()) { | 28609 | const target = mod.getTarget(); |
| 27956 | .decl_ref, | ||
| 27957 | .decl_ref_mut, | ||
| 27958 | => blk: { | ||
| 27959 | const decl_index = switch (ptr_val.tag()) { | ||
| 27960 | .decl_ref => ptr_val.castTag(.decl_ref).?.data, | ||
| 27961 | .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index, | ||
| 27962 | else => unreachable, | ||
| 27963 | }; | ||
| 27964 | const is_mutable = ptr_val.tag() == .decl_ref_mut; | ||
| 27965 | const decl = sema.mod.declPtr(decl_index); | ||
| 27966 | const decl_tv = try decl.typedValue(); | ||
| 27967 | if (decl_tv.val.tag() == .variable) return error.RuntimeLoad; | ||
| 27968 | |||
| 27969 | const layout_defined = decl.ty.hasWellDefinedLayout(); | ||
| 27970 | break :blk ComptimePtrLoadKit{ | ||
| 27971 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, | ||
| 27972 | .pointee = decl_tv, | ||
| 27973 | .is_mutable = is_mutable, | ||
| 27974 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, | ||
| 27975 | }; | ||
| 27976 | }, | ||
| 27977 | |||
| 27978 | .elem_ptr => blk: { | ||
| 27979 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | ||
| 27980 | const elem_ty = elem_ptr.elem_ty; | ||
| 27981 | var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.array_ptr, null); | ||
| 27982 | |||
| 27983 | // This code assumes that elem_ptrs have been "flattened" in order for direct dereference | ||
| 27984 | // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that | ||
| 27985 | // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened" | ||
| 27986 | if (elem_ptr.array_ptr.castTag(.elem_ptr)) |parent_elem_ptr| { | ||
| 27987 | assert(!(parent_elem_ptr.data.elem_ty.eql(elem_ty, sema.mod))); | ||
| 27988 | } | ||
| 27989 | |||
| 27990 | if (elem_ptr.index != 0) { | ||
| 27991 | if (elem_ty.hasWellDefinedLayout()) { | ||
| 27992 | if (deref.parent) |*parent| { | ||
| 27993 | // Update the byte offset (in-place) | ||
| 27994 | const elem_size = try sema.typeAbiSize(elem_ty); | ||
| 27995 | const offset = parent.byte_offset + elem_size * elem_ptr.index; | ||
| 27996 | parent.byte_offset = try sema.usizeCast(block, src, offset); | ||
| 27997 | } | ||
| 27998 | } else { | ||
| 27999 | deref.parent = null; | ||
| 28000 | deref.ty_without_well_defined_layout = elem_ty; | ||
| 28001 | } | ||
| 28002 | } | ||
| 28003 | |||
| 28004 | // If we're loading an elem_ptr that was derived from a different type | ||
| 28005 | // than the true type of the underlying decl, we cannot deref directly | ||
| 28006 | const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector()) x: { | ||
| 28007 | const deref_elem_ty = deref.pointee.?.ty.childType(); | ||
| 28008 | break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or | ||
| 28009 | (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; | ||
| 28010 | } else false; | ||
| 28011 | if (!ty_matches) { | ||
| 28012 | deref.pointee = null; | ||
| 28013 | break :blk deref; | ||
| 28014 | } | ||
| 28015 | |||
| 28016 | var array_tv = deref.pointee.?; | ||
| 28017 | const check_len = array_tv.ty.arrayLenIncludingSentinel(); | ||
| 28018 | if (maybe_array_ty) |load_ty| { | ||
| 28019 | // It's possible that we're loading a [N]T, in which case we'd like to slice | ||
| 28020 | // the pointee array directly from our parent array. | ||
| 28021 | if (load_ty.isArrayOrVector() and load_ty.childType().eql(elem_ty, sema.mod)) { | ||
| 28022 | const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel()); | ||
| 28023 | deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{ | ||
| 28024 | .ty = try Type.array(sema.arena, N, null, elem_ty, sema.mod), | ||
| 28025 | .val = try array_tv.val.sliceArray(sema.mod, sema.arena, elem_ptr.index, elem_ptr.index + N), | ||
| 28026 | } else null; | ||
| 28027 | break :blk deref; | ||
| 28028 | } | ||
| 28029 | } | ||
| 28030 | |||
| 28031 | if (elem_ptr.index >= check_len) { | ||
| 28032 | deref.pointee = null; | ||
| 28033 | break :blk deref; | ||
| 28034 | } | ||
| 28035 | if (elem_ptr.index == check_len - 1) { | ||
| 28036 | if (array_tv.ty.sentinel()) |sent| { | ||
| 28037 | deref.pointee = TypedValue{ | ||
| 28038 | .ty = elem_ty, | ||
| 28039 | .val = sent, | ||
| 28040 | }; | ||
| 28041 | break :blk deref; | ||
| 28042 | } | ||
| 28043 | } | ||
| 28044 | deref.pointee = TypedValue{ | ||
| 28045 | .ty = elem_ty, | ||
| 28046 | .val = try array_tv.val.elemValue(sema.mod, sema.arena, elem_ptr.index), | ||
| 28047 | }; | ||
| 28048 | break :blk deref; | ||
| 28049 | }, | ||
| 28050 | |||
| 28051 | .slice => blk: { | ||
| 28052 | const slice = ptr_val.castTag(.slice).?.data; | ||
| 28053 | break :blk try sema.beginComptimePtrLoad(block, src, slice.ptr, null); | ||
| 28054 | }, | ||
| 28055 | 28610 | ||
| 28056 | .field_ptr => blk: { | 28611 | var deref: ComptimePtrLoadKit = switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { |
| 28057 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | 28612 | .ptr => |ptr| switch (ptr.addr) { |
| 28058 | const field_index = @intCast(u32, field_ptr.field_index); | 28613 | .decl, .mut_decl => blk: { |
| 28059 | var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.container_ptr, field_ptr.container_ty); | 28614 | const decl_index = switch (ptr.addr) { |
| 28615 | .decl => |decl| decl, | ||
| 28616 | .mut_decl => |mut_decl| mut_decl.decl, | ||
| 28617 | else => unreachable, | ||
| 28618 | }; | ||
| 28619 | const is_mutable = ptr.addr == .mut_decl; | ||
| 28620 | const decl = mod.declPtr(decl_index); | ||
| 28621 | const decl_tv = try decl.typedValue(); | ||
| 28622 | if (decl.val.getVariable(mod) != null) return error.RuntimeLoad; | ||
| 28623 | |||
| 28624 | const layout_defined = decl.ty.hasWellDefinedLayout(mod); | ||
| 28625 | break :blk ComptimePtrLoadKit{ | ||
| 28626 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, | ||
| 28627 | .pointee = decl_tv, | ||
| 28628 | .is_mutable = is_mutable, | ||
| 28629 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, | ||
| 28630 | }; | ||
| 28631 | }, | ||
| 28632 | .int => return error.RuntimeLoad, | ||
| 28633 | .eu_payload, .opt_payload => |container_ptr| blk: { | ||
| 28634 | const container_ty = mod.intern_pool.typeOf(container_ptr).toType().childType(mod); | ||
| 28635 | const payload_ty = switch (ptr.addr) { | ||
| 28636 | .eu_payload => container_ty.errorUnionPayload(mod), | ||
| 28637 | .opt_payload => container_ty.optionalChild(mod), | ||
| 28638 | else => unreachable, | ||
| 28639 | }; | ||
| 28640 | var deref = try sema.beginComptimePtrLoad(block, src, container_ptr.toValue(), container_ty); | ||
| 28060 | 28641 | ||
| 28061 | if (field_ptr.container_ty.hasWellDefinedLayout()) { | 28642 | // eu_payload and opt_payload never have a well-defined layout |
| 28062 | const struct_ty = field_ptr.container_ty.castTag(.@"struct"); | 28643 | if (deref.parent != null) { |
| 28063 | if (struct_ty != null and struct_ty.?.data.layout == .Packed) { | ||
| 28064 | // packed structs are not byte addressable | ||
| 28065 | deref.parent = null; | 28644 | deref.parent = null; |
| 28066 | } else if (deref.parent) |*parent| { | 28645 | deref.ty_without_well_defined_layout = container_ty; |
| 28067 | // Update the byte offset (in-place) | 28646 | } |
| 28068 | try sema.resolveTypeLayout(field_ptr.container_ty); | 28647 | |
| 28069 | const field_offset = field_ptr.container_ty.structFieldOffset(field_index, target); | 28648 | if (deref.pointee) |*tv| { |
| 28070 | parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); | 28649 | const coerce_in_mem_ok = |
| 28650 | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or | ||
| 28651 | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; | ||
| 28652 | if (coerce_in_mem_ok) { | ||
| 28653 | const payload_val = switch (tv.val.ip_index) { | ||
| 28654 | .none => tv.val.cast(Value.Payload.SubValue).?.data, | ||
| 28655 | .null_value => return sema.fail(block, src, "attempt to use null value", .{}), | ||
| 28656 | else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) { | ||
| 28657 | .error_union => |error_union| switch (error_union.val) { | ||
| 28658 | .err_name => |err_name| return sema.fail( | ||
| 28659 | block, | ||
| 28660 | src, | ||
| 28661 | "attempt to unwrap error: {}", | ||
| 28662 | .{err_name.fmt(&mod.intern_pool)}, | ||
| 28663 | ), | ||
| 28664 | .payload => |payload| payload, | ||
| 28665 | }, | ||
| 28666 | .opt => |opt| switch (opt.val) { | ||
| 28667 | .none => return sema.fail(block, src, "attempt to use null value", .{}), | ||
| 28668 | else => |payload| payload, | ||
| 28669 | }, | ||
| 28670 | else => unreachable, | ||
| 28671 | }.toValue(), | ||
| 28672 | }; | ||
| 28673 | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; | ||
| 28674 | break :blk deref; | ||
| 28675 | } | ||
| 28071 | } | 28676 | } |
| 28072 | } else { | ||
| 28073 | deref.parent = null; | ||
| 28074 | deref.ty_without_well_defined_layout = field_ptr.container_ty; | ||
| 28075 | } | ||
| 28076 | |||
| 28077 | const tv = deref.pointee orelse { | ||
| 28078 | deref.pointee = null; | ||
| 28079 | break :blk deref; | ||
| 28080 | }; | ||
| 28081 | const coerce_in_mem_ok = | ||
| 28082 | (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or | ||
| 28083 | (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok; | ||
| 28084 | if (!coerce_in_mem_ok) { | ||
| 28085 | deref.pointee = null; | 28677 | deref.pointee = null; |
| 28086 | break :blk deref; | 28678 | break :blk deref; |
| 28087 | } | 28679 | }, |
| 28088 | 28680 | .comptime_field => |comptime_field| blk: { | |
| 28089 | if (field_ptr.container_ty.isSlice()) { | 28681 | const field_ty = mod.intern_pool.typeOf(comptime_field).toType(); |
| 28090 | const slice_val = tv.val.castTag(.slice).?.data; | 28682 | break :blk ComptimePtrLoadKit{ |
| 28091 | deref.pointee = switch (field_index) { | 28683 | .parent = null, |
| 28092 | Value.Payload.Slice.ptr_index => TypedValue{ | 28684 | .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() }, |
| 28093 | .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)), | 28685 | .is_mutable = false, |
| 28094 | .val = slice_val.ptr, | 28686 | .ty_without_well_defined_layout = field_ty, |
| 28095 | }, | ||
| 28096 | Value.Payload.Slice.len_index => TypedValue{ | ||
| 28097 | .ty = Type.usize, | ||
| 28098 | .val = slice_val.len, | ||
| 28099 | }, | ||
| 28100 | else => unreachable, | ||
| 28101 | }; | ||
| 28102 | } else { | ||
| 28103 | const field_ty = field_ptr.container_ty.structFieldType(field_index); | ||
| 28104 | deref.pointee = TypedValue{ | ||
| 28105 | .ty = field_ty, | ||
| 28106 | .val = tv.val.fieldValue(tv.ty, field_index), | ||
| 28107 | }; | 28687 | }; |
| 28108 | } | 28688 | }, |
| 28109 | break :blk deref; | 28689 | .elem => |elem_ptr| blk: { |
| 28110 | }, | 28690 | const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod); |
| 28691 | var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null); | ||
| 28692 | |||
| 28693 | // This code assumes that elem_ptrs have been "flattened" in order for direct dereference | ||
| 28694 | // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that | ||
| 28695 | // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened" | ||
| 28696 | switch (mod.intern_pool.indexToKey(elem_ptr.base)) { | ||
| 28697 | .ptr => |base_ptr| switch (base_ptr.addr) { | ||
| 28698 | .elem => |base_elem| assert(!mod.intern_pool.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)), | ||
| 28699 | else => {}, | ||
| 28700 | }, | ||
| 28701 | else => {}, | ||
| 28702 | } | ||
| 28111 | 28703 | ||
| 28112 | .comptime_field_ptr => blk: { | 28704 | if (elem_ptr.index != 0) { |
| 28113 | const comptime_field_ptr = ptr_val.castTag(.comptime_field_ptr).?.data; | 28705 | if (elem_ty.hasWellDefinedLayout(mod)) { |
| 28114 | break :blk ComptimePtrLoadKit{ | 28706 | if (deref.parent) |*parent| { |
| 28115 | .parent = null, | 28707 | // Update the byte offset (in-place) |
| 28116 | .pointee = .{ .ty = comptime_field_ptr.field_ty, .val = comptime_field_ptr.field_val }, | 28708 | const elem_size = try sema.typeAbiSize(elem_ty); |
| 28117 | .is_mutable = false, | 28709 | const offset = parent.byte_offset + elem_size * elem_ptr.index; |
| 28118 | .ty_without_well_defined_layout = comptime_field_ptr.field_ty, | 28710 | parent.byte_offset = try sema.usizeCast(block, src, offset); |
| 28119 | }; | 28711 | } |
| 28120 | }, | 28712 | } else { |
| 28713 | deref.parent = null; | ||
| 28714 | deref.ty_without_well_defined_layout = elem_ty; | ||
| 28715 | } | ||
| 28716 | } | ||
| 28121 | 28717 | ||
| 28122 | .opt_payload_ptr, | 28718 | // If we're loading an elem that was derived from a different type |
| 28123 | .eu_payload_ptr, | 28719 | // than the true type of the underlying decl, we cannot deref directly |
| 28124 | => blk: { | 28720 | const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: { |
| 28125 | const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data; | 28721 | const deref_elem_ty = deref.pointee.?.ty.childType(mod); |
| 28126 | const payload_ty = switch (ptr_val.tag()) { | 28722 | break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or |
| 28127 | .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(), | 28723 | (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; |
| 28128 | .opt_payload_ptr => try payload_ptr.container_ty.optionalChildAlloc(sema.arena), | 28724 | } else false; |
| 28129 | else => unreachable, | 28725 | if (!ty_matches) { |
| 28130 | }; | 28726 | deref.pointee = null; |
| 28131 | var deref = try sema.beginComptimePtrLoad(block, src, payload_ptr.container_ptr, payload_ptr.container_ty); | 28727 | break :blk deref; |
| 28728 | } | ||
| 28132 | 28729 | ||
| 28133 | // eu_payload_ptr and opt_payload_ptr never have a well-defined layout | 28730 | var array_tv = deref.pointee.?; |
| 28134 | if (deref.parent != null) { | 28731 | const check_len = array_tv.ty.arrayLenIncludingSentinel(mod); |
| 28135 | deref.parent = null; | 28732 | if (maybe_array_ty) |load_ty| { |
| 28136 | deref.ty_without_well_defined_layout = payload_ptr.container_ty; | 28733 | // It's possible that we're loading a [N]T, in which case we'd like to slice |
| 28137 | } | 28734 | // the pointee array directly from our parent array. |
| 28735 | if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, mod)) { | ||
| 28736 | const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod)); | ||
| 28737 | const elem_idx = try sema.usizeCast(block, src, elem_ptr.index); | ||
| 28738 | deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{ | ||
| 28739 | .ty = try Type.array(sema.arena, N, null, elem_ty, mod), | ||
| 28740 | .val = try array_tv.val.sliceArray(mod, sema.arena, elem_idx, elem_idx + N), | ||
| 28741 | } else null; | ||
| 28742 | break :blk deref; | ||
| 28743 | } | ||
| 28744 | } | ||
| 28745 | |||
| 28746 | if (elem_ptr.index >= check_len) { | ||
| 28747 | deref.pointee = null; | ||
| 28748 | break :blk deref; | ||
| 28749 | } | ||
| 28750 | if (elem_ptr.index == check_len - 1) { | ||
| 28751 | if (array_tv.ty.sentinel(mod)) |sent| { | ||
| 28752 | deref.pointee = TypedValue{ | ||
| 28753 | .ty = elem_ty, | ||
| 28754 | .val = sent, | ||
| 28755 | }; | ||
| 28756 | break :blk deref; | ||
| 28757 | } | ||
| 28758 | } | ||
| 28759 | deref.pointee = TypedValue{ | ||
| 28760 | .ty = elem_ty, | ||
| 28761 | .val = try array_tv.val.elemValue(mod, @intCast(usize, elem_ptr.index)), | ||
| 28762 | }; | ||
| 28763 | break :blk deref; | ||
| 28764 | }, | ||
| 28765 | .field => |field_ptr| blk: { | ||
| 28766 | const field_index = @intCast(u32, field_ptr.index); | ||
| 28767 | const container_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); | ||
| 28768 | var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty); | ||
| 28769 | |||
| 28770 | if (container_ty.hasWellDefinedLayout(mod)) { | ||
| 28771 | const struct_obj = mod.typeToStruct(container_ty); | ||
| 28772 | if (struct_obj != null and struct_obj.?.layout == .Packed) { | ||
| 28773 | // packed structs are not byte addressable | ||
| 28774 | deref.parent = null; | ||
| 28775 | } else if (deref.parent) |*parent| { | ||
| 28776 | // Update the byte offset (in-place) | ||
| 28777 | try sema.resolveTypeLayout(container_ty); | ||
| 28778 | const field_offset = container_ty.structFieldOffset(field_index, mod); | ||
| 28779 | parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); | ||
| 28780 | } | ||
| 28781 | } else { | ||
| 28782 | deref.parent = null; | ||
| 28783 | deref.ty_without_well_defined_layout = container_ty; | ||
| 28784 | } | ||
| 28138 | 28785 | ||
| 28139 | if (deref.pointee) |*tv| { | 28786 | const tv = deref.pointee orelse { |
| 28787 | deref.pointee = null; | ||
| 28788 | break :blk deref; | ||
| 28789 | }; | ||
| 28140 | const coerce_in_mem_ok = | 28790 | const coerce_in_mem_ok = |
| 28141 | (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or | 28791 | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or |
| 28142 | (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok; | 28792 | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; |
| 28143 | if (coerce_in_mem_ok) { | 28793 | if (!coerce_in_mem_ok) { |
| 28144 | const payload_val = switch (ptr_val.tag()) { | 28794 | deref.pointee = null; |
| 28145 | .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else { | 28795 | break :blk deref; |
| 28146 | return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name}); | 28796 | } |
| 28797 | |||
| 28798 | if (container_ty.isSlice(mod)) { | ||
| 28799 | deref.pointee = switch (field_index) { | ||
| 28800 | Value.slice_ptr_index => TypedValue{ | ||
| 28801 | .ty = container_ty.slicePtrFieldType(mod), | ||
| 28802 | .val = tv.val.slicePtr(mod), | ||
| 28147 | }, | 28803 | }, |
| 28148 | .opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: { | 28804 | Value.slice_len_index => TypedValue{ |
| 28149 | if (tv.val.isNull()) return sema.fail(block, src, "attempt to use null value", .{}); | 28805 | .ty = Type.usize, |
| 28150 | break :opt tv.val; | 28806 | .val = mod.intern_pool.indexToKey(tv.val.toIntern()).ptr.len.toValue(), |
| 28151 | }, | 28807 | }, |
| 28152 | else => unreachable, | 28808 | else => unreachable, |
| 28153 | }; | 28809 | }; |
| 28154 | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; | 28810 | } else { |
| 28155 | break :blk deref; | 28811 | const field_ty = container_ty.structFieldType(field_index, mod); |
| 28812 | deref.pointee = TypedValue{ | ||
| 28813 | .ty = field_ty, | ||
| 28814 | .val = try tv.val.fieldValue(mod, field_index), | ||
| 28815 | }; | ||
| 28156 | } | 28816 | } |
| 28157 | } | 28817 | break :blk deref; |
| 28158 | deref.pointee = null; | 28818 | }, |
| 28159 | break :blk deref; | ||
| 28160 | }, | ||
| 28161 | .null_value => { | ||
| 28162 | return sema.fail(block, src, "attempt to use null value", .{}); | ||
| 28163 | }, | 28819 | }, |
| 28164 | .opt_payload => blk: { | 28820 | .opt => |opt| switch (opt.val) { |
| 28165 | const opt_payload = ptr_val.castTag(.opt_payload).?.data; | 28821 | .none => return sema.fail(block, src, "attempt to use null value", .{}), |
| 28166 | break :blk try sema.beginComptimePtrLoad(block, src, opt_payload, null); | 28822 | else => |payload| try sema.beginComptimePtrLoad(block, src, payload.toValue(), null), |
| 28167 | }, | 28823 | }, |
| 28168 | |||
| 28169 | .zero, | ||
| 28170 | .one, | ||
| 28171 | .int_u64, | ||
| 28172 | .int_i64, | ||
| 28173 | .int_big_positive, | ||
| 28174 | .int_big_negative, | ||
| 28175 | .variable, | ||
| 28176 | .extern_fn, | ||
| 28177 | .function, | ||
| 28178 | => return error.RuntimeLoad, | ||
| 28179 | |||
| 28180 | else => unreachable, | 28824 | else => unreachable, |
| 28181 | }; | 28825 | }; |
| 28182 | 28826 | ||
| 28183 | if (deref.pointee) |tv| { | 28827 | if (deref.pointee) |tv| { |
| 28184 | if (deref.parent == null and tv.ty.hasWellDefinedLayout()) { | 28828 | if (deref.parent == null and tv.ty.hasWellDefinedLayout(mod)) { |
| 28185 | deref.parent = .{ .tv = tv, .byte_offset = 0 }; | 28829 | deref.parent = .{ .tv = tv, .byte_offset = 0 }; |
| 28186 | } | 28830 | } |
| 28187 | } | 28831 | } |
| ... | @@ -28196,21 +28840,21 @@ fn bitCast( | ... | @@ -28196,21 +28840,21 @@ fn bitCast( |
| 28196 | inst_src: LazySrcLoc, | 28840 | inst_src: LazySrcLoc, |
| 28197 | operand_src: ?LazySrcLoc, | 28841 | operand_src: ?LazySrcLoc, |
| 28198 | ) CompileError!Air.Inst.Ref { | 28842 | ) CompileError!Air.Inst.Ref { |
| 28843 | const mod = sema.mod; | ||
| 28199 | const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); | 28844 | const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved); |
| 28200 | try sema.resolveTypeLayout(dest_ty); | 28845 | try sema.resolveTypeLayout(dest_ty); |
| 28201 | 28846 | ||
| 28202 | const old_ty = try sema.resolveTypeFields(sema.typeOf(inst)); | 28847 | const old_ty = try sema.resolveTypeFields(sema.typeOf(inst)); |
| 28203 | try sema.resolveTypeLayout(old_ty); | 28848 | try sema.resolveTypeLayout(old_ty); |
| 28204 | 28849 | ||
| 28205 | const target = sema.mod.getTarget(); | 28850 | const dest_bits = dest_ty.bitSize(mod); |
| 28206 | const dest_bits = dest_ty.bitSize(target); | 28851 | const old_bits = old_ty.bitSize(mod); |
| 28207 | const old_bits = old_ty.bitSize(target); | ||
| 28208 | 28852 | ||
| 28209 | if (old_bits != dest_bits) { | 28853 | if (old_bits != dest_bits) { |
| 28210 | return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{ | 28854 | return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{ |
| 28211 | dest_ty.fmt(sema.mod), | 28855 | dest_ty.fmt(mod), |
| 28212 | dest_bits, | 28856 | dest_bits, |
| 28213 | old_ty.fmt(sema.mod), | 28857 | old_ty.fmt(mod), |
| 28214 | old_bits, | 28858 | old_bits, |
| 28215 | }); | 28859 | }); |
| 28216 | } | 28860 | } |
| ... | @@ -28233,20 +28877,21 @@ fn bitCastVal( | ... | @@ -28233,20 +28877,21 @@ fn bitCastVal( |
| 28233 | new_ty: Type, | 28877 | new_ty: Type, |
| 28234 | buffer_offset: usize, | 28878 | buffer_offset: usize, |
| 28235 | ) !?Value { | 28879 | ) !?Value { |
| 28236 | const target = sema.mod.getTarget(); | 28880 | const mod = sema.mod; |
| 28237 | if (old_ty.eql(new_ty, sema.mod)) return val; | 28881 | if (old_ty.eql(new_ty, mod)) return val; |
| 28238 | 28882 | ||
| 28239 | // For types with well-defined memory layouts, we serialize them a byte buffer, | 28883 | // For types with well-defined memory layouts, we serialize them a byte buffer, |
| 28240 | // then deserialize to the new type. | 28884 | // then deserialize to the new type. |
| 28241 | const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(target)); | 28885 | const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(mod)); |
| 28242 | const buffer = try sema.gpa.alloc(u8, abi_size); | 28886 | const buffer = try sema.gpa.alloc(u8, abi_size); |
| 28243 | defer sema.gpa.free(buffer); | 28887 | defer sema.gpa.free(buffer); |
| 28244 | val.writeToMemory(old_ty, sema.mod, buffer) catch |err| switch (err) { | 28888 | val.writeToMemory(old_ty, mod, buffer) catch |err| switch (err) { |
| 28889 | error.OutOfMemory => return error.OutOfMemory, | ||
| 28245 | error.ReinterpretDeclRef => return null, | 28890 | error.ReinterpretDeclRef => return null, |
| 28246 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already | 28891 | error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already |
| 28247 | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{old_ty.fmt(sema.mod)}), | 28892 | error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{old_ty.fmt(mod)}), |
| 28248 | }; | 28893 | }; |
| 28249 | return try Value.readFromMemory(new_ty, sema.mod, buffer[buffer_offset..], sema.arena); | 28894 | return try Value.readFromMemory(new_ty, mod, buffer[buffer_offset..], sema.arena); |
| 28250 | } | 28895 | } |
| 28251 | 28896 | ||
| 28252 | fn coerceArrayPtrToSlice( | 28897 | fn coerceArrayPtrToSlice( |
| ... | @@ -28256,25 +28901,32 @@ fn coerceArrayPtrToSlice( | ... | @@ -28256,25 +28901,32 @@ fn coerceArrayPtrToSlice( |
| 28256 | inst: Air.Inst.Ref, | 28901 | inst: Air.Inst.Ref, |
| 28257 | inst_src: LazySrcLoc, | 28902 | inst_src: LazySrcLoc, |
| 28258 | ) CompileError!Air.Inst.Ref { | 28903 | ) CompileError!Air.Inst.Ref { |
| 28904 | const mod = sema.mod; | ||
| 28259 | if (try sema.resolveMaybeUndefVal(inst)) |val| { | 28905 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 28260 | const ptr_array_ty = sema.typeOf(inst); | 28906 | const ptr_array_ty = sema.typeOf(inst); |
| 28261 | const array_ty = ptr_array_ty.childType(); | 28907 | const array_ty = ptr_array_ty.childType(mod); |
| 28262 | const slice_val = try Value.Tag.slice.create(sema.arena, .{ | 28908 | const slice_val = try mod.intern(.{ .ptr = .{ |
| 28263 | .ptr = val, | 28909 | .ty = dest_ty.toIntern(), |
| 28264 | .len = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()), | 28910 | .addr = switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 28265 | }); | 28911 | .undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) }, |
| 28266 | return sema.addConstant(dest_ty, slice_val); | 28912 | .ptr => |ptr| ptr.addr, |
| 28913 | else => unreachable, | ||
| 28914 | }, | ||
| 28915 | .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(), | ||
| 28916 | } }); | ||
| 28917 | return sema.addConstant(dest_ty, slice_val.toValue()); | ||
| 28267 | } | 28918 | } |
| 28268 | try sema.requireRuntimeBlock(block, inst_src, null); | 28919 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28269 | return block.addTyOp(.array_to_slice, dest_ty, inst); | 28920 | return block.addTyOp(.array_to_slice, dest_ty, inst); |
| 28270 | } | 28921 | } |
| 28271 | 28922 | ||
| 28272 | fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_result: *InMemoryCoercionResult) bool { | 28923 | fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_result: *InMemoryCoercionResult) bool { |
| 28273 | const dest_info = dest_ty.ptrInfo().data; | 28924 | const mod = sema.mod; |
| 28274 | const inst_info = inst_ty.ptrInfo().data; | 28925 | const dest_info = dest_ty.ptrInfo(mod); |
| 28275 | const len0 = (inst_info.pointee_type.zigTypeTag() == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel() == 0 or | 28926 | const inst_info = inst_ty.ptrInfo(mod); |
| 28276 | (inst_info.pointee_type.arrayLen() == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or | 28927 | const len0 = (inst_info.pointee_type.zigTypeTag(mod) == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel(mod) == 0 or |
| 28277 | (inst_info.pointee_type.isTuple() and inst_info.pointee_type.structFieldCount() == 0); | 28928 | (inst_info.pointee_type.arrayLen(mod) == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or |
| 28929 | (inst_info.pointee_type.isTuple(mod) and inst_info.pointee_type.structFieldCount(mod) == 0); | ||
| 28278 | 28930 | ||
| 28279 | const ok_cv_qualifiers = | 28931 | const ok_cv_qualifiers = |
| 28280 | ((inst_info.mutable or !dest_info.mutable) or len0) and | 28932 | ((inst_info.mutable or !dest_info.mutable) or len0) and |
| ... | @@ -28298,17 +28950,16 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul | ... | @@ -28298,17 +28950,16 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul |
| 28298 | } | 28950 | } |
| 28299 | if (inst_info.@"align" == 0 and dest_info.@"align" == 0) return true; | 28951 | if (inst_info.@"align" == 0 and dest_info.@"align" == 0) return true; |
| 28300 | if (len0) return true; | 28952 | if (len0) return true; |
| 28301 | const target = sema.mod.getTarget(); | ||
| 28302 | 28953 | ||
| 28303 | const inst_align = if (inst_info.@"align" != 0) | 28954 | const inst_align = if (inst_info.@"align" != 0) |
| 28304 | inst_info.@"align" | 28955 | inst_info.@"align" |
| 28305 | else | 28956 | else |
| 28306 | inst_info.pointee_type.abiAlignment(target); | 28957 | inst_info.pointee_type.abiAlignment(mod); |
| 28307 | 28958 | ||
| 28308 | const dest_align = if (dest_info.@"align" != 0) | 28959 | const dest_align = if (dest_info.@"align" != 0) |
| 28309 | dest_info.@"align" | 28960 | dest_info.@"align" |
| 28310 | else | 28961 | else |
| 28311 | dest_info.pointee_type.abiAlignment(target); | 28962 | dest_info.pointee_type.abiAlignment(mod); |
| 28312 | 28963 | ||
| 28313 | if (dest_align > inst_align) { | 28964 | if (dest_align > inst_align) { |
| 28314 | in_memory_result.* = .{ .ptr_alignment = .{ | 28965 | in_memory_result.* = .{ .ptr_alignment = .{ |
| ... | @@ -28327,26 +28978,30 @@ fn coerceCompatiblePtrs( | ... | @@ -28327,26 +28978,30 @@ fn coerceCompatiblePtrs( |
| 28327 | inst: Air.Inst.Ref, | 28978 | inst: Air.Inst.Ref, |
| 28328 | inst_src: LazySrcLoc, | 28979 | inst_src: LazySrcLoc, |
| 28329 | ) !Air.Inst.Ref { | 28980 | ) !Air.Inst.Ref { |
| 28981 | const mod = sema.mod; | ||
| 28330 | const inst_ty = sema.typeOf(inst); | 28982 | const inst_ty = sema.typeOf(inst); |
| 28331 | if (try sema.resolveMaybeUndefVal(inst)) |val| { | 28983 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 28332 | if (!val.isUndef() and val.isNull() and !dest_ty.isAllowzeroPtr()) { | 28984 | if (!val.isUndef(mod) and val.isNull(mod) and !dest_ty.isAllowzeroPtr(mod)) { |
| 28333 | return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)}); | 28985 | return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)}); |
| 28334 | } | 28986 | } |
| 28335 | // The comptime Value representation is compatible with both types. | 28987 | // The comptime Value representation is compatible with both types. |
| 28336 | return sema.addConstant(dest_ty, val); | 28988 | return sema.addConstant( |
| 28989 | dest_ty, | ||
| 28990 | try mod.getCoerced((try val.intern(inst_ty, mod)).toValue(), dest_ty), | ||
| 28991 | ); | ||
| 28337 | } | 28992 | } |
| 28338 | try sema.requireRuntimeBlock(block, inst_src, null); | 28993 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28339 | const inst_allows_zero = inst_ty.zigTypeTag() != .Pointer or inst_ty.ptrAllowsZero(); | 28994 | const inst_allows_zero = inst_ty.zigTypeTag(mod) != .Pointer or inst_ty.ptrAllowsZero(mod); |
| 28340 | if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and | 28995 | if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(mod) and |
| 28341 | (try sema.typeHasRuntimeBits(dest_ty.elemType2()) or dest_ty.elemType2().zigTypeTag() == .Fn)) | 28996 | (try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn)) |
| 28342 | { | 28997 | { |
| 28343 | const actual_ptr = if (inst_ty.isSlice()) | 28998 | const actual_ptr = if (inst_ty.isSlice(mod)) |
| 28344 | try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) | 28999 | try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) |
| 28345 | else | 29000 | else |
| 28346 | inst; | 29001 | inst; |
| 28347 | const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); | 29002 | const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr); |
| 28348 | const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize); | 29003 | const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize); |
| 28349 | const ok = if (inst_ty.isSlice()) ok: { | 29004 | const ok = if (inst_ty.isSlice(mod)) ok: { |
| 28350 | const len = try sema.analyzeSliceLen(block, inst_src, inst); | 29005 | const len = try sema.analyzeSliceLen(block, inst_src, inst); |
| 28351 | const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); | 29006 | const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); |
| 28352 | break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero); | 29007 | break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero); |
| ... | @@ -28364,9 +29019,11 @@ fn coerceEnumToUnion( | ... | @@ -28364,9 +29019,11 @@ fn coerceEnumToUnion( |
| 28364 | inst: Air.Inst.Ref, | 29019 | inst: Air.Inst.Ref, |
| 28365 | inst_src: LazySrcLoc, | 29020 | inst_src: LazySrcLoc, |
| 28366 | ) !Air.Inst.Ref { | 29021 | ) !Air.Inst.Ref { |
| 29022 | const mod = sema.mod; | ||
| 29023 | const ip = &mod.intern_pool; | ||
| 28367 | const inst_ty = sema.typeOf(inst); | 29024 | const inst_ty = sema.typeOf(inst); |
| 28368 | 29025 | ||
| 28369 | const tag_ty = union_ty.unionTagType() orelse { | 29026 | const tag_ty = union_ty.unionTagType(mod) orelse { |
| 28370 | const msg = msg: { | 29027 | const msg = msg: { |
| 28371 | const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ | 29028 | const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ |
| 28372 | union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod), | 29029 | union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod), |
| ... | @@ -28393,16 +29050,18 @@ fn coerceEnumToUnion( | ... | @@ -28393,16 +29050,18 @@ fn coerceEnumToUnion( |
| 28393 | return sema.failWithOwnedErrorMsg(msg); | 29050 | return sema.failWithOwnedErrorMsg(msg); |
| 28394 | }; | 29051 | }; |
| 28395 | 29052 | ||
| 28396 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 29053 | const union_obj = mod.typeToUnion(union_ty).?; |
| 28397 | const field = union_obj.fields.values()[field_index]; | 29054 | const field = union_obj.fields.values()[field_index]; |
| 28398 | const field_ty = try sema.resolveTypeFields(field.ty); | 29055 | const field_ty = try sema.resolveTypeFields(field.ty); |
| 28399 | if (field_ty.zigTypeTag() == .NoReturn) { | 29056 | if (field_ty.zigTypeTag(mod) == .NoReturn) { |
| 28400 | const msg = msg: { | 29057 | const msg = msg: { |
| 28401 | const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{}); | 29058 | const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{}); |
| 28402 | errdefer msg.destroy(sema.gpa); | 29059 | errdefer msg.destroy(sema.gpa); |
| 28403 | 29060 | ||
| 28404 | const field_name = union_obj.fields.keys()[field_index]; | 29061 | const field_name = union_obj.fields.keys()[field_index]; |
| 28405 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); | 29062 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{ |
| 29063 | field_name.fmt(ip), | ||
| 29064 | }); | ||
| 28406 | try sema.addDeclaredHereNote(msg, union_ty); | 29065 | try sema.addDeclaredHereNote(msg, union_ty); |
| 28407 | break :msg msg; | 29066 | break :msg msg; |
| 28408 | }; | 29067 | }; |
| ... | @@ -28411,27 +29070,27 @@ fn coerceEnumToUnion( | ... | @@ -28411,27 +29070,27 @@ fn coerceEnumToUnion( |
| 28411 | const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse { | 29070 | const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse { |
| 28412 | const msg = msg: { | 29071 | const msg = msg: { |
| 28413 | const field_name = union_obj.fields.keys()[field_index]; | 29072 | const field_name = union_obj.fields.keys()[field_index]; |
| 28414 | const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{s}'", .{ | 29073 | const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{ |
| 28415 | inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), field_ty.fmt(sema.mod), field_name, | 29074 | inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), |
| 29075 | field_ty.fmt(sema.mod), field_name.fmt(ip), | ||
| 28416 | }); | 29076 | }); |
| 28417 | errdefer msg.destroy(sema.gpa); | 29077 | errdefer msg.destroy(sema.gpa); |
| 28418 | 29078 | ||
| 28419 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); | 29079 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{ |
| 29080 | field_name.fmt(ip), | ||
| 29081 | }); | ||
| 28420 | try sema.addDeclaredHereNote(msg, union_ty); | 29082 | try sema.addDeclaredHereNote(msg, union_ty); |
| 28421 | break :msg msg; | 29083 | break :msg msg; |
| 28422 | }; | 29084 | }; |
| 28423 | return sema.failWithOwnedErrorMsg(msg); | 29085 | return sema.failWithOwnedErrorMsg(msg); |
| 28424 | }; | 29086 | }; |
| 28425 | 29087 | ||
| 28426 | return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{ | 29088 | return sema.addConstant(union_ty, try mod.unionValue(union_ty, val, opv)); |
| 28427 | .tag = val, | ||
| 28428 | .val = opv, | ||
| 28429 | })); | ||
| 28430 | } | 29089 | } |
| 28431 | 29090 | ||
| 28432 | try sema.requireRuntimeBlock(block, inst_src, null); | 29091 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28433 | 29092 | ||
| 28434 | if (tag_ty.isNonexhaustiveEnum()) { | 29093 | if (tag_ty.isNonexhaustiveEnum(mod)) { |
| 28435 | const msg = msg: { | 29094 | const msg = msg: { |
| 28436 | const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{ | 29095 | const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{ |
| 28437 | union_ty.fmt(sema.mod), | 29096 | union_ty.fmt(sema.mod), |
| ... | @@ -28443,13 +29102,13 @@ fn coerceEnumToUnion( | ... | @@ -28443,13 +29102,13 @@ fn coerceEnumToUnion( |
| 28443 | return sema.failWithOwnedErrorMsg(msg); | 29102 | return sema.failWithOwnedErrorMsg(msg); |
| 28444 | } | 29103 | } |
| 28445 | 29104 | ||
| 28446 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 29105 | const union_obj = mod.typeToUnion(union_ty).?; |
| 28447 | { | 29106 | { |
| 28448 | var msg: ?*Module.ErrorMsg = null; | 29107 | var msg: ?*Module.ErrorMsg = null; |
| 28449 | errdefer if (msg) |some| some.destroy(sema.gpa); | 29108 | errdefer if (msg) |some| some.destroy(sema.gpa); |
| 28450 | 29109 | ||
| 28451 | for (union_obj.fields.values(), 0..) |field, i| { | 29110 | for (union_obj.fields.values(), 0..) |field, i| { |
| 28452 | if (field.ty.zigTypeTag() == .NoReturn) { | 29111 | if (field.ty.zigTypeTag(mod) == .NoReturn) { |
| 28453 | const err_msg = msg orelse try sema.errMsg( | 29112 | const err_msg = msg orelse try sema.errMsg( |
| 28454 | block, | 29113 | block, |
| 28455 | inst_src, | 29114 | inst_src, |
| ... | @@ -28469,7 +29128,7 @@ fn coerceEnumToUnion( | ... | @@ -28469,7 +29128,7 @@ fn coerceEnumToUnion( |
| 28469 | } | 29128 | } |
| 28470 | 29129 | ||
| 28471 | // If the union has all fields 0 bits, the union value is just the enum value. | 29130 | // If the union has all fields 0 bits, the union value is just the enum value. |
| 28472 | if (union_ty.unionHasAllZeroBitFieldTypes()) { | 29131 | if (union_ty.unionHasAllZeroBitFieldTypes(mod)) { |
| 28473 | return block.addBitCast(union_ty, enum_tag); | 29132 | return block.addBitCast(union_ty, enum_tag); |
| 28474 | } | 29133 | } |
| 28475 | 29134 | ||
| ... | @@ -28487,8 +29146,11 @@ fn coerceEnumToUnion( | ... | @@ -28487,8 +29146,11 @@ fn coerceEnumToUnion( |
| 28487 | while (it.next()) |field| : (field_index += 1) { | 29146 | while (it.next()) |field| : (field_index += 1) { |
| 28488 | const field_name = field.key_ptr.*; | 29147 | const field_name = field.key_ptr.*; |
| 28489 | const field_ty = field.value_ptr.ty; | 29148 | const field_ty = field.value_ptr.ty; |
| 28490 | if (!field_ty.hasRuntimeBits()) continue; | 29149 | if (!(try sema.typeHasRuntimeBits(field_ty))) continue; |
| 28491 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) }); | 29150 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{ |
| 29151 | field_name.fmt(ip), | ||
| 29152 | field_ty.fmt(sema.mod), | ||
| 29153 | }); | ||
| 28492 | } | 29154 | } |
| 28493 | try sema.addDeclaredHereNote(msg, union_ty); | 29155 | try sema.addDeclaredHereNote(msg, union_ty); |
| 28494 | break :msg msg; | 29156 | break :msg msg; |
| ... | @@ -28504,36 +29166,55 @@ fn coerceAnonStructToUnion( | ... | @@ -28504,36 +29166,55 @@ fn coerceAnonStructToUnion( |
| 28504 | inst: Air.Inst.Ref, | 29166 | inst: Air.Inst.Ref, |
| 28505 | inst_src: LazySrcLoc, | 29167 | inst_src: LazySrcLoc, |
| 28506 | ) !Air.Inst.Ref { | 29168 | ) !Air.Inst.Ref { |
| 29169 | const mod = sema.mod; | ||
| 28507 | const inst_ty = sema.typeOf(inst); | 29170 | const inst_ty = sema.typeOf(inst); |
| 28508 | const field_count = inst_ty.structFieldCount(); | 29171 | const field_info: union(enum) { |
| 28509 | if (field_count != 1) { | 29172 | name: InternPool.NullTerminatedString, |
| 28510 | const msg = msg: { | 29173 | count: usize, |
| 28511 | const msg = if (field_count > 1) try sema.errMsg( | 29174 | } = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { |
| 28512 | block, | 29175 | .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 1) |
| 28513 | inst_src, | 29176 | .{ .name = anon_struct_type.names[0] } |
| 28514 | "cannot initialize multiple union fields at once; unions can only have one active field", | 29177 | else |
| 28515 | .{}, | 29178 | .{ .count = anon_struct_type.names.len }, |
| 28516 | ) else try sema.errMsg( | 29179 | .struct_type => |struct_type| name: { |
| 28517 | block, | 29180 | const field_names = mod.structPtrUnwrap(struct_type.index).?.fields.keys(); |
| 28518 | inst_src, | 29181 | break :name if (field_names.len == 1) |
| 28519 | "union initializer must initialize one field", | 29182 | .{ .name = field_names[0] } |
| 28520 | .{}, | 29183 | else |
| 28521 | ); | 29184 | .{ .count = field_names.len }; |
| 28522 | errdefer msg.destroy(sema.gpa); | 29185 | }, |
| 29186 | else => unreachable, | ||
| 29187 | }; | ||
| 29188 | switch (field_info) { | ||
| 29189 | .name => |field_name| { | ||
| 29190 | const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty); | ||
| 29191 | return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src); | ||
| 29192 | }, | ||
| 29193 | .count => |field_count| { | ||
| 29194 | assert(field_count != 1); | ||
| 29195 | const msg = msg: { | ||
| 29196 | const msg = if (field_count > 1) try sema.errMsg( | ||
| 29197 | block, | ||
| 29198 | inst_src, | ||
| 29199 | "cannot initialize multiple union fields at once; unions can only have one active field", | ||
| 29200 | .{}, | ||
| 29201 | ) else try sema.errMsg( | ||
| 29202 | block, | ||
| 29203 | inst_src, | ||
| 29204 | "union initializer must initialize one field", | ||
| 29205 | .{}, | ||
| 29206 | ); | ||
| 29207 | errdefer msg.destroy(sema.gpa); | ||
| 28523 | 29208 | ||
| 28524 | // TODO add notes for where the anon struct was created to point out | 29209 | // TODO add notes for where the anon struct was created to point out |
| 28525 | // the extra fields. | 29210 | // the extra fields. |
| 28526 | 29211 | ||
| 28527 | try sema.addDeclaredHereNote(msg, union_ty); | 29212 | try sema.addDeclaredHereNote(msg, union_ty); |
| 28528 | break :msg msg; | 29213 | break :msg msg; |
| 28529 | }; | 29214 | }; |
| 28530 | return sema.failWithOwnedErrorMsg(msg); | 29215 | return sema.failWithOwnedErrorMsg(msg); |
| 29216 | }, | ||
| 28531 | } | 29217 | } |
| 28532 | |||
| 28533 | const anon_struct = inst_ty.castTag(.anon_struct).?.data; | ||
| 28534 | const field_name = anon_struct.names[0]; | ||
| 28535 | const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty); | ||
| 28536 | return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src); | ||
| 28537 | } | 29218 | } |
| 28538 | 29219 | ||
| 28539 | fn coerceAnonStructToUnionPtrs( | 29220 | fn coerceAnonStructToUnionPtrs( |
| ... | @@ -28544,7 +29225,8 @@ fn coerceAnonStructToUnionPtrs( | ... | @@ -28544,7 +29225,8 @@ fn coerceAnonStructToUnionPtrs( |
| 28544 | ptr_anon_struct: Air.Inst.Ref, | 29225 | ptr_anon_struct: Air.Inst.Ref, |
| 28545 | anon_struct_src: LazySrcLoc, | 29226 | anon_struct_src: LazySrcLoc, |
| 28546 | ) !Air.Inst.Ref { | 29227 | ) !Air.Inst.Ref { |
| 28547 | const union_ty = ptr_union_ty.childType(); | 29228 | const mod = sema.mod; |
| 29229 | const union_ty = ptr_union_ty.childType(mod); | ||
| 28548 | const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src); | 29230 | const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src); |
| 28549 | const union_inst = try sema.coerceAnonStructToUnion(block, union_ty, union_ty_src, anon_struct, anon_struct_src); | 29231 | const union_inst = try sema.coerceAnonStructToUnion(block, union_ty, union_ty_src, anon_struct, anon_struct_src); |
| 28550 | return sema.analyzeRef(block, union_ty_src, union_inst); | 29232 | return sema.analyzeRef(block, union_ty_src, union_inst); |
| ... | @@ -28558,7 +29240,8 @@ fn coerceAnonStructToStructPtrs( | ... | @@ -28558,7 +29240,8 @@ fn coerceAnonStructToStructPtrs( |
| 28558 | ptr_anon_struct: Air.Inst.Ref, | 29240 | ptr_anon_struct: Air.Inst.Ref, |
| 28559 | anon_struct_src: LazySrcLoc, | 29241 | anon_struct_src: LazySrcLoc, |
| 28560 | ) !Air.Inst.Ref { | 29242 | ) !Air.Inst.Ref { |
| 28561 | const struct_ty = ptr_struct_ty.childType(); | 29243 | const mod = sema.mod; |
| 29244 | const struct_ty = ptr_struct_ty.childType(mod); | ||
| 28562 | const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src); | 29245 | const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src); |
| 28563 | const struct_inst = try sema.coerceTupleToStruct(block, struct_ty, anon_struct, anon_struct_src); | 29246 | const struct_inst = try sema.coerceTupleToStruct(block, struct_ty, anon_struct, anon_struct_src); |
| 28564 | return sema.analyzeRef(block, struct_ty_src, struct_inst); | 29247 | return sema.analyzeRef(block, struct_ty_src, struct_inst); |
| ... | @@ -28573,15 +29256,16 @@ fn coerceArrayLike( | ... | @@ -28573,15 +29256,16 @@ fn coerceArrayLike( |
| 28573 | inst: Air.Inst.Ref, | 29256 | inst: Air.Inst.Ref, |
| 28574 | inst_src: LazySrcLoc, | 29257 | inst_src: LazySrcLoc, |
| 28575 | ) !Air.Inst.Ref { | 29258 | ) !Air.Inst.Ref { |
| 29259 | const mod = sema.mod; | ||
| 28576 | const inst_ty = sema.typeOf(inst); | 29260 | const inst_ty = sema.typeOf(inst); |
| 28577 | const inst_len = inst_ty.arrayLen(); | 29261 | const inst_len = inst_ty.arrayLen(mod); |
| 28578 | const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen()); | 29262 | const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(mod)); |
| 28579 | const target = sema.mod.getTarget(); | 29263 | const target = mod.getTarget(); |
| 28580 | 29264 | ||
| 28581 | if (dest_len != inst_len) { | 29265 | if (dest_len != inst_len) { |
| 28582 | const msg = msg: { | 29266 | const msg = msg: { |
| 28583 | const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ | 29267 | const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ |
| 28584 | dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod), | 29268 | dest_ty.fmt(mod), inst_ty.fmt(mod), |
| 28585 | }); | 29269 | }); |
| 28586 | errdefer msg.destroy(sema.gpa); | 29270 | errdefer msg.destroy(sema.gpa); |
| 28587 | try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len}); | 29271 | try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len}); |
| ... | @@ -28591,35 +29275,32 @@ fn coerceArrayLike( | ... | @@ -28591,35 +29275,32 @@ fn coerceArrayLike( |
| 28591 | return sema.failWithOwnedErrorMsg(msg); | 29275 | return sema.failWithOwnedErrorMsg(msg); |
| 28592 | } | 29276 | } |
| 28593 | 29277 | ||
| 28594 | const dest_elem_ty = dest_ty.childType(); | 29278 | const dest_elem_ty = dest_ty.childType(mod); |
| 28595 | const inst_elem_ty = inst_ty.childType(); | 29279 | const inst_elem_ty = inst_ty.childType(mod); |
| 28596 | const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src); | 29280 | const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src); |
| 28597 | if (in_memory_result == .ok) { | 29281 | if (in_memory_result == .ok) { |
| 28598 | if (try sema.resolveMaybeUndefVal(inst)) |inst_val| { | 29282 | if (try sema.resolveMaybeUndefVal(inst)) |inst_val| { |
| 28599 | // These types share the same comptime value representation. | 29283 | // These types share the same comptime value representation. |
| 28600 | return sema.addConstant(dest_ty, inst_val); | 29284 | return sema.coerceInMemory(block, inst_val, inst_ty, dest_ty, dest_ty_src); |
| 28601 | } | 29285 | } |
| 28602 | try sema.requireRuntimeBlock(block, inst_src, null); | 29286 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 28603 | return block.addBitCast(dest_ty, inst); | 29287 | return block.addBitCast(dest_ty, inst); |
| 28604 | } | 29288 | } |
| 28605 | 29289 | ||
| 28606 | const element_vals = try sema.arena.alloc(Value, dest_len); | 29290 | const element_vals = try sema.arena.alloc(InternPool.Index, dest_len); |
| 28607 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_len); | 29291 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_len); |
| 28608 | var runtime_src: ?LazySrcLoc = null; | 29292 | var runtime_src: ?LazySrcLoc = null; |
| 28609 | 29293 | ||
| 28610 | for (element_vals, 0..) |*elem, i| { | 29294 | for (element_vals, element_refs, 0..) |*val, *ref, i| { |
| 28611 | const index_ref = try sema.addConstant( | 29295 | const index_ref = try sema.addConstant(Type.usize, try mod.intValue(Type.usize, i)); |
| 28612 | Type.usize, | ||
| 28613 | try Value.Tag.int_u64.create(sema.arena, i), | ||
| 28614 | ); | ||
| 28615 | const src = inst_src; // TODO better source location | 29296 | const src = inst_src; // TODO better source location |
| 28616 | const elem_src = inst_src; // TODO better source location | 29297 | const elem_src = inst_src; // TODO better source location |
| 28617 | const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref, true); | 29298 | const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref, true); |
| 28618 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); | 29299 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); |
| 28619 | element_refs[i] = coerced; | 29300 | ref.* = coerced; |
| 28620 | if (runtime_src == null) { | 29301 | if (runtime_src == null) { |
| 28621 | if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| { | 29302 | if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| { |
| 28622 | elem.* = elem_val; | 29303 | val.* = try elem_val.intern(dest_elem_ty, mod); |
| 28623 | } else { | 29304 | } else { |
| 28624 | runtime_src = elem_src; | 29305 | runtime_src = elem_src; |
| 28625 | } | 29306 | } |
| ... | @@ -28631,10 +29312,10 @@ fn coerceArrayLike( | ... | @@ -28631,10 +29312,10 @@ fn coerceArrayLike( |
| 28631 | return block.addAggregateInit(dest_ty, element_refs); | 29312 | return block.addAggregateInit(dest_ty, element_refs); |
| 28632 | } | 29313 | } |
| 28633 | 29314 | ||
| 28634 | return sema.addConstant( | 29315 | return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{ |
| 28635 | dest_ty, | 29316 | .ty = dest_ty.toIntern(), |
| 28636 | try Value.Tag.aggregate.create(sema.arena, element_vals), | 29317 | .storage = .{ .elems = element_vals }, |
| 28637 | ); | 29318 | } })).toValue()); |
| 28638 | } | 29319 | } |
| 28639 | 29320 | ||
| 28640 | /// If the lengths match, coerces element-wise. | 29321 | /// If the lengths match, coerces element-wise. |
| ... | @@ -28646,9 +29327,10 @@ fn coerceTupleToArray( | ... | @@ -28646,9 +29327,10 @@ fn coerceTupleToArray( |
| 28646 | inst: Air.Inst.Ref, | 29327 | inst: Air.Inst.Ref, |
| 28647 | inst_src: LazySrcLoc, | 29328 | inst_src: LazySrcLoc, |
| 28648 | ) !Air.Inst.Ref { | 29329 | ) !Air.Inst.Ref { |
| 29330 | const mod = sema.mod; | ||
| 28649 | const inst_ty = sema.typeOf(inst); | 29331 | const inst_ty = sema.typeOf(inst); |
| 28650 | const inst_len = inst_ty.arrayLen(); | 29332 | const inst_len = inst_ty.arrayLen(mod); |
| 28651 | const dest_len = dest_ty.arrayLen(); | 29333 | const dest_len = dest_ty.arrayLen(mod); |
| 28652 | 29334 | ||
| 28653 | if (dest_len != inst_len) { | 29335 | if (dest_len != inst_len) { |
| 28654 | const msg = msg: { | 29336 | const msg = msg: { |
| ... | @@ -28663,26 +29345,27 @@ fn coerceTupleToArray( | ... | @@ -28663,26 +29345,27 @@ fn coerceTupleToArray( |
| 28663 | return sema.failWithOwnedErrorMsg(msg); | 29345 | return sema.failWithOwnedErrorMsg(msg); |
| 28664 | } | 29346 | } |
| 28665 | 29347 | ||
| 28666 | const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLenIncludingSentinel()); | 29348 | const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_len); |
| 28667 | const element_vals = try sema.arena.alloc(Value, dest_elems); | 29349 | const element_vals = try sema.arena.alloc(InternPool.Index, dest_elems); |
| 28668 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_elems); | 29350 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_elems); |
| 28669 | const dest_elem_ty = dest_ty.childType(); | 29351 | const dest_elem_ty = dest_ty.childType(mod); |
| 28670 | 29352 | ||
| 28671 | var runtime_src: ?LazySrcLoc = null; | 29353 | var runtime_src: ?LazySrcLoc = null; |
| 28672 | for (element_vals, 0..) |*elem, i_usize| { | 29354 | for (element_vals, element_refs, 0..) |*val, *ref, i_usize| { |
| 28673 | const i = @intCast(u32, i_usize); | 29355 | const i = @intCast(u32, i_usize); |
| 28674 | if (i_usize == inst_len) { | 29356 | if (i_usize == inst_len) { |
| 28675 | elem.* = dest_ty.sentinel().?; | 29357 | const sentinel_val = dest_ty.sentinel(mod).?; |
| 28676 | element_refs[i] = try sema.addConstant(dest_elem_ty, elem.*); | 29358 | val.* = sentinel_val.toIntern(); |
| 29359 | ref.* = try sema.addConstant(dest_elem_ty, sentinel_val); | ||
| 28677 | break; | 29360 | break; |
| 28678 | } | 29361 | } |
| 28679 | const elem_src = inst_src; // TODO better source location | 29362 | const elem_src = inst_src; // TODO better source location |
| 28680 | const elem_ref = try sema.tupleField(block, inst_src, inst, elem_src, i); | 29363 | const elem_ref = try sema.tupleField(block, inst_src, inst, elem_src, i); |
| 28681 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); | 29364 | const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src); |
| 28682 | element_refs[i] = coerced; | 29365 | ref.* = coerced; |
| 28683 | if (runtime_src == null) { | 29366 | if (runtime_src == null) { |
| 28684 | if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| { | 29367 | if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| { |
| 28685 | elem.* = elem_val; | 29368 | val.* = try elem_val.intern(dest_elem_ty, mod); |
| 28686 | } else { | 29369 | } else { |
| 28687 | runtime_src = elem_src; | 29370 | runtime_src = elem_src; |
| 28688 | } | 29371 | } |
| ... | @@ -28694,10 +29377,10 @@ fn coerceTupleToArray( | ... | @@ -28694,10 +29377,10 @@ fn coerceTupleToArray( |
| 28694 | return block.addAggregateInit(dest_ty, element_refs); | 29377 | return block.addAggregateInit(dest_ty, element_refs); |
| 28695 | } | 29378 | } |
| 28696 | 29379 | ||
| 28697 | return sema.addConstant( | 29380 | return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{ |
| 28698 | dest_ty, | 29381 | .ty = dest_ty.toIntern(), |
| 28699 | try Value.Tag.aggregate.create(sema.arena, element_vals), | 29382 | .storage = .{ .elems = element_vals }, |
| 28700 | ); | 29383 | } })).toValue()); |
| 28701 | } | 29384 | } |
| 28702 | 29385 | ||
| 28703 | /// If the lengths match, coerces element-wise. | 29386 | /// If the lengths match, coerces element-wise. |
| ... | @@ -28709,10 +29392,11 @@ fn coerceTupleToSlicePtrs( | ... | @@ -28709,10 +29392,11 @@ fn coerceTupleToSlicePtrs( |
| 28709 | ptr_tuple: Air.Inst.Ref, | 29392 | ptr_tuple: Air.Inst.Ref, |
| 28710 | tuple_src: LazySrcLoc, | 29393 | tuple_src: LazySrcLoc, |
| 28711 | ) !Air.Inst.Ref { | 29394 | ) !Air.Inst.Ref { |
| 28712 | const tuple_ty = sema.typeOf(ptr_tuple).childType(); | 29395 | const mod = sema.mod; |
| 29396 | const tuple_ty = sema.typeOf(ptr_tuple).childType(mod); | ||
| 28713 | const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src); | 29397 | const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src); |
| 28714 | const slice_info = slice_ty.ptrInfo().data; | 29398 | const slice_info = slice_ty.ptrInfo(mod); |
| 28715 | const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(), slice_info.sentinel, slice_info.pointee_type, sema.mod); | 29399 | const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(mod), slice_info.sentinel, slice_info.pointee_type, sema.mod); |
| 28716 | const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src); | 29400 | const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src); |
| 28717 | if (slice_info.@"align" != 0) { | 29401 | if (slice_info.@"align" != 0) { |
| 28718 | return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{}); | 29402 | return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{}); |
| ... | @@ -28730,8 +29414,9 @@ fn coerceTupleToArrayPtrs( | ... | @@ -28730,8 +29414,9 @@ fn coerceTupleToArrayPtrs( |
| 28730 | ptr_tuple: Air.Inst.Ref, | 29414 | ptr_tuple: Air.Inst.Ref, |
| 28731 | tuple_src: LazySrcLoc, | 29415 | tuple_src: LazySrcLoc, |
| 28732 | ) !Air.Inst.Ref { | 29416 | ) !Air.Inst.Ref { |
| 29417 | const mod = sema.mod; | ||
| 28733 | const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src); | 29418 | const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src); |
| 28734 | const ptr_info = ptr_array_ty.ptrInfo().data; | 29419 | const ptr_info = ptr_array_ty.ptrInfo(mod); |
| 28735 | const array_ty = ptr_info.pointee_type; | 29420 | const array_ty = ptr_info.pointee_type; |
| 28736 | const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src); | 29421 | const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src); |
| 28737 | if (ptr_info.@"align" != 0) { | 29422 | if (ptr_info.@"align" != 0) { |
| ... | @@ -28750,27 +29435,41 @@ fn coerceTupleToStruct( | ... | @@ -28750,27 +29435,41 @@ fn coerceTupleToStruct( |
| 28750 | inst: Air.Inst.Ref, | 29435 | inst: Air.Inst.Ref, |
| 28751 | inst_src: LazySrcLoc, | 29436 | inst_src: LazySrcLoc, |
| 28752 | ) !Air.Inst.Ref { | 29437 | ) !Air.Inst.Ref { |
| 29438 | const mod = sema.mod; | ||
| 29439 | const ip = &mod.intern_pool; | ||
| 28753 | const struct_ty = try sema.resolveTypeFields(dest_ty); | 29440 | const struct_ty = try sema.resolveTypeFields(dest_ty); |
| 28754 | 29441 | ||
| 28755 | if (struct_ty.isTupleOrAnonStruct()) { | 29442 | if (struct_ty.isTupleOrAnonStruct(mod)) { |
| 28756 | return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); | 29443 | return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src); |
| 28757 | } | 29444 | } |
| 28758 | 29445 | ||
| 28759 | const fields = struct_ty.structFields(); | 29446 | const fields = struct_ty.structFields(mod); |
| 28760 | const field_vals = try sema.arena.alloc(Value, fields.count()); | 29447 | const field_vals = try sema.arena.alloc(InternPool.Index, fields.count()); |
| 28761 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); | 29448 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); |
| 28762 | @memset(field_refs, .none); | 29449 | @memset(field_refs, .none); |
| 28763 | 29450 | ||
| 28764 | const inst_ty = sema.typeOf(inst); | 29451 | const inst_ty = sema.typeOf(inst); |
| 28765 | var runtime_src: ?LazySrcLoc = null; | 29452 | var runtime_src: ?LazySrcLoc = null; |
| 28766 | const field_count = inst_ty.structFieldCount(); | 29453 | const field_count = switch (ip.indexToKey(inst_ty.toIntern())) { |
| 28767 | var field_i: u32 = 0; | 29454 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, |
| 28768 | while (field_i < field_count) : (field_i += 1) { | 29455 | .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| |
| 28769 | const field_src = inst_src; // TODO better source location | 29456 | struct_obj.fields.count() |
| 28770 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| | ||
| 28771 | payload.data.names[field_i] | ||
| 28772 | else | 29457 | else |
| 28773 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); | 29458 | 0, |
| 29459 | else => unreachable, | ||
| 29460 | }; | ||
| 29461 | for (0..field_count) |field_index_usize| { | ||
| 29462 | const field_i = @intCast(u32, field_index_usize); | ||
| 29463 | const field_src = inst_src; // TODO better source location | ||
| 29464 | // https://github.com/ziglang/zig/issues/15709 | ||
| 29465 | const field_name: InternPool.NullTerminatedString = switch (ip.indexToKey(inst_ty.toIntern())) { | ||
| 29466 | .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0) | ||
| 29467 | anon_struct_type.names[field_i] | ||
| 29468 | else | ||
| 29469 | try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}), | ||
| 29470 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i], | ||
| 29471 | else => unreachable, | ||
| 29472 | }; | ||
| 28774 | const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); | 29473 | const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src); |
| 28775 | const field = fields.values()[field_index]; | 29474 | const field = fields.values()[field_index]; |
| 28776 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); | 29475 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); |
| ... | @@ -28781,13 +29480,13 @@ fn coerceTupleToStruct( | ... | @@ -28781,13 +29480,13 @@ fn coerceTupleToStruct( |
| 28781 | return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); | 29480 | return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); |
| 28782 | }; | 29481 | }; |
| 28783 | 29482 | ||
| 28784 | if (!init_val.eql(field.default_val, field.ty, sema.mod)) { | 29483 | if (!init_val.eql(field.default_val.toValue(), field.ty, sema.mod)) { |
| 28785 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); | 29484 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); |
| 28786 | } | 29485 | } |
| 28787 | } | 29486 | } |
| 28788 | if (runtime_src == null) { | 29487 | if (runtime_src == null) { |
| 28789 | if (try sema.resolveMaybeUndefVal(coerced)) |field_val| { | 29488 | if (try sema.resolveMaybeUndefVal(coerced)) |field_val| { |
| 28790 | field_vals[field_index] = field_val; | 29489 | field_vals[field_index] = field_val.toIntern(); |
| 28791 | } else { | 29490 | } else { |
| 28792 | runtime_src = field_src; | 29491 | runtime_src = field_src; |
| 28793 | } | 29492 | } |
| ... | @@ -28804,9 +29503,9 @@ fn coerceTupleToStruct( | ... | @@ -28804,9 +29503,9 @@ fn coerceTupleToStruct( |
| 28804 | const field_name = fields.keys()[i]; | 29503 | const field_name = fields.keys()[i]; |
| 28805 | const field = fields.values()[i]; | 29504 | const field = fields.values()[i]; |
| 28806 | const field_src = inst_src; // TODO better source location | 29505 | const field_src = inst_src; // TODO better source location |
| 28807 | if (field.default_val.tag() == .unreachable_value) { | 29506 | if (field.default_val == .none) { |
| 28808 | const template = "missing struct field: {s}"; | 29507 | const template = "missing struct field: {}"; |
| 28809 | const args = .{field_name}; | 29508 | const args = .{field_name.fmt(ip)}; |
| 28810 | if (root_msg) |msg| { | 29509 | if (root_msg) |msg| { |
| 28811 | try sema.errNote(block, field_src, msg, template, args); | 29510 | try sema.errNote(block, field_src, msg, template, args); |
| 28812 | } else { | 29511 | } else { |
| ... | @@ -28817,7 +29516,7 @@ fn coerceTupleToStruct( | ... | @@ -28817,7 +29516,7 @@ fn coerceTupleToStruct( |
| 28817 | if (runtime_src == null) { | 29516 | if (runtime_src == null) { |
| 28818 | field_vals[i] = field.default_val; | 29517 | field_vals[i] = field.default_val; |
| 28819 | } else { | 29518 | } else { |
| 28820 | field_ref.* = try sema.addConstant(field.ty, field.default_val); | 29519 | field_ref.* = try sema.addConstant(field.ty, field.default_val.toValue()); |
| 28821 | } | 29520 | } |
| 28822 | } | 29521 | } |
| 28823 | 29522 | ||
| ... | @@ -28832,10 +29531,14 @@ fn coerceTupleToStruct( | ... | @@ -28832,10 +29531,14 @@ fn coerceTupleToStruct( |
| 28832 | return block.addAggregateInit(struct_ty, field_refs); | 29531 | return block.addAggregateInit(struct_ty, field_refs); |
| 28833 | } | 29532 | } |
| 28834 | 29533 | ||
| 28835 | return sema.addConstant( | 29534 | const struct_val = try mod.intern(.{ .aggregate = .{ |
| 28836 | struct_ty, | 29535 | .ty = struct_ty.toIntern(), |
| 28837 | try Value.Tag.aggregate.create(sema.arena, field_vals), | 29536 | .storage = .{ .elems = field_vals }, |
| 28838 | ); | 29537 | } }); |
| 29538 | // TODO: figure out InternPool removals for incremental compilation | ||
| 29539 | //errdefer ip.remove(struct_val); | ||
| 29540 | |||
| 29541 | return sema.addConstant(struct_ty, struct_val.toValue()); | ||
| 28839 | } | 29542 | } |
| 28840 | 29543 | ||
| 28841 | fn coerceTupleToTuple( | 29544 | fn coerceTupleToTuple( |
| ... | @@ -28845,47 +29548,76 @@ fn coerceTupleToTuple( | ... | @@ -28845,47 +29548,76 @@ fn coerceTupleToTuple( |
| 28845 | inst: Air.Inst.Ref, | 29548 | inst: Air.Inst.Ref, |
| 28846 | inst_src: LazySrcLoc, | 29549 | inst_src: LazySrcLoc, |
| 28847 | ) !Air.Inst.Ref { | 29550 | ) !Air.Inst.Ref { |
| 28848 | const dest_field_count = tuple_ty.structFieldCount(); | 29551 | const mod = sema.mod; |
| 28849 | const field_vals = try sema.arena.alloc(Value, dest_field_count); | 29552 | const ip = &mod.intern_pool; |
| 29553 | const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) { | ||
| 29554 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, | ||
| 29555 | .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| | ||
| 29556 | struct_obj.fields.count() | ||
| 29557 | else | ||
| 29558 | 0, | ||
| 29559 | else => unreachable, | ||
| 29560 | }; | ||
| 29561 | const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count); | ||
| 28850 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); | 29562 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); |
| 28851 | @memset(field_refs, .none); | 29563 | @memset(field_refs, .none); |
| 28852 | 29564 | ||
| 28853 | const inst_ty = sema.typeOf(inst); | 29565 | const inst_ty = sema.typeOf(inst); |
| 28854 | const inst_field_count = inst_ty.structFieldCount(); | 29566 | const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) { |
| 28855 | if (inst_field_count > dest_field_count) return error.NotCoercible; | 29567 | .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, |
| 29568 | .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| | ||
| 29569 | struct_obj.fields.count() | ||
| 29570 | else | ||
| 29571 | 0, | ||
| 29572 | else => unreachable, | ||
| 29573 | }; | ||
| 29574 | if (src_field_count > dest_field_count) return error.NotCoercible; | ||
| 28856 | 29575 | ||
| 28857 | var runtime_src: ?LazySrcLoc = null; | 29576 | var runtime_src: ?LazySrcLoc = null; |
| 28858 | var field_i: u32 = 0; | 29577 | for (0..dest_field_count) |field_index_usize| { |
| 28859 | while (field_i < inst_field_count) : (field_i += 1) { | 29578 | const field_i = @intCast(u32, field_index_usize); |
| 28860 | const field_src = inst_src; // TODO better source location | 29579 | const field_src = inst_src; // TODO better source location |
| 28861 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| | 29580 | // https://github.com/ziglang/zig/issues/15709 |
| 28862 | payload.data.names[field_i] | 29581 | const field_name: InternPool.NullTerminatedString = switch (ip.indexToKey(inst_ty.toIntern())) { |
| 28863 | else | 29582 | .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0) |
| 28864 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}); | 29583 | anon_struct_type.names[field_i] |
| 29584 | else | ||
| 29585 | try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}), | ||
| 29586 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i], | ||
| 29587 | else => unreachable, | ||
| 29588 | }; | ||
| 28865 | 29589 | ||
| 28866 | if (mem.eql(u8, field_name, "len")) { | 29590 | if (ip.stringEqlSlice(field_name, "len")) |
| 28867 | return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); | 29591 | return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); |
| 28868 | } | 29592 | |
| 29593 | const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) { | ||
| 29594 | .anon_struct_type => |anon_struct_type| anon_struct_type.types[field_index_usize].toType(), | ||
| 29595 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].ty, | ||
| 29596 | else => unreachable, | ||
| 29597 | }; | ||
| 29598 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { | ||
| 29599 | .anon_struct_type => |anon_struct_type| anon_struct_type.values[field_index_usize], | ||
| 29600 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].default_val, | ||
| 29601 | else => unreachable, | ||
| 29602 | }; | ||
| 28869 | 29603 | ||
| 28870 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); | 29604 | const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src); |
| 28871 | 29605 | ||
| 28872 | const field_ty = tuple_ty.structFieldType(field_i); | ||
| 28873 | const default_val = tuple_ty.structFieldDefaultValue(field_i); | ||
| 28874 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); | 29606 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); |
| 28875 | const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); | 29607 | const coerced = try sema.coerce(block, field_ty, elem_ref, field_src); |
| 28876 | field_refs[field_index] = coerced; | 29608 | field_refs[field_index] = coerced; |
| 28877 | if (default_val.tag() != .unreachable_value) { | 29609 | if (default_val != .none) { |
| 28878 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { | 29610 | const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| 28879 | return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); | 29611 | return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); |
| 28880 | }; | 29612 | }; |
| 28881 | 29613 | ||
| 28882 | if (!init_val.eql(default_val, field_ty, sema.mod)) { | 29614 | if (!init_val.eql(default_val.toValue(), field_ty, sema.mod)) { |
| 28883 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); | 29615 | return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); |
| 28884 | } | 29616 | } |
| 28885 | } | 29617 | } |
| 28886 | if (runtime_src == null) { | 29618 | if (runtime_src == null) { |
| 28887 | if (try sema.resolveMaybeUndefVal(coerced)) |field_val| { | 29619 | if (try sema.resolveMaybeUndefVal(coerced)) |field_val| { |
| 28888 | field_vals[field_index] = field_val; | 29620 | field_vals[field_index] = field_val.toIntern(); |
| 28889 | } else { | 29621 | } else { |
| 28890 | runtime_src = field_src; | 29622 | runtime_src = field_src; |
| 28891 | } | 29623 | } |
| ... | @@ -28899,12 +29631,15 @@ fn coerceTupleToTuple( | ... | @@ -28899,12 +29631,15 @@ fn coerceTupleToTuple( |
| 28899 | for (field_refs, 0..) |*field_ref, i| { | 29631 | for (field_refs, 0..) |*field_ref, i| { |
| 28900 | if (field_ref.* != .none) continue; | 29632 | if (field_ref.* != .none) continue; |
| 28901 | 29633 | ||
| 28902 | const default_val = tuple_ty.structFieldDefaultValue(i); | 29634 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { |
| 28903 | const field_ty = tuple_ty.structFieldType(i); | 29635 | .anon_struct_type => |anon_struct_type| anon_struct_type.values[i], |
| 29636 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].default_val, | ||
| 29637 | else => unreachable, | ||
| 29638 | }; | ||
| 28904 | 29639 | ||
| 28905 | const field_src = inst_src; // TODO better source location | 29640 | const field_src = inst_src; // TODO better source location |
| 28906 | if (default_val.tag() == .unreachable_value) { | 29641 | if (default_val == .none) { |
| 28907 | if (tuple_ty.isTuple()) { | 29642 | if (tuple_ty.isTuple(mod)) { |
| 28908 | const template = "missing tuple field: {d}"; | 29643 | const template = "missing tuple field: {d}"; |
| 28909 | if (root_msg) |msg| { | 29644 | if (root_msg) |msg| { |
| 28910 | try sema.errNote(block, field_src, msg, template, .{i}); | 29645 | try sema.errNote(block, field_src, msg, template, .{i}); |
| ... | @@ -28913,8 +29648,8 @@ fn coerceTupleToTuple( | ... | @@ -28913,8 +29648,8 @@ fn coerceTupleToTuple( |
| 28913 | } | 29648 | } |
| 28914 | continue; | 29649 | continue; |
| 28915 | } | 29650 | } |
| 28916 | const template = "missing struct field: {s}"; | 29651 | const template = "missing struct field: {}"; |
| 28917 | const args = .{tuple_ty.structFieldName(i)}; | 29652 | const args = .{tuple_ty.structFieldName(i, mod).fmt(ip)}; |
| 28918 | if (root_msg) |msg| { | 29653 | if (root_msg) |msg| { |
| 28919 | try sema.errNote(block, field_src, msg, template, args); | 29654 | try sema.errNote(block, field_src, msg, template, args); |
| 28920 | } else { | 29655 | } else { |
| ... | @@ -28925,7 +29660,12 @@ fn coerceTupleToTuple( | ... | @@ -28925,7 +29660,12 @@ fn coerceTupleToTuple( |
| 28925 | if (runtime_src == null) { | 29660 | if (runtime_src == null) { |
| 28926 | field_vals[i] = default_val; | 29661 | field_vals[i] = default_val; |
| 28927 | } else { | 29662 | } else { |
| 28928 | field_ref.* = try sema.addConstant(field_ty, default_val); | 29663 | const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) { |
| 29664 | .anon_struct_type => |anon_struct_type| anon_struct_type.types[i].toType(), | ||
| 29665 | .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].ty, | ||
| 29666 | else => unreachable, | ||
| 29667 | }; | ||
| 29668 | field_ref.* = try sema.addConstant(field_ty, default_val.toValue()); | ||
| 28929 | } | 29669 | } |
| 28930 | } | 29670 | } |
| 28931 | 29671 | ||
| ... | @@ -28942,7 +29682,10 @@ fn coerceTupleToTuple( | ... | @@ -28942,7 +29682,10 @@ fn coerceTupleToTuple( |
| 28942 | 29682 | ||
| 28943 | return sema.addConstant( | 29683 | return sema.addConstant( |
| 28944 | tuple_ty, | 29684 | tuple_ty, |
| 28945 | try Value.Tag.aggregate.create(sema.arena, field_vals), | 29685 | (try mod.intern(.{ .aggregate = .{ |
| 29686 | .ty = tuple_ty.toIntern(), | ||
| 29687 | .storage = .{ .elems = field_vals }, | ||
| 29688 | } })).toValue(), | ||
| 28946 | ); | 29689 | ); |
| 28947 | } | 29690 | } |
| 28948 | 29691 | ||
| ... | @@ -28959,7 +29702,7 @@ fn analyzeDeclVal( | ... | @@ -28959,7 +29702,7 @@ fn analyzeDeclVal( |
| 28959 | const decl_ref = try sema.analyzeDeclRefInner(decl_index, false); | 29702 | const decl_ref = try sema.analyzeDeclRefInner(decl_index, false); |
| 28960 | const result = try sema.analyzeLoad(block, src, decl_ref, src); | 29703 | const result = try sema.analyzeLoad(block, src, decl_ref, src); |
| 28961 | if (Air.refToIndex(result)) |index| { | 29704 | if (Air.refToIndex(result)) |index| { |
| 28962 | if (sema.air_instructions.items(.tag)[index] == .constant and !block.is_typeof) { | 29705 | if (sema.air_instructions.items(.tag)[index] == .interned and !block.is_typeof) { |
| 28963 | try sema.decl_val_table.put(sema.gpa, decl_index, result); | 29706 | try sema.decl_val_table.put(sema.gpa, decl_index, result); |
| 28964 | } | 29707 | } |
| 28965 | } | 29708 | } |
| ... | @@ -28980,13 +29723,14 @@ fn addReferencedBy( | ... | @@ -28980,13 +29723,14 @@ fn addReferencedBy( |
| 28980 | } | 29723 | } |
| 28981 | 29724 | ||
| 28982 | fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void { | 29725 | fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void { |
| 28983 | const decl = sema.mod.declPtr(decl_index); | 29726 | const mod = sema.mod; |
| 29727 | const decl = mod.declPtr(decl_index); | ||
| 28984 | if (decl.analysis == .in_progress) { | 29728 | if (decl.analysis == .in_progress) { |
| 28985 | const msg = try Module.ErrorMsg.create(sema.gpa, decl.srcLoc(), "dependency loop detected", .{}); | 29729 | const msg = try Module.ErrorMsg.create(sema.gpa, decl.srcLoc(mod), "dependency loop detected", .{}); |
| 28986 | return sema.failWithOwnedErrorMsg(msg); | 29730 | return sema.failWithOwnedErrorMsg(msg); |
| 28987 | } | 29731 | } |
| 28988 | 29732 | ||
| 28989 | sema.mod.ensureDeclAnalyzed(decl_index) catch |err| { | 29733 | mod.ensureDeclAnalyzed(decl_index) catch |err| { |
| 28990 | if (sema.owner_func) |owner_func| { | 29734 | if (sema.owner_func) |owner_func| { |
| 28991 | owner_func.state = .dependency_failure; | 29735 | owner_func.state = .dependency_failure; |
| 28992 | } else { | 29736 | } else { |
| ... | @@ -28996,7 +29740,7 @@ fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void { | ... | @@ -28996,7 +29740,7 @@ fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void { |
| 28996 | }; | 29740 | }; |
| 28997 | } | 29741 | } |
| 28998 | 29742 | ||
| 28999 | fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void { | 29743 | fn ensureFuncBodyAnalyzed(sema: *Sema, func: Module.Fn.Index) CompileError!void { |
| 29000 | sema.mod.ensureFuncBodyAnalyzed(func) catch |err| { | 29744 | sema.mod.ensureFuncBodyAnalyzed(func) catch |err| { |
| 29001 | if (sema.owner_func) |owner_func| { | 29745 | if (sema.owner_func) |owner_func| { |
| 29002 | owner_func.state = .dependency_failure; | 29746 | owner_func.state = .dependency_failure; |
| ... | @@ -29008,23 +29752,33 @@ fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void { | ... | @@ -29008,23 +29752,33 @@ fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void { |
| 29008 | } | 29752 | } |
| 29009 | 29753 | ||
| 29010 | fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value { | 29754 | fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value { |
| 29755 | const mod = sema.mod; | ||
| 29011 | var anon_decl = try block.startAnonDecl(); | 29756 | var anon_decl = try block.startAnonDecl(); |
| 29012 | defer anon_decl.deinit(); | 29757 | defer anon_decl.deinit(); |
| 29013 | const decl = try anon_decl.finish( | 29758 | const decl = try anon_decl.finish( |
| 29014 | try ty.copy(anon_decl.arena()), | 29759 | ty, |
| 29015 | try val.copy(anon_decl.arena()), | 29760 | val, |
| 29016 | 0, // default alignment | 29761 | 0, // default alignment |
| 29017 | ); | 29762 | ); |
| 29018 | try sema.maybeQueueFuncBodyAnalysis(decl); | 29763 | try sema.maybeQueueFuncBodyAnalysis(decl); |
| 29019 | try sema.mod.declareDeclDependency(sema.owner_decl_index, decl); | 29764 | try mod.declareDeclDependency(sema.owner_decl_index, decl); |
| 29020 | return try Value.Tag.decl_ref.create(sema.arena, decl); | 29765 | const result = try mod.intern(.{ .ptr = .{ |
| 29766 | .ty = (try mod.singleConstPtrType(ty)).toIntern(), | ||
| 29767 | .addr = .{ .decl = decl }, | ||
| 29768 | } }); | ||
| 29769 | return result.toValue(); | ||
| 29021 | } | 29770 | } |
| 29022 | 29771 | ||
| 29023 | fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value { | 29772 | fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value { |
| 29024 | const val = opt_val orelse return Value.null; | 29773 | const mod = sema.mod; |
| 29025 | const ptr_val = try sema.refValue(block, ty, val); | 29774 | const ptr_anyopaque_ty = try mod.singleConstPtrType(Type.anyopaque); |
| 29026 | const result = try Value.Tag.opt_payload.create(sema.arena, ptr_val); | 29775 | return (try mod.intern(.{ .opt = .{ |
| 29027 | return result; | 29776 | .ty = (try mod.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(), |
| 29777 | .val = if (opt_val) |val| (try mod.getCoerced( | ||
| 29778 | try sema.refValue(block, ty, val), | ||
| 29779 | ptr_anyopaque_ty, | ||
| 29780 | )).toIntern() else .none, | ||
| 29781 | } })).toValue(); | ||
| 29028 | } | 29782 | } |
| 29029 | 29783 | ||
| 29030 | fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref { | 29784 | fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -29036,42 +29790,37 @@ fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref | ... | @@ -29036,42 +29790,37 @@ fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref |
| 29036 | /// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps | 29790 | /// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps |
| 29037 | /// this function with `analyze_fn_body` set to true. | 29791 | /// this function with `analyze_fn_body` set to true. |
| 29038 | fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: bool) CompileError!Air.Inst.Ref { | 29792 | fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: bool) CompileError!Air.Inst.Ref { |
| 29039 | try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); | 29793 | const mod = sema.mod; |
| 29794 | try mod.declareDeclDependency(sema.owner_decl_index, decl_index); | ||
| 29040 | try sema.ensureDeclAnalyzed(decl_index); | 29795 | try sema.ensureDeclAnalyzed(decl_index); |
| 29041 | 29796 | ||
| 29042 | const decl = sema.mod.declPtr(decl_index); | 29797 | const decl = mod.declPtr(decl_index); |
| 29043 | const decl_tv = try decl.typedValue(); | 29798 | const decl_tv = try decl.typedValue(); |
| 29044 | if (decl_tv.val.castTag(.variable)) |payload| { | 29799 | const ptr_ty = try mod.ptrType(.{ |
| 29045 | const variable = payload.data; | 29800 | .child = decl_tv.ty.toIntern(), |
| 29046 | const ty = try Type.ptr(sema.arena, sema.mod, .{ | 29801 | .flags = .{ |
| 29047 | .pointee_type = decl_tv.ty, | 29802 | .alignment = InternPool.Alignment.fromByteUnits(decl.@"align"), |
| 29048 | .mutable = variable.is_mutable, | 29803 | .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true, |
| 29049 | .@"addrspace" = decl.@"addrspace", | 29804 | .address_space = decl.@"addrspace", |
| 29050 | .@"align" = decl.@"align", | 29805 | }, |
| 29051 | }); | 29806 | }); |
| 29052 | return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl_index)); | ||
| 29053 | } | ||
| 29054 | if (analyze_fn_body) { | 29807 | if (analyze_fn_body) { |
| 29055 | try sema.maybeQueueFuncBodyAnalysis(decl_index); | 29808 | try sema.maybeQueueFuncBodyAnalysis(decl_index); |
| 29056 | } | 29809 | } |
| 29057 | return sema.addConstant( | 29810 | return sema.addConstant(ptr_ty, (try mod.intern(.{ .ptr = .{ |
| 29058 | try Type.ptr(sema.arena, sema.mod, .{ | 29811 | .ty = ptr_ty.toIntern(), |
| 29059 | .pointee_type = decl_tv.ty, | 29812 | .addr = .{ .decl = decl_index }, |
| 29060 | .mutable = false, | 29813 | } })).toValue()); |
| 29061 | .@"addrspace" = decl.@"addrspace", | ||
| 29062 | .@"align" = decl.@"align", | ||
| 29063 | }), | ||
| 29064 | try Value.Tag.decl_ref.create(sema.arena, decl_index), | ||
| 29065 | ); | ||
| 29066 | } | 29814 | } |
| 29067 | 29815 | ||
| 29068 | fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: Decl.Index) !void { | 29816 | fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: Decl.Index) !void { |
| 29069 | const decl = sema.mod.declPtr(decl_index); | 29817 | const mod = sema.mod; |
| 29818 | const decl = mod.declPtr(decl_index); | ||
| 29070 | const tv = try decl.typedValue(); | 29819 | const tv = try decl.typedValue(); |
| 29071 | if (tv.ty.zigTypeTag() != .Fn) return; | 29820 | if (tv.ty.zigTypeTag(mod) != .Fn) return; |
| 29072 | if (!try sema.fnHasRuntimeBits(tv.ty)) return; | 29821 | if (!try sema.fnHasRuntimeBits(tv.ty)) return; |
| 29073 | const func = tv.val.castTag(.function) orelse return; // undef or extern_fn | 29822 | const func_index = mod.intern_pool.indexToFunc(tv.val.toIntern()).unwrap() orelse return; // undef or extern_fn |
| 29074 | try sema.mod.ensureFuncBodyAnalysisQueued(func.data); | 29823 | try mod.ensureFuncBodyAnalysisQueued(func_index); |
| 29075 | } | 29824 | } |
| 29076 | 29825 | ||
| 29077 | fn analyzeRef( | 29826 | fn analyzeRef( |
| ... | @@ -29083,18 +29832,16 @@ fn analyzeRef( | ... | @@ -29083,18 +29832,16 @@ fn analyzeRef( |
| 29083 | const operand_ty = sema.typeOf(operand); | 29832 | const operand_ty = sema.typeOf(operand); |
| 29084 | 29833 | ||
| 29085 | if (try sema.resolveMaybeUndefVal(operand)) |val| { | 29834 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 29086 | switch (val.tag()) { | 29835 | switch (sema.mod.intern_pool.indexToKey(val.toIntern())) { |
| 29087 | .extern_fn, .function => { | 29836 | .extern_func => |extern_func| return sema.analyzeDeclRef(extern_func.decl), |
| 29088 | const decl_index = val.pointerDecl().?; | 29837 | .func => |func| return sema.analyzeDeclRef(sema.mod.funcPtr(func.index).owner_decl), |
| 29089 | return sema.analyzeDeclRef(decl_index); | ||
| 29090 | }, | ||
| 29091 | else => {}, | 29838 | else => {}, |
| 29092 | } | 29839 | } |
| 29093 | var anon_decl = try block.startAnonDecl(); | 29840 | var anon_decl = try block.startAnonDecl(); |
| 29094 | defer anon_decl.deinit(); | 29841 | defer anon_decl.deinit(); |
| 29095 | return sema.analyzeDeclRef(try anon_decl.finish( | 29842 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 29096 | try operand_ty.copy(anon_decl.arena()), | 29843 | operand_ty, |
| 29097 | try val.copy(anon_decl.arena()), | 29844 | val, |
| 29098 | 0, // default alignment | 29845 | 0, // default alignment |
| 29099 | )); | 29846 | )); |
| 29100 | } | 29847 | } |
| ... | @@ -29124,9 +29871,10 @@ fn analyzeLoad( | ... | @@ -29124,9 +29871,10 @@ fn analyzeLoad( |
| 29124 | ptr: Air.Inst.Ref, | 29871 | ptr: Air.Inst.Ref, |
| 29125 | ptr_src: LazySrcLoc, | 29872 | ptr_src: LazySrcLoc, |
| 29126 | ) CompileError!Air.Inst.Ref { | 29873 | ) CompileError!Air.Inst.Ref { |
| 29874 | const mod = sema.mod; | ||
| 29127 | const ptr_ty = sema.typeOf(ptr); | 29875 | const ptr_ty = sema.typeOf(ptr); |
| 29128 | const elem_ty = switch (ptr_ty.zigTypeTag()) { | 29876 | const elem_ty = switch (ptr_ty.zigTypeTag(mod)) { |
| 29129 | .Pointer => ptr_ty.childType(), | 29877 | .Pointer => ptr_ty.childType(mod), |
| 29130 | else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}), | 29878 | else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}), |
| 29131 | }; | 29879 | }; |
| 29132 | 29880 | ||
| ... | @@ -29136,11 +29884,11 @@ fn analyzeLoad( | ... | @@ -29136,11 +29884,11 @@ fn analyzeLoad( |
| 29136 | 29884 | ||
| 29137 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { | 29885 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { |
| 29138 | if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| { | 29886 | if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| { |
| 29139 | return sema.addConstant(elem_ty, elem_val); | 29887 | return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty)); |
| 29140 | } | 29888 | } |
| 29141 | } | 29889 | } |
| 29142 | 29890 | ||
| 29143 | if (ptr_ty.ptrInfo().data.vector_index == .runtime) { | 29891 | if (ptr_ty.ptrInfo(mod).vector_index == .runtime) { |
| 29144 | const ptr_inst = Air.refToIndex(ptr).?; | 29892 | const ptr_inst = Air.refToIndex(ptr).?; |
| 29145 | const air_tags = sema.air_instructions.items(.tag); | 29893 | const air_tags = sema.air_instructions.items(.tag); |
| 29146 | if (air_tags[ptr_inst] == .ptr_elem_ptr) { | 29894 | if (air_tags[ptr_inst] == .ptr_elem_ptr) { |
| ... | @@ -29163,11 +29911,11 @@ fn analyzeSlicePtr( | ... | @@ -29163,11 +29911,11 @@ fn analyzeSlicePtr( |
| 29163 | slice: Air.Inst.Ref, | 29911 | slice: Air.Inst.Ref, |
| 29164 | slice_ty: Type, | 29912 | slice_ty: Type, |
| 29165 | ) CompileError!Air.Inst.Ref { | 29913 | ) CompileError!Air.Inst.Ref { |
| 29166 | const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer); | 29914 | const mod = sema.mod; |
| 29167 | const result_ty = slice_ty.slicePtrFieldType(buf); | 29915 | const result_ty = slice_ty.slicePtrFieldType(mod); |
| 29168 | if (try sema.resolveMaybeUndefVal(slice)) |val| { | 29916 | if (try sema.resolveMaybeUndefVal(slice)) |val| { |
| 29169 | if (val.isUndef()) return sema.addConstUndef(result_ty); | 29917 | if (val.isUndef(mod)) return sema.addConstUndef(result_ty); |
| 29170 | return sema.addConstant(result_ty, val.slicePtr()); | 29918 | return sema.addConstant(result_ty, val.slicePtr(mod)); |
| 29171 | } | 29919 | } |
| 29172 | try sema.requireRuntimeBlock(block, slice_src, null); | 29920 | try sema.requireRuntimeBlock(block, slice_src, null); |
| 29173 | return block.addTyOp(.slice_ptr, result_ty, slice); | 29921 | return block.addTyOp(.slice_ptr, result_ty, slice); |
| ... | @@ -29179,8 +29927,9 @@ fn analyzeSliceLen( | ... | @@ -29179,8 +29927,9 @@ fn analyzeSliceLen( |
| 29179 | src: LazySrcLoc, | 29927 | src: LazySrcLoc, |
| 29180 | slice_inst: Air.Inst.Ref, | 29928 | slice_inst: Air.Inst.Ref, |
| 29181 | ) CompileError!Air.Inst.Ref { | 29929 | ) CompileError!Air.Inst.Ref { |
| 29930 | const mod = sema.mod; | ||
| 29182 | if (try sema.resolveMaybeUndefVal(slice_inst)) |slice_val| { | 29931 | if (try sema.resolveMaybeUndefVal(slice_inst)) |slice_val| { |
| 29183 | if (slice_val.isUndef()) { | 29932 | if (slice_val.isUndef(mod)) { |
| 29184 | return sema.addConstUndef(Type.usize); | 29933 | return sema.addConstUndef(Type.usize); |
| 29185 | } | 29934 | } |
| 29186 | return sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)); | 29935 | return sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod)); |
| ... | @@ -29196,12 +29945,13 @@ fn analyzeIsNull( | ... | @@ -29196,12 +29945,13 @@ fn analyzeIsNull( |
| 29196 | operand: Air.Inst.Ref, | 29945 | operand: Air.Inst.Ref, |
| 29197 | invert_logic: bool, | 29946 | invert_logic: bool, |
| 29198 | ) CompileError!Air.Inst.Ref { | 29947 | ) CompileError!Air.Inst.Ref { |
| 29948 | const mod = sema.mod; | ||
| 29199 | const result_ty = Type.bool; | 29949 | const result_ty = Type.bool; |
| 29200 | if (try sema.resolveMaybeUndefVal(operand)) |opt_val| { | 29950 | if (try sema.resolveMaybeUndefVal(operand)) |opt_val| { |
| 29201 | if (opt_val.isUndef()) { | 29951 | if (opt_val.isUndef(mod)) { |
| 29202 | return sema.addConstUndef(result_ty); | 29952 | return sema.addConstUndef(result_ty); |
| 29203 | } | 29953 | } |
| 29204 | const is_null = opt_val.isNull(); | 29954 | const is_null = opt_val.isNull(mod); |
| 29205 | const bool_value = if (invert_logic) !is_null else is_null; | 29955 | const bool_value = if (invert_logic) !is_null else is_null; |
| 29206 | if (bool_value) { | 29956 | if (bool_value) { |
| 29207 | return Air.Inst.Ref.bool_true; | 29957 | return Air.Inst.Ref.bool_true; |
| ... | @@ -29212,11 +29962,10 @@ fn analyzeIsNull( | ... | @@ -29212,11 +29962,10 @@ fn analyzeIsNull( |
| 29212 | 29962 | ||
| 29213 | const inverted_non_null_res = if (invert_logic) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; | 29963 | const inverted_non_null_res = if (invert_logic) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; |
| 29214 | const operand_ty = sema.typeOf(operand); | 29964 | const operand_ty = sema.typeOf(operand); |
| 29215 | var buf: Type.Payload.ElemType = undefined; | 29965 | if (operand_ty.zigTypeTag(mod) == .Optional and operand_ty.optionalChild(mod).zigTypeTag(mod) == .NoReturn) { |
| 29216 | if (operand_ty.zigTypeTag() == .Optional and operand_ty.optionalChild(&buf).zigTypeTag() == .NoReturn) { | ||
| 29217 | return inverted_non_null_res; | 29966 | return inverted_non_null_res; |
| 29218 | } | 29967 | } |
| 29219 | if (operand_ty.zigTypeTag() != .Optional and !operand_ty.isPtrLikeOptional()) { | 29968 | if (operand_ty.zigTypeTag(mod) != .Optional and !operand_ty.isPtrLikeOptional(mod)) { |
| 29220 | return inverted_non_null_res; | 29969 | return inverted_non_null_res; |
| 29221 | } | 29970 | } |
| 29222 | try sema.requireRuntimeBlock(block, src, null); | 29971 | try sema.requireRuntimeBlock(block, src, null); |
| ... | @@ -29230,11 +29979,12 @@ fn analyzePtrIsNonErrComptimeOnly( | ... | @@ -29230,11 +29979,12 @@ fn analyzePtrIsNonErrComptimeOnly( |
| 29230 | src: LazySrcLoc, | 29979 | src: LazySrcLoc, |
| 29231 | operand: Air.Inst.Ref, | 29980 | operand: Air.Inst.Ref, |
| 29232 | ) CompileError!Air.Inst.Ref { | 29981 | ) CompileError!Air.Inst.Ref { |
| 29982 | const mod = sema.mod; | ||
| 29233 | const ptr_ty = sema.typeOf(operand); | 29983 | const ptr_ty = sema.typeOf(operand); |
| 29234 | assert(ptr_ty.zigTypeTag() == .Pointer); | 29984 | assert(ptr_ty.zigTypeTag(mod) == .Pointer); |
| 29235 | const child_ty = ptr_ty.childType(); | 29985 | const child_ty = ptr_ty.childType(mod); |
| 29236 | 29986 | ||
| 29237 | const child_tag = child_ty.zigTypeTag(); | 29987 | const child_tag = child_ty.zigTypeTag(mod); |
| 29238 | if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true; | 29988 | if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true; |
| 29239 | if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false; | 29989 | if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false; |
| 29240 | assert(child_tag == .ErrorUnion); | 29990 | assert(child_tag == .ErrorUnion); |
| ... | @@ -29251,14 +30001,15 @@ fn analyzeIsNonErrComptimeOnly( | ... | @@ -29251,14 +30001,15 @@ fn analyzeIsNonErrComptimeOnly( |
| 29251 | src: LazySrcLoc, | 30001 | src: LazySrcLoc, |
| 29252 | operand: Air.Inst.Ref, | 30002 | operand: Air.Inst.Ref, |
| 29253 | ) CompileError!Air.Inst.Ref { | 30003 | ) CompileError!Air.Inst.Ref { |
| 30004 | const mod = sema.mod; | ||
| 29254 | const operand_ty = sema.typeOf(operand); | 30005 | const operand_ty = sema.typeOf(operand); |
| 29255 | const ot = operand_ty.zigTypeTag(); | 30006 | const ot = operand_ty.zigTypeTag(mod); |
| 29256 | if (ot != .ErrorSet and ot != .ErrorUnion) return Air.Inst.Ref.bool_true; | 30007 | if (ot != .ErrorSet and ot != .ErrorUnion) return Air.Inst.Ref.bool_true; |
| 29257 | if (ot == .ErrorSet) return Air.Inst.Ref.bool_false; | 30008 | if (ot == .ErrorSet) return Air.Inst.Ref.bool_false; |
| 29258 | assert(ot == .ErrorUnion); | 30009 | assert(ot == .ErrorUnion); |
| 29259 | 30010 | ||
| 29260 | const payload_ty = operand_ty.errorUnionPayload(); | 30011 | const payload_ty = operand_ty.errorUnionPayload(mod); |
| 29261 | if (payload_ty.zigTypeTag() == .NoReturn) { | 30012 | if (payload_ty.zigTypeTag(mod) == .NoReturn) { |
| 29262 | return Air.Inst.Ref.bool_false; | 30013 | return Air.Inst.Ref.bool_false; |
| 29263 | } | 30014 | } |
| 29264 | 30015 | ||
| ... | @@ -29279,50 +30030,56 @@ fn analyzeIsNonErrComptimeOnly( | ... | @@ -29279,50 +30030,56 @@ fn analyzeIsNonErrComptimeOnly( |
| 29279 | 30030 | ||
| 29280 | // exception if the error union error set is known to be empty, | 30031 | // exception if the error union error set is known to be empty, |
| 29281 | // we allow the comparison but always make it comptime-known. | 30032 | // we allow the comparison but always make it comptime-known. |
| 29282 | const set_ty = operand_ty.errorUnionSet(); | 30033 | const set_ty = operand_ty.errorUnionSet(mod); |
| 29283 | switch (set_ty.tag()) { | 30034 | switch (set_ty.toIntern()) { |
| 29284 | .anyerror => {}, | 30035 | .anyerror_type => {}, |
| 29285 | .error_set_inferred => blk: { | 30036 | else => switch (mod.intern_pool.indexToKey(set_ty.toIntern())) { |
| 29286 | // If the error set is empty, we must return a comptime true or false. | 30037 | .error_set_type => |error_set_type| { |
| 29287 | // However we want to avoid unnecessarily resolving an inferred error set | 30038 | if (error_set_type.names.len == 0) return Air.Inst.Ref.bool_true; |
| 29288 | // in case it is already non-empty. | 30039 | }, |
| 29289 | const ies = set_ty.castTag(.error_set_inferred).?.data; | 30040 | .inferred_error_set_type => |ies_index| blk: { |
| 29290 | if (ies.is_anyerror) break :blk; | 30041 | // If the error set is empty, we must return a comptime true or false. |
| 29291 | if (ies.errors.count() != 0) break :blk; | 30042 | // However we want to avoid unnecessarily resolving an inferred error set |
| 29292 | if (maybe_operand_val == null) { | 30043 | // in case it is already non-empty. |
| 29293 | // Try to avoid resolving inferred error set if possible. | 30044 | const ies = mod.inferredErrorSetPtr(ies_index); |
| 29294 | if (ies.errors.count() != 0) break :blk; | ||
| 29295 | if (ies.is_anyerror) break :blk; | 30045 | if (ies.is_anyerror) break :blk; |
| 29296 | for (ies.inferred_error_sets.keys()) |other_ies| { | 30046 | if (ies.errors.count() != 0) break :blk; |
| 29297 | if (ies == other_ies) continue; | 30047 | if (maybe_operand_val == null) { |
| 29298 | try sema.resolveInferredErrorSet(block, src, other_ies); | 30048 | // Try to avoid resolving inferred error set if possible. |
| 29299 | if (other_ies.is_anyerror) { | 30049 | if (ies.errors.count() != 0) break :blk; |
| 29300 | ies.is_anyerror = true; | 30050 | if (ies.is_anyerror) break :blk; |
| 29301 | ies.is_resolved = true; | 30051 | for (ies.inferred_error_sets.keys()) |other_ies_index| { |
| 29302 | break :blk; | 30052 | if (ies_index == other_ies_index) continue; |
| 29303 | } | 30053 | try sema.resolveInferredErrorSet(block, src, other_ies_index); |
| 30054 | const other_ies = mod.inferredErrorSetPtr(other_ies_index); | ||
| 30055 | if (other_ies.is_anyerror) { | ||
| 30056 | ies.is_anyerror = true; | ||
| 30057 | ies.is_resolved = true; | ||
| 30058 | break :blk; | ||
| 30059 | } | ||
| 29304 | 30060 | ||
| 29305 | if (other_ies.errors.count() != 0) break :blk; | 30061 | if (other_ies.errors.count() != 0) break :blk; |
| 29306 | } | 30062 | } |
| 29307 | if (ies.func == sema.owner_func) { | 30063 | if (ies.func == sema.owner_func_index.unwrap()) { |
| 29308 | // We're checking the inferred errorset of the current function and none of | 30064 | // We're checking the inferred errorset of the current function and none of |
| 29309 | // its child inferred error sets contained any errors meaning that any value | 30065 | // its child inferred error sets contained any errors meaning that any value |
| 29310 | // so far with this type can't contain errors either. | 30066 | // so far with this type can't contain errors either. |
| 29311 | return Air.Inst.Ref.bool_true; | 30067 | return Air.Inst.Ref.bool_true; |
| 30068 | } | ||
| 30069 | try sema.resolveInferredErrorSet(block, src, ies_index); | ||
| 30070 | if (ies.is_anyerror) break :blk; | ||
| 30071 | if (ies.errors.count() == 0) return Air.Inst.Ref.bool_true; | ||
| 29312 | } | 30072 | } |
| 29313 | try sema.resolveInferredErrorSet(block, src, ies); | 30073 | }, |
| 29314 | if (ies.is_anyerror) break :blk; | 30074 | else => unreachable, |
| 29315 | if (ies.errors.count() == 0) return Air.Inst.Ref.bool_true; | ||
| 29316 | } | ||
| 29317 | }, | 30075 | }, |
| 29318 | else => if (set_ty.errorSetNames().len == 0) return Air.Inst.Ref.bool_true, | ||
| 29319 | } | 30076 | } |
| 29320 | 30077 | ||
| 29321 | if (maybe_operand_val) |err_union| { | 30078 | if (maybe_operand_val) |err_union| { |
| 29322 | if (err_union.isUndef()) { | 30079 | if (err_union.isUndef(mod)) { |
| 29323 | return sema.addConstUndef(Type.bool); | 30080 | return sema.addConstUndef(Type.bool); |
| 29324 | } | 30081 | } |
| 29325 | if (err_union.getError() == null) { | 30082 | if (err_union.getErrorName(mod) == .none) { |
| 29326 | return Air.Inst.Ref.bool_true; | 30083 | return Air.Inst.Ref.bool_true; |
| 29327 | } else { | 30084 | } else { |
| 29328 | return Air.Inst.Ref.bool_false; | 30085 | return Air.Inst.Ref.bool_false; |
| ... | @@ -29375,72 +30132,78 @@ fn analyzeSlice( | ... | @@ -29375,72 +30132,78 @@ fn analyzeSlice( |
| 29375 | end_src: LazySrcLoc, | 30132 | end_src: LazySrcLoc, |
| 29376 | by_length: bool, | 30133 | by_length: bool, |
| 29377 | ) CompileError!Air.Inst.Ref { | 30134 | ) CompileError!Air.Inst.Ref { |
| 30135 | const mod = sema.mod; | ||
| 29378 | // Slice expressions can operate on a variable whose type is an array. This requires | 30136 | // Slice expressions can operate on a variable whose type is an array. This requires |
| 29379 | // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer. | 30137 | // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer. |
| 29380 | const ptr_ptr_ty = sema.typeOf(ptr_ptr); | 30138 | const ptr_ptr_ty = sema.typeOf(ptr_ptr); |
| 29381 | const target = sema.mod.getTarget(); | 30139 | const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag(mod)) { |
| 29382 | const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag()) { | 30140 | .Pointer => ptr_ptr_ty.childType(mod), |
| 29383 | .Pointer => ptr_ptr_ty.elemType(), | 30141 | else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(mod)}), |
| 29384 | else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(sema.mod)}), | ||
| 29385 | }; | 30142 | }; |
| 29386 | const mod = sema.mod; | ||
| 29387 | 30143 | ||
| 29388 | var array_ty = ptr_ptr_child_ty; | 30144 | var array_ty = ptr_ptr_child_ty; |
| 29389 | var slice_ty = ptr_ptr_ty; | 30145 | var slice_ty = ptr_ptr_ty; |
| 29390 | var ptr_or_slice = ptr_ptr; | 30146 | var ptr_or_slice = ptr_ptr; |
| 29391 | var elem_ty: Type = undefined; | 30147 | var elem_ty: Type = undefined; |
| 29392 | var ptr_sentinel: ?Value = null; | 30148 | var ptr_sentinel: ?Value = null; |
| 29393 | switch (ptr_ptr_child_ty.zigTypeTag()) { | 30149 | switch (ptr_ptr_child_ty.zigTypeTag(mod)) { |
| 29394 | .Array => { | 30150 | .Array => { |
| 29395 | ptr_sentinel = ptr_ptr_child_ty.sentinel(); | 30151 | ptr_sentinel = ptr_ptr_child_ty.sentinel(mod); |
| 29396 | elem_ty = ptr_ptr_child_ty.childType(); | 30152 | elem_ty = ptr_ptr_child_ty.childType(mod); |
| 29397 | }, | 30153 | }, |
| 29398 | .Pointer => switch (ptr_ptr_child_ty.ptrSize()) { | 30154 | .Pointer => switch (ptr_ptr_child_ty.ptrSize(mod)) { |
| 29399 | .One => { | 30155 | .One => { |
| 29400 | const double_child_ty = ptr_ptr_child_ty.childType(); | 30156 | const double_child_ty = ptr_ptr_child_ty.childType(mod); |
| 29401 | if (double_child_ty.zigTypeTag() == .Array) { | 30157 | if (double_child_ty.zigTypeTag(mod) == .Array) { |
| 29402 | ptr_sentinel = double_child_ty.sentinel(); | 30158 | ptr_sentinel = double_child_ty.sentinel(mod); |
| 29403 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); | 30159 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); |
| 29404 | slice_ty = ptr_ptr_child_ty; | 30160 | slice_ty = ptr_ptr_child_ty; |
| 29405 | array_ty = double_child_ty; | 30161 | array_ty = double_child_ty; |
| 29406 | elem_ty = double_child_ty.childType(); | 30162 | elem_ty = double_child_ty.childType(mod); |
| 29407 | } else { | 30163 | } else { |
| 29408 | return sema.fail(block, src, "slice of single-item pointer", .{}); | 30164 | return sema.fail(block, src, "slice of single-item pointer", .{}); |
| 29409 | } | 30165 | } |
| 29410 | }, | 30166 | }, |
| 29411 | .Many, .C => { | 30167 | .Many, .C => { |
| 29412 | ptr_sentinel = ptr_ptr_child_ty.sentinel(); | 30168 | ptr_sentinel = ptr_ptr_child_ty.sentinel(mod); |
| 29413 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); | 30169 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); |
| 29414 | slice_ty = ptr_ptr_child_ty; | 30170 | slice_ty = ptr_ptr_child_ty; |
| 29415 | array_ty = ptr_ptr_child_ty; | 30171 | array_ty = ptr_ptr_child_ty; |
| 29416 | elem_ty = ptr_ptr_child_ty.childType(); | 30172 | elem_ty = ptr_ptr_child_ty.childType(mod); |
| 29417 | 30173 | ||
| 29418 | if (ptr_ptr_child_ty.ptrSize() == .C) { | 30174 | if (ptr_ptr_child_ty.ptrSize(mod) == .C) { |
| 29419 | if (try sema.resolveDefinedValue(block, ptr_src, ptr_or_slice)) |ptr_val| { | 30175 | if (try sema.resolveDefinedValue(block, ptr_src, ptr_or_slice)) |ptr_val| { |
| 29420 | if (ptr_val.isNull()) { | 30176 | if (ptr_val.isNull(mod)) { |
| 29421 | return sema.fail(block, src, "slice of null pointer", .{}); | 30177 | return sema.fail(block, src, "slice of null pointer", .{}); |
| 29422 | } | 30178 | } |
| 29423 | } | 30179 | } |
| 29424 | } | 30180 | } |
| 29425 | }, | 30181 | }, |
| 29426 | .Slice => { | 30182 | .Slice => { |
| 29427 | ptr_sentinel = ptr_ptr_child_ty.sentinel(); | 30183 | ptr_sentinel = ptr_ptr_child_ty.sentinel(mod); |
| 29428 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); | 30184 | ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src); |
| 29429 | slice_ty = ptr_ptr_child_ty; | 30185 | slice_ty = ptr_ptr_child_ty; |
| 29430 | array_ty = ptr_ptr_child_ty; | 30186 | array_ty = ptr_ptr_child_ty; |
| 29431 | elem_ty = ptr_ptr_child_ty.childType(); | 30187 | elem_ty = ptr_ptr_child_ty.childType(mod); |
| 29432 | }, | 30188 | }, |
| 29433 | }, | 30189 | }, |
| 29434 | else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(mod)}), | 30190 | else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(mod)}), |
| 29435 | } | 30191 | } |
| 29436 | 30192 | ||
| 29437 | const ptr = if (slice_ty.isSlice()) | 30193 | const ptr = if (slice_ty.isSlice(mod)) |
| 29438 | try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty) | 30194 | try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty) |
| 29439 | else | 30195 | else if (array_ty.zigTypeTag(mod) == .Array) ptr: { |
| 29440 | ptr_or_slice; | 30196 | var manyptr_ty_key = mod.intern_pool.indexToKey(slice_ty.toIntern()).ptr_type; |
| 30197 | assert(manyptr_ty_key.child == array_ty.toIntern()); | ||
| 30198 | assert(manyptr_ty_key.flags.size == .One); | ||
| 30199 | manyptr_ty_key.child = elem_ty.toIntern(); | ||
| 30200 | manyptr_ty_key.flags.size = .Many; | ||
| 30201 | break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src); | ||
| 30202 | } else ptr_or_slice; | ||
| 29441 | 30203 | ||
| 29442 | const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); | 30204 | const start = try sema.coerce(block, Type.usize, uncasted_start, start_src); |
| 29443 | const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src); | 30205 | const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src); |
| 30206 | const new_ptr_ty = sema.typeOf(new_ptr); | ||
| 29444 | 30207 | ||
| 29445 | // true if and only if the end index of the slice, implicitly or explicitly, equals | 30208 | // true if and only if the end index of the slice, implicitly or explicitly, equals |
| 29446 | // the length of the underlying object being sliced. we might learn the length of the | 30209 | // the length of the underlying object being sliced. we might learn the length of the |
| ... | @@ -29448,8 +30211,8 @@ fn analyzeSlice( | ... | @@ -29448,8 +30211,8 @@ fn analyzeSlice( |
| 29448 | // we might learn of the length because it is a comptime-known slice value. | 30211 | // we might learn of the length because it is a comptime-known slice value. |
| 29449 | var end_is_len = uncasted_end_opt == .none; | 30212 | var end_is_len = uncasted_end_opt == .none; |
| 29450 | const end = e: { | 30213 | const end = e: { |
| 29451 | if (array_ty.zigTypeTag() == .Array) { | 30214 | if (array_ty.zigTypeTag(mod) == .Array) { |
| 29452 | const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()); | 30215 | const len_val = try mod.intValue(Type.usize, array_ty.arrayLen(mod)); |
| 29453 | 30216 | ||
| 29454 | if (!end_is_len) { | 30217 | if (!end_is_len) { |
| 29455 | const end = if (by_length) end: { | 30218 | const end = if (by_length) end: { |
| ... | @@ -29458,12 +30221,12 @@ fn analyzeSlice( | ... | @@ -29458,12 +30221,12 @@ fn analyzeSlice( |
| 29458 | break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); | 30221 | break :end try sema.coerce(block, Type.usize, uncasted_end, end_src); |
| 29459 | } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); | 30222 | } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29460 | if (try sema.resolveMaybeUndefVal(end)) |end_val| { | 30223 | if (try sema.resolveMaybeUndefVal(end)) |end_val| { |
| 29461 | const len_s_val = try Value.Tag.int_u64.create( | 30224 | const len_s_val = try mod.intValue( |
| 29462 | sema.arena, | 30225 | Type.usize, |
| 29463 | array_ty.arrayLenIncludingSentinel(), | 30226 | array_ty.arrayLenIncludingSentinel(mod), |
| 29464 | ); | 30227 | ); |
| 29465 | if (!(try sema.compareAll(end_val, .lte, len_s_val, Type.usize))) { | 30228 | if (!(try sema.compareAll(end_val, .lte, len_s_val, Type.usize))) { |
| 29466 | const sentinel_label: []const u8 = if (array_ty.sentinel() != null) | 30229 | const sentinel_label: []const u8 = if (array_ty.sentinel(mod) != null) |
| 29467 | " +1 (sentinel)" | 30230 | " +1 (sentinel)" |
| 29468 | else | 30231 | else |
| 29469 | ""; | 30232 | ""; |
| ... | @@ -29491,7 +30254,7 @@ fn analyzeSlice( | ... | @@ -29491,7 +30254,7 @@ fn analyzeSlice( |
| 29491 | } | 30254 | } |
| 29492 | 30255 | ||
| 29493 | break :e try sema.addConstant(Type.usize, len_val); | 30256 | break :e try sema.addConstant(Type.usize, len_val); |
| 29494 | } else if (slice_ty.isSlice()) { | 30257 | } else if (slice_ty.isSlice(mod)) { |
| 29495 | if (!end_is_len) { | 30258 | if (!end_is_len) { |
| 29496 | const end = if (by_length) end: { | 30259 | const end = if (by_length) end: { |
| 29497 | const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); | 30260 | const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| ... | @@ -29500,16 +30263,14 @@ fn analyzeSlice( | ... | @@ -29500,16 +30263,14 @@ fn analyzeSlice( |
| 29500 | } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); | 30263 | } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src); |
| 29501 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { | 30264 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| 29502 | if (try sema.resolveMaybeUndefVal(ptr_or_slice)) |slice_val| { | 30265 | if (try sema.resolveMaybeUndefVal(ptr_or_slice)) |slice_val| { |
| 29503 | if (slice_val.isUndef()) { | 30266 | if (slice_val.isUndef(mod)) { |
| 29504 | return sema.fail(block, src, "slice of undefined", .{}); | 30267 | return sema.fail(block, src, "slice of undefined", .{}); |
| 29505 | } | 30268 | } |
| 29506 | const has_sentinel = slice_ty.sentinel() != null; | 30269 | const has_sentinel = slice_ty.sentinel(mod) != null; |
| 29507 | var int_payload: Value.Payload.U64 = .{ | 30270 | const slice_len = slice_val.sliceLen(mod); |
| 29508 | .base = .{ .tag = .int_u64 }, | 30271 | const len_plus_sent = slice_len + @boolToInt(has_sentinel); |
| 29509 | .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel), | 30272 | const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent); |
| 29510 | }; | 30273 | if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) { |
| 29511 | const slice_len_val = Value.initPayload(&int_payload.base); | ||
| 29512 | if (!(try sema.compareAll(end_val, .lte, slice_len_val, Type.usize))) { | ||
| 29513 | const sentinel_label: []const u8 = if (has_sentinel) | 30274 | const sentinel_label: []const u8 = if (has_sentinel) |
| 29514 | " +1 (sentinel)" | 30275 | " +1 (sentinel)" |
| 29515 | else | 30276 | else |
| ... | @@ -29527,13 +30288,10 @@ fn analyzeSlice( | ... | @@ -29527,13 +30288,10 @@ fn analyzeSlice( |
| 29527 | ); | 30288 | ); |
| 29528 | } | 30289 | } |
| 29529 | 30290 | ||
| 29530 | // If the slice has a sentinel, we subtract one so that | 30291 | // If the slice has a sentinel, we consider end_is_len |
| 29531 | // end_is_len is only true if it equals the length WITHOUT | 30292 | // is only true if it equals the length WITHOUT the |
| 29532 | // the sentinel, so we don't add a sentinel type. | 30293 | // sentinel, so we don't add a sentinel type. |
| 29533 | if (has_sentinel) { | 30294 | const slice_len_val = try mod.intValue(Type.usize, slice_len); |
| 29534 | int_payload.data -= 1; | ||
| 29535 | } | ||
| 29536 | |||
| 29537 | if (end_val.eql(slice_len_val, Type.usize, mod)) { | 30295 | if (end_val.eql(slice_len_val, Type.usize, mod)) { |
| 29538 | end_is_len = true; | 30296 | end_is_len = true; |
| 29539 | } | 30297 | } |
| ... | @@ -29569,11 +30327,12 @@ fn analyzeSlice( | ... | @@ -29569,11 +30327,12 @@ fn analyzeSlice( |
| 29569 | }; | 30327 | }; |
| 29570 | const slice_sentinel = if (sentinel_opt != .none) sentinel else null; | 30328 | const slice_sentinel = if (sentinel_opt != .none) sentinel else null; |
| 29571 | 30329 | ||
| 30330 | var checked_start_lte_end = by_length; | ||
| 30331 | var runtime_src: ?LazySrcLoc = null; | ||
| 30332 | |||
| 29572 | // requirement: start <= end | 30333 | // requirement: start <= end |
| 29573 | var need_start_gt_end_check = true; | ||
| 29574 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { | 30334 | if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| { |
| 29575 | if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { | 30335 | if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| { |
| 29576 | need_start_gt_end_check = false; | ||
| 29577 | if (!by_length and !(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { | 30336 | if (!by_length and !(try sema.compareAll(start_val, .lte, end_val, Type.usize))) { |
| 29578 | return sema.fail( | 30337 | return sema.fail( |
| 29579 | block, | 30338 | block, |
| ... | @@ -29585,14 +30344,18 @@ fn analyzeSlice( | ... | @@ -29585,14 +30344,18 @@ fn analyzeSlice( |
| 29585 | }, | 30344 | }, |
| 29586 | ); | 30345 | ); |
| 29587 | } | 30346 | } |
| 30347 | checked_start_lte_end = true; | ||
| 29588 | if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: { | 30348 | if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: { |
| 29589 | const expected_sentinel = sentinel orelse break :sentinel_check; | 30349 | const expected_sentinel = sentinel orelse break :sentinel_check; |
| 29590 | const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?; | 30350 | const start_int = start_val.getUnsignedInt(mod).?; |
| 29591 | const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?; | 30351 | const end_int = end_val.getUnsignedInt(mod).?; |
| 29592 | const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); | 30352 | const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); |
| 29593 | 30353 | ||
| 29594 | const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod); | 30354 | const many_ptr_ty = try mod.manyConstPtrType(elem_ty); |
| 29595 | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); | 30355 | const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty); |
| 30356 | const elem_ptr_ty = try mod.singleConstPtrType(elem_ty); | ||
| 30357 | const elem_ptr = try many_ptr_val.elemPtr(elem_ptr_ty, sentinel_index, mod); | ||
| 30358 | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty); | ||
| 29596 | const actual_sentinel = switch (res) { | 30359 | const actual_sentinel = switch (res) { |
| 29597 | .runtime_load => break :sentinel_check, | 30360 | .runtime_load => break :sentinel_check, |
| 29598 | .val => |v| v, | 30361 | .val => |v| v, |
| ... | @@ -29600,36 +30363,49 @@ fn analyzeSlice( | ... | @@ -29600,36 +30363,49 @@ fn analyzeSlice( |
| 29600 | block, | 30363 | block, |
| 29601 | src, | 30364 | src, |
| 29602 | "comptime dereference requires '{}' to have a well-defined layout, but it does not.", | 30365 | "comptime dereference requires '{}' to have a well-defined layout, but it does not.", |
| 29603 | .{ty.fmt(sema.mod)}, | 30366 | .{ty.fmt(mod)}, |
| 29604 | ), | 30367 | ), |
| 29605 | .out_of_bounds => |ty| return sema.fail( | 30368 | .out_of_bounds => |ty| return sema.fail( |
| 29606 | block, | 30369 | block, |
| 29607 | end_src, | 30370 | end_src, |
| 29608 | "slice end index {d} exceeds bounds of containing decl of type '{}'", | 30371 | "slice end index {d} exceeds bounds of containing decl of type '{}'", |
| 29609 | .{ end_int, ty.fmt(sema.mod) }, | 30372 | .{ end_int, ty.fmt(mod) }, |
| 29610 | ), | 30373 | ), |
| 29611 | }; | 30374 | }; |
| 29612 | 30375 | ||
| 29613 | if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { | 30376 | if (!actual_sentinel.eql(expected_sentinel, elem_ty, mod)) { |
| 29614 | const msg = msg: { | 30377 | const msg = msg: { |
| 29615 | const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); | 30378 | const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); |
| 29616 | errdefer msg.destroy(sema.gpa); | 30379 | errdefer msg.destroy(sema.gpa); |
| 29617 | try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ | 30380 | try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ |
| 29618 | expected_sentinel.fmtValue(elem_ty, sema.mod), | 30381 | expected_sentinel.fmtValue(elem_ty, mod), |
| 29619 | actual_sentinel.fmtValue(elem_ty, sema.mod), | 30382 | actual_sentinel.fmtValue(elem_ty, mod), |
| 29620 | }); | 30383 | }); |
| 29621 | 30384 | ||
| 29622 | break :msg msg; | 30385 | break :msg msg; |
| 29623 | }; | 30386 | }; |
| 29624 | return sema.failWithOwnedErrorMsg(msg); | 30387 | return sema.failWithOwnedErrorMsg(msg); |
| 29625 | } | 30388 | } |
| 30389 | } else { | ||
| 30390 | runtime_src = ptr_src; | ||
| 29626 | } | 30391 | } |
| 30392 | } else { | ||
| 30393 | runtime_src = start_src; | ||
| 29627 | } | 30394 | } |
| 30395 | } else { | ||
| 30396 | runtime_src = end_src; | ||
| 29628 | } | 30397 | } |
| 29629 | 30398 | ||
| 29630 | if (!by_length and block.wantSafety() and !block.is_comptime and need_start_gt_end_check) { | 30399 | if (!checked_start_lte_end and block.wantSafety() and !block.is_comptime) { |
| 29631 | // requirement: start <= end | 30400 | // requirement: start <= end |
| 29632 | try sema.panicStartGreaterThanEnd(block, start, end); | 30401 | assert(!block.is_comptime); |
| 30402 | try sema.requireRuntimeBlock(block, src, runtime_src.?); | ||
| 30403 | const ok = try block.addBinOp(.cmp_lte, start, end); | ||
| 30404 | if (!sema.mod.comp.formatted_panics) { | ||
| 30405 | try sema.addSafetyCheck(block, ok, .start_index_greater_than_end); | ||
| 30406 | } else { | ||
| 30407 | try sema.safetyCheckFormatted(block, ok, "panicStartGreaterThanEnd", &.{ start, end }); | ||
| 30408 | } | ||
| 29633 | } | 30409 | } |
| 29634 | const new_len = if (by_length) | 30410 | const new_len = if (by_length) |
| 29635 | try sema.coerce(block, Type.usize, uncasted_end_opt, end_src) | 30411 | try sema.coerce(block, Type.usize, uncasted_end_opt, end_src) |
| ... | @@ -29637,11 +30413,11 @@ fn analyzeSlice( | ... | @@ -29637,11 +30413,11 @@ fn analyzeSlice( |
| 29637 | try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false); | 30413 | try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false); |
| 29638 | const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); | 30414 | const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len); |
| 29639 | 30415 | ||
| 29640 | const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data; | 30416 | const new_ptr_ty_info = new_ptr_ty.ptrInfo(mod); |
| 29641 | const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize() != .C; | 30417 | const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize(mod) != .C; |
| 29642 | 30418 | ||
| 29643 | if (opt_new_len_val) |new_len_val| { | 30419 | if (opt_new_len_val) |new_len_val| { |
| 29644 | const new_len_int = new_len_val.toUnsignedInt(target); | 30420 | const new_len_int = new_len_val.toUnsignedInt(mod); |
| 29645 | 30421 | ||
| 29646 | const return_ty = try Type.ptr(sema.arena, mod, .{ | 30422 | const return_ty = try Type.ptr(sema.arena, mod, .{ |
| 29647 | .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty, mod), | 30423 | .pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty, mod), |
| ... | @@ -29659,14 +30435,14 @@ fn analyzeSlice( | ... | @@ -29659,14 +30435,14 @@ fn analyzeSlice( |
| 29659 | const result = try block.addBitCast(return_ty, new_ptr); | 30435 | const result = try block.addBitCast(return_ty, new_ptr); |
| 29660 | if (block.wantSafety()) { | 30436 | if (block.wantSafety()) { |
| 29661 | // requirement: slicing C ptr is non-null | 30437 | // requirement: slicing C ptr is non-null |
| 29662 | if (ptr_ptr_child_ty.isCPtr()) { | 30438 | if (ptr_ptr_child_ty.isCPtr(mod)) { |
| 29663 | const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true); | 30439 | const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true); |
| 29664 | try sema.addSafetyCheck(block, is_non_null, .unwrap_null); | 30440 | try sema.addSafetyCheck(block, is_non_null, .unwrap_null); |
| 29665 | } | 30441 | } |
| 29666 | 30442 | ||
| 29667 | if (slice_ty.isSlice()) { | 30443 | if (slice_ty.isSlice(mod)) { |
| 29668 | const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); | 30444 | const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); |
| 29669 | const actual_len = if (slice_ty.sentinel() == null) | 30445 | const actual_len = if (slice_ty.sentinel(mod) == null) |
| 29670 | slice_len_inst | 30446 | slice_len_inst |
| 29671 | else | 30447 | else |
| 29672 | try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true); | 30448 | try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true); |
| ... | @@ -29685,8 +30461,11 @@ fn analyzeSlice( | ... | @@ -29685,8 +30461,11 @@ fn analyzeSlice( |
| 29685 | return result; | 30461 | return result; |
| 29686 | }; | 30462 | }; |
| 29687 | 30463 | ||
| 29688 | if (!new_ptr_val.isUndef()) { | 30464 | if (!new_ptr_val.isUndef(mod)) { |
| 29689 | return sema.addConstant(return_ty, new_ptr_val); | 30465 | return sema.addConstant(return_ty, try mod.getCoerced( |
| 30466 | (try new_ptr_val.intern(new_ptr_ty, mod)).toValue(), | ||
| 30467 | return_ty, | ||
| 30468 | )); | ||
| 29690 | } | 30469 | } |
| 29691 | 30470 | ||
| 29692 | // Special case: @as([]i32, undefined)[x..x] | 30471 | // Special case: @as([]i32, undefined)[x..x] |
| ... | @@ -29708,25 +30487,18 @@ fn analyzeSlice( | ... | @@ -29708,25 +30487,18 @@ fn analyzeSlice( |
| 29708 | .size = .Slice, | 30487 | .size = .Slice, |
| 29709 | }); | 30488 | }); |
| 29710 | 30489 | ||
| 29711 | const runtime_src = if ((try sema.resolveMaybeUndefVal(ptr_or_slice)) == null) | 30490 | try sema.requireRuntimeBlock(block, src, runtime_src.?); |
| 29712 | ptr_src | ||
| 29713 | else if ((try sema.resolveMaybeUndefVal(start)) == null) | ||
| 29714 | start_src | ||
| 29715 | else | ||
| 29716 | end_src; | ||
| 29717 | |||
| 29718 | try sema.requireRuntimeBlock(block, src, runtime_src); | ||
| 29719 | if (block.wantSafety()) { | 30491 | if (block.wantSafety()) { |
| 29720 | // requirement: slicing C ptr is non-null | 30492 | // requirement: slicing C ptr is non-null |
| 29721 | if (ptr_ptr_child_ty.isCPtr()) { | 30493 | if (ptr_ptr_child_ty.isCPtr(mod)) { |
| 29722 | const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true); | 30494 | const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true); |
| 29723 | try sema.addSafetyCheck(block, is_non_null, .unwrap_null); | 30495 | try sema.addSafetyCheck(block, is_non_null, .unwrap_null); |
| 29724 | } | 30496 | } |
| 29725 | 30497 | ||
| 29726 | // requirement: end <= len | 30498 | // requirement: end <= len |
| 29727 | const opt_len_inst = if (array_ty.zigTypeTag() == .Array) | 30499 | const opt_len_inst = if (array_ty.zigTypeTag(mod) == .Array) |
| 29728 | try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel()) | 30500 | try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel(mod)) |
| 29729 | else if (slice_ty.isSlice()) blk: { | 30501 | else if (slice_ty.isSlice(mod)) blk: { |
| 29730 | if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { | 30502 | if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { |
| 29731 | // we don't need to add one for sentinels because the | 30503 | // we don't need to add one for sentinels because the |
| 29732 | // underlying value data includes the sentinel | 30504 | // underlying value data includes the sentinel |
| ... | @@ -29734,7 +30506,7 @@ fn analyzeSlice( | ... | @@ -29734,7 +30506,7 @@ fn analyzeSlice( |
| 29734 | } | 30506 | } |
| 29735 | 30507 | ||
| 29736 | const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); | 30508 | const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice); |
| 29737 | if (slice_ty.sentinel() == null) break :blk slice_len_inst; | 30509 | if (slice_ty.sentinel(mod) == null) break :blk slice_len_inst; |
| 29738 | 30510 | ||
| 29739 | // we have to add one because slice lengths don't include the sentinel | 30511 | // we have to add one because slice lengths don't include the sentinel |
| 29740 | break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true); | 30512 | break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true); |
| ... | @@ -29778,15 +30550,16 @@ fn cmpNumeric( | ... | @@ -29778,15 +30550,16 @@ fn cmpNumeric( |
| 29778 | lhs_src: LazySrcLoc, | 30550 | lhs_src: LazySrcLoc, |
| 29779 | rhs_src: LazySrcLoc, | 30551 | rhs_src: LazySrcLoc, |
| 29780 | ) CompileError!Air.Inst.Ref { | 30552 | ) CompileError!Air.Inst.Ref { |
| 30553 | const mod = sema.mod; | ||
| 29781 | const lhs_ty = sema.typeOf(uncasted_lhs); | 30554 | const lhs_ty = sema.typeOf(uncasted_lhs); |
| 29782 | const rhs_ty = sema.typeOf(uncasted_rhs); | 30555 | const rhs_ty = sema.typeOf(uncasted_rhs); |
| 29783 | 30556 | ||
| 29784 | assert(lhs_ty.isNumeric()); | 30557 | assert(lhs_ty.isNumeric(mod)); |
| 29785 | assert(rhs_ty.isNumeric()); | 30558 | assert(rhs_ty.isNumeric(mod)); |
| 29786 | 30559 | ||
| 29787 | const lhs_ty_tag = lhs_ty.zigTypeTag(); | 30560 | const lhs_ty_tag = lhs_ty.zigTypeTag(mod); |
| 29788 | const rhs_ty_tag = rhs_ty.zigTypeTag(); | 30561 | const rhs_ty_tag = rhs_ty.zigTypeTag(mod); |
| 29789 | const target = sema.mod.getTarget(); | 30562 | const target = mod.getTarget(); |
| 29790 | 30563 | ||
| 29791 | // One exception to heterogeneous comparison: comptime_float needs to | 30564 | // One exception to heterogeneous comparison: comptime_float needs to |
| 29792 | // coerce to fixed-width float. | 30565 | // coerce to fixed-width float. |
| ... | @@ -29805,49 +30578,45 @@ fn cmpNumeric( | ... | @@ -29805,49 +30578,45 @@ fn cmpNumeric( |
| 29805 | if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { | 30578 | if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { |
| 29806 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { | 30579 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { |
| 29807 | // Compare ints: const vs. undefined (or vice versa) | 30580 | // Compare ints: const vs. undefined (or vice versa) |
| 29808 | if (!lhs_val.isUndef() and (lhs_ty.isInt() or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt() and rhs_val.isUndef()) { | 30581 | if (!lhs_val.isUndef(mod) and (lhs_ty.isInt(mod) or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt(mod) and rhs_val.isUndef(mod)) { |
| 29809 | try sema.resolveLazyValue(lhs_val); | 30582 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| { |
| 29810 | if (sema.compareIntsOnlyPossibleResult(target, lhs_val, op, rhs_ty)) |res| { | ||
| 29811 | return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; | 30583 | return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; |
| 29812 | } | 30584 | } |
| 29813 | } else if (!rhs_val.isUndef() and (rhs_ty.isInt() or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt() and lhs_val.isUndef()) { | 30585 | } else if (!rhs_val.isUndef(mod) and (rhs_ty.isInt(mod) or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt(mod) and lhs_val.isUndef(mod)) { |
| 29814 | try sema.resolveLazyValue(rhs_val); | 30586 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| { |
| 29815 | if (sema.compareIntsOnlyPossibleResult(target, rhs_val, op.reverse(), lhs_ty)) |res| { | ||
| 29816 | return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; | 30587 | return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; |
| 29817 | } | 30588 | } |
| 29818 | } | 30589 | } |
| 29819 | 30590 | ||
| 29820 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | 30591 | if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) { |
| 29821 | return sema.addConstUndef(Type.bool); | 30592 | return sema.addConstUndef(Type.bool); |
| 29822 | } | 30593 | } |
| 29823 | if (lhs_val.isNan() or rhs_val.isNan()) { | 30594 | if (lhs_val.isNan(mod) or rhs_val.isNan(mod)) { |
| 29824 | if (op == std.math.CompareOperator.neq) { | 30595 | if (op == std.math.CompareOperator.neq) { |
| 29825 | return Air.Inst.Ref.bool_true; | 30596 | return Air.Inst.Ref.bool_true; |
| 29826 | } else { | 30597 | } else { |
| 29827 | return Air.Inst.Ref.bool_false; | 30598 | return Air.Inst.Ref.bool_false; |
| 29828 | } | 30599 | } |
| 29829 | } | 30600 | } |
| 29830 | if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, target, sema)) { | 30601 | if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, mod, sema)) { |
| 29831 | return Air.Inst.Ref.bool_true; | 30602 | return Air.Inst.Ref.bool_true; |
| 29832 | } else { | 30603 | } else { |
| 29833 | return Air.Inst.Ref.bool_false; | 30604 | return Air.Inst.Ref.bool_false; |
| 29834 | } | 30605 | } |
| 29835 | } else { | 30606 | } else { |
| 29836 | if (!lhs_val.isUndef() and (lhs_ty.isInt() or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt()) { | 30607 | if (!lhs_val.isUndef(mod) and (lhs_ty.isInt(mod) or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt(mod)) { |
| 29837 | // Compare ints: const vs. var | 30608 | // Compare ints: const vs. var |
| 29838 | try sema.resolveLazyValue(lhs_val); | 30609 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| { |
| 29839 | if (sema.compareIntsOnlyPossibleResult(target, lhs_val, op, rhs_ty)) |res| { | ||
| 29840 | return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; | 30610 | return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; |
| 29841 | } | 30611 | } |
| 29842 | } | 30612 | } |
| 29843 | break :src rhs_src; | 30613 | break :src rhs_src; |
| 29844 | } | 30614 | } |
| 29845 | } else { | 30615 | } else { |
| 29846 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { | 30616 | if (try sema.resolveMaybeUndefLazyVal(rhs)) |rhs_val| { |
| 29847 | if (!rhs_val.isUndef() and (rhs_ty.isInt() or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt()) { | 30617 | if (!rhs_val.isUndef(mod) and (rhs_ty.isInt(mod) or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt(mod)) { |
| 29848 | // Compare ints: var vs. const | 30618 | // Compare ints: var vs. const |
| 29849 | try sema.resolveLazyValue(rhs_val); | 30619 | if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| { |
| 29850 | if (sema.compareIntsOnlyPossibleResult(target, rhs_val, op.reverse(), lhs_ty)) |res| { | ||
| 29851 | return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; | 30620 | return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false; |
| 29852 | } | 30621 | } |
| 29853 | } | 30622 | } |
| ... | @@ -29901,32 +30670,31 @@ fn cmpNumeric( | ... | @@ -29901,32 +30670,31 @@ fn cmpNumeric( |
| 29901 | const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| | 30670 | const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| |
| 29902 | !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema)) | 30671 | !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema)) |
| 29903 | else | 30672 | else |
| 29904 | (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt()); | 30673 | (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(mod)); |
| 29905 | const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| | 30674 | const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| |
| 29906 | !(try rhs_val.compareAllWithZeroAdvanced(.gte, sema)) | 30675 | !(try rhs_val.compareAllWithZeroAdvanced(.gte, sema)) |
| 29907 | else | 30676 | else |
| 29908 | (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt()); | 30677 | (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(mod)); |
| 29909 | const dest_int_is_signed = lhs_is_signed or rhs_is_signed; | 30678 | const dest_int_is_signed = lhs_is_signed or rhs_is_signed; |
| 29910 | 30679 | ||
| 29911 | var dest_float_type: ?Type = null; | 30680 | var dest_float_type: ?Type = null; |
| 29912 | 30681 | ||
| 29913 | var lhs_bits: usize = undefined; | 30682 | var lhs_bits: usize = undefined; |
| 29914 | if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| { | 30683 | if (try sema.resolveMaybeUndefLazyVal(lhs)) |lhs_val| { |
| 29915 | try sema.resolveLazyValue(lhs_val); | 30684 | if (lhs_val.isUndef(mod)) |
| 29916 | if (lhs_val.isUndef()) | ||
| 29917 | return sema.addConstUndef(Type.bool); | 30685 | return sema.addConstUndef(Type.bool); |
| 29918 | if (lhs_val.isNan()) switch (op) { | 30686 | if (lhs_val.isNan(mod)) switch (op) { |
| 29919 | .neq => return Air.Inst.Ref.bool_true, | 30687 | .neq => return Air.Inst.Ref.bool_true, |
| 29920 | else => return Air.Inst.Ref.bool_false, | 30688 | else => return Air.Inst.Ref.bool_false, |
| 29921 | }; | 30689 | }; |
| 29922 | if (lhs_val.isInf()) switch (op) { | 30690 | if (lhs_val.isInf(mod)) switch (op) { |
| 29923 | .neq => return Air.Inst.Ref.bool_true, | 30691 | .neq => return Air.Inst.Ref.bool_true, |
| 29924 | .eq => return Air.Inst.Ref.bool_false, | 30692 | .eq => return Air.Inst.Ref.bool_false, |
| 29925 | .gt, .gte => return if (lhs_val.isNegativeInf()) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, | 30693 | .gt, .gte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, |
| 29926 | .lt, .lte => return if (lhs_val.isNegativeInf()) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, | 30694 | .lt, .lte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, |
| 29927 | }; | 30695 | }; |
| 29928 | if (!rhs_is_signed) { | 30696 | if (!rhs_is_signed) { |
| 29929 | switch (lhs_val.orderAgainstZero()) { | 30697 | switch (lhs_val.orderAgainstZero(mod)) { |
| 29930 | .gt => {}, | 30698 | .gt => {}, |
| 29931 | .eq => switch (op) { // LHS = 0, RHS is unsigned | 30699 | .eq => switch (op) { // LHS = 0, RHS is unsigned |
| 29932 | .lte => return Air.Inst.Ref.bool_true, | 30700 | .lte => return Air.Inst.Ref.bool_true, |
| ... | @@ -29940,7 +30708,7 @@ fn cmpNumeric( | ... | @@ -29940,7 +30708,7 @@ fn cmpNumeric( |
| 29940 | } | 30708 | } |
| 29941 | } | 30709 | } |
| 29942 | if (lhs_is_float) { | 30710 | if (lhs_is_float) { |
| 29943 | if (lhs_val.floatHasFraction()) { | 30711 | if (lhs_val.floatHasFraction(mod)) { |
| 29944 | switch (op) { | 30712 | switch (op) { |
| 29945 | .eq => return Air.Inst.Ref.bool_false, | 30713 | .eq => return Air.Inst.Ref.bool_false, |
| 29946 | .neq => return Air.Inst.Ref.bool_true, | 30714 | .neq => return Air.Inst.Ref.bool_true, |
| ... | @@ -29948,9 +30716,9 @@ fn cmpNumeric( | ... | @@ -29948,9 +30716,9 @@ fn cmpNumeric( |
| 29948 | } | 30716 | } |
| 29949 | } | 30717 | } |
| 29950 | 30718 | ||
| 29951 | var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128)); | 30719 | var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128, mod)); |
| 29952 | defer bigint.deinit(); | 30720 | defer bigint.deinit(); |
| 29953 | if (lhs_val.floatHasFraction()) { | 30721 | if (lhs_val.floatHasFraction(mod)) { |
| 29954 | if (lhs_is_signed) { | 30722 | if (lhs_is_signed) { |
| 29955 | try bigint.addScalar(&bigint, -1); | 30723 | try bigint.addScalar(&bigint, -1); |
| 29956 | } else { | 30724 | } else { |
| ... | @@ -29959,33 +30727,32 @@ fn cmpNumeric( | ... | @@ -29959,33 +30727,32 @@ fn cmpNumeric( |
| 29959 | } | 30727 | } |
| 29960 | lhs_bits = bigint.toConst().bitCountTwosComp(); | 30728 | lhs_bits = bigint.toConst().bitCountTwosComp(); |
| 29961 | } else { | 30729 | } else { |
| 29962 | lhs_bits = lhs_val.intBitCountTwosComp(target); | 30730 | lhs_bits = lhs_val.intBitCountTwosComp(mod); |
| 29963 | } | 30731 | } |
| 29964 | lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed); | 30732 | lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed); |
| 29965 | } else if (lhs_is_float) { | 30733 | } else if (lhs_is_float) { |
| 29966 | dest_float_type = lhs_ty; | 30734 | dest_float_type = lhs_ty; |
| 29967 | } else { | 30735 | } else { |
| 29968 | const int_info = lhs_ty.intInfo(target); | 30736 | const int_info = lhs_ty.intInfo(mod); |
| 29969 | lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed); | 30737 | lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed); |
| 29970 | } | 30738 | } |
| 29971 | 30739 | ||
| 29972 | var rhs_bits: usize = undefined; | 30740 | var rhs_bits: usize = undefined; |
| 29973 | if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| { | 30741 | if (try sema.resolveMaybeUndefLazyVal(rhs)) |rhs_val| { |
| 29974 | try sema.resolveLazyValue(rhs_val); | 30742 | if (rhs_val.isUndef(mod)) |
| 29975 | if (rhs_val.isUndef()) | ||
| 29976 | return sema.addConstUndef(Type.bool); | 30743 | return sema.addConstUndef(Type.bool); |
| 29977 | if (rhs_val.isNan()) switch (op) { | 30744 | if (rhs_val.isNan(mod)) switch (op) { |
| 29978 | .neq => return Air.Inst.Ref.bool_true, | 30745 | .neq => return Air.Inst.Ref.bool_true, |
| 29979 | else => return Air.Inst.Ref.bool_false, | 30746 | else => return Air.Inst.Ref.bool_false, |
| 29980 | }; | 30747 | }; |
| 29981 | if (rhs_val.isInf()) switch (op) { | 30748 | if (rhs_val.isInf(mod)) switch (op) { |
| 29982 | .neq => return Air.Inst.Ref.bool_true, | 30749 | .neq => return Air.Inst.Ref.bool_true, |
| 29983 | .eq => return Air.Inst.Ref.bool_false, | 30750 | .eq => return Air.Inst.Ref.bool_false, |
| 29984 | .gt, .gte => return if (rhs_val.isNegativeInf()) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, | 30751 | .gt, .gte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, |
| 29985 | .lt, .lte => return if (rhs_val.isNegativeInf()) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, | 30752 | .lt, .lte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, |
| 29986 | }; | 30753 | }; |
| 29987 | if (!lhs_is_signed) { | 30754 | if (!lhs_is_signed) { |
| 29988 | switch (rhs_val.orderAgainstZero()) { | 30755 | switch (rhs_val.orderAgainstZero(mod)) { |
| 29989 | .gt => {}, | 30756 | .gt => {}, |
| 29990 | .eq => switch (op) { // RHS = 0, LHS is unsigned | 30757 | .eq => switch (op) { // RHS = 0, LHS is unsigned |
| 29991 | .gte => return Air.Inst.Ref.bool_true, | 30758 | .gte => return Air.Inst.Ref.bool_true, |
| ... | @@ -29999,7 +30766,7 @@ fn cmpNumeric( | ... | @@ -29999,7 +30766,7 @@ fn cmpNumeric( |
| 29999 | } | 30766 | } |
| 30000 | } | 30767 | } |
| 30001 | if (rhs_is_float) { | 30768 | if (rhs_is_float) { |
| 30002 | if (rhs_val.floatHasFraction()) { | 30769 | if (rhs_val.floatHasFraction(mod)) { |
| 30003 | switch (op) { | 30770 | switch (op) { |
| 30004 | .eq => return Air.Inst.Ref.bool_false, | 30771 | .eq => return Air.Inst.Ref.bool_false, |
| 30005 | .neq => return Air.Inst.Ref.bool_true, | 30772 | .neq => return Air.Inst.Ref.bool_true, |
| ... | @@ -30007,9 +30774,9 @@ fn cmpNumeric( | ... | @@ -30007,9 +30774,9 @@ fn cmpNumeric( |
| 30007 | } | 30774 | } |
| 30008 | } | 30775 | } |
| 30009 | 30776 | ||
| 30010 | var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128)); | 30777 | var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128, mod)); |
| 30011 | defer bigint.deinit(); | 30778 | defer bigint.deinit(); |
| 30012 | if (rhs_val.floatHasFraction()) { | 30779 | if (rhs_val.floatHasFraction(mod)) { |
| 30013 | if (rhs_is_signed) { | 30780 | if (rhs_is_signed) { |
| 30014 | try bigint.addScalar(&bigint, -1); | 30781 | try bigint.addScalar(&bigint, -1); |
| 30015 | } else { | 30782 | } else { |
| ... | @@ -30018,13 +30785,13 @@ fn cmpNumeric( | ... | @@ -30018,13 +30785,13 @@ fn cmpNumeric( |
| 30018 | } | 30785 | } |
| 30019 | rhs_bits = bigint.toConst().bitCountTwosComp(); | 30786 | rhs_bits = bigint.toConst().bitCountTwosComp(); |
| 30020 | } else { | 30787 | } else { |
| 30021 | rhs_bits = rhs_val.intBitCountTwosComp(target); | 30788 | rhs_bits = rhs_val.intBitCountTwosComp(mod); |
| 30022 | } | 30789 | } |
| 30023 | rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed); | 30790 | rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed); |
| 30024 | } else if (rhs_is_float) { | 30791 | } else if (rhs_is_float) { |
| 30025 | dest_float_type = rhs_ty; | 30792 | dest_float_type = rhs_ty; |
| 30026 | } else { | 30793 | } else { |
| 30027 | const int_info = rhs_ty.intInfo(target); | 30794 | const int_info = rhs_ty.intInfo(mod); |
| 30028 | rhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed); | 30795 | rhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed); |
| 30029 | } | 30796 | } |
| 30030 | 30797 | ||
| ... | @@ -30032,7 +30799,7 @@ fn cmpNumeric( | ... | @@ -30032,7 +30799,7 @@ fn cmpNumeric( |
| 30032 | const max_bits = std.math.max(lhs_bits, rhs_bits); | 30799 | const max_bits = std.math.max(lhs_bits, rhs_bits); |
| 30033 | const casted_bits = std.math.cast(u16, max_bits) orelse return sema.fail(block, src, "{d} exceeds maximum integer bit count", .{max_bits}); | 30800 | const casted_bits = std.math.cast(u16, max_bits) orelse return sema.fail(block, src, "{d} exceeds maximum integer bit count", .{max_bits}); |
| 30034 | const signedness: std.builtin.Signedness = if (dest_int_is_signed) .signed else .unsigned; | 30801 | const signedness: std.builtin.Signedness = if (dest_int_is_signed) .signed else .unsigned; |
| 30035 | break :blk try Module.makeIntType(sema.arena, signedness, casted_bits); | 30802 | break :blk try mod.intType(signedness, casted_bits); |
| 30036 | }; | 30803 | }; |
| 30037 | const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); | 30804 | const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); |
| 30038 | const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); | 30805 | const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); |
| ... | @@ -30040,13 +30807,20 @@ fn cmpNumeric( | ... | @@ -30040,13 +30807,20 @@ fn cmpNumeric( |
| 30040 | return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs); | 30807 | return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs); |
| 30041 | } | 30808 | } |
| 30042 | 30809 | ||
| 30043 | /// Asserts that LHS value is an int or comptime int and not undefined, and that RHS type is an int. | 30810 | /// Asserts that LHS value is an int or comptime int and not undefined, and |
| 30044 | /// Given a const LHS and an unknown RHS, attempt to determine whether `op` has a guaranteed result. | 30811 | /// that RHS type is an int. Given a const LHS and an unknown RHS, attempt to |
| 30812 | /// determine whether `op` has a guaranteed result. | ||
| 30045 | /// If it cannot be determined, returns null. | 30813 | /// If it cannot be determined, returns null. |
| 30046 | /// Otherwise returns a bool for the guaranteed comparison operation. | 30814 | /// Otherwise returns a bool for the guaranteed comparison operation. |
| 30047 | fn compareIntsOnlyPossibleResult(sema: *Sema, target: std.Target, lhs_val: Value, op: std.math.CompareOperator, rhs_ty: Type) ?bool { | 30815 | fn compareIntsOnlyPossibleResult( |
| 30048 | const rhs_info = rhs_ty.intInfo(target); | 30816 | sema: *Sema, |
| 30049 | const vs_zero = lhs_val.orderAgainstZeroAdvanced(sema) catch unreachable; | 30817 | lhs_val: Value, |
| 30818 | op: std.math.CompareOperator, | ||
| 30819 | rhs_ty: Type, | ||
| 30820 | ) Allocator.Error!?bool { | ||
| 30821 | const mod = sema.mod; | ||
| 30822 | const rhs_info = rhs_ty.intInfo(mod); | ||
| 30823 | const vs_zero = lhs_val.orderAgainstZeroAdvanced(mod, sema) catch unreachable; | ||
| 30050 | const is_zero = vs_zero == .eq; | 30824 | const is_zero = vs_zero == .eq; |
| 30051 | const is_negative = vs_zero == .lt; | 30825 | const is_negative = vs_zero == .lt; |
| 30052 | const is_positive = vs_zero == .gt; | 30826 | const is_positive = vs_zero == .gt; |
| ... | @@ -30078,7 +30852,7 @@ fn compareIntsOnlyPossibleResult(sema: *Sema, target: std.Target, lhs_val: Value | ... | @@ -30078,7 +30852,7 @@ fn compareIntsOnlyPossibleResult(sema: *Sema, target: std.Target, lhs_val: Value |
| 30078 | }; | 30852 | }; |
| 30079 | 30853 | ||
| 30080 | const sign_adj = @boolToInt(!is_negative and rhs_info.signedness == .signed); | 30854 | const sign_adj = @boolToInt(!is_negative and rhs_info.signedness == .signed); |
| 30081 | const req_bits = lhs_val.intBitCountTwosComp(target) + sign_adj; | 30855 | const req_bits = lhs_val.intBitCountTwosComp(mod) + sign_adj; |
| 30082 | 30856 | ||
| 30083 | // No sized type can have more than 65535 bits. | 30857 | // No sized type can have more than 65535 bits. |
| 30084 | // The RHS type operand is either a runtime value or sized (but undefined) constant. | 30858 | // The RHS type operand is either a runtime value or sized (but undefined) constant. |
| ... | @@ -30111,12 +30885,11 @@ fn compareIntsOnlyPossibleResult(sema: *Sema, target: std.Target, lhs_val: Value | ... | @@ -30111,12 +30885,11 @@ fn compareIntsOnlyPossibleResult(sema: *Sema, target: std.Target, lhs_val: Value |
| 30111 | .max = false, | 30885 | .max = false, |
| 30112 | }; | 30886 | }; |
| 30113 | 30887 | ||
| 30114 | var ty_buffer: Type.Payload.Bits = .{ | 30888 | const ty = try mod.intType( |
| 30115 | .base = .{ .tag = if (is_negative) .int_signed else .int_unsigned }, | 30889 | if (is_negative) .signed else .unsigned, |
| 30116 | .data = @intCast(u16, req_bits), | 30890 | @intCast(u16, req_bits), |
| 30117 | }; | 30891 | ); |
| 30118 | const ty = Type.initPayload(&ty_buffer.base); | 30892 | const pop_count = lhs_val.popCount(ty, mod); |
| 30119 | const pop_count = lhs_val.popCount(ty, target); | ||
| 30120 | 30893 | ||
| 30121 | if (is_negative) { | 30894 | if (is_negative) { |
| 30122 | break :edge .{ | 30895 | break :edge .{ |
| ... | @@ -30152,22 +30925,26 @@ fn cmpVector( | ... | @@ -30152,22 +30925,26 @@ fn cmpVector( |
| 30152 | lhs_src: LazySrcLoc, | 30925 | lhs_src: LazySrcLoc, |
| 30153 | rhs_src: LazySrcLoc, | 30926 | rhs_src: LazySrcLoc, |
| 30154 | ) CompileError!Air.Inst.Ref { | 30927 | ) CompileError!Air.Inst.Ref { |
| 30928 | const mod = sema.mod; | ||
| 30155 | const lhs_ty = sema.typeOf(lhs); | 30929 | const lhs_ty = sema.typeOf(lhs); |
| 30156 | const rhs_ty = sema.typeOf(rhs); | 30930 | const rhs_ty = sema.typeOf(rhs); |
| 30157 | assert(lhs_ty.zigTypeTag() == .Vector); | 30931 | assert(lhs_ty.zigTypeTag(mod) == .Vector); |
| 30158 | assert(rhs_ty.zigTypeTag() == .Vector); | 30932 | assert(rhs_ty.zigTypeTag(mod) == .Vector); |
| 30159 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | 30933 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 30160 | 30934 | ||
| 30161 | const resolved_ty = try sema.resolvePeerTypes(block, src, &.{ lhs, rhs }, .{ .override = &.{ lhs_src, rhs_src } }); | 30935 | const resolved_ty = try sema.resolvePeerTypes(block, src, &.{ lhs, rhs }, .{ .override = &.{ lhs_src, rhs_src } }); |
| 30162 | const casted_lhs = try sema.coerce(block, resolved_ty, lhs, lhs_src); | 30936 | const casted_lhs = try sema.coerce(block, resolved_ty, lhs, lhs_src); |
| 30163 | const casted_rhs = try sema.coerce(block, resolved_ty, rhs, rhs_src); | 30937 | const casted_rhs = try sema.coerce(block, resolved_ty, rhs, rhs_src); |
| 30164 | 30938 | ||
| 30165 | const result_ty = try Type.vector(sema.arena, lhs_ty.vectorLen(), Type.bool); | 30939 | const result_ty = try mod.vectorType(.{ |
| 30940 | .len = lhs_ty.vectorLen(mod), | ||
| 30941 | .child = .bool_type, | ||
| 30942 | }); | ||
| 30166 | 30943 | ||
| 30167 | const runtime_src: LazySrcLoc = src: { | 30944 | const runtime_src: LazySrcLoc = src: { |
| 30168 | if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| { | 30945 | if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| { |
| 30169 | if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| { | 30946 | if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| { |
| 30170 | if (lhs_val.isUndef() or rhs_val.isUndef()) { | 30947 | if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) { |
| 30171 | return sema.addConstUndef(result_ty); | 30948 | return sema.addConstUndef(result_ty); |
| 30172 | } | 30949 | } |
| 30173 | const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_ty); | 30950 | const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_ty); |
| ... | @@ -30192,7 +30969,10 @@ fn wrapOptional( | ... | @@ -30192,7 +30969,10 @@ fn wrapOptional( |
| 30192 | inst_src: LazySrcLoc, | 30969 | inst_src: LazySrcLoc, |
| 30193 | ) !Air.Inst.Ref { | 30970 | ) !Air.Inst.Ref { |
| 30194 | if (try sema.resolveMaybeUndefVal(inst)) |val| { | 30971 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 30195 | return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, val)); | 30972 | return sema.addConstant(dest_ty, (try sema.mod.intern(.{ .opt = .{ |
| 30973 | .ty = dest_ty.toIntern(), | ||
| 30974 | .val = val.toIntern(), | ||
| 30975 | } })).toValue()); | ||
| 30196 | } | 30976 | } |
| 30197 | 30977 | ||
| 30198 | try sema.requireRuntimeBlock(block, inst_src, null); | 30978 | try sema.requireRuntimeBlock(block, inst_src, null); |
| ... | @@ -30206,10 +30986,14 @@ fn wrapErrorUnionPayload( | ... | @@ -30206,10 +30986,14 @@ fn wrapErrorUnionPayload( |
| 30206 | inst: Air.Inst.Ref, | 30986 | inst: Air.Inst.Ref, |
| 30207 | inst_src: LazySrcLoc, | 30987 | inst_src: LazySrcLoc, |
| 30208 | ) !Air.Inst.Ref { | 30988 | ) !Air.Inst.Ref { |
| 30209 | const dest_payload_ty = dest_ty.errorUnionPayload(); | 30989 | const mod = sema.mod; |
| 30990 | const dest_payload_ty = dest_ty.errorUnionPayload(mod); | ||
| 30210 | const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false }); | 30991 | const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false }); |
| 30211 | if (try sema.resolveMaybeUndefVal(coerced)) |val| { | 30992 | if (try sema.resolveMaybeUndefVal(coerced)) |val| { |
| 30212 | return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val)); | 30993 | return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{ |
| 30994 | .ty = dest_ty.toIntern(), | ||
| 30995 | .val = .{ .payload = try val.intern(dest_payload_ty, mod) }, | ||
| 30996 | } })).toValue()); | ||
| 30213 | } | 30997 | } |
| 30214 | try sema.requireRuntimeBlock(block, inst_src, null); | 30998 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 30215 | try sema.queueFullTypeResolution(dest_payload_ty); | 30999 | try sema.queueFullTypeResolution(dest_payload_ty); |
| ... | @@ -30223,48 +31007,41 @@ fn wrapErrorUnionSet( | ... | @@ -30223,48 +31007,41 @@ fn wrapErrorUnionSet( |
| 30223 | inst: Air.Inst.Ref, | 31007 | inst: Air.Inst.Ref, |
| 30224 | inst_src: LazySrcLoc, | 31008 | inst_src: LazySrcLoc, |
| 30225 | ) !Air.Inst.Ref { | 31009 | ) !Air.Inst.Ref { |
| 31010 | const mod = sema.mod; | ||
| 31011 | const ip = &mod.intern_pool; | ||
| 30226 | const inst_ty = sema.typeOf(inst); | 31012 | const inst_ty = sema.typeOf(inst); |
| 30227 | const dest_err_set_ty = dest_ty.errorUnionSet(); | 31013 | const dest_err_set_ty = dest_ty.errorUnionSet(mod); |
| 30228 | if (try sema.resolveMaybeUndefVal(inst)) |val| { | 31014 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 30229 | switch (dest_err_set_ty.tag()) { | 31015 | switch (dest_err_set_ty.toIntern()) { |
| 30230 | .anyerror => {}, | 31016 | .anyerror_type => {}, |
| 30231 | .error_set_single => ok: { | 31017 | else => switch (ip.indexToKey(dest_err_set_ty.toIntern())) { |
| 30232 | const expected_name = val.castTag(.@"error").?.data.name; | 31018 | .error_set_type => |error_set_type| ok: { |
| 30233 | const n = dest_err_set_ty.castTag(.error_set_single).?.data; | 31019 | const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; |
| 30234 | if (mem.eql(u8, expected_name, n)) break :ok; | 31020 | if (error_set_type.nameIndex(ip, expected_name) != null) break :ok; |
| 30235 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); | ||
| 30236 | }, | ||
| 30237 | .error_set => { | ||
| 30238 | const expected_name = val.castTag(.@"error").?.data.name; | ||
| 30239 | const error_set = dest_err_set_ty.castTag(.error_set).?.data; | ||
| 30240 | if (!error_set.names.contains(expected_name)) { | ||
| 30241 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); | 31021 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); |
| 30242 | } | 31022 | }, |
| 30243 | }, | 31023 | .inferred_error_set_type => |ies_index| ok: { |
| 30244 | .error_set_inferred => ok: { | 31024 | const ies = mod.inferredErrorSetPtr(ies_index); |
| 30245 | const expected_name = val.castTag(.@"error").?.data.name; | 31025 | const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; |
| 30246 | const ies = dest_err_set_ty.castTag(.error_set_inferred).?.data; | ||
| 30247 | 31026 | ||
| 30248 | // We carefully do this in an order that avoids unnecessarily | 31027 | // We carefully do this in an order that avoids unnecessarily |
| 30249 | // resolving the destination error set type. | 31028 | // resolving the destination error set type. |
| 30250 | if (ies.is_anyerror) break :ok; | 31029 | if (ies.is_anyerror) break :ok; |
| 30251 | if (ies.errors.contains(expected_name)) break :ok; | 31030 | |
| 30252 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) { | 31031 | if (ies.errors.contains(expected_name)) break :ok; |
| 30253 | break :ok; | 31032 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) break :ok; |
| 30254 | } | ||
| 30255 | 31033 | ||
| 30256 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); | ||
| 30257 | }, | ||
| 30258 | .error_set_merged => { | ||
| 30259 | const expected_name = val.castTag(.@"error").?.data.name; | ||
| 30260 | const error_set = dest_err_set_ty.castTag(.error_set_merged).?.data; | ||
| 30261 | if (!error_set.contains(expected_name)) { | ||
| 30262 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); | 31034 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); |
| 30263 | } | 31035 | }, |
| 31036 | else => unreachable, | ||
| 30264 | }, | 31037 | }, |
| 30265 | else => unreachable, | ||
| 30266 | } | 31038 | } |
| 30267 | return sema.addConstant(dest_ty, val); | 31039 | return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{ |
| 31040 | .ty = dest_ty.toIntern(), | ||
| 31041 | .val = .{ | ||
| 31042 | .err_name = mod.intern_pool.indexToKey(try val.intern(dest_err_set_ty, mod)).err.name, | ||
| 31043 | }, | ||
| 31044 | } })).toValue()); | ||
| 30268 | } | 31045 | } |
| 30269 | 31046 | ||
| 30270 | try sema.requireRuntimeBlock(block, inst_src, null); | 31047 | try sema.requireRuntimeBlock(block, inst_src, null); |
| ... | @@ -30279,11 +31056,12 @@ fn unionToTag( | ... | @@ -30279,11 +31056,12 @@ fn unionToTag( |
| 30279 | un: Air.Inst.Ref, | 31056 | un: Air.Inst.Ref, |
| 30280 | un_src: LazySrcLoc, | 31057 | un_src: LazySrcLoc, |
| 30281 | ) !Air.Inst.Ref { | 31058 | ) !Air.Inst.Ref { |
| 31059 | const mod = sema.mod; | ||
| 30282 | if ((try sema.typeHasOnePossibleValue(enum_ty))) |opv| { | 31060 | if ((try sema.typeHasOnePossibleValue(enum_ty))) |opv| { |
| 30283 | return sema.addConstant(enum_ty, opv); | 31061 | return sema.addConstant(enum_ty, opv); |
| 30284 | } | 31062 | } |
| 30285 | if (try sema.resolveMaybeUndefVal(un)) |un_val| { | 31063 | if (try sema.resolveMaybeUndefVal(un)) |un_val| { |
| 30286 | return sema.addConstant(enum_ty, un_val.unionTag()); | 31064 | return sema.addConstant(enum_ty, un_val.unionTag(mod)); |
| 30287 | } | 31065 | } |
| 30288 | try sema.requireRuntimeBlock(block, un_src, null); | 31066 | try sema.requireRuntimeBlock(block, un_src, null); |
| 30289 | return block.addTyOp(.get_union_tag, enum_ty, un); | 31067 | return block.addTyOp(.get_union_tag, enum_ty, un); |
| ... | @@ -30296,16 +31074,17 @@ fn resolvePeerTypes( | ... | @@ -30296,16 +31074,17 @@ fn resolvePeerTypes( |
| 30296 | instructions: []const Air.Inst.Ref, | 31074 | instructions: []const Air.Inst.Ref, |
| 30297 | candidate_srcs: Module.PeerTypeCandidateSrc, | 31075 | candidate_srcs: Module.PeerTypeCandidateSrc, |
| 30298 | ) !Type { | 31076 | ) !Type { |
| 31077 | const mod = sema.mod; | ||
| 30299 | switch (instructions.len) { | 31078 | switch (instructions.len) { |
| 30300 | 0 => return Type.initTag(.noreturn), | 31079 | 0 => return Type.noreturn, |
| 30301 | 1 => return sema.typeOf(instructions[0]), | 31080 | 1 => return sema.typeOf(instructions[0]), |
| 30302 | else => {}, | 31081 | else => {}, |
| 30303 | } | 31082 | } |
| 30304 | 31083 | ||
| 30305 | const target = sema.mod.getTarget(); | 31084 | const target = mod.getTarget(); |
| 30306 | 31085 | ||
| 30307 | var chosen = instructions[0]; | 31086 | var chosen = instructions[0]; |
| 30308 | // If this is non-null then it does the following thing, depending on the chosen zigTypeTag(). | 31087 | // If this is non-null then it does the following thing, depending on the chosen zigTypeTag(mod). |
| 30309 | // * ErrorSet: this is an override | 31088 | // * ErrorSet: this is an override |
| 30310 | // * ErrorUnion: this is an override of the error set only | 31089 | // * ErrorUnion: this is an override of the error set only |
| 30311 | // * other: at the end we make an ErrorUnion with the other thing and this | 31090 | // * other: at the end we make an ErrorUnion with the other thing and this |
| ... | @@ -30318,8 +31097,8 @@ fn resolvePeerTypes( | ... | @@ -30318,8 +31097,8 @@ fn resolvePeerTypes( |
| 30318 | const candidate_ty = sema.typeOf(candidate); | 31097 | const candidate_ty = sema.typeOf(candidate); |
| 30319 | const chosen_ty = sema.typeOf(chosen); | 31098 | const chosen_ty = sema.typeOf(chosen); |
| 30320 | 31099 | ||
| 30321 | const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison(); | 31100 | const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison(mod); |
| 30322 | const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison(); | 31101 | const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison(mod); |
| 30323 | 31102 | ||
| 30324 | // If the candidate can coerce into our chosen type, we're done. | 31103 | // If the candidate can coerce into our chosen type, we're done. |
| 30325 | // If the chosen type can coerce into the candidate, use that. | 31104 | // If the chosen type can coerce into the candidate, use that. |
| ... | @@ -30347,8 +31126,8 @@ fn resolvePeerTypes( | ... | @@ -30347,8 +31126,8 @@ fn resolvePeerTypes( |
| 30347 | continue; | 31126 | continue; |
| 30348 | }, | 31127 | }, |
| 30349 | .Int => { | 31128 | .Int => { |
| 30350 | const chosen_info = chosen_ty.intInfo(target); | 31129 | const chosen_info = chosen_ty.intInfo(mod); |
| 30351 | const candidate_info = candidate_ty.intInfo(target); | 31130 | const candidate_info = candidate_ty.intInfo(mod); |
| 30352 | 31131 | ||
| 30353 | if (chosen_info.bits < candidate_info.bits) { | 31132 | if (chosen_info.bits < candidate_info.bits) { |
| 30354 | chosen = candidate; | 31133 | chosen = candidate; |
| ... | @@ -30356,12 +31135,12 @@ fn resolvePeerTypes( | ... | @@ -30356,12 +31135,12 @@ fn resolvePeerTypes( |
| 30356 | } | 31135 | } |
| 30357 | continue; | 31136 | continue; |
| 30358 | }, | 31137 | }, |
| 30359 | .Pointer => if (chosen_ty.ptrSize() == .C) continue, | 31138 | .Pointer => if (chosen_ty.ptrSize(mod) == .C) continue, |
| 30360 | else => {}, | 31139 | else => {}, |
| 30361 | }, | 31140 | }, |
| 30362 | .ComptimeInt => switch (chosen_ty_tag) { | 31141 | .ComptimeInt => switch (chosen_ty_tag) { |
| 30363 | .Int, .Float, .ComptimeFloat => continue, | 31142 | .Int, .Float, .ComptimeFloat => continue, |
| 30364 | .Pointer => if (chosen_ty.ptrSize() == .C) continue, | 31143 | .Pointer => if (chosen_ty.ptrSize(mod) == .C) continue, |
| 30365 | else => {}, | 31144 | else => {}, |
| 30366 | }, | 31145 | }, |
| 30367 | .Float => switch (chosen_ty_tag) { | 31146 | .Float => switch (chosen_ty_tag) { |
| ... | @@ -30426,11 +31205,11 @@ fn resolvePeerTypes( | ... | @@ -30426,11 +31205,11 @@ fn resolvePeerTypes( |
| 30426 | continue; | 31205 | continue; |
| 30427 | } | 31206 | } |
| 30428 | 31207 | ||
| 30429 | err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty); | 31208 | err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty); |
| 30430 | continue; | 31209 | continue; |
| 30431 | }, | 31210 | }, |
| 30432 | .ErrorUnion => { | 31211 | .ErrorUnion => { |
| 30433 | const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); | 31212 | const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); |
| 30434 | 31213 | ||
| 30435 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) { | 31214 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) { |
| 30436 | continue; | 31215 | continue; |
| ... | @@ -30440,7 +31219,7 @@ fn resolvePeerTypes( | ... | @@ -30440,7 +31219,7 @@ fn resolvePeerTypes( |
| 30440 | continue; | 31219 | continue; |
| 30441 | } | 31220 | } |
| 30442 | 31221 | ||
| 30443 | err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty); | 31222 | err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty); |
| 30444 | continue; | 31223 | continue; |
| 30445 | }, | 31224 | }, |
| 30446 | else => { | 31225 | else => { |
| ... | @@ -30453,7 +31232,7 @@ fn resolvePeerTypes( | ... | @@ -30453,7 +31232,7 @@ fn resolvePeerTypes( |
| 30453 | continue; | 31232 | continue; |
| 30454 | } | 31233 | } |
| 30455 | 31234 | ||
| 30456 | err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty); | 31235 | err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_ty); |
| 30457 | continue; | 31236 | continue; |
| 30458 | } else { | 31237 | } else { |
| 30459 | err_set_ty = candidate_ty; | 31238 | err_set_ty = candidate_ty; |
| ... | @@ -30464,14 +31243,14 @@ fn resolvePeerTypes( | ... | @@ -30464,14 +31243,14 @@ fn resolvePeerTypes( |
| 30464 | .ErrorUnion => switch (chosen_ty_tag) { | 31243 | .ErrorUnion => switch (chosen_ty_tag) { |
| 30465 | .ErrorSet => { | 31244 | .ErrorSet => { |
| 30466 | const chosen_set_ty = err_set_ty orelse chosen_ty; | 31245 | const chosen_set_ty = err_set_ty orelse chosen_ty; |
| 30467 | const candidate_set_ty = candidate_ty.errorUnionSet(); | 31246 | const candidate_set_ty = candidate_ty.errorUnionSet(mod); |
| 30468 | 31247 | ||
| 30469 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { | 31248 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { |
| 30470 | err_set_ty = chosen_set_ty; | 31249 | err_set_ty = chosen_set_ty; |
| 30471 | } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { | 31250 | } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { |
| 30472 | err_set_ty = null; | 31251 | err_set_ty = null; |
| 30473 | } else { | 31252 | } else { |
| 30474 | err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty); | 31253 | err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty); |
| 30475 | } | 31254 | } |
| 30476 | chosen = candidate; | 31255 | chosen = candidate; |
| 30477 | chosen_i = candidate_i + 1; | 31256 | chosen_i = candidate_i + 1; |
| ... | @@ -30479,8 +31258,8 @@ fn resolvePeerTypes( | ... | @@ -30479,8 +31258,8 @@ fn resolvePeerTypes( |
| 30479 | }, | 31258 | }, |
| 30480 | 31259 | ||
| 30481 | .ErrorUnion => { | 31260 | .ErrorUnion => { |
| 30482 | const chosen_payload_ty = chosen_ty.errorUnionPayload(); | 31261 | const chosen_payload_ty = chosen_ty.errorUnionPayload(mod); |
| 30483 | const candidate_payload_ty = candidate_ty.errorUnionPayload(); | 31262 | const candidate_payload_ty = candidate_ty.errorUnionPayload(mod); |
| 30484 | 31263 | ||
| 30485 | const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok; | 31264 | const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok; |
| 30486 | const coerce_candidate = (try sema.coerceInMemoryAllowed(block, candidate_payload_ty, chosen_payload_ty, false, target, src, src)) == .ok; | 31265 | const coerce_candidate = (try sema.coerceInMemoryAllowed(block, candidate_payload_ty, chosen_payload_ty, false, target, src, src)) == .ok; |
| ... | @@ -30494,15 +31273,15 @@ fn resolvePeerTypes( | ... | @@ -30494,15 +31273,15 @@ fn resolvePeerTypes( |
| 30494 | chosen_i = candidate_i + 1; | 31273 | chosen_i = candidate_i + 1; |
| 30495 | } | 31274 | } |
| 30496 | 31275 | ||
| 30497 | const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); | 31276 | const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); |
| 30498 | const candidate_set_ty = candidate_ty.errorUnionSet(); | 31277 | const candidate_set_ty = candidate_ty.errorUnionSet(mod); |
| 30499 | 31278 | ||
| 30500 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { | 31279 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { |
| 30501 | err_set_ty = chosen_set_ty; | 31280 | err_set_ty = chosen_set_ty; |
| 30502 | } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { | 31281 | } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { |
| 30503 | err_set_ty = candidate_set_ty; | 31282 | err_set_ty = candidate_set_ty; |
| 30504 | } else { | 31283 | } else { |
| 30505 | err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty); | 31284 | err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty); |
| 30506 | } | 31285 | } |
| 30507 | continue; | 31286 | continue; |
| 30508 | } | 31287 | } |
| ... | @@ -30510,26 +31289,26 @@ fn resolvePeerTypes( | ... | @@ -30510,26 +31289,26 @@ fn resolvePeerTypes( |
| 30510 | 31289 | ||
| 30511 | else => { | 31290 | else => { |
| 30512 | if (err_set_ty) |chosen_set_ty| { | 31291 | if (err_set_ty) |chosen_set_ty| { |
| 30513 | const candidate_set_ty = candidate_ty.errorUnionSet(); | 31292 | const candidate_set_ty = candidate_ty.errorUnionSet(mod); |
| 30514 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { | 31293 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) { |
| 30515 | err_set_ty = chosen_set_ty; | 31294 | err_set_ty = chosen_set_ty; |
| 30516 | } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { | 31295 | } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) { |
| 30517 | err_set_ty = null; | 31296 | err_set_ty = null; |
| 30518 | } else { | 31297 | } else { |
| 30519 | err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty); | 31298 | err_set_ty = try sema.errorSetMerge(chosen_set_ty, candidate_set_ty); |
| 30520 | } | 31299 | } |
| 30521 | } | 31300 | } |
| 30522 | seen_const = seen_const or chosen_ty.isConstPtr(); | 31301 | seen_const = seen_const or chosen_ty.isConstPtr(mod); |
| 30523 | chosen = candidate; | 31302 | chosen = candidate; |
| 30524 | chosen_i = candidate_i + 1; | 31303 | chosen_i = candidate_i + 1; |
| 30525 | continue; | 31304 | continue; |
| 30526 | }, | 31305 | }, |
| 30527 | }, | 31306 | }, |
| 30528 | .Pointer => { | 31307 | .Pointer => { |
| 30529 | const cand_info = candidate_ty.ptrInfo().data; | 31308 | const cand_info = candidate_ty.ptrInfo(mod); |
| 30530 | switch (chosen_ty_tag) { | 31309 | switch (chosen_ty_tag) { |
| 30531 | .Pointer => { | 31310 | .Pointer => { |
| 30532 | const chosen_info = chosen_ty.ptrInfo().data; | 31311 | const chosen_info = chosen_ty.ptrInfo(mod); |
| 30533 | 31312 | ||
| 30534 | seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; | 31313 | seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; |
| 30535 | 31314 | ||
| ... | @@ -30537,7 +31316,7 @@ fn resolvePeerTypes( | ... | @@ -30537,7 +31316,7 @@ fn resolvePeerTypes( |
| 30537 | // *[N]T to []T | 31316 | // *[N]T to []T |
| 30538 | if ((cand_info.size == .Many or cand_info.size == .Slice) and | 31317 | if ((cand_info.size == .Many or cand_info.size == .Slice) and |
| 30539 | chosen_info.size == .One and | 31318 | chosen_info.size == .One and |
| 30540 | chosen_info.pointee_type.zigTypeTag() == .Array) | 31319 | chosen_info.pointee_type.zigTypeTag(mod) == .Array) |
| 30541 | { | 31320 | { |
| 30542 | // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T` | 31321 | // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T` |
| 30543 | convert_to_slice = false; | 31322 | convert_to_slice = false; |
| ... | @@ -30546,7 +31325,7 @@ fn resolvePeerTypes( | ... | @@ -30546,7 +31325,7 @@ fn resolvePeerTypes( |
| 30546 | continue; | 31325 | continue; |
| 30547 | } | 31326 | } |
| 30548 | if (cand_info.size == .One and | 31327 | if (cand_info.size == .One and |
| 30549 | cand_info.pointee_type.zigTypeTag() == .Array and | 31328 | cand_info.pointee_type.zigTypeTag(mod) == .Array and |
| 30550 | (chosen_info.size == .Many or chosen_info.size == .Slice)) | 31329 | (chosen_info.size == .Many or chosen_info.size == .Slice)) |
| 30551 | { | 31330 | { |
| 30552 | // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T` | 31331 | // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T` |
| ... | @@ -30559,11 +31338,11 @@ fn resolvePeerTypes( | ... | @@ -30559,11 +31338,11 @@ fn resolvePeerTypes( |
| 30559 | // Keep the one whose element type can be coerced into. | 31338 | // Keep the one whose element type can be coerced into. |
| 30560 | if (chosen_info.size == .One and | 31339 | if (chosen_info.size == .One and |
| 30561 | cand_info.size == .One and | 31340 | cand_info.size == .One and |
| 30562 | chosen_info.pointee_type.zigTypeTag() == .Array and | 31341 | chosen_info.pointee_type.zigTypeTag(mod) == .Array and |
| 30563 | cand_info.pointee_type.zigTypeTag() == .Array) | 31342 | cand_info.pointee_type.zigTypeTag(mod) == .Array) |
| 30564 | { | 31343 | { |
| 30565 | const chosen_elem_ty = chosen_info.pointee_type.childType(); | 31344 | const chosen_elem_ty = chosen_info.pointee_type.childType(mod); |
| 30566 | const cand_elem_ty = cand_info.pointee_type.childType(); | 31345 | const cand_elem_ty = cand_info.pointee_type.childType(mod); |
| 30567 | 31346 | ||
| 30568 | const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_elem_ty, cand_elem_ty, chosen_info.mutable, target, src, src); | 31347 | const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_elem_ty, cand_elem_ty, chosen_info.mutable, target, src, src); |
| 30569 | if (chosen_ok) { | 31348 | if (chosen_ok) { |
| ... | @@ -30629,17 +31408,16 @@ fn resolvePeerTypes( | ... | @@ -30629,17 +31408,16 @@ fn resolvePeerTypes( |
| 30629 | } | 31408 | } |
| 30630 | }, | 31409 | }, |
| 30631 | .Optional => { | 31410 | .Optional => { |
| 30632 | var opt_child_buf: Type.Payload.ElemType = undefined; | 31411 | const chosen_ptr_ty = chosen_ty.optionalChild(mod); |
| 30633 | const chosen_ptr_ty = chosen_ty.optionalChild(&opt_child_buf); | 31412 | if (chosen_ptr_ty.zigTypeTag(mod) == .Pointer) { |
| 30634 | if (chosen_ptr_ty.zigTypeTag() == .Pointer) { | 31413 | const chosen_info = chosen_ptr_ty.ptrInfo(mod); |
| 30635 | const chosen_info = chosen_ptr_ty.ptrInfo().data; | ||
| 30636 | 31414 | ||
| 30637 | seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; | 31415 | seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; |
| 30638 | 31416 | ||
| 30639 | // *[N]T to ?![*]T | 31417 | // *[N]T to ?![*]T |
| 30640 | // *[N]T to ?![]T | 31418 | // *[N]T to ?![]T |
| 30641 | if (cand_info.size == .One and | 31419 | if (cand_info.size == .One and |
| 30642 | cand_info.pointee_type.zigTypeTag() == .Array and | 31420 | cand_info.pointee_type.zigTypeTag(mod) == .Array and |
| 30643 | (chosen_info.size == .Many or chosen_info.size == .Slice)) | 31421 | (chosen_info.size == .Many or chosen_info.size == .Slice)) |
| 30644 | { | 31422 | { |
| 30645 | continue; | 31423 | continue; |
| ... | @@ -30647,16 +31425,16 @@ fn resolvePeerTypes( | ... | @@ -30647,16 +31425,16 @@ fn resolvePeerTypes( |
| 30647 | } | 31425 | } |
| 30648 | }, | 31426 | }, |
| 30649 | .ErrorUnion => { | 31427 | .ErrorUnion => { |
| 30650 | const chosen_ptr_ty = chosen_ty.errorUnionPayload(); | 31428 | const chosen_ptr_ty = chosen_ty.errorUnionPayload(mod); |
| 30651 | if (chosen_ptr_ty.zigTypeTag() == .Pointer) { | 31429 | if (chosen_ptr_ty.zigTypeTag(mod) == .Pointer) { |
| 30652 | const chosen_info = chosen_ptr_ty.ptrInfo().data; | 31430 | const chosen_info = chosen_ptr_ty.ptrInfo(mod); |
| 30653 | 31431 | ||
| 30654 | seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; | 31432 | seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable; |
| 30655 | 31433 | ||
| 30656 | // *[N]T to E![*]T | 31434 | // *[N]T to E![*]T |
| 30657 | // *[N]T to E![]T | 31435 | // *[N]T to E![]T |
| 30658 | if (cand_info.size == .One and | 31436 | if (cand_info.size == .One and |
| 30659 | cand_info.pointee_type.zigTypeTag() == .Array and | 31437 | cand_info.pointee_type.zigTypeTag(mod) == .Array and |
| 30660 | (chosen_info.size == .Many or chosen_info.size == .Slice)) | 31438 | (chosen_info.size == .Many or chosen_info.size == .Slice)) |
| 30661 | { | 31439 | { |
| 30662 | continue; | 31440 | continue; |
| ... | @@ -30664,7 +31442,7 @@ fn resolvePeerTypes( | ... | @@ -30664,7 +31442,7 @@ fn resolvePeerTypes( |
| 30664 | } | 31442 | } |
| 30665 | }, | 31443 | }, |
| 30666 | .Fn => { | 31444 | .Fn => { |
| 30667 | if (!cand_info.mutable and cand_info.pointee_type.zigTypeTag() == .Fn and .ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty, cand_info.pointee_type, target, src, src)) { | 31445 | if (!cand_info.mutable and cand_info.pointee_type.zigTypeTag(mod) == .Fn and .ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty, cand_info.pointee_type, target, src, src)) { |
| 30668 | chosen = candidate; | 31446 | chosen = candidate; |
| 30669 | chosen_i = candidate_i + 1; | 31447 | chosen_i = candidate_i + 1; |
| 30670 | continue; | 31448 | continue; |
| ... | @@ -30674,15 +31452,14 @@ fn resolvePeerTypes( | ... | @@ -30674,15 +31452,14 @@ fn resolvePeerTypes( |
| 30674 | } | 31452 | } |
| 30675 | }, | 31453 | }, |
| 30676 | .Optional => { | 31454 | .Optional => { |
| 30677 | var opt_child_buf: Type.Payload.ElemType = undefined; | 31455 | const opt_child_ty = candidate_ty.optionalChild(mod); |
| 30678 | const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf); | ||
| 30679 | if ((try sema.coerceInMemoryAllowed(block, chosen_ty, opt_child_ty, false, target, src, src)) == .ok) { | 31456 | if ((try sema.coerceInMemoryAllowed(block, chosen_ty, opt_child_ty, false, target, src, src)) == .ok) { |
| 30680 | seen_const = seen_const or opt_child_ty.isConstPtr(); | 31457 | seen_const = seen_const or opt_child_ty.isConstPtr(mod); |
| 30681 | any_are_null = true; | 31458 | any_are_null = true; |
| 30682 | continue; | 31459 | continue; |
| 30683 | } | 31460 | } |
| 30684 | 31461 | ||
| 30685 | seen_const = seen_const or chosen_ty.isConstPtr(); | 31462 | seen_const = seen_const or chosen_ty.isConstPtr(mod); |
| 30686 | any_are_null = false; | 31463 | any_are_null = false; |
| 30687 | chosen = candidate; | 31464 | chosen = candidate; |
| 30688 | chosen_i = candidate_i + 1; | 31465 | chosen_i = candidate_i + 1; |
| ... | @@ -30690,23 +31467,23 @@ fn resolvePeerTypes( | ... | @@ -30690,23 +31467,23 @@ fn resolvePeerTypes( |
| 30690 | }, | 31467 | }, |
| 30691 | .Vector => switch (chosen_ty_tag) { | 31468 | .Vector => switch (chosen_ty_tag) { |
| 30692 | .Vector => { | 31469 | .Vector => { |
| 30693 | const chosen_len = chosen_ty.vectorLen(); | 31470 | const chosen_len = chosen_ty.vectorLen(mod); |
| 30694 | const candidate_len = candidate_ty.vectorLen(); | 31471 | const candidate_len = candidate_ty.vectorLen(mod); |
| 30695 | if (chosen_len != candidate_len) | 31472 | if (chosen_len != candidate_len) |
| 30696 | continue; | 31473 | continue; |
| 30697 | 31474 | ||
| 30698 | const chosen_child_ty = chosen_ty.childType(); | 31475 | const chosen_child_ty = chosen_ty.childType(mod); |
| 30699 | const candidate_child_ty = candidate_ty.childType(); | 31476 | const candidate_child_ty = candidate_ty.childType(mod); |
| 30700 | if (chosen_child_ty.zigTypeTag() == .Int and candidate_child_ty.zigTypeTag() == .Int) { | 31477 | if (chosen_child_ty.zigTypeTag(mod) == .Int and candidate_child_ty.zigTypeTag(mod) == .Int) { |
| 30701 | const chosen_info = chosen_child_ty.intInfo(target); | 31478 | const chosen_info = chosen_child_ty.intInfo(mod); |
| 30702 | const candidate_info = candidate_child_ty.intInfo(target); | 31479 | const candidate_info = candidate_child_ty.intInfo(mod); |
| 30703 | if (chosen_info.bits < candidate_info.bits) { | 31480 | if (chosen_info.bits < candidate_info.bits) { |
| 30704 | chosen = candidate; | 31481 | chosen = candidate; |
| 30705 | chosen_i = candidate_i + 1; | 31482 | chosen_i = candidate_i + 1; |
| 30706 | } | 31483 | } |
| 30707 | continue; | 31484 | continue; |
| 30708 | } | 31485 | } |
| 30709 | if (chosen_child_ty.zigTypeTag() == .Float and candidate_child_ty.zigTypeTag() == .Float) { | 31486 | if (chosen_child_ty.zigTypeTag(mod) == .Float and candidate_child_ty.zigTypeTag(mod) == .Float) { |
| 30710 | if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) { | 31487 | if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) { |
| 30711 | chosen = candidate; | 31488 | chosen = candidate; |
| 30712 | chosen_i = candidate_i + 1; | 31489 | chosen_i = candidate_i + 1; |
| ... | @@ -30725,8 +31502,8 @@ fn resolvePeerTypes( | ... | @@ -30725,8 +31502,8 @@ fn resolvePeerTypes( |
| 30725 | .Vector => continue, | 31502 | .Vector => continue, |
| 30726 | else => {}, | 31503 | else => {}, |
| 30727 | }, | 31504 | }, |
| 30728 | .Fn => if (chosen_ty.isSinglePointer() and chosen_ty.isConstPtr() and chosen_ty.childType().zigTypeTag() == .Fn) { | 31505 | .Fn => if (chosen_ty.isSinglePointer(mod) and chosen_ty.isConstPtr(mod) and chosen_ty.childType(mod).zigTypeTag(mod) == .Fn) { |
| 30729 | if (.ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty.childType(), candidate_ty, target, src, src)) { | 31506 | if (.ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty.childType(mod), candidate_ty, target, src, src)) { |
| 30730 | continue; | 31507 | continue; |
| 30731 | } | 31508 | } |
| 30732 | }, | 31509 | }, |
| ... | @@ -30746,8 +31523,7 @@ fn resolvePeerTypes( | ... | @@ -30746,8 +31523,7 @@ fn resolvePeerTypes( |
| 30746 | continue; | 31523 | continue; |
| 30747 | }, | 31524 | }, |
| 30748 | .Optional => { | 31525 | .Optional => { |
| 30749 | var opt_child_buf: Type.Payload.ElemType = undefined; | 31526 | const opt_child_ty = chosen_ty.optionalChild(mod); |
| 30750 | const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf); | ||
| 30751 | if ((try sema.coerceInMemoryAllowed(block, opt_child_ty, candidate_ty, false, target, src, src)) == .ok) { | 31527 | if ((try sema.coerceInMemoryAllowed(block, opt_child_ty, candidate_ty, false, target, src, src)) == .ok) { |
| 30752 | continue; | 31528 | continue; |
| 30753 | } | 31529 | } |
| ... | @@ -30759,7 +31535,7 @@ fn resolvePeerTypes( | ... | @@ -30759,7 +31535,7 @@ fn resolvePeerTypes( |
| 30759 | } | 31535 | } |
| 30760 | }, | 31536 | }, |
| 30761 | .ErrorUnion => { | 31537 | .ErrorUnion => { |
| 30762 | const payload_ty = chosen_ty.errorUnionPayload(); | 31538 | const payload_ty = chosen_ty.errorUnionPayload(mod); |
| 30763 | if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) { | 31539 | if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) { |
| 30764 | continue; | 31540 | continue; |
| 30765 | } | 31541 | } |
| ... | @@ -30776,7 +31552,7 @@ fn resolvePeerTypes( | ... | @@ -30776,7 +31552,7 @@ fn resolvePeerTypes( |
| 30776 | continue; | 31552 | continue; |
| 30777 | } | 31553 | } |
| 30778 | 31554 | ||
| 30779 | err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, chosen_ty); | 31555 | err_set_ty = try sema.errorSetMerge(chosen_set_ty, chosen_ty); |
| 30780 | continue; | 31556 | continue; |
| 30781 | } else { | 31557 | } else { |
| 30782 | err_set_ty = chosen_ty; | 31558 | err_set_ty = chosen_ty; |
| ... | @@ -30789,28 +31565,28 @@ fn resolvePeerTypes( | ... | @@ -30789,28 +31565,28 @@ fn resolvePeerTypes( |
| 30789 | // At this point, we hit a compile error. We need to recover | 31565 | // At this point, we hit a compile error. We need to recover |
| 30790 | // the source locations. | 31566 | // the source locations. |
| 30791 | const chosen_src = candidate_srcs.resolve( | 31567 | const chosen_src = candidate_srcs.resolve( |
| 30792 | sema.gpa, | 31568 | mod, |
| 30793 | sema.mod.declPtr(block.src_decl), | 31569 | mod.declPtr(block.src_decl), |
| 30794 | chosen_i, | 31570 | chosen_i, |
| 30795 | ); | 31571 | ); |
| 30796 | const candidate_src = candidate_srcs.resolve( | 31572 | const candidate_src = candidate_srcs.resolve( |
| 30797 | sema.gpa, | 31573 | mod, |
| 30798 | sema.mod.declPtr(block.src_decl), | 31574 | mod.declPtr(block.src_decl), |
| 30799 | candidate_i + 1, | 31575 | candidate_i + 1, |
| 30800 | ); | 31576 | ); |
| 30801 | 31577 | ||
| 30802 | const msg = msg: { | 31578 | const msg = msg: { |
| 30803 | const msg = try sema.errMsg(block, src, "incompatible types: '{}' and '{}'", .{ | 31579 | const msg = try sema.errMsg(block, src, "incompatible types: '{}' and '{}'", .{ |
| 30804 | chosen_ty.fmt(sema.mod), | 31580 | chosen_ty.fmt(mod), |
| 30805 | candidate_ty.fmt(sema.mod), | 31581 | candidate_ty.fmt(mod), |
| 30806 | }); | 31582 | }); |
| 30807 | errdefer msg.destroy(sema.gpa); | 31583 | errdefer msg.destroy(sema.gpa); |
| 30808 | 31584 | ||
| 30809 | if (chosen_src) |src_loc| | 31585 | if (chosen_src) |src_loc| |
| 30810 | try sema.errNote(block, src_loc, msg, "type '{}' here", .{chosen_ty.fmt(sema.mod)}); | 31586 | try sema.errNote(block, src_loc, msg, "type '{}' here", .{chosen_ty.fmt(mod)}); |
| 30811 | 31587 | ||
| 30812 | if (candidate_src) |src_loc| | 31588 | if (candidate_src) |src_loc| |
| 30813 | try sema.errNote(block, src_loc, msg, "type '{}' here", .{candidate_ty.fmt(sema.mod)}); | 31589 | try sema.errNote(block, src_loc, msg, "type '{}' here", .{candidate_ty.fmt(mod)}); |
| 30814 | 31590 | ||
| 30815 | break :msg msg; | 31591 | break :msg msg; |
| 30816 | }; | 31592 | }; |
| ... | @@ -30821,139 +31597,231 @@ fn resolvePeerTypes( | ... | @@ -30821,139 +31597,231 @@ fn resolvePeerTypes( |
| 30821 | 31597 | ||
| 30822 | if (convert_to_slice) { | 31598 | if (convert_to_slice) { |
| 30823 | // turn *[N]T => []T | 31599 | // turn *[N]T => []T |
| 30824 | const chosen_child_ty = chosen_ty.childType(); | 31600 | const chosen_child_ty = chosen_ty.childType(mod); |
| 30825 | var info = chosen_ty.ptrInfo(); | 31601 | var info = chosen_ty.ptrInfo(mod); |
| 30826 | info.data.sentinel = chosen_child_ty.sentinel(); | 31602 | info.sentinel = chosen_child_ty.sentinel(mod); |
| 30827 | info.data.size = .Slice; | 31603 | info.size = .Slice; |
| 30828 | info.data.mutable = !(seen_const or chosen_child_ty.isConstPtr()); | 31604 | info.mutable = !(seen_const or chosen_child_ty.isConstPtr(mod)); |
| 30829 | info.data.pointee_type = chosen_child_ty.elemType2(); | 31605 | info.pointee_type = chosen_child_ty.elemType2(mod); |
| 30830 | 31606 | ||
| 30831 | const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); | 31607 | const new_ptr_ty = try Type.ptr(sema.arena, mod, info); |
| 30832 | const opt_ptr_ty = if (any_are_null) | 31608 | const opt_ptr_ty = if (any_are_null) |
| 30833 | try Type.optional(sema.arena, new_ptr_ty) | 31609 | try Type.optional(sema.arena, new_ptr_ty, mod) |
| 30834 | else | 31610 | else |
| 30835 | new_ptr_ty; | 31611 | new_ptr_ty; |
| 30836 | const set_ty = err_set_ty orelse return opt_ptr_ty; | 31612 | const set_ty = err_set_ty orelse return opt_ptr_ty; |
| 30837 | return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod); | 31613 | return try mod.errorUnionType(set_ty, opt_ptr_ty); |
| 30838 | } | 31614 | } |
| 30839 | 31615 | ||
| 30840 | if (seen_const) { | 31616 | if (seen_const) { |
| 30841 | // turn []T => []const T | 31617 | // turn []T => []const T |
| 30842 | switch (chosen_ty.zigTypeTag()) { | 31618 | switch (chosen_ty.zigTypeTag(mod)) { |
| 30843 | .ErrorUnion => { | 31619 | .ErrorUnion => { |
| 30844 | const ptr_ty = chosen_ty.errorUnionPayload(); | 31620 | const ptr_ty = chosen_ty.errorUnionPayload(mod); |
| 30845 | var info = ptr_ty.ptrInfo(); | 31621 | var info = ptr_ty.ptrInfo(mod); |
| 30846 | info.data.mutable = false; | 31622 | info.mutable = false; |
| 30847 | const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); | 31623 | const new_ptr_ty = try Type.ptr(sema.arena, mod, info); |
| 30848 | const opt_ptr_ty = if (any_are_null) | 31624 | const opt_ptr_ty = if (any_are_null) |
| 30849 | try Type.optional(sema.arena, new_ptr_ty) | 31625 | try Type.optional(sema.arena, new_ptr_ty, mod) |
| 30850 | else | 31626 | else |
| 30851 | new_ptr_ty; | 31627 | new_ptr_ty; |
| 30852 | const set_ty = err_set_ty orelse chosen_ty.errorUnionSet(); | 31628 | const set_ty = err_set_ty orelse chosen_ty.errorUnionSet(mod); |
| 30853 | return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod); | 31629 | return try mod.errorUnionType(set_ty, opt_ptr_ty); |
| 30854 | }, | 31630 | }, |
| 30855 | .Pointer => { | 31631 | .Pointer => { |
| 30856 | var info = chosen_ty.ptrInfo(); | 31632 | var info = chosen_ty.ptrInfo(mod); |
| 30857 | info.data.mutable = false; | 31633 | info.mutable = false; |
| 30858 | const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data); | 31634 | const new_ptr_ty = try Type.ptr(sema.arena, mod, info); |
| 30859 | const opt_ptr_ty = if (any_are_null) | 31635 | const opt_ptr_ty = if (any_are_null) |
| 30860 | try Type.optional(sema.arena, new_ptr_ty) | 31636 | try Type.optional(sema.arena, new_ptr_ty, mod) |
| 30861 | else | 31637 | else |
| 30862 | new_ptr_ty; | 31638 | new_ptr_ty; |
| 30863 | const set_ty = err_set_ty orelse return opt_ptr_ty; | 31639 | const set_ty = err_set_ty orelse return opt_ptr_ty; |
| 30864 | return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod); | 31640 | return try mod.errorUnionType(set_ty, opt_ptr_ty); |
| 30865 | }, | 31641 | }, |
| 30866 | else => return chosen_ty, | 31642 | else => return chosen_ty, |
| 30867 | } | 31643 | } |
| 30868 | } | 31644 | } |
| 30869 | 31645 | ||
| 30870 | if (any_are_null) { | 31646 | if (any_are_null) { |
| 30871 | const opt_ty = switch (chosen_ty.zigTypeTag()) { | 31647 | const opt_ty = switch (chosen_ty.zigTypeTag(mod)) { |
| 30872 | .Null, .Optional => chosen_ty, | 31648 | .Null, .Optional => chosen_ty, |
| 30873 | else => try Type.optional(sema.arena, chosen_ty), | 31649 | else => try Type.optional(sema.arena, chosen_ty, mod), |
| 30874 | }; | 31650 | }; |
| 30875 | const set_ty = err_set_ty orelse return opt_ty; | 31651 | const set_ty = err_set_ty orelse return opt_ty; |
| 30876 | return try Type.errorUnion(sema.arena, set_ty, opt_ty, sema.mod); | 31652 | return try mod.errorUnionType(set_ty, opt_ty); |
| 30877 | } | 31653 | } |
| 30878 | 31654 | ||
| 30879 | if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag()) { | 31655 | if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag(mod)) { |
| 30880 | .ErrorSet => return ty, | 31656 | .ErrorSet => return ty, |
| 30881 | .ErrorUnion => { | 31657 | .ErrorUnion => { |
| 30882 | const payload_ty = chosen_ty.errorUnionPayload(); | 31658 | const payload_ty = chosen_ty.errorUnionPayload(mod); |
| 30883 | return try Type.errorUnion(sema.arena, ty, payload_ty, sema.mod); | 31659 | return try mod.errorUnionType(ty, payload_ty); |
| 30884 | }, | 31660 | }, |
| 30885 | else => return try Type.errorUnion(sema.arena, ty, chosen_ty, sema.mod), | 31661 | else => return try mod.errorUnionType(ty, chosen_ty), |
| 30886 | }; | 31662 | }; |
| 30887 | 31663 | ||
| 30888 | return chosen_ty; | 31664 | return chosen_ty; |
| 30889 | } | 31665 | } |
| 30890 | 31666 | ||
| 30891 | pub fn resolveFnTypes(sema: *Sema, fn_info: Type.Payload.Function.Data) CompileError!void { | 31667 | pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void { |
| 30892 | try sema.resolveTypeFully(fn_info.return_type); | 31668 | const mod = sema.mod; |
| 31669 | try sema.resolveTypeFully(mod.typeToFunc(fn_ty).?.return_type.toType()); | ||
| 30893 | 31670 | ||
| 30894 | if (sema.mod.comp.bin_file.options.error_return_tracing and fn_info.return_type.isError()) { | 31671 | if (mod.comp.bin_file.options.error_return_tracing and mod.typeToFunc(fn_ty).?.return_type.toType().isError(mod)) { |
| 30895 | // Ensure the type exists so that backends can assume that. | 31672 | // Ensure the type exists so that backends can assume that. |
| 30896 | _ = try sema.getBuiltinType("StackTrace"); | 31673 | _ = try sema.getBuiltinType("StackTrace"); |
| 30897 | } | 31674 | } |
| 30898 | 31675 | ||
| 30899 | for (fn_info.param_types) |param_ty| { | 31676 | for (0..mod.typeToFunc(fn_ty).?.param_types.len) |i| { |
| 30900 | try sema.resolveTypeFully(param_ty); | 31677 | try sema.resolveTypeFully(mod.typeToFunc(fn_ty).?.param_types[i].toType()); |
| 30901 | } | 31678 | } |
| 30902 | } | 31679 | } |
| 30903 | 31680 | ||
| 30904 | /// Make it so that calling hash() and eql() on `val` will not assert due | 31681 | /// Make it so that calling hash() and eql() on `val` will not assert due |
| 30905 | /// to a type not having its layout resolved. | 31682 | /// to a type not having its layout resolved. |
| 30906 | fn resolveLazyValue(sema: *Sema, val: Value) CompileError!void { | 31683 | fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { |
| 30907 | switch (val.tag()) { | 31684 | const mod = sema.mod; |
| 30908 | .lazy_align => { | 31685 | switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 30909 | const ty = val.castTag(.lazy_align).?.data; | 31686 | .int => |int| switch (int.storage) { |
| 30910 | return sema.resolveTypeLayout(ty); | 31687 | .u64, .i64, .big_int => return val, |
| 30911 | }, | 31688 | .lazy_align, .lazy_size => return (try mod.intern(.{ .int = .{ |
| 30912 | .lazy_size => { | 31689 | .ty = int.ty, |
| 30913 | const ty = val.castTag(.lazy_size).?.data; | 31690 | .storage = .{ .u64 = (try val.getUnsignedIntAdvanced(mod, sema)).? }, |
| 30914 | return sema.resolveTypeLayout(ty); | 31691 | } })).toValue(), |
| 30915 | }, | 31692 | }, |
| 30916 | .comptime_field_ptr => { | 31693 | .ptr => |ptr| { |
| 30917 | const field_ptr = val.castTag(.comptime_field_ptr).?.data; | 31694 | const resolved_len = switch (ptr.len) { |
| 30918 | return sema.resolveLazyValue(field_ptr.field_val); | 31695 | .none => .none, |
| 30919 | }, | 31696 | else => (try sema.resolveLazyValue(ptr.len.toValue())).toIntern(), |
| 30920 | .eu_payload, | 31697 | }; |
| 30921 | .opt_payload, | 31698 | switch (ptr.addr) { |
| 30922 | => { | 31699 | .decl, .mut_decl => return if (resolved_len == ptr.len) |
| 30923 | const sub_val = val.cast(Value.Payload.SubValue).?.data; | 31700 | val |
| 30924 | return sema.resolveLazyValue(sub_val); | 31701 | else |
| 30925 | }, | 31702 | (try mod.intern(.{ .ptr = .{ |
| 30926 | .@"union" => { | 31703 | .ty = ptr.ty, |
| 30927 | const union_val = val.castTag(.@"union").?.data; | 31704 | .addr = switch (ptr.addr) { |
| 30928 | return sema.resolveLazyValue(union_val.val); | 31705 | .decl => |decl| .{ .decl = decl }, |
| 30929 | }, | 31706 | .mut_decl => |mut_decl| .{ .mut_decl = mut_decl }, |
| 30930 | .aggregate => { | 31707 | else => unreachable, |
| 30931 | const aggregate = val.castTag(.aggregate).?.data; | 31708 | }, |
| 30932 | for (aggregate) |elem_val| { | 31709 | .len = resolved_len, |
| 30933 | try sema.resolveLazyValue(elem_val); | 31710 | } })).toValue(), |
| 31711 | .comptime_field => |field_val| { | ||
| 31712 | const resolved_field_val = | ||
| 31713 | (try sema.resolveLazyValue(field_val.toValue())).toIntern(); | ||
| 31714 | return if (resolved_field_val == field_val and resolved_len == ptr.len) | ||
| 31715 | val | ||
| 31716 | else | ||
| 31717 | (try mod.intern(.{ .ptr = .{ | ||
| 31718 | .ty = ptr.ty, | ||
| 31719 | .addr = .{ .comptime_field = resolved_field_val }, | ||
| 31720 | .len = resolved_len, | ||
| 31721 | } })).toValue(); | ||
| 31722 | }, | ||
| 31723 | .int => |int| { | ||
| 31724 | const resolved_int = (try sema.resolveLazyValue(int.toValue())).toIntern(); | ||
| 31725 | return if (resolved_int == int and resolved_len == ptr.len) | ||
| 31726 | val | ||
| 31727 | else | ||
| 31728 | (try mod.intern(.{ .ptr = .{ | ||
| 31729 | .ty = ptr.ty, | ||
| 31730 | .addr = .{ .int = resolved_int }, | ||
| 31731 | .len = resolved_len, | ||
| 31732 | } })).toValue(); | ||
| 31733 | }, | ||
| 31734 | .eu_payload, .opt_payload => |base| { | ||
| 31735 | const resolved_base = (try sema.resolveLazyValue(base.toValue())).toIntern(); | ||
| 31736 | return if (resolved_base == base and resolved_len == ptr.len) | ||
| 31737 | val | ||
| 31738 | else | ||
| 31739 | (try mod.intern(.{ .ptr = .{ | ||
| 31740 | .ty = ptr.ty, | ||
| 31741 | .addr = switch (ptr.addr) { | ||
| 31742 | .eu_payload => .{ .eu_payload = resolved_base }, | ||
| 31743 | .opt_payload => .{ .opt_payload = resolved_base }, | ||
| 31744 | else => unreachable, | ||
| 31745 | }, | ||
| 31746 | .len = ptr.len, | ||
| 31747 | } })).toValue(); | ||
| 31748 | }, | ||
| 31749 | .elem, .field => |base_index| { | ||
| 31750 | const resolved_base = (try sema.resolveLazyValue(base_index.base.toValue())).toIntern(); | ||
| 31751 | return if (resolved_base == base_index.base and resolved_len == ptr.len) | ||
| 31752 | val | ||
| 31753 | else | ||
| 31754 | (try mod.intern(.{ .ptr = .{ | ||
| 31755 | .ty = ptr.ty, | ||
| 31756 | .addr = switch (ptr.addr) { | ||
| 31757 | .elem => .{ .elem = .{ | ||
| 31758 | .base = resolved_base, | ||
| 31759 | .index = base_index.index, | ||
| 31760 | } }, | ||
| 31761 | .field => .{ .field = .{ | ||
| 31762 | .base = resolved_base, | ||
| 31763 | .index = base_index.index, | ||
| 31764 | } }, | ||
| 31765 | else => unreachable, | ||
| 31766 | }, | ||
| 31767 | .len = ptr.len, | ||
| 31768 | } })).toValue(); | ||
| 31769 | }, | ||
| 30934 | } | 31770 | } |
| 30935 | }, | 31771 | }, |
| 30936 | .slice => { | 31772 | .aggregate => |aggregate| switch (aggregate.storage) { |
| 30937 | const slice = val.castTag(.slice).?.data; | 31773 | .bytes => return val, |
| 30938 | try sema.resolveLazyValue(slice.ptr); | 31774 | .elems => |elems| { |
| 30939 | return sema.resolveLazyValue(slice.len); | 31775 | var resolved_elems: []InternPool.Index = &.{}; |
| 31776 | for (elems, 0..) |elem, i| { | ||
| 31777 | const resolved_elem = (try sema.resolveLazyValue(elem.toValue())).toIntern(); | ||
| 31778 | if (resolved_elems.len == 0 and resolved_elem != elem) { | ||
| 31779 | resolved_elems = try sema.arena.alloc(InternPool.Index, elems.len); | ||
| 31780 | @memcpy(resolved_elems[0..i], elems[0..i]); | ||
| 31781 | } | ||
| 31782 | if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem; | ||
| 31783 | } | ||
| 31784 | return if (resolved_elems.len == 0) val else (try mod.intern(.{ .aggregate = .{ | ||
| 31785 | .ty = aggregate.ty, | ||
| 31786 | .storage = .{ .elems = resolved_elems }, | ||
| 31787 | } })).toValue(); | ||
| 31788 | }, | ||
| 31789 | .repeated_elem => |elem| { | ||
| 31790 | const resolved_elem = (try sema.resolveLazyValue(elem.toValue())).toIntern(); | ||
| 31791 | return if (resolved_elem == elem) val else (try mod.intern(.{ .aggregate = .{ | ||
| 31792 | .ty = aggregate.ty, | ||
| 31793 | .storage = .{ .repeated_elem = resolved_elem }, | ||
| 31794 | } })).toValue(); | ||
| 31795 | }, | ||
| 31796 | }, | ||
| 31797 | .un => |un| { | ||
| 31798 | const resolved_tag = (try sema.resolveLazyValue(un.tag.toValue())).toIntern(); | ||
| 31799 | const resolved_val = (try sema.resolveLazyValue(un.val.toValue())).toIntern(); | ||
| 31800 | return if (resolved_tag == un.tag and resolved_val == un.val) | ||
| 31801 | val | ||
| 31802 | else | ||
| 31803 | (try mod.intern(.{ .un = .{ | ||
| 31804 | .ty = un.ty, | ||
| 31805 | .tag = resolved_tag, | ||
| 31806 | .val = resolved_val, | ||
| 31807 | } })).toValue(); | ||
| 30940 | }, | 31808 | }, |
| 30941 | else => return, | 31809 | else => return val, |
| 30942 | } | 31810 | } |
| 30943 | } | 31811 | } |
| 30944 | 31812 | ||
| 30945 | pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { | 31813 | pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { |
| 30946 | switch (ty.zigTypeTag()) { | 31814 | const mod = sema.mod; |
| 31815 | switch (ty.zigTypeTag(mod)) { | ||
| 30947 | .Struct => return sema.resolveStructLayout(ty), | 31816 | .Struct => return sema.resolveStructLayout(ty), |
| 30948 | .Union => return sema.resolveUnionLayout(ty), | 31817 | .Union => return sema.resolveUnionLayout(ty), |
| 30949 | .Array => { | 31818 | .Array => { |
| 30950 | if (ty.arrayLenIncludingSentinel() == 0) return; | 31819 | if (ty.arrayLenIncludingSentinel(mod) == 0) return; |
| 30951 | const elem_ty = ty.childType(); | 31820 | const elem_ty = ty.childType(mod); |
| 30952 | return sema.resolveTypeLayout(elem_ty); | 31821 | return sema.resolveTypeLayout(elem_ty); |
| 30953 | }, | 31822 | }, |
| 30954 | .Optional => { | 31823 | .Optional => { |
| 30955 | var buf: Type.Payload.ElemType = undefined; | 31824 | const payload_ty = ty.optionalChild(mod); |
| 30956 | const payload_ty = ty.optionalChild(&buf); | ||
| 30957 | // In case of querying the ABI alignment of this optional, we will ask | 31825 | // In case of querying the ABI alignment of this optional, we will ask |
| 30958 | // for hasRuntimeBits() of the payload type, so we need "requires comptime" | 31826 | // for hasRuntimeBits() of the payload type, so we need "requires comptime" |
| 30959 | // to be known already before this function returns. | 31827 | // to be known already before this function returns. |
| ... | @@ -30961,37 +31829,37 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -30961,37 +31829,37 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void { |
| 30961 | return sema.resolveTypeLayout(payload_ty); | 31829 | return sema.resolveTypeLayout(payload_ty); |
| 30962 | }, | 31830 | }, |
| 30963 | .ErrorUnion => { | 31831 | .ErrorUnion => { |
| 30964 | const payload_ty = ty.errorUnionPayload(); | 31832 | const payload_ty = ty.errorUnionPayload(mod); |
| 30965 | return sema.resolveTypeLayout(payload_ty); | 31833 | return sema.resolveTypeLayout(payload_ty); |
| 30966 | }, | 31834 | }, |
| 30967 | .Fn => { | 31835 | .Fn => { |
| 30968 | const info = ty.fnInfo(); | 31836 | const info = mod.typeToFunc(ty).?; |
| 30969 | if (info.is_generic) { | 31837 | if (info.is_generic) { |
| 30970 | // Resolving of generic function types is deferred to when | 31838 | // Resolving of generic function types is deferred to when |
| 30971 | // the function is instantiated. | 31839 | // the function is instantiated. |
| 30972 | return; | 31840 | return; |
| 30973 | } | 31841 | } |
| 30974 | for (info.param_types) |param_ty| { | 31842 | for (info.param_types) |param_ty| { |
| 30975 | try sema.resolveTypeLayout(param_ty); | 31843 | try sema.resolveTypeLayout(param_ty.toType()); |
| 30976 | } | 31844 | } |
| 30977 | try sema.resolveTypeLayout(info.return_type); | 31845 | try sema.resolveTypeLayout(info.return_type.toType()); |
| 30978 | }, | 31846 | }, |
| 30979 | else => {}, | 31847 | else => {}, |
| 30980 | } | 31848 | } |
| 30981 | } | 31849 | } |
| 30982 | 31850 | ||
| 30983 | fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { | 31851 | fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31852 | const mod = sema.mod; | ||
| 30984 | const resolved_ty = try sema.resolveTypeFields(ty); | 31853 | const resolved_ty = try sema.resolveTypeFields(ty); |
| 30985 | if (resolved_ty.castTag(.@"struct")) |payload| { | 31854 | if (mod.typeToStruct(resolved_ty)) |struct_obj| { |
| 30986 | const struct_obj = payload.data; | ||
| 30987 | switch (struct_obj.status) { | 31855 | switch (struct_obj.status) { |
| 30988 | .none, .have_field_types => {}, | 31856 | .none, .have_field_types => {}, |
| 30989 | .field_types_wip, .layout_wip => { | 31857 | .field_types_wip, .layout_wip => { |
| 30990 | const msg = try Module.ErrorMsg.create( | 31858 | const msg = try Module.ErrorMsg.create( |
| 30991 | sema.gpa, | 31859 | sema.gpa, |
| 30992 | struct_obj.srcLoc(sema.mod), | 31860 | struct_obj.srcLoc(mod), |
| 30993 | "struct '{}' depends on itself", | 31861 | "struct '{}' depends on itself", |
| 30994 | .{ty.fmt(sema.mod)}, | 31862 | .{ty.fmt(mod)}, |
| 30995 | ); | 31863 | ); |
| 30996 | return sema.failWithOwnedErrorMsg(msg); | 31864 | return sema.failWithOwnedErrorMsg(msg); |
| 30997 | }, | 31865 | }, |
| ... | @@ -31015,35 +31883,27 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -31015,35 +31883,27 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31015 | } | 31883 | } |
| 31016 | 31884 | ||
| 31017 | if (struct_obj.layout == .Packed) { | 31885 | if (struct_obj.layout == .Packed) { |
| 31018 | try semaBackingIntType(sema.mod, struct_obj); | 31886 | try semaBackingIntType(mod, struct_obj); |
| 31019 | } | 31887 | } |
| 31020 | 31888 | ||
| 31021 | struct_obj.status = .have_layout; | 31889 | struct_obj.status = .have_layout; |
| 31022 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); | 31890 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); |
| 31023 | 31891 | ||
| 31024 | if (struct_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) { | 31892 | if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) { |
| 31025 | const msg = try Module.ErrorMsg.create( | 31893 | const msg = try Module.ErrorMsg.create( |
| 31026 | sema.gpa, | 31894 | sema.gpa, |
| 31027 | struct_obj.srcLoc(sema.mod), | 31895 | struct_obj.srcLoc(mod), |
| 31028 | "struct layout depends on it having runtime bits", | 31896 | "struct layout depends on it having runtime bits", |
| 31029 | .{}, | 31897 | .{}, |
| 31030 | ); | 31898 | ); |
| 31031 | return sema.failWithOwnedErrorMsg(msg); | 31899 | return sema.failWithOwnedErrorMsg(msg); |
| 31032 | } | 31900 | } |
| 31033 | 31901 | ||
| 31034 | if (struct_obj.layout == .Auto and sema.mod.backendSupportsFeature(.field_reordering)) { | 31902 | if (struct_obj.layout == .Auto and mod.backendSupportsFeature(.field_reordering)) { |
| 31035 | const optimized_order = if (struct_obj.owner_decl == sema.owner_decl_index) | 31903 | const optimized_order = try mod.tmp_hack_arena.allocator().alloc(u32, struct_obj.fields.count()); |
| 31036 | try sema.perm_arena.alloc(u32, struct_obj.fields.count()) | ||
| 31037 | else blk: { | ||
| 31038 | const decl = sema.mod.declPtr(struct_obj.owner_decl); | ||
| 31039 | var decl_arena: std.heap.ArenaAllocator = undefined; | ||
| 31040 | const decl_arena_allocator = decl.value_arena.?.acquire(sema.mod.gpa, &decl_arena); | ||
| 31041 | defer decl.value_arena.?.release(&decl_arena); | ||
| 31042 | break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count()); | ||
| 31043 | }; | ||
| 31044 | 31904 | ||
| 31045 | for (struct_obj.fields.values(), 0..) |field, i| { | 31905 | for (struct_obj.fields.values(), 0..) |field, i| { |
| 31046 | optimized_order[i] = if (field.ty.hasRuntimeBits()) | 31906 | optimized_order[i] = if (try sema.typeHasRuntimeBits(field.ty)) |
| 31047 | @intCast(u32, i) | 31907 | @intCast(u32, i) |
| 31048 | else | 31908 | else |
| 31049 | Module.Struct.omitted_field; | 31909 | Module.Struct.omitted_field; |
| ... | @@ -31054,11 +31914,11 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -31054,11 +31914,11 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31054 | sema: *Sema, | 31914 | sema: *Sema, |
| 31055 | 31915 | ||
| 31056 | fn lessThan(ctx: @This(), a: u32, b: u32) bool { | 31916 | fn lessThan(ctx: @This(), a: u32, b: u32) bool { |
| 31917 | const m = ctx.sema.mod; | ||
| 31057 | if (a == Module.Struct.omitted_field) return false; | 31918 | if (a == Module.Struct.omitted_field) return false; |
| 31058 | if (b == Module.Struct.omitted_field) return true; | 31919 | if (b == Module.Struct.omitted_field) return true; |
| 31059 | const target = ctx.sema.mod.getTarget(); | 31920 | return ctx.struct_obj.fields.values()[a].ty.abiAlignment(m) > |
| 31060 | return ctx.struct_obj.fields.values()[a].ty.abiAlignment(target) > | 31921 | ctx.struct_obj.fields.values()[b].ty.abiAlignment(m); |
| 31061 | ctx.struct_obj.fields.values()[b].ty.abiAlignment(target); | ||
| 31062 | } | 31922 | } |
| 31063 | }; | 31923 | }; |
| 31064 | mem.sort(u32, optimized_order, AlignSortContext{ | 31924 | mem.sort(u32, optimized_order, AlignSortContext{ |
| ... | @@ -31073,20 +31933,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -31073,20 +31933,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31073 | 31933 | ||
| 31074 | fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void { | 31934 | fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void { |
| 31075 | const gpa = mod.gpa; | 31935 | const gpa = mod.gpa; |
| 31076 | const target = mod.getTarget(); | ||
| 31077 | 31936 | ||
| 31078 | var fields_bit_sum: u64 = 0; | 31937 | var fields_bit_sum: u64 = 0; |
| 31079 | for (struct_obj.fields.values()) |field| { | 31938 | for (struct_obj.fields.values()) |field| { |
| 31080 | fields_bit_sum += field.ty.bitSize(target); | 31939 | fields_bit_sum += field.ty.bitSize(mod); |
| 31081 | } | 31940 | } |
| 31082 | 31941 | ||
| 31083 | const decl_index = struct_obj.owner_decl; | 31942 | const decl_index = struct_obj.owner_decl; |
| 31084 | const decl = mod.declPtr(decl_index); | 31943 | const decl = mod.declPtr(decl_index); |
| 31085 | var decl_arena: std.heap.ArenaAllocator = undefined; | ||
| 31086 | const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); | ||
| 31087 | defer decl.value_arena.?.release(&decl_arena); | ||
| 31088 | 31944 | ||
| 31089 | const zir = struct_obj.namespace.file_scope.zir; | 31945 | const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir; |
| 31090 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; | 31946 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; |
| 31091 | assert(extended.opcode == .struct_decl); | 31947 | assert(extended.opcode == .struct_decl); |
| 31092 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); | 31948 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| ... | @@ -31103,28 +31959,33 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi | ... | @@ -31103,28 +31959,33 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 31103 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | 31959 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 31104 | defer analysis_arena.deinit(); | 31960 | defer analysis_arena.deinit(); |
| 31105 | 31961 | ||
| 31962 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | ||
| 31963 | defer comptime_mutable_decls.deinit(); | ||
| 31964 | |||
| 31106 | var sema: Sema = .{ | 31965 | var sema: Sema = .{ |
| 31107 | .mod = mod, | 31966 | .mod = mod, |
| 31108 | .gpa = gpa, | 31967 | .gpa = gpa, |
| 31109 | .arena = analysis_arena.allocator(), | 31968 | .arena = analysis_arena.allocator(), |
| 31110 | .perm_arena = decl_arena_allocator, | ||
| 31111 | .code = zir, | 31969 | .code = zir, |
| 31112 | .owner_decl = decl, | 31970 | .owner_decl = decl, |
| 31113 | .owner_decl_index = decl_index, | 31971 | .owner_decl_index = decl_index, |
| 31114 | .func = null, | 31972 | .func = null, |
| 31973 | .func_index = .none, | ||
| 31115 | .fn_ret_ty = Type.void, | 31974 | .fn_ret_ty = Type.void, |
| 31116 | .owner_func = null, | 31975 | .owner_func = null, |
| 31976 | .owner_func_index = .none, | ||
| 31977 | .comptime_mutable_decls = &comptime_mutable_decls, | ||
| 31117 | }; | 31978 | }; |
| 31118 | defer sema.deinit(); | 31979 | defer sema.deinit(); |
| 31119 | 31980 | ||
| 31120 | var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); | 31981 | var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope); |
| 31121 | defer wip_captures.deinit(); | 31982 | defer wip_captures.deinit(); |
| 31122 | 31983 | ||
| 31123 | var block: Block = .{ | 31984 | var block: Block = .{ |
| 31124 | .parent = null, | 31985 | .parent = null, |
| 31125 | .sema = &sema, | 31986 | .sema = &sema, |
| 31126 | .src_decl = decl_index, | 31987 | .src_decl = decl_index, |
| 31127 | .namespace = &struct_obj.namespace, | 31988 | .namespace = struct_obj.namespace, |
| 31128 | .wip_capture_scope = wip_captures.scope, | 31989 | .wip_capture_scope = wip_captures.scope, |
| 31129 | .instructions = .{}, | 31990 | .instructions = .{}, |
| 31130 | .inlining = null, | 31991 | .inlining = null, |
| ... | @@ -31148,21 +32009,27 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi | ... | @@ -31148,21 +32009,27 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 31148 | }; | 32009 | }; |
| 31149 | 32010 | ||
| 31150 | try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum); | 32011 | try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum); |
| 31151 | struct_obj.backing_int_ty = try backing_int_ty.copy(decl_arena_allocator); | 32012 | struct_obj.backing_int_ty = backing_int_ty; |
| 31152 | try wip_captures.finalize(); | 32013 | try wip_captures.finalize(); |
| 32014 | for (comptime_mutable_decls.items) |ct_decl_index| { | ||
| 32015 | const ct_decl = mod.declPtr(ct_decl_index); | ||
| 32016 | try ct_decl.intern(mod); | ||
| 32017 | } | ||
| 31153 | } else { | 32018 | } else { |
| 31154 | if (fields_bit_sum > std.math.maxInt(u16)) { | 32019 | if (fields_bit_sum > std.math.maxInt(u16)) { |
| 31155 | var sema: Sema = .{ | 32020 | var sema: Sema = .{ |
| 31156 | .mod = mod, | 32021 | .mod = mod, |
| 31157 | .gpa = gpa, | 32022 | .gpa = gpa, |
| 31158 | .arena = undefined, | 32023 | .arena = undefined, |
| 31159 | .perm_arena = decl_arena_allocator, | ||
| 31160 | .code = zir, | 32024 | .code = zir, |
| 31161 | .owner_decl = decl, | 32025 | .owner_decl = decl, |
| 31162 | .owner_decl_index = decl_index, | 32026 | .owner_decl_index = decl_index, |
| 31163 | .func = null, | 32027 | .func = null, |
| 32028 | .func_index = .none, | ||
| 31164 | .fn_ret_ty = Type.void, | 32029 | .fn_ret_ty = Type.void, |
| 31165 | .owner_func = null, | 32030 | .owner_func = null, |
| 32031 | .owner_func_index = .none, | ||
| 32032 | .comptime_mutable_decls = undefined, | ||
| 31166 | }; | 32033 | }; |
| 31167 | defer sema.deinit(); | 32034 | defer sema.deinit(); |
| 31168 | 32035 | ||
| ... | @@ -31170,7 +32037,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi | ... | @@ -31170,7 +32037,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 31170 | .parent = null, | 32037 | .parent = null, |
| 31171 | .sema = &sema, | 32038 | .sema = &sema, |
| 31172 | .src_decl = decl_index, | 32039 | .src_decl = decl_index, |
| 31173 | .namespace = &struct_obj.namespace, | 32040 | .namespace = struct_obj.namespace, |
| 31174 | .wip_capture_scope = undefined, | 32041 | .wip_capture_scope = undefined, |
| 31175 | .instructions = .{}, | 32042 | .instructions = .{}, |
| 31176 | .inlining = null, | 32043 | .inlining = null, |
| ... | @@ -31178,32 +32045,29 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi | ... | @@ -31178,32 +32045,29 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 31178 | }; | 32045 | }; |
| 31179 | return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum}); | 32046 | return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum}); |
| 31180 | } | 32047 | } |
| 31181 | var buf: Type.Payload.Bits = .{ | 32048 | struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum)); |
| 31182 | .base = .{ .tag = .int_unsigned }, | ||
| 31183 | .data = @intCast(u16, fields_bit_sum), | ||
| 31184 | }; | ||
| 31185 | struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(decl_arena_allocator); | ||
| 31186 | } | 32049 | } |
| 31187 | } | 32050 | } |
| 31188 | 32051 | ||
| 31189 | fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void { | 32052 | fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void { |
| 31190 | const target = sema.mod.getTarget(); | 32053 | const mod = sema.mod; |
| 31191 | 32054 | ||
| 31192 | if (!backing_int_ty.isInt()) { | 32055 | if (!backing_int_ty.isInt(mod)) { |
| 31193 | return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(sema.mod)}); | 32056 | return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(sema.mod)}); |
| 31194 | } | 32057 | } |
| 31195 | if (backing_int_ty.bitSize(target) != fields_bit_sum) { | 32058 | if (backing_int_ty.bitSize(mod) != fields_bit_sum) { |
| 31196 | return sema.fail( | 32059 | return sema.fail( |
| 31197 | block, | 32060 | block, |
| 31198 | src, | 32061 | src, |
| 31199 | "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}", | 32062 | "backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}", |
| 31200 | .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(target), fields_bit_sum }, | 32063 | .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(mod), fields_bit_sum }, |
| 31201 | ); | 32064 | ); |
| 31202 | } | 32065 | } |
| 31203 | } | 32066 | } |
| 31204 | 32067 | ||
| 31205 | fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { | 32068 | fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { |
| 31206 | if (!ty.isIndexable()) { | 32069 | const mod = sema.mod; |
| 32070 | if (!ty.isIndexable(mod)) { | ||
| 31207 | const msg = msg: { | 32071 | const msg = msg: { |
| 31208 | const msg = try sema.errMsg(block, src, "type '{}' does not support indexing", .{ty.fmt(sema.mod)}); | 32072 | const msg = try sema.errMsg(block, src, "type '{}' does not support indexing", .{ty.fmt(sema.mod)}); |
| 31209 | errdefer msg.destroy(sema.gpa); | 32073 | errdefer msg.destroy(sema.gpa); |
| ... | @@ -31215,12 +32079,13 @@ fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { | ... | @@ -31215,12 +32079,13 @@ fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { |
| 31215 | } | 32079 | } |
| 31216 | 32080 | ||
| 31217 | fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { | 32081 | fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { |
| 31218 | if (ty.zigTypeTag() == .Pointer) { | 32082 | const mod = sema.mod; |
| 31219 | switch (ty.ptrSize()) { | 32083 | if (ty.zigTypeTag(mod) == .Pointer) { |
| 32084 | switch (ty.ptrSize(mod)) { | ||
| 31220 | .Slice, .Many, .C => return, | 32085 | .Slice, .Many, .C => return, |
| 31221 | .One => { | 32086 | .One => { |
| 31222 | const elem_ty = ty.childType(); | 32087 | const elem_ty = ty.childType(mod); |
| 31223 | if (elem_ty.zigTypeTag() == .Array) return; | 32088 | if (elem_ty.zigTypeTag(mod) == .Array) return; |
| 31224 | // TODO https://github.com/ziglang/zig/issues/15479 | 32089 | // TODO https://github.com/ziglang/zig/issues/15479 |
| 31225 | // if (elem_ty.isTuple()) return; | 32090 | // if (elem_ty.isTuple()) return; |
| 31226 | }, | 32091 | }, |
| ... | @@ -31236,8 +32101,9 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void | ... | @@ -31236,8 +32101,9 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void |
| 31236 | } | 32101 | } |
| 31237 | 32102 | ||
| 31238 | fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { | 32103 | fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 32104 | const mod = sema.mod; | ||
| 31239 | const resolved_ty = try sema.resolveTypeFields(ty); | 32105 | const resolved_ty = try sema.resolveTypeFields(ty); |
| 31240 | const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; | 32106 | const union_obj = mod.typeToUnion(resolved_ty).?; |
| 31241 | switch (union_obj.status) { | 32107 | switch (union_obj.status) { |
| 31242 | .none, .have_field_types => {}, | 32108 | .none, .have_field_types => {}, |
| 31243 | .field_types_wip, .layout_wip => { | 32109 | .field_types_wip, .layout_wip => { |
| ... | @@ -31270,7 +32136,7 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -31270,7 +32136,7 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31270 | union_obj.status = .have_layout; | 32136 | union_obj.status = .have_layout; |
| 31271 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); | 32137 | _ = try sema.resolveTypeRequiresComptime(resolved_ty); |
| 31272 | 32138 | ||
| 31273 | if (union_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) { | 32139 | if (union_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) { |
| 31274 | const msg = try Module.ErrorMsg.create( | 32140 | const msg = try Module.ErrorMsg.create( |
| 31275 | sema.gpa, | 32141 | sema.gpa, |
| 31276 | union_obj.srcLoc(sema.mod), | 32142 | union_obj.srcLoc(sema.mod), |
| ... | @@ -31285,188 +32151,154 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -31285,188 +32151,154 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31285 | // for hasRuntimeBits() of each field, so we need "requires comptime" | 32151 | // for hasRuntimeBits() of each field, so we need "requires comptime" |
| 31286 | // to be known already before this function returns. | 32152 | // to be known already before this function returns. |
| 31287 | pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { | 32153 | pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 31288 | return switch (ty.tag()) { | 32154 | const mod = sema.mod; |
| 31289 | .u1, | ||
| 31290 | .u8, | ||
| 31291 | .i8, | ||
| 31292 | .u16, | ||
| 31293 | .i16, | ||
| 31294 | .u29, | ||
| 31295 | .u32, | ||
| 31296 | .i32, | ||
| 31297 | .u64, | ||
| 31298 | .i64, | ||
| 31299 | .u128, | ||
| 31300 | .i128, | ||
| 31301 | .usize, | ||
| 31302 | .isize, | ||
| 31303 | .c_char, | ||
| 31304 | .c_short, | ||
| 31305 | .c_ushort, | ||
| 31306 | .c_int, | ||
| 31307 | .c_uint, | ||
| 31308 | .c_long, | ||
| 31309 | .c_ulong, | ||
| 31310 | .c_longlong, | ||
| 31311 | .c_ulonglong, | ||
| 31312 | .c_longdouble, | ||
| 31313 | .f16, | ||
| 31314 | .f32, | ||
| 31315 | .f64, | ||
| 31316 | .f80, | ||
| 31317 | .f128, | ||
| 31318 | .anyopaque, | ||
| 31319 | .bool, | ||
| 31320 | .void, | ||
| 31321 | .anyerror, | ||
| 31322 | .noreturn, | ||
| 31323 | .@"anyframe", | ||
| 31324 | .null, | ||
| 31325 | .undefined, | ||
| 31326 | .atomic_order, | ||
| 31327 | .atomic_rmw_op, | ||
| 31328 | .calling_convention, | ||
| 31329 | .address_space, | ||
| 31330 | .float_mode, | ||
| 31331 | .reduce_op, | ||
| 31332 | .modifier, | ||
| 31333 | .prefetch_options, | ||
| 31334 | .export_options, | ||
| 31335 | .extern_options, | ||
| 31336 | .manyptr_u8, | ||
| 31337 | .manyptr_const_u8, | ||
| 31338 | .manyptr_const_u8_sentinel_0, | ||
| 31339 | .const_slice_u8, | ||
| 31340 | .const_slice_u8_sentinel_0, | ||
| 31341 | .anyerror_void_error_union, | ||
| 31342 | .empty_struct_literal, | ||
| 31343 | .empty_struct, | ||
| 31344 | .error_set, | ||
| 31345 | .error_set_single, | ||
| 31346 | .error_set_inferred, | ||
| 31347 | .error_set_merged, | ||
| 31348 | .@"opaque", | ||
| 31349 | .generic_poison, | ||
| 31350 | .array_u8, | ||
| 31351 | .array_u8_sentinel_0, | ||
| 31352 | .int_signed, | ||
| 31353 | .int_unsigned, | ||
| 31354 | .enum_simple, | ||
| 31355 | => false, | ||
| 31356 | |||
| 31357 | .single_const_pointer_to_comptime_int, | ||
| 31358 | .type, | ||
| 31359 | .comptime_int, | ||
| 31360 | .comptime_float, | ||
| 31361 | .enum_literal, | ||
| 31362 | .type_info, | ||
| 31363 | // These are function bodies, not function pointers. | ||
| 31364 | .fn_noreturn_no_args, | ||
| 31365 | .fn_void_no_args, | ||
| 31366 | .fn_naked_noreturn_no_args, | ||
| 31367 | .fn_ccc_void_no_args, | ||
| 31368 | .function, | ||
| 31369 | => true, | ||
| 31370 | |||
| 31371 | .inferred_alloc_mut => unreachable, | ||
| 31372 | .inferred_alloc_const => unreachable, | ||
| 31373 | |||
| 31374 | .array, | ||
| 31375 | .array_sentinel, | ||
| 31376 | .vector, | ||
| 31377 | => return sema.resolveTypeRequiresComptime(ty.childType()), | ||
| 31378 | |||
| 31379 | .pointer, | ||
| 31380 | .single_const_pointer, | ||
| 31381 | .single_mut_pointer, | ||
| 31382 | .many_const_pointer, | ||
| 31383 | .many_mut_pointer, | ||
| 31384 | .c_const_pointer, | ||
| 31385 | .c_mut_pointer, | ||
| 31386 | .const_slice, | ||
| 31387 | .mut_slice, | ||
| 31388 | => { | ||
| 31389 | const child_ty = ty.childType(); | ||
| 31390 | if (child_ty.zigTypeTag() == .Fn) { | ||
| 31391 | return child_ty.fnInfo().is_generic; | ||
| 31392 | } else { | ||
| 31393 | return sema.resolveTypeRequiresComptime(child_ty); | ||
| 31394 | } | ||
| 31395 | }, | ||
| 31396 | |||
| 31397 | .optional, | ||
| 31398 | .optional_single_mut_pointer, | ||
| 31399 | .optional_single_const_pointer, | ||
| 31400 | => { | ||
| 31401 | var buf: Type.Payload.ElemType = undefined; | ||
| 31402 | return sema.resolveTypeRequiresComptime(ty.optionalChild(&buf)); | ||
| 31403 | }, | ||
| 31404 | 32155 | ||
| 31405 | .tuple, .anon_struct => { | 32156 | return switch (ty.toIntern()) { |
| 31406 | const tuple = ty.tupleFields(); | 32157 | .empty_struct_type => false, |
| 31407 | for (tuple.types, 0..) |field_ty, i| { | 32158 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 31408 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; | 32159 | .int_type => false, |
| 31409 | if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty)) { | 32160 | .ptr_type => |ptr_type| { |
| 31410 | return true; | 32161 | const child_ty = ptr_type.child.toType(); |
| 32162 | if (child_ty.zigTypeTag(mod) == .Fn) { | ||
| 32163 | return mod.typeToFunc(child_ty).?.is_generic; | ||
| 32164 | } else { | ||
| 32165 | return sema.resolveTypeRequiresComptime(child_ty); | ||
| 31411 | } | 32166 | } |
| 31412 | } | 32167 | }, |
| 31413 | return false; | 32168 | .anyframe_type => |child| { |
| 31414 | }, | 32169 | if (child == .none) return false; |
| 32170 | return sema.resolveTypeRequiresComptime(child.toType()); | ||
| 32171 | }, | ||
| 32172 | .array_type => |array_type| return sema.resolveTypeRequiresComptime(array_type.child.toType()), | ||
| 32173 | .vector_type => |vector_type| return sema.resolveTypeRequiresComptime(vector_type.child.toType()), | ||
| 32174 | .opt_type => |child| return sema.resolveTypeRequiresComptime(child.toType()), | ||
| 32175 | .error_union_type => |error_union_type| return sema.resolveTypeRequiresComptime(error_union_type.payload_type.toType()), | ||
| 32176 | .error_set_type, .inferred_error_set_type => false, | ||
| 32177 | |||
| 32178 | .func_type => true, | ||
| 32179 | |||
| 32180 | .simple_type => |t| switch (t) { | ||
| 32181 | .f16, | ||
| 32182 | .f32, | ||
| 32183 | .f64, | ||
| 32184 | .f80, | ||
| 32185 | .f128, | ||
| 32186 | .usize, | ||
| 32187 | .isize, | ||
| 32188 | .c_char, | ||
| 32189 | .c_short, | ||
| 32190 | .c_ushort, | ||
| 32191 | .c_int, | ||
| 32192 | .c_uint, | ||
| 32193 | .c_long, | ||
| 32194 | .c_ulong, | ||
| 32195 | .c_longlong, | ||
| 32196 | .c_ulonglong, | ||
| 32197 | .c_longdouble, | ||
| 32198 | .anyopaque, | ||
| 32199 | .bool, | ||
| 32200 | .void, | ||
| 32201 | .anyerror, | ||
| 32202 | .noreturn, | ||
| 32203 | .generic_poison, | ||
| 32204 | .atomic_order, | ||
| 32205 | .atomic_rmw_op, | ||
| 32206 | .calling_convention, | ||
| 32207 | .address_space, | ||
| 32208 | .float_mode, | ||
| 32209 | .reduce_op, | ||
| 32210 | .call_modifier, | ||
| 32211 | .prefetch_options, | ||
| 32212 | .export_options, | ||
| 32213 | .extern_options, | ||
| 32214 | => false, | ||
| 32215 | |||
| 32216 | .type, | ||
| 32217 | .comptime_int, | ||
| 32218 | .comptime_float, | ||
| 32219 | .null, | ||
| 32220 | .undefined, | ||
| 32221 | .enum_literal, | ||
| 32222 | .type_info, | ||
| 32223 | => true, | ||
| 32224 | }, | ||
| 32225 | .struct_type => |struct_type| { | ||
| 32226 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | ||
| 32227 | switch (struct_obj.requires_comptime) { | ||
| 32228 | .no, .wip => return false, | ||
| 32229 | .yes => return true, | ||
| 32230 | .unknown => { | ||
| 32231 | var requires_comptime = false; | ||
| 32232 | struct_obj.requires_comptime = .wip; | ||
| 32233 | for (struct_obj.fields.values()) |field| { | ||
| 32234 | if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true; | ||
| 32235 | } | ||
| 32236 | if (requires_comptime) { | ||
| 32237 | struct_obj.requires_comptime = .yes; | ||
| 32238 | } else { | ||
| 32239 | struct_obj.requires_comptime = .no; | ||
| 32240 | } | ||
| 32241 | return requires_comptime; | ||
| 32242 | }, | ||
| 32243 | } | ||
| 32244 | }, | ||
| 31415 | 32245 | ||
| 31416 | .@"struct" => { | 32246 | .anon_struct_type => |tuple| { |
| 31417 | const struct_obj = ty.castTag(.@"struct").?.data; | 32247 | for (tuple.types, tuple.values) |field_ty, field_val| { |
| 31418 | switch (struct_obj.requires_comptime) { | 32248 | const have_comptime_val = field_val != .none; |
| 31419 | .no, .wip => return false, | 32249 | if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty.toType())) { |
| 31420 | .yes => return true, | 32250 | return true; |
| 31421 | .unknown => { | ||
| 31422 | var requires_comptime = false; | ||
| 31423 | struct_obj.requires_comptime = .wip; | ||
| 31424 | for (struct_obj.fields.values()) |field| { | ||
| 31425 | if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true; | ||
| 31426 | } | 32251 | } |
| 31427 | if (requires_comptime) { | 32252 | } |
| 31428 | struct_obj.requires_comptime = .yes; | 32253 | return false; |
| 31429 | } else { | 32254 | }, |
| 31430 | struct_obj.requires_comptime = .no; | ||
| 31431 | } | ||
| 31432 | return requires_comptime; | ||
| 31433 | }, | ||
| 31434 | } | ||
| 31435 | }, | ||
| 31436 | 32255 | ||
| 31437 | .@"union", .union_safety_tagged, .union_tagged => { | 32256 | .union_type => |union_type| { |
| 31438 | const union_obj = ty.cast(Type.Payload.Union).?.data; | 32257 | const union_obj = mod.unionPtr(union_type.index); |
| 31439 | switch (union_obj.requires_comptime) { | 32258 | switch (union_obj.requires_comptime) { |
| 31440 | .no, .wip => return false, | 32259 | .no, .wip => return false, |
| 31441 | .yes => return true, | 32260 | .yes => return true, |
| 31442 | .unknown => { | 32261 | .unknown => { |
| 31443 | var requires_comptime = false; | 32262 | var requires_comptime = false; |
| 31444 | union_obj.requires_comptime = .wip; | 32263 | union_obj.requires_comptime = .wip; |
| 31445 | for (union_obj.fields.values()) |field| { | 32264 | for (union_obj.fields.values()) |field| { |
| 31446 | if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true; | 32265 | if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true; |
| 31447 | } | 32266 | } |
| 31448 | if (requires_comptime) { | 32267 | if (requires_comptime) { |
| 31449 | union_obj.requires_comptime = .yes; | 32268 | union_obj.requires_comptime = .yes; |
| 31450 | } else { | 32269 | } else { |
| 31451 | union_obj.requires_comptime = .no; | 32270 | union_obj.requires_comptime = .no; |
| 31452 | } | 32271 | } |
| 31453 | return requires_comptime; | 32272 | return requires_comptime; |
| 31454 | }, | 32273 | }, |
| 31455 | } | 32274 | } |
| 31456 | }, | 32275 | }, |
| 31457 | 32276 | ||
| 31458 | .error_union => return sema.resolveTypeRequiresComptime(ty.errorUnionPayload()), | 32277 | .opaque_type => false, |
| 31459 | .anyframe_T => { | 32278 | |
| 31460 | const child_ty = ty.castTag(.anyframe_T).?.data; | 32279 | .enum_type => |enum_type| try sema.resolveTypeRequiresComptime(enum_type.tag_ty.toType()), |
| 31461 | return sema.resolveTypeRequiresComptime(child_ty); | 32280 | |
| 31462 | }, | 32281 | // values, not types |
| 31463 | .enum_numbered => { | 32282 | .undef, |
| 31464 | const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; | 32283 | .runtime_value, |
| 31465 | return sema.resolveTypeRequiresComptime(tag_ty); | 32284 | .simple_value, |
| 31466 | }, | 32285 | .variable, |
| 31467 | .enum_full, .enum_nonexhaustive => { | 32286 | .extern_func, |
| 31468 | const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; | 32287 | .func, |
| 31469 | return sema.resolveTypeRequiresComptime(tag_ty); | 32288 | .int, |
| 32289 | .err, | ||
| 32290 | .error_union, | ||
| 32291 | .enum_literal, | ||
| 32292 | .enum_tag, | ||
| 32293 | .empty_enum_value, | ||
| 32294 | .float, | ||
| 32295 | .ptr, | ||
| 32296 | .opt, | ||
| 32297 | .aggregate, | ||
| 32298 | .un, | ||
| 32299 | // memoization, not types | ||
| 32300 | .memoized_call, | ||
| 32301 | => unreachable, | ||
| 31470 | }, | 32302 | }, |
| 31471 | }; | 32303 | }; |
| 31472 | } | 32304 | } |
| ... | @@ -31474,40 +32306,38 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { | ... | @@ -31474,40 +32306,38 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 31474 | /// Returns `error.AnalysisFail` if any of the types (recursively) failed to | 32306 | /// Returns `error.AnalysisFail` if any of the types (recursively) failed to |
| 31475 | /// be resolved. | 32307 | /// be resolved. |
| 31476 | pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { | 32308 | pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { |
| 31477 | switch (ty.zigTypeTag()) { | 32309 | const mod = sema.mod; |
| 32310 | switch (ty.zigTypeTag(mod)) { | ||
| 31478 | .Pointer => { | 32311 | .Pointer => { |
| 31479 | const child_ty = try sema.resolveTypeFields(ty.childType()); | 32312 | const child_ty = try sema.resolveTypeFields(ty.childType(mod)); |
| 31480 | return sema.resolveTypeFully(child_ty); | 32313 | return sema.resolveTypeFully(child_ty); |
| 31481 | }, | 32314 | }, |
| 31482 | .Struct => switch (ty.tag()) { | 32315 | .Struct => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 31483 | .@"struct" => return sema.resolveStructFully(ty), | 32316 | .struct_type => return sema.resolveStructFully(ty), |
| 31484 | .tuple, .anon_struct => { | 32317 | .anon_struct_type => |tuple| { |
| 31485 | const tuple = ty.tupleFields(); | ||
| 31486 | |||
| 31487 | for (tuple.types) |field_ty| { | 32318 | for (tuple.types) |field_ty| { |
| 31488 | try sema.resolveTypeFully(field_ty); | 32319 | try sema.resolveTypeFully(field_ty.toType()); |
| 31489 | } | 32320 | } |
| 31490 | }, | 32321 | }, |
| 31491 | else => {}, | 32322 | else => {}, |
| 31492 | }, | 32323 | }, |
| 31493 | .Union => return sema.resolveUnionFully(ty), | 32324 | .Union => return sema.resolveUnionFully(ty), |
| 31494 | .Array => return sema.resolveTypeFully(ty.childType()), | 32325 | .Array => return sema.resolveTypeFully(ty.childType(mod)), |
| 31495 | .Optional => { | 32326 | .Optional => { |
| 31496 | var buf: Type.Payload.ElemType = undefined; | 32327 | return sema.resolveTypeFully(ty.optionalChild(mod)); |
| 31497 | return sema.resolveTypeFully(ty.optionalChild(&buf)); | ||
| 31498 | }, | 32328 | }, |
| 31499 | .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload()), | 32329 | .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload(mod)), |
| 31500 | .Fn => { | 32330 | .Fn => { |
| 31501 | const info = ty.fnInfo(); | 32331 | const info = mod.typeToFunc(ty).?; |
| 31502 | if (info.is_generic) { | 32332 | if (info.is_generic) { |
| 31503 | // Resolving of generic function types is deferred to when | 32333 | // Resolving of generic function types is deferred to when |
| 31504 | // the function is instantiated. | 32334 | // the function is instantiated. |
| 31505 | return; | 32335 | return; |
| 31506 | } | 32336 | } |
| 31507 | for (info.param_types) |param_ty| { | 32337 | for (info.param_types) |param_ty| { |
| 31508 | try sema.resolveTypeFully(param_ty); | 32338 | try sema.resolveTypeFully(param_ty.toType()); |
| 31509 | } | 32339 | } |
| 31510 | try sema.resolveTypeFully(info.return_type); | 32340 | try sema.resolveTypeFully(info.return_type.toType()); |
| 31511 | }, | 32341 | }, |
| 31512 | else => {}, | 32342 | else => {}, |
| 31513 | } | 32343 | } |
| ... | @@ -31516,9 +32346,9 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -31516,9 +32346,9 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void { |
| 31516 | fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { | 32346 | fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { |
| 31517 | try sema.resolveStructLayout(ty); | 32347 | try sema.resolveStructLayout(ty); |
| 31518 | 32348 | ||
| 32349 | const mod = sema.mod; | ||
| 31519 | const resolved_ty = try sema.resolveTypeFields(ty); | 32350 | const resolved_ty = try sema.resolveTypeFields(ty); |
| 31520 | const payload = resolved_ty.castTag(.@"struct").?; | 32351 | const struct_obj = mod.typeToStruct(resolved_ty).?; |
| 31521 | const struct_obj = payload.data; | ||
| 31522 | 32352 | ||
| 31523 | switch (struct_obj.status) { | 32353 | switch (struct_obj.status) { |
| 31524 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, | 32354 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, |
| ... | @@ -31546,8 +32376,9 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -31546,8 +32376,9 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { |
| 31546 | fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { | 32376 | fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { |
| 31547 | try sema.resolveUnionLayout(ty); | 32377 | try sema.resolveUnionLayout(ty); |
| 31548 | 32378 | ||
| 32379 | const mod = sema.mod; | ||
| 31549 | const resolved_ty = try sema.resolveTypeFields(ty); | 32380 | const resolved_ty = try sema.resolveTypeFields(ty); |
| 31550 | const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; | 32381 | const union_obj = mod.typeToUnion(resolved_ty).?; |
| 31551 | switch (union_obj.status) { | 32382 | switch (union_obj.status) { |
| 31552 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, | 32383 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, |
| 31553 | .fully_resolved_wip, .fully_resolved => return, | 32384 | .fully_resolved_wip, .fully_resolved => return, |
| ... | @@ -31572,30 +32403,111 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -31572,30 +32403,111 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { |
| 31572 | } | 32403 | } |
| 31573 | 32404 | ||
| 31574 | pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { | 32405 | pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { |
| 31575 | switch (ty.tag()) { | 32406 | const mod = sema.mod; |
| 31576 | .@"struct" => { | 32407 | |
| 31577 | const struct_obj = ty.castTag(.@"struct").?.data; | 32408 | switch (ty.toIntern()) { |
| 31578 | try sema.resolveTypeFieldsStruct(ty, struct_obj); | 32409 | .var_args_param_type => unreachable, |
| 31579 | return ty; | 32410 | |
| 31580 | }, | 32411 | .none => unreachable, |
| 31581 | .@"union", .union_safety_tagged, .union_tagged => { | 32412 | |
| 31582 | const union_obj = ty.cast(Type.Payload.Union).?.data; | 32413 | .u1_type, |
| 31583 | try sema.resolveTypeFieldsUnion(ty, union_obj); | 32414 | .u8_type, |
| 31584 | return ty; | 32415 | .i8_type, |
| 31585 | }, | 32416 | .u16_type, |
| 31586 | .type_info => return sema.getBuiltinType("Type"), | 32417 | .i16_type, |
| 31587 | .extern_options => return sema.getBuiltinType("ExternOptions"), | 32418 | .u29_type, |
| 31588 | .export_options => return sema.getBuiltinType("ExportOptions"), | 32419 | .u32_type, |
| 31589 | .atomic_order => return sema.getBuiltinType("AtomicOrder"), | 32420 | .i32_type, |
| 31590 | .atomic_rmw_op => return sema.getBuiltinType("AtomicRmwOp"), | 32421 | .u64_type, |
| 31591 | .calling_convention => return sema.getBuiltinType("CallingConvention"), | 32422 | .i64_type, |
| 31592 | .address_space => return sema.getBuiltinType("AddressSpace"), | 32423 | .u80_type, |
| 31593 | .float_mode => return sema.getBuiltinType("FloatMode"), | 32424 | .u128_type, |
| 31594 | .reduce_op => return sema.getBuiltinType("ReduceOp"), | 32425 | .i128_type, |
| 31595 | .modifier => return sema.getBuiltinType("CallModifier"), | 32426 | .usize_type, |
| 31596 | .prefetch_options => return sema.getBuiltinType("PrefetchOptions"), | 32427 | .isize_type, |
| 32428 | .c_char_type, | ||
| 32429 | .c_short_type, | ||
| 32430 | .c_ushort_type, | ||
| 32431 | .c_int_type, | ||
| 32432 | .c_uint_type, | ||
| 32433 | .c_long_type, | ||
| 32434 | .c_ulong_type, | ||
| 32435 | .c_longlong_type, | ||
| 32436 | .c_ulonglong_type, | ||
| 32437 | .c_longdouble_type, | ||
| 32438 | .f16_type, | ||
| 32439 | .f32_type, | ||
| 32440 | .f64_type, | ||
| 32441 | .f80_type, | ||
| 32442 | .f128_type, | ||
| 32443 | .anyopaque_type, | ||
| 32444 | .bool_type, | ||
| 32445 | .void_type, | ||
| 32446 | .type_type, | ||
| 32447 | .anyerror_type, | ||
| 32448 | .comptime_int_type, | ||
| 32449 | .comptime_float_type, | ||
| 32450 | .noreturn_type, | ||
| 32451 | .anyframe_type, | ||
| 32452 | .null_type, | ||
| 32453 | .undefined_type, | ||
| 32454 | .enum_literal_type, | ||
| 32455 | .manyptr_u8_type, | ||
| 32456 | .manyptr_const_u8_type, | ||
| 32457 | .manyptr_const_u8_sentinel_0_type, | ||
| 32458 | .single_const_pointer_to_comptime_int_type, | ||
| 32459 | .slice_const_u8_type, | ||
| 32460 | .slice_const_u8_sentinel_0_type, | ||
| 32461 | .anyerror_void_error_union_type, | ||
| 32462 | .generic_poison_type, | ||
| 32463 | .empty_struct_type, | ||
| 32464 | => return ty, | ||
| 32465 | |||
| 32466 | .undef => unreachable, | ||
| 32467 | .zero => unreachable, | ||
| 32468 | .zero_usize => unreachable, | ||
| 32469 | .zero_u8 => unreachable, | ||
| 32470 | .one => unreachable, | ||
| 32471 | .one_usize => unreachable, | ||
| 32472 | .one_u8 => unreachable, | ||
| 32473 | .four_u8 => unreachable, | ||
| 32474 | .negative_one => unreachable, | ||
| 32475 | .calling_convention_c => unreachable, | ||
| 32476 | .calling_convention_inline => unreachable, | ||
| 32477 | .void_value => unreachable, | ||
| 32478 | .unreachable_value => unreachable, | ||
| 32479 | .null_value => unreachable, | ||
| 32480 | .bool_true => unreachable, | ||
| 32481 | .bool_false => unreachable, | ||
| 32482 | .empty_struct => unreachable, | ||
| 32483 | .generic_poison => unreachable, | ||
| 32484 | |||
| 32485 | .type_info_type => return sema.getBuiltinType("Type"), | ||
| 32486 | .extern_options_type => return sema.getBuiltinType("ExternOptions"), | ||
| 32487 | .export_options_type => return sema.getBuiltinType("ExportOptions"), | ||
| 32488 | .atomic_order_type => return sema.getBuiltinType("AtomicOrder"), | ||
| 32489 | .atomic_rmw_op_type => return sema.getBuiltinType("AtomicRmwOp"), | ||
| 32490 | .calling_convention_type => return sema.getBuiltinType("CallingConvention"), | ||
| 32491 | .address_space_type => return sema.getBuiltinType("AddressSpace"), | ||
| 32492 | .float_mode_type => return sema.getBuiltinType("FloatMode"), | ||
| 32493 | .reduce_op_type => return sema.getBuiltinType("ReduceOp"), | ||
| 32494 | .call_modifier_type => return sema.getBuiltinType("CallModifier"), | ||
| 32495 | .prefetch_options_type => return sema.getBuiltinType("PrefetchOptions"), | ||
| 32496 | |||
| 32497 | _ => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | ||
| 32498 | .struct_type => |struct_type| { | ||
| 32499 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return ty; | ||
| 32500 | try sema.resolveTypeFieldsStruct(ty, struct_obj); | ||
| 32501 | return ty; | ||
| 32502 | }, | ||
| 32503 | .union_type => |union_type| { | ||
| 32504 | const union_obj = mod.unionPtr(union_type.index); | ||
| 32505 | try sema.resolveTypeFieldsUnion(ty, union_obj); | ||
| 32506 | return ty; | ||
| 32507 | }, | ||
| 31597 | 32508 | ||
| 31598 | else => return ty, | 32509 | else => return ty, |
| 32510 | }, | ||
| 31599 | } | 32511 | } |
| 31600 | } | 32512 | } |
| 31601 | 32513 | ||
| ... | @@ -31682,35 +32594,39 @@ fn resolveInferredErrorSet( | ... | @@ -31682,35 +32594,39 @@ fn resolveInferredErrorSet( |
| 31682 | sema: *Sema, | 32594 | sema: *Sema, |
| 31683 | block: *Block, | 32595 | block: *Block, |
| 31684 | src: LazySrcLoc, | 32596 | src: LazySrcLoc, |
| 31685 | ies: *Module.Fn.InferredErrorSet, | 32597 | ies_index: Module.Fn.InferredErrorSet.Index, |
| 31686 | ) CompileError!void { | 32598 | ) CompileError!void { |
| 32599 | const mod = sema.mod; | ||
| 32600 | const ies = mod.inferredErrorSetPtr(ies_index); | ||
| 32601 | |||
| 31687 | if (ies.is_resolved) return; | 32602 | if (ies.is_resolved) return; |
| 31688 | 32603 | ||
| 31689 | if (ies.func.state == .in_progress) { | 32604 | const func = mod.funcPtr(ies.func); |
| 32605 | if (func.state == .in_progress) { | ||
| 31690 | return sema.fail(block, src, "unable to resolve inferred error set", .{}); | 32606 | return sema.fail(block, src, "unable to resolve inferred error set", .{}); |
| 31691 | } | 32607 | } |
| 31692 | 32608 | ||
| 31693 | // In order to ensure that all dependencies are properly added to the set, we | 32609 | // In order to ensure that all dependencies are properly added to the set, we |
| 31694 | // need to ensure the function body is analyzed of the inferred error set. | 32610 | // need to ensure the function body is analyzed of the inferred error set. |
| 31695 | // However, in the case of comptime/inline function calls with inferred error sets, | 32611 | // However, in the case of comptime/inline function calls with inferred error sets, |
| 31696 | // each call gets a new InferredErrorSet object, which points to the same | 32612 | // each call gets a new InferredErrorSet object, which contains the same |
| 31697 | // `*Module.Fn`. Not only is the function not relevant to the inferred error set | 32613 | // `Module.Fn.Index`. Not only is the function not relevant to the inferred error set |
| 31698 | // in this case, it may be a generic function which would cause an assertion failure | 32614 | // in this case, it may be a generic function which would cause an assertion failure |
| 31699 | // if we called `ensureFuncBodyAnalyzed` on it here. | 32615 | // if we called `ensureFuncBodyAnalyzed` on it here. |
| 31700 | const ies_func_owner_decl = sema.mod.declPtr(ies.func.owner_decl); | 32616 | const ies_func_owner_decl = mod.declPtr(func.owner_decl); |
| 31701 | const ies_func_info = ies_func_owner_decl.ty.fnInfo(); | 32617 | const ies_func_info = mod.typeToFunc(ies_func_owner_decl.ty).?; |
| 31702 | // if ies declared by a inline function with generic return type, the return_type should be generic_poison, | 32618 | // if ies declared by a inline function with generic return type, the return_type should be generic_poison, |
| 31703 | // because inline function does not create a new declaration, and the ies has been filled with analyzeCall, | 32619 | // because inline function does not create a new declaration, and the ies has been filled with analyzeCall, |
| 31704 | // so here we can simply skip this case. | 32620 | // so here we can simply skip this case. |
| 31705 | if (ies_func_info.return_type.tag() == .generic_poison) { | 32621 | if (ies_func_info.return_type == .generic_poison_type) { |
| 31706 | assert(ies_func_info.cc == .Inline); | 32622 | assert(ies_func_info.cc == .Inline); |
| 31707 | } else if (ies_func_info.return_type.errorUnionSet().castTag(.error_set_inferred).?.data == ies) { | 32623 | } else if (mod.typeToInferredErrorSet(ies_func_info.return_type.toType().errorUnionSet(mod)).? == ies) { |
| 31708 | if (ies_func_info.is_generic) { | 32624 | if (ies_func_info.is_generic) { |
| 31709 | const msg = msg: { | 32625 | const msg = msg: { |
| 31710 | const msg = try sema.errMsg(block, src, "unable to resolve inferred error set of generic function", .{}); | 32626 | const msg = try sema.errMsg(block, src, "unable to resolve inferred error set of generic function", .{}); |
| 31711 | errdefer msg.destroy(sema.gpa); | 32627 | errdefer msg.destroy(sema.gpa); |
| 31712 | 32628 | ||
| 31713 | try sema.mod.errNoteNonLazy(ies_func_owner_decl.srcLoc(), msg, "generic function declared here", .{}); | 32629 | try sema.mod.errNoteNonLazy(ies_func_owner_decl.srcLoc(mod), msg, "generic function declared here", .{}); |
| 31714 | break :msg msg; | 32630 | break :msg msg; |
| 31715 | }; | 32631 | }; |
| 31716 | return sema.failWithOwnedErrorMsg(msg); | 32632 | return sema.failWithOwnedErrorMsg(msg); |
| ... | @@ -31722,10 +32638,11 @@ fn resolveInferredErrorSet( | ... | @@ -31722,10 +32638,11 @@ fn resolveInferredErrorSet( |
| 31722 | 32638 | ||
| 31723 | ies.is_resolved = true; | 32639 | ies.is_resolved = true; |
| 31724 | 32640 | ||
| 31725 | for (ies.inferred_error_sets.keys()) |other_ies| { | 32641 | for (ies.inferred_error_sets.keys()) |other_ies_index| { |
| 31726 | if (ies == other_ies) continue; | 32642 | if (ies_index == other_ies_index) continue; |
| 31727 | try sema.resolveInferredErrorSet(block, src, other_ies); | 32643 | try sema.resolveInferredErrorSet(block, src, other_ies_index); |
| 31728 | 32644 | ||
| 32645 | const other_ies = mod.inferredErrorSetPtr(other_ies_index); | ||
| 31729 | for (other_ies.errors.keys()) |key| { | 32646 | for (other_ies.errors.keys()) |key| { |
| 31730 | try ies.errors.put(sema.gpa, key, {}); | 32647 | try ies.errors.put(sema.gpa, key, {}); |
| 31731 | } | 32648 | } |
| ... | @@ -31740,15 +32657,17 @@ fn resolveInferredErrorSetTy( | ... | @@ -31740,15 +32657,17 @@ fn resolveInferredErrorSetTy( |
| 31740 | src: LazySrcLoc, | 32657 | src: LazySrcLoc, |
| 31741 | ty: Type, | 32658 | ty: Type, |
| 31742 | ) CompileError!void { | 32659 | ) CompileError!void { |
| 31743 | if (ty.castTag(.error_set_inferred)) |inferred| { | 32660 | const mod = sema.mod; |
| 31744 | try sema.resolveInferredErrorSet(block, src, inferred.data); | 32661 | if (mod.typeToInferredErrorSetIndex(ty).unwrap()) |ies_index| { |
| 32662 | try sema.resolveInferredErrorSet(block, src, ies_index); | ||
| 31745 | } | 32663 | } |
| 31746 | } | 32664 | } |
| 31747 | 32665 | ||
| 31748 | fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void { | 32666 | fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void { |
| 31749 | const gpa = mod.gpa; | 32667 | const gpa = mod.gpa; |
| 32668 | const ip = &mod.intern_pool; | ||
| 31750 | const decl_index = struct_obj.owner_decl; | 32669 | const decl_index = struct_obj.owner_decl; |
| 31751 | const zir = struct_obj.namespace.file_scope.zir; | 32670 | const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir; |
| 31752 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; | 32671 | const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; |
| 31753 | assert(extended.opcode == .struct_decl); | 32672 | assert(extended.opcode == .struct_decl); |
| 31754 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); | 32673 | const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small); |
| ... | @@ -31794,35 +32713,37 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -31794,35 +32713,37 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31794 | } | 32713 | } |
| 31795 | 32714 | ||
| 31796 | const decl = mod.declPtr(decl_index); | 32715 | const decl = mod.declPtr(decl_index); |
| 31797 | var decl_arena: std.heap.ArenaAllocator = undefined; | ||
| 31798 | const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); | ||
| 31799 | defer decl.value_arena.?.release(&decl_arena); | ||
| 31800 | 32716 | ||
| 31801 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | 32717 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 31802 | defer analysis_arena.deinit(); | 32718 | defer analysis_arena.deinit(); |
| 31803 | 32719 | ||
| 32720 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | ||
| 32721 | defer comptime_mutable_decls.deinit(); | ||
| 32722 | |||
| 31804 | var sema: Sema = .{ | 32723 | var sema: Sema = .{ |
| 31805 | .mod = mod, | 32724 | .mod = mod, |
| 31806 | .gpa = gpa, | 32725 | .gpa = gpa, |
| 31807 | .arena = analysis_arena.allocator(), | 32726 | .arena = analysis_arena.allocator(), |
| 31808 | .perm_arena = decl_arena_allocator, | ||
| 31809 | .code = zir, | 32727 | .code = zir, |
| 31810 | .owner_decl = decl, | 32728 | .owner_decl = decl, |
| 31811 | .owner_decl_index = decl_index, | 32729 | .owner_decl_index = decl_index, |
| 31812 | .func = null, | 32730 | .func = null, |
| 32731 | .func_index = .none, | ||
| 31813 | .fn_ret_ty = Type.void, | 32732 | .fn_ret_ty = Type.void, |
| 31814 | .owner_func = null, | 32733 | .owner_func = null, |
| 32734 | .owner_func_index = .none, | ||
| 32735 | .comptime_mutable_decls = &comptime_mutable_decls, | ||
| 31815 | }; | 32736 | }; |
| 31816 | defer sema.deinit(); | 32737 | defer sema.deinit(); |
| 31817 | 32738 | ||
| 31818 | var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); | 32739 | var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope); |
| 31819 | defer wip_captures.deinit(); | 32740 | defer wip_captures.deinit(); |
| 31820 | 32741 | ||
| 31821 | var block_scope: Block = .{ | 32742 | var block_scope: Block = .{ |
| 31822 | .parent = null, | 32743 | .parent = null, |
| 31823 | .sema = &sema, | 32744 | .sema = &sema, |
| 31824 | .src_decl = decl_index, | 32745 | .src_decl = decl_index, |
| 31825 | .namespace = &struct_obj.namespace, | 32746 | .namespace = struct_obj.namespace, |
| 31826 | .wip_capture_scope = wip_captures.scope, | 32747 | .wip_capture_scope = wip_captures.scope, |
| 31827 | .instructions = .{}, | 32748 | .instructions = .{}, |
| 31828 | .inlining = null, | 32749 | .inlining = null, |
| ... | @@ -31834,13 +32755,13 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -31834,13 +32755,13 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31834 | } | 32755 | } |
| 31835 | 32756 | ||
| 31836 | struct_obj.fields = .{}; | 32757 | struct_obj.fields = .{}; |
| 31837 | try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); | 32758 | try struct_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); |
| 31838 | 32759 | ||
| 31839 | const Field = struct { | 32760 | const Field = struct { |
| 31840 | type_body_len: u32 = 0, | 32761 | type_body_len: u32 = 0, |
| 31841 | align_body_len: u32 = 0, | 32762 | align_body_len: u32 = 0, |
| 31842 | init_body_len: u32 = 0, | 32763 | init_body_len: u32 = 0, |
| 31843 | type_ref: Air.Inst.Ref = .none, | 32764 | type_ref: Zir.Inst.Ref = .none, |
| 31844 | }; | 32765 | }; |
| 31845 | const fields = try sema.arena.alloc(Field, fields_len); | 32766 | const fields = try sema.arena.alloc(Field, fields_len); |
| 31846 | var any_inits = false; | 32767 | var any_inits = false; |
| ... | @@ -31885,30 +32806,30 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -31885,30 +32806,30 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31885 | extra_index += 1; | 32806 | extra_index += 1; |
| 31886 | 32807 | ||
| 31887 | // This string needs to outlive the ZIR code. | 32808 | // This string needs to outlive the ZIR code. |
| 31888 | const field_name = if (field_name_zir) |some| | 32809 | const field_name = try ip.getOrPutString(gpa, if (field_name_zir) |s| |
| 31889 | try decl_arena_allocator.dupe(u8, some) | 32810 | s |
| 31890 | else | 32811 | else |
| 31891 | try std.fmt.allocPrint(decl_arena_allocator, "{d}", .{field_i}); | 32812 | try std.fmt.allocPrint(sema.arena, "{d}", .{field_i})); |
| 31892 | 32813 | ||
| 31893 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); | 32814 | const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); |
| 31894 | if (gop.found_existing) { | 32815 | if (gop.found_existing) { |
| 31895 | const msg = msg: { | 32816 | const msg = msg: { |
| 31896 | const field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; | 32817 | const field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = field_i }).lazy; |
| 31897 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name}); | 32818 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)}); |
| 31898 | errdefer msg.destroy(gpa); | 32819 | errdefer msg.destroy(gpa); |
| 31899 | 32820 | ||
| 31900 | const prev_field_index = struct_obj.fields.getIndex(field_name).?; | 32821 | const prev_field_index = struct_obj.fields.getIndex(field_name).?; |
| 31901 | const prev_field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index }); | 32822 | const prev_field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = prev_field_index }); |
| 31902 | try sema.mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); | 32823 | try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{}); |
| 31903 | try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); | 32824 | try sema.errNote(&block_scope, src, msg, "struct declared here", .{}); |
| 31904 | break :msg msg; | 32825 | break :msg msg; |
| 31905 | }; | 32826 | }; |
| 31906 | return sema.failWithOwnedErrorMsg(msg); | 32827 | return sema.failWithOwnedErrorMsg(msg); |
| 31907 | } | 32828 | } |
| 31908 | gop.value_ptr.* = .{ | 32829 | gop.value_ptr.* = .{ |
| 31909 | .ty = Type.initTag(.noreturn), | 32830 | .ty = Type.noreturn, |
| 31910 | .abi_align = 0, | 32831 | .abi_align = 0, |
| 31911 | .default_val = Value.initTag(.unreachable_value), | 32832 | .default_val = .none, |
| 31912 | .is_comptime = is_comptime, | 32833 | .is_comptime = is_comptime, |
| 31913 | .offset = undefined, | 32834 | .offset = undefined, |
| 31914 | }; | 32835 | }; |
| ... | @@ -31934,7 +32855,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -31934,7 +32855,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31934 | if (zir_field.type_ref != .none) { | 32855 | if (zir_field.type_ref != .none) { |
| 31935 | break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) { | 32856 | break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) { |
| 31936 | error.NeededSourceLocation => { | 32857 | error.NeededSourceLocation => { |
| 31937 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | 32858 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ |
| 31938 | .index = field_i, | 32859 | .index = field_i, |
| 31939 | .range = .type, | 32860 | .range = .type, |
| 31940 | }).lazy; | 32861 | }).lazy; |
| ... | @@ -31950,7 +32871,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -31950,7 +32871,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31950 | const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); | 32871 | const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); |
| 31951 | break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) { | 32872 | break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) { |
| 31952 | error.NeededSourceLocation => { | 32873 | error.NeededSourceLocation => { |
| 31953 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | 32874 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ |
| 31954 | .index = field_i, | 32875 | .index = field_i, |
| 31955 | .range = .type, | 32876 | .range = .type, |
| 31956 | }).lazy; | 32877 | }).lazy; |
| ... | @@ -31960,16 +32881,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -31960,16 +32881,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31960 | else => |e| return e, | 32881 | else => |e| return e, |
| 31961 | }; | 32882 | }; |
| 31962 | }; | 32883 | }; |
| 31963 | if (field_ty.tag() == .generic_poison) { | 32884 | if (field_ty.isGenericPoison()) { |
| 31964 | return error.GenericPoison; | 32885 | return error.GenericPoison; |
| 31965 | } | 32886 | } |
| 31966 | 32887 | ||
| 31967 | const field = &struct_obj.fields.values()[field_i]; | 32888 | const field = &struct_obj.fields.values()[field_i]; |
| 31968 | field.ty = try field_ty.copy(decl_arena_allocator); | 32889 | field.ty = field_ty; |
| 31969 | 32890 | ||
| 31970 | if (field_ty.zigTypeTag() == .Opaque) { | 32891 | if (field_ty.zigTypeTag(mod) == .Opaque) { |
| 31971 | const msg = msg: { | 32892 | const msg = msg: { |
| 31972 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | 32893 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ |
| 31973 | .index = field_i, | 32894 | .index = field_i, |
| 31974 | .range = .type, | 32895 | .range = .type, |
| 31975 | }).lazy; | 32896 | }).lazy; |
| ... | @@ -31981,9 +32902,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -31981,9 +32902,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31981 | }; | 32902 | }; |
| 31982 | return sema.failWithOwnedErrorMsg(msg); | 32903 | return sema.failWithOwnedErrorMsg(msg); |
| 31983 | } | 32904 | } |
| 31984 | if (field_ty.zigTypeTag() == .NoReturn) { | 32905 | if (field_ty.zigTypeTag(mod) == .NoReturn) { |
| 31985 | const msg = msg: { | 32906 | const msg = msg: { |
| 31986 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | 32907 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ |
| 31987 | .index = field_i, | 32908 | .index = field_i, |
| 31988 | .range = .type, | 32909 | .range = .type, |
| 31989 | }).lazy; | 32910 | }).lazy; |
| ... | @@ -31997,11 +32918,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -31997,11 +32918,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 31997 | } | 32918 | } |
| 31998 | if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) { | 32919 | if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) { |
| 31999 | const msg = msg: { | 32920 | const msg = msg: { |
| 32000 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | 32921 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ |
| 32001 | .index = field_i, | 32922 | .index = field_i, |
| 32002 | .range = .type, | 32923 | .range = .type, |
| 32003 | }); | 32924 | }); |
| 32004 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); | 32925 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)}); |
| 32005 | errdefer msg.destroy(sema.gpa); | 32926 | errdefer msg.destroy(sema.gpa); |
| 32006 | 32927 | ||
| 32007 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, field.ty, .struct_field); | 32928 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, field.ty, .struct_field); |
| ... | @@ -32010,13 +32931,13 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -32010,13 +32931,13 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 32010 | break :msg msg; | 32931 | break :msg msg; |
| 32011 | }; | 32932 | }; |
| 32012 | return sema.failWithOwnedErrorMsg(msg); | 32933 | return sema.failWithOwnedErrorMsg(msg); |
| 32013 | } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) { | 32934 | } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) { |
| 32014 | const msg = msg: { | 32935 | const msg = msg: { |
| 32015 | const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{ | 32936 | const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ |
| 32016 | .index = field_i, | 32937 | .index = field_i, |
| 32017 | .range = .type, | 32938 | .range = .type, |
| 32018 | }); | 32939 | }); |
| 32019 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)}); | 32940 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)}); |
| 32020 | errdefer msg.destroy(sema.gpa); | 32941 | errdefer msg.destroy(sema.gpa); |
| 32021 | 32942 | ||
| 32022 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty); | 32943 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty); |
| ... | @@ -32033,7 +32954,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -32033,7 +32954,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 32033 | const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); | 32954 | const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index); |
| 32034 | field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { | 32955 | field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { |
| 32035 | error.NeededSourceLocation => { | 32956 | error.NeededSourceLocation => { |
| 32036 | const align_src = struct_obj.fieldSrcLoc(sema.mod, .{ | 32957 | const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ |
| 32037 | .index = field_i, | 32958 | .index = field_i, |
| 32038 | .range = .alignment, | 32959 | .range = .alignment, |
| 32039 | }).lazy; | 32960 | }).lazy; |
| ... | @@ -32061,7 +32982,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -32061,7 +32982,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 32061 | const field = &struct_obj.fields.values()[field_i]; | 32982 | const field = &struct_obj.fields.values()[field_i]; |
| 32062 | const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) { | 32983 | const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) { |
| 32063 | error.NeededSourceLocation => { | 32984 | error.NeededSourceLocation => { |
| 32064 | const init_src = struct_obj.fieldSrcLoc(sema.mod, .{ | 32985 | const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ |
| 32065 | .index = field_i, | 32986 | .index = field_i, |
| 32066 | .range = .value, | 32987 | .range = .value, |
| 32067 | }).lazy; | 32988 | }).lazy; |
| ... | @@ -32071,17 +32992,21 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void | ... | @@ -32071,17 +32992,21 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 32071 | else => |e| return e, | 32992 | else => |e| return e, |
| 32072 | }; | 32993 | }; |
| 32073 | const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { | 32994 | const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse { |
| 32074 | const init_src = struct_obj.fieldSrcLoc(sema.mod, .{ | 32995 | const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ |
| 32075 | .index = field_i, | 32996 | .index = field_i, |
| 32076 | .range = .value, | 32997 | .range = .value, |
| 32077 | }).lazy; | 32998 | }).lazy; |
| 32078 | return sema.failWithNeededComptime(&block_scope, init_src, "struct field default value must be comptime-known"); | 32999 | return sema.failWithNeededComptime(&block_scope, init_src, "struct field default value must be comptime-known"); |
| 32079 | }; | 33000 | }; |
| 32080 | field.default_val = try default_val.copy(decl_arena_allocator); | 33001 | field.default_val = try default_val.intern(field.ty, mod); |
| 32081 | } | 33002 | } |
| 32082 | } | 33003 | } |
| 32083 | } | 33004 | } |
| 32084 | try wip_captures.finalize(); | 33005 | try wip_captures.finalize(); |
| 33006 | for (comptime_mutable_decls.items) |ct_decl_index| { | ||
| 33007 | const ct_decl = mod.declPtr(ct_decl_index); | ||
| 33008 | try ct_decl.intern(mod); | ||
| 33009 | } | ||
| 32085 | 33010 | ||
| 32086 | struct_obj.have_field_inits = true; | 33011 | struct_obj.have_field_inits = true; |
| 32087 | } | 33012 | } |
| ... | @@ -32091,8 +33016,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32091,8 +33016,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32091 | defer tracy.end(); | 33016 | defer tracy.end(); |
| 32092 | 33017 | ||
| 32093 | const gpa = mod.gpa; | 33018 | const gpa = mod.gpa; |
| 33019 | const ip = &mod.intern_pool; | ||
| 32094 | const decl_index = union_obj.owner_decl; | 33020 | const decl_index = union_obj.owner_decl; |
| 32095 | const zir = union_obj.namespace.file_scope.zir; | 33021 | const zir = mod.namespacePtr(union_obj.namespace).file_scope.zir; |
| 32096 | const extended = zir.instructions.items(.data)[union_obj.zir_index].extended; | 33022 | const extended = zir.instructions.items(.data)[union_obj.zir_index].extended; |
| 32097 | assert(extended.opcode == .union_decl); | 33023 | assert(extended.opcode == .union_decl); |
| 32098 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); | 33024 | const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small); |
| ... | @@ -32134,35 +33060,37 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32134,35 +33060,37 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32134 | extra_index += body.len; | 33060 | extra_index += body.len; |
| 32135 | 33061 | ||
| 32136 | const decl = mod.declPtr(decl_index); | 33062 | const decl = mod.declPtr(decl_index); |
| 32137 | var decl_arena: std.heap.ArenaAllocator = undefined; | ||
| 32138 | const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); | ||
| 32139 | defer decl.value_arena.?.release(&decl_arena); | ||
| 32140 | 33063 | ||
| 32141 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | 33064 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 32142 | defer analysis_arena.deinit(); | 33065 | defer analysis_arena.deinit(); |
| 32143 | 33066 | ||
| 33067 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); | ||
| 33068 | defer comptime_mutable_decls.deinit(); | ||
| 33069 | |||
| 32144 | var sema: Sema = .{ | 33070 | var sema: Sema = .{ |
| 32145 | .mod = mod, | 33071 | .mod = mod, |
| 32146 | .gpa = gpa, | 33072 | .gpa = gpa, |
| 32147 | .arena = analysis_arena.allocator(), | 33073 | .arena = analysis_arena.allocator(), |
| 32148 | .perm_arena = decl_arena_allocator, | ||
| 32149 | .code = zir, | 33074 | .code = zir, |
| 32150 | .owner_decl = decl, | 33075 | .owner_decl = decl, |
| 32151 | .owner_decl_index = decl_index, | 33076 | .owner_decl_index = decl_index, |
| 32152 | .func = null, | 33077 | .func = null, |
| 33078 | .func_index = .none, | ||
| 32153 | .fn_ret_ty = Type.void, | 33079 | .fn_ret_ty = Type.void, |
| 32154 | .owner_func = null, | 33080 | .owner_func = null, |
| 33081 | .owner_func_index = .none, | ||
| 33082 | .comptime_mutable_decls = &comptime_mutable_decls, | ||
| 32155 | }; | 33083 | }; |
| 32156 | defer sema.deinit(); | 33084 | defer sema.deinit(); |
| 32157 | 33085 | ||
| 32158 | var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); | 33086 | var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope); |
| 32159 | defer wip_captures.deinit(); | 33087 | defer wip_captures.deinit(); |
| 32160 | 33088 | ||
| 32161 | var block_scope: Block = .{ | 33089 | var block_scope: Block = .{ |
| 32162 | .parent = null, | 33090 | .parent = null, |
| 32163 | .sema = &sema, | 33091 | .sema = &sema, |
| 32164 | .src_decl = decl_index, | 33092 | .src_decl = decl_index, |
| 32165 | .namespace = &union_obj.namespace, | 33093 | .namespace = union_obj.namespace, |
| 32166 | .wip_capture_scope = wip_captures.scope, | 33094 | .wip_capture_scope = wip_captures.scope, |
| 32167 | .instructions = .{}, | 33095 | .instructions = .{}, |
| 32168 | .inlining = null, | 33096 | .inlining = null, |
| ... | @@ -32178,66 +33106,61 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32178,66 +33106,61 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32178 | } | 33106 | } |
| 32179 | 33107 | ||
| 32180 | try wip_captures.finalize(); | 33108 | try wip_captures.finalize(); |
| 33109 | for (comptime_mutable_decls.items) |ct_decl_index| { | ||
| 33110 | const ct_decl = mod.declPtr(ct_decl_index); | ||
| 33111 | try ct_decl.intern(mod); | ||
| 33112 | } | ||
| 32181 | 33113 | ||
| 32182 | try union_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); | 33114 | try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); |
| 32183 | 33115 | ||
| 32184 | var int_tag_ty: Type = undefined; | 33116 | var int_tag_ty: Type = undefined; |
| 32185 | var enum_field_names: ?*Module.EnumNumbered.NameMap = null; | 33117 | var enum_field_names: []InternPool.NullTerminatedString = &.{}; |
| 32186 | var enum_value_map: ?*Module.EnumNumbered.ValueMap = null; | 33118 | var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{}; |
| 32187 | var tag_ty_field_names: ?Module.EnumFull.NameMap = null; | 33119 | var explicit_tags_seen: []bool = &.{}; |
| 32188 | if (tag_type_ref != .none) { | 33120 | if (tag_type_ref != .none) { |
| 32189 | const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x }; | 33121 | const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x }; |
| 32190 | const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref); | 33122 | const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref); |
| 32191 | if (small.auto_enum_tag) { | 33123 | if (small.auto_enum_tag) { |
| 32192 | // The provided type is an integer type and we must construct the enum tag type here. | 33124 | // The provided type is an integer type and we must construct the enum tag type here. |
| 32193 | int_tag_ty = provided_ty; | 33125 | int_tag_ty = provided_ty; |
| 32194 | if (int_tag_ty.zigTypeTag() != .Int and int_tag_ty.zigTypeTag() != .ComptimeInt) { | 33126 | if (int_tag_ty.zigTypeTag(mod) != .Int and int_tag_ty.zigTypeTag(mod) != .ComptimeInt) { |
| 32195 | return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(sema.mod)}); | 33127 | return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(mod)}); |
| 32196 | } | 33128 | } |
| 32197 | 33129 | ||
| 32198 | if (fields_len > 0) { | 33130 | if (fields_len > 0) { |
| 32199 | var field_count_val: Value.Payload.U64 = .{ | 33131 | const field_count_val = try mod.intValue(Type.comptime_int, fields_len - 1); |
| 32200 | .base = .{ .tag = .int_u64 }, | 33132 | if (!(try sema.intFitsInType(field_count_val, int_tag_ty, null))) { |
| 32201 | .data = fields_len - 1, | ||
| 32202 | }; | ||
| 32203 | if (!(try sema.intFitsInType(Value.initPayload(&field_count_val.base), int_tag_ty, null))) { | ||
| 32204 | const msg = msg: { | 33133 | const msg = msg: { |
| 32205 | const msg = try sema.errMsg(&block_scope, tag_ty_src, "specified integer tag type cannot represent every field", .{}); | 33134 | const msg = try sema.errMsg(&block_scope, tag_ty_src, "specified integer tag type cannot represent every field", .{}); |
| 32206 | errdefer msg.destroy(sema.gpa); | 33135 | errdefer msg.destroy(sema.gpa); |
| 32207 | try sema.errNote(&block_scope, tag_ty_src, msg, "type '{}' cannot fit values in range 0...{d}", .{ | 33136 | try sema.errNote(&block_scope, tag_ty_src, msg, "type '{}' cannot fit values in range 0...{d}", .{ |
| 32208 | int_tag_ty.fmt(sema.mod), | 33137 | int_tag_ty.fmt(mod), |
| 32209 | fields_len - 1, | 33138 | fields_len - 1, |
| 32210 | }); | 33139 | }); |
| 32211 | break :msg msg; | 33140 | break :msg msg; |
| 32212 | }; | 33141 | }; |
| 32213 | return sema.failWithOwnedErrorMsg(msg); | 33142 | return sema.failWithOwnedErrorMsg(msg); |
| 32214 | } | 33143 | } |
| 33144 | enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); | ||
| 33145 | try enum_field_vals.ensureTotalCapacity(sema.arena, fields_len); | ||
| 32215 | } | 33146 | } |
| 32216 | union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty, union_obj); | ||
| 32217 | const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data; | ||
| 32218 | enum_field_names = &enum_obj.fields; | ||
| 32219 | enum_value_map = &enum_obj.values; | ||
| 32220 | } else { | 33147 | } else { |
| 32221 | // The provided type is the enum tag type. | 33148 | // The provided type is the enum tag type. |
| 32222 | union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator); | 33149 | union_obj.tag_ty = provided_ty; |
| 32223 | if (union_obj.tag_ty.zigTypeTag() != .Enum) { | 33150 | const enum_type = switch (ip.indexToKey(union_obj.tag_ty.toIntern())) { |
| 32224 | return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)}); | 33151 | .enum_type => |x| x, |
| 32225 | } | 33152 | else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(mod)}), |
| 33153 | }; | ||
| 32226 | // The fields of the union must match the enum exactly. | 33154 | // The fields of the union must match the enum exactly. |
| 32227 | // Store a copy of the enum field names so we can check for | 33155 | // A flag per field is used to check for missing and extraneous fields. |
| 32228 | // missing or extraneous fields later. | 33156 | explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len); |
| 32229 | tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena); | 33157 | @memset(explicit_tags_seen, false); |
| 32230 | } | 33158 | } |
| 32231 | } else { | 33159 | } else { |
| 32232 | // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis | 33160 | // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis |
| 32233 | // purposes, we still auto-generate an enum tag type the same way. That the union is | 33161 | // purposes, we still auto-generate an enum tag type the same way. That the union is |
| 32234 | // untagged is represented by the Type tag (union vs union_tagged). | 33162 | // untagged is represented by the Type tag (union vs union_tagged). |
| 32235 | union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, fields_len, union_obj); | 33163 | enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); |
| 32236 | enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields; | ||
| 32237 | } | ||
| 32238 | |||
| 32239 | if (fields_len == 0) { | ||
| 32240 | return; | ||
| 32241 | } | 33164 | } |
| 32242 | 33165 | ||
| 32243 | const bits_per_field = 4; | 33166 | const bits_per_field = 4; |
| ... | @@ -32281,17 +33204,17 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32281,17 +33204,17 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32281 | break :blk align_ref; | 33204 | break :blk align_ref; |
| 32282 | } else .none; | 33205 | } else .none; |
| 32283 | 33206 | ||
| 32284 | const tag_ref: Zir.Inst.Ref = if (has_tag) blk: { | 33207 | const tag_ref: Air.Inst.Ref = if (has_tag) blk: { |
| 32285 | const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); | 33208 | const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]); |
| 32286 | extra_index += 1; | 33209 | extra_index += 1; |
| 32287 | break :blk try sema.resolveInst(tag_ref); | 33210 | break :blk try sema.resolveInst(tag_ref); |
| 32288 | } else .none; | 33211 | } else .none; |
| 32289 | 33212 | ||
| 32290 | if (enum_value_map) |map| { | 33213 | if (enum_field_vals.capacity() > 0) { |
| 32291 | const copied_val = if (tag_ref != .none) blk: { | 33214 | const enum_tag_val = if (tag_ref != .none) blk: { |
| 32292 | const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) { | 33215 | const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) { |
| 32293 | error.NeededSourceLocation => { | 33216 | error.NeededSourceLocation => { |
| 32294 | const val_src = union_obj.fieldSrcLoc(sema.mod, .{ | 33217 | const val_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ |
| 32295 | .index = field_i, | 33218 | .index = field_i, |
| 32296 | .range = .value, | 33219 | .range = .value, |
| 32297 | }).lazy; | 33220 | }).lazy; |
| ... | @@ -32302,27 +33225,22 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32302,27 +33225,22 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32302 | }; | 33225 | }; |
| 32303 | last_tag_val = val; | 33226 | last_tag_val = val; |
| 32304 | 33227 | ||
| 32305 | // This puts the memory into the union arena, not the enum arena, but | 33228 | break :blk val; |
| 32306 | // it is OK since they share the same lifetime. | ||
| 32307 | break :blk try val.copy(decl_arena_allocator); | ||
| 32308 | } else blk: { | 33229 | } else blk: { |
| 32309 | const val = if (last_tag_val) |val| | 33230 | const val = if (last_tag_val) |val| |
| 32310 | try sema.intAdd(val, Value.one, int_tag_ty) | 33231 | try sema.intAdd(val, Value.one_comptime_int, int_tag_ty, undefined) |
| 32311 | else | 33232 | else |
| 32312 | Value.zero; | 33233 | try mod.intValue(int_tag_ty, 0); |
| 32313 | last_tag_val = val; | 33234 | last_tag_val = val; |
| 32314 | 33235 | ||
| 32315 | break :blk try val.copy(decl_arena_allocator); | 33236 | break :blk val; |
| 32316 | }; | 33237 | }; |
| 32317 | const gop = map.getOrPutAssumeCapacityContext(copied_val, .{ | 33238 | const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern()); |
| 32318 | .ty = int_tag_ty, | ||
| 32319 | .mod = mod, | ||
| 32320 | }); | ||
| 32321 | if (gop.found_existing) { | 33239 | if (gop.found_existing) { |
| 32322 | const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; | 33240 | const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy; |
| 32323 | const other_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = gop.index }).lazy; | 33241 | const other_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = gop.index }).lazy; |
| 32324 | const msg = msg: { | 33242 | const msg = msg: { |
| 32325 | const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{copied_val.fmtValue(int_tag_ty, sema.mod)}); | 33243 | const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(int_tag_ty, mod)}); |
| 32326 | errdefer msg.destroy(gpa); | 33244 | errdefer msg.destroy(gpa); |
| 32327 | try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{}); | 33245 | try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{}); |
| 32328 | break :msg msg; | 33246 | break :msg msg; |
| ... | @@ -32332,19 +33250,19 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32332,19 +33250,19 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32332 | } | 33250 | } |
| 32333 | 33251 | ||
| 32334 | // This string needs to outlive the ZIR code. | 33252 | // This string needs to outlive the ZIR code. |
| 32335 | const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); | 33253 | const field_name = try ip.getOrPutString(gpa, field_name_zir); |
| 32336 | if (enum_field_names) |set| { | 33254 | if (enum_field_names.len != 0) { |
| 32337 | set.putAssumeCapacity(field_name, {}); | 33255 | enum_field_names[field_i] = field_name; |
| 32338 | } | 33256 | } |
| 32339 | 33257 | ||
| 32340 | const field_ty: Type = if (!has_type) | 33258 | const field_ty: Type = if (!has_type) |
| 32341 | Type.void | 33259 | Type.void |
| 32342 | else if (field_type_ref == .none) | 33260 | else if (field_type_ref == .none) |
| 32343 | Type.initTag(.noreturn) | 33261 | Type.noreturn |
| 32344 | else | 33262 | else |
| 32345 | sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) { | 33263 | sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) { |
| 32346 | error.NeededSourceLocation => { | 33264 | error.NeededSourceLocation => { |
| 32347 | const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ | 33265 | const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ |
| 32348 | .index = field_i, | 33266 | .index = field_i, |
| 32349 | .range = .type, | 33267 | .range = .type, |
| 32350 | }).lazy; | 33268 | }).lazy; |
| ... | @@ -32354,46 +33272,54 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32354,46 +33272,54 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32354 | else => |e| return e, | 33272 | else => |e| return e, |
| 32355 | }; | 33273 | }; |
| 32356 | 33274 | ||
| 32357 | if (field_ty.tag() == .generic_poison) { | 33275 | if (field_ty.isGenericPoison()) { |
| 32358 | return error.GenericPoison; | 33276 | return error.GenericPoison; |
| 32359 | } | 33277 | } |
| 32360 | 33278 | ||
| 32361 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); | 33279 | const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); |
| 32362 | if (gop.found_existing) { | 33280 | if (gop.found_existing) { |
| 32363 | const msg = msg: { | 33281 | const msg = msg: { |
| 32364 | const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy; | 33282 | const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy; |
| 32365 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name}); | 33283 | const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{}'", .{ |
| 33284 | field_name.fmt(ip), | ||
| 33285 | }); | ||
| 32366 | errdefer msg.destroy(gpa); | 33286 | errdefer msg.destroy(gpa); |
| 32367 | 33287 | ||
| 32368 | const prev_field_index = union_obj.fields.getIndex(field_name).?; | 33288 | const prev_field_index = union_obj.fields.getIndex(field_name).?; |
| 32369 | const prev_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index }).lazy; | 33289 | const prev_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = prev_field_index }).lazy; |
| 32370 | try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{}); | 33290 | try mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl, mod), msg, "other field here", .{}); |
| 32371 | try sema.errNote(&block_scope, src, msg, "union declared here", .{}); | 33291 | try sema.errNote(&block_scope, src, msg, "union declared here", .{}); |
| 32372 | break :msg msg; | 33292 | break :msg msg; |
| 32373 | }; | 33293 | }; |
| 32374 | return sema.failWithOwnedErrorMsg(msg); | 33294 | return sema.failWithOwnedErrorMsg(msg); |
| 32375 | } | 33295 | } |
| 32376 | 33296 | ||
| 32377 | if (tag_ty_field_names) |*names| { | 33297 | if (explicit_tags_seen.len > 0) { |
| 32378 | const enum_has_field = names.orderedRemove(field_name); | 33298 | const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type; |
| 32379 | if (!enum_has_field) { | 33299 | const enum_index = tag_info.nameIndex(ip, field_name) orelse { |
| 32380 | const msg = msg: { | 33300 | const msg = msg: { |
| 32381 | const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ | 33301 | const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ |
| 32382 | .index = field_i, | 33302 | .index = field_i, |
| 32383 | .range = .type, | 33303 | .range = .type, |
| 32384 | }).lazy; | 33304 | }).lazy; |
| 32385 | const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) }); | 33305 | const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{}' in enum '{}'", .{ |
| 33306 | field_name.fmt(ip), union_obj.tag_ty.fmt(mod), | ||
| 33307 | }); | ||
| 32386 | errdefer msg.destroy(sema.gpa); | 33308 | errdefer msg.destroy(sema.gpa); |
| 32387 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); | 33309 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 32388 | break :msg msg; | 33310 | break :msg msg; |
| 32389 | }; | 33311 | }; |
| 32390 | return sema.failWithOwnedErrorMsg(msg); | 33312 | return sema.failWithOwnedErrorMsg(msg); |
| 32391 | } | 33313 | }; |
| 33314 | // No check for duplicate because the check already happened in order | ||
| 33315 | // to create the enum type in the first place. | ||
| 33316 | assert(!explicit_tags_seen[enum_index]); | ||
| 33317 | explicit_tags_seen[enum_index] = true; | ||
| 32392 | } | 33318 | } |
| 32393 | 33319 | ||
| 32394 | if (field_ty.zigTypeTag() == .Opaque) { | 33320 | if (field_ty.zigTypeTag(mod) == .Opaque) { |
| 32395 | const msg = msg: { | 33321 | const msg = msg: { |
| 32396 | const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ | 33322 | const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ |
| 32397 | .index = field_i, | 33323 | .index = field_i, |
| 32398 | .range = .type, | 33324 | .range = .type, |
| 32399 | }).lazy; | 33325 | }).lazy; |
| ... | @@ -32407,11 +33333,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32407,11 +33333,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32407 | } | 33333 | } |
| 32408 | if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) { | 33334 | if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) { |
| 32409 | const msg = msg: { | 33335 | const msg = msg: { |
| 32410 | const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ | 33336 | const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ |
| 32411 | .index = field_i, | 33337 | .index = field_i, |
| 32412 | .range = .type, | 33338 | .range = .type, |
| 32413 | }); | 33339 | }); |
| 32414 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | 33340 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); |
| 32415 | errdefer msg.destroy(sema.gpa); | 33341 | errdefer msg.destroy(sema.gpa); |
| 32416 | 33342 | ||
| 32417 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .union_field); | 33343 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .union_field); |
| ... | @@ -32420,13 +33346,13 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32420,13 +33346,13 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32420 | break :msg msg; | 33346 | break :msg msg; |
| 32421 | }; | 33347 | }; |
| 32422 | return sema.failWithOwnedErrorMsg(msg); | 33348 | return sema.failWithOwnedErrorMsg(msg); |
| 32423 | } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) { | 33349 | } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) { |
| 32424 | const msg = msg: { | 33350 | const msg = msg: { |
| 32425 | const ty_src = union_obj.fieldSrcLoc(sema.mod, .{ | 33351 | const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ |
| 32426 | .index = field_i, | 33352 | .index = field_i, |
| 32427 | .range = .type, | 33353 | .range = .type, |
| 32428 | }); | 33354 | }); |
| 32429 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)}); | 33355 | const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)}); |
| 32430 | errdefer msg.destroy(sema.gpa); | 33356 | errdefer msg.destroy(sema.gpa); |
| 32431 | 33357 | ||
| 32432 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty); | 33358 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty); |
| ... | @@ -32438,14 +33364,14 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32438,14 +33364,14 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32438 | } | 33364 | } |
| 32439 | 33365 | ||
| 32440 | gop.value_ptr.* = .{ | 33366 | gop.value_ptr.* = .{ |
| 32441 | .ty = try field_ty.copy(decl_arena_allocator), | 33367 | .ty = field_ty, |
| 32442 | .abi_align = 0, | 33368 | .abi_align = 0, |
| 32443 | }; | 33369 | }; |
| 32444 | 33370 | ||
| 32445 | if (align_ref != .none) { | 33371 | if (align_ref != .none) { |
| 32446 | gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { | 33372 | gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) { |
| 32447 | error.NeededSourceLocation => { | 33373 | error.NeededSourceLocation => { |
| 32448 | const align_src = union_obj.fieldSrcLoc(sema.mod, .{ | 33374 | const align_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ |
| 32449 | .index = field_i, | 33375 | .index = field_i, |
| 32450 | .range = .alignment, | 33376 | .range = .alignment, |
| 32451 | }).lazy; | 33377 | }).lazy; |
| ... | @@ -32459,22 +33385,29 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { | ... | @@ -32459,22 +33385,29 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32459 | } | 33385 | } |
| 32460 | } | 33386 | } |
| 32461 | 33387 | ||
| 32462 | if (tag_ty_field_names) |names| { | 33388 | if (explicit_tags_seen.len > 0) { |
| 32463 | if (names.count() > 0) { | 33389 | const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type; |
| 33390 | if (tag_info.names.len > fields_len) { | ||
| 32464 | const msg = msg: { | 33391 | const msg = msg: { |
| 32465 | const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{}); | 33392 | const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{}); |
| 32466 | errdefer msg.destroy(sema.gpa); | 33393 | errdefer msg.destroy(sema.gpa); |
| 32467 | 33394 | ||
| 32468 | const enum_ty = union_obj.tag_ty; | 33395 | const enum_ty = union_obj.tag_ty; |
| 32469 | for (names.keys()) |field_name| { | 33396 | for (tag_info.names, 0..) |field_name, field_index| { |
| 32470 | const field_index = enum_ty.enumFieldIndex(field_name).?; | 33397 | if (explicit_tags_seen[field_index]) continue; |
| 32471 | try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name}); | 33398 | try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{}' missing, declared here", .{ |
| 33399 | field_name.fmt(ip), | ||
| 33400 | }); | ||
| 32472 | } | 33401 | } |
| 32473 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); | 33402 | try sema.addDeclaredHereNote(msg, union_obj.tag_ty); |
| 32474 | break :msg msg; | 33403 | break :msg msg; |
| 32475 | }; | 33404 | }; |
| 32476 | return sema.failWithOwnedErrorMsg(msg); | 33405 | return sema.failWithOwnedErrorMsg(msg); |
| 32477 | } | 33406 | } |
| 33407 | } else if (enum_field_vals.count() > 0) { | ||
| 33408 | union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_obj); | ||
| 33409 | } else { | ||
| 33410 | union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_obj); | ||
| 32478 | } | 33411 | } |
| 32479 | } | 33412 | } |
| 32480 | 33413 | ||
| ... | @@ -32486,116 +33419,103 @@ fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Ty | ... | @@ -32486,116 +33419,103 @@ fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Ty |
| 32486 | fn generateUnionTagTypeNumbered( | 33419 | fn generateUnionTagTypeNumbered( |
| 32487 | sema: *Sema, | 33420 | sema: *Sema, |
| 32488 | block: *Block, | 33421 | block: *Block, |
| 32489 | fields_len: u32, | 33422 | enum_field_names: []const InternPool.NullTerminatedString, |
| 32490 | int_ty: Type, | 33423 | enum_field_vals: []const InternPool.Index, |
| 32491 | union_obj: *Module.Union, | 33424 | union_obj: *Module.Union, |
| 32492 | ) !Type { | 33425 | ) !Type { |
| 32493 | const mod = sema.mod; | 33426 | const mod = sema.mod; |
| 32494 | 33427 | const gpa = sema.gpa; | |
| 32495 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | ||
| 32496 | errdefer new_decl_arena.deinit(); | ||
| 32497 | const new_decl_arena_allocator = new_decl_arena.allocator(); | ||
| 32498 | |||
| 32499 | const enum_obj = try new_decl_arena_allocator.create(Module.EnumNumbered); | ||
| 32500 | const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumNumbered); | ||
| 32501 | enum_ty_payload.* = .{ | ||
| 32502 | .base = .{ .tag = .enum_numbered }, | ||
| 32503 | .data = enum_obj, | ||
| 32504 | }; | ||
| 32505 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | ||
| 32506 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); | ||
| 32507 | 33428 | ||
| 32508 | const src_decl = mod.declPtr(block.src_decl); | 33429 | const src_decl = mod.declPtr(block.src_decl); |
| 32509 | const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); | 33430 | const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); |
| 32510 | errdefer mod.destroyDecl(new_decl_index); | 33431 | errdefer mod.destroyDecl(new_decl_index); |
| 32511 | const name = name: { | 33432 | const fqn = try union_obj.getFullyQualifiedName(mod); |
| 32512 | const fqn = try union_obj.getFullyQualifiedName(mod); | 33433 | const name = try mod.intern_pool.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(&mod.intern_pool)}); |
| 32513 | defer sema.gpa.free(fqn); | ||
| 32514 | break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); | ||
| 32515 | }; | ||
| 32516 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ | 33434 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ |
| 32517 | .ty = Type.type, | 33435 | .ty = Type.noreturn, |
| 32518 | .val = enum_val, | 33436 | .val = Value.@"unreachable", |
| 32519 | }, name); | 33437 | }, name); |
| 32520 | sema.mod.declPtr(new_decl_index).name_fully_qualified = true; | 33438 | errdefer mod.abortAnonDecl(new_decl_index); |
| 32521 | 33439 | ||
| 32522 | const new_decl = mod.declPtr(new_decl_index); | 33440 | const new_decl = mod.declPtr(new_decl_index); |
| 33441 | new_decl.name_fully_qualified = true; | ||
| 32523 | new_decl.owns_tv = true; | 33442 | new_decl.owns_tv = true; |
| 32524 | new_decl.name_fully_qualified = true; | 33443 | new_decl.name_fully_qualified = true; |
| 32525 | errdefer mod.abortAnonDecl(new_decl_index); | ||
| 32526 | 33444 | ||
| 32527 | const copied_int_ty = try int_ty.copy(new_decl_arena_allocator); | 33445 | const enum_ty = try mod.intern(.{ .enum_type = .{ |
| 32528 | enum_obj.* = .{ | 33446 | .decl = new_decl_index, |
| 32529 | .owner_decl = new_decl_index, | 33447 | .namespace = .none, |
| 32530 | .tag_ty = copied_int_ty, | 33448 | .tag_ty = if (enum_field_vals.len == 0) |
| 32531 | .fields = .{}, | 33449 | (try mod.intType(.unsigned, 0)).toIntern() |
| 32532 | .values = .{}, | 33450 | else |
| 32533 | }; | 33451 | mod.intern_pool.typeOf(enum_field_vals[0]), |
| 32534 | // Here we pre-allocate the maps using the decl arena. | 33452 | .names = enum_field_names, |
| 32535 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); | 33453 | .values = enum_field_vals, |
| 32536 | try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{ | 33454 | .tag_mode = .explicit, |
| 32537 | .ty = copied_int_ty, | 33455 | } }); |
| 32538 | .mod = mod, | ||
| 32539 | }); | ||
| 32540 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 32541 | return enum_ty; | ||
| 32542 | } | ||
| 32543 | 33456 | ||
| 32544 | fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, maybe_union_obj: ?*Module.Union) !Type { | 33457 | new_decl.ty = Type.type; |
| 32545 | const mod = sema.mod; | 33458 | new_decl.val = enum_ty.toValue(); |
| 32546 | 33459 | ||
| 32547 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | 33460 | try mod.finalizeAnonDecl(new_decl_index); |
| 32548 | errdefer new_decl_arena.deinit(); | 33461 | return enum_ty.toType(); |
| 32549 | const new_decl_arena_allocator = new_decl_arena.allocator(); | 33462 | } |
| 32550 | 33463 | ||
| 32551 | const enum_obj = try new_decl_arena_allocator.create(Module.EnumSimple); | 33464 | fn generateUnionTagTypeSimple( |
| 32552 | const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumSimple); | 33465 | sema: *Sema, |
| 32553 | enum_ty_payload.* = .{ | 33466 | block: *Block, |
| 32554 | .base = .{ .tag = .enum_simple }, | 33467 | enum_field_names: []const InternPool.NullTerminatedString, |
| 32555 | .data = enum_obj, | 33468 | maybe_union_obj: ?*Module.Union, |
| 32556 | }; | 33469 | ) !Type { |
| 32557 | const enum_ty = Type.initPayload(&enum_ty_payload.base); | 33470 | const mod = sema.mod; |
| 32558 | const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty); | 33471 | const gpa = sema.gpa; |
| 32559 | 33472 | ||
| 32560 | const new_decl_index = new_decl_index: { | 33473 | const new_decl_index = new_decl_index: { |
| 32561 | const union_obj = maybe_union_obj orelse { | 33474 | const union_obj = maybe_union_obj orelse { |
| 32562 | break :new_decl_index try mod.createAnonymousDecl(block, .{ | 33475 | break :new_decl_index try mod.createAnonymousDecl(block, .{ |
| 32563 | .ty = Type.type, | 33476 | .ty = Type.noreturn, |
| 32564 | .val = enum_val, | 33477 | .val = Value.@"unreachable", |
| 32565 | }); | 33478 | }); |
| 32566 | }; | 33479 | }; |
| 32567 | const src_decl = mod.declPtr(block.src_decl); | 33480 | const src_decl = mod.declPtr(block.src_decl); |
| 32568 | const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); | 33481 | const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); |
| 32569 | errdefer mod.destroyDecl(new_decl_index); | 33482 | errdefer mod.destroyDecl(new_decl_index); |
| 32570 | const name = name: { | 33483 | const fqn = try union_obj.getFullyQualifiedName(mod); |
| 32571 | const fqn = try union_obj.getFullyQualifiedName(mod); | 33484 | const name = try mod.intern_pool.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(&mod.intern_pool)}); |
| 32572 | defer sema.gpa.free(fqn); | ||
| 32573 | break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); | ||
| 32574 | }; | ||
| 32575 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ | 33485 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ |
| 32576 | .ty = Type.type, | 33486 | .ty = Type.noreturn, |
| 32577 | .val = enum_val, | 33487 | .val = Value.@"unreachable", |
| 32578 | }, name); | 33488 | }, name); |
| 32579 | sema.mod.declPtr(new_decl_index).name_fully_qualified = true; | 33489 | mod.declPtr(new_decl_index).name_fully_qualified = true; |
| 32580 | break :new_decl_index new_decl_index; | 33490 | break :new_decl_index new_decl_index; |
| 32581 | }; | 33491 | }; |
| 33492 | errdefer mod.abortAnonDecl(new_decl_index); | ||
| 33493 | |||
| 33494 | const enum_ty = try mod.intern(.{ .enum_type = .{ | ||
| 33495 | .decl = new_decl_index, | ||
| 33496 | .namespace = .none, | ||
| 33497 | .tag_ty = if (enum_field_names.len == 0) | ||
| 33498 | (try mod.intType(.unsigned, 0)).toIntern() | ||
| 33499 | else | ||
| 33500 | (try mod.smallestUnsignedInt(enum_field_names.len - 1)).toIntern(), | ||
| 33501 | .names = enum_field_names, | ||
| 33502 | .values = &.{}, | ||
| 33503 | .tag_mode = .auto, | ||
| 33504 | } }); | ||
| 32582 | 33505 | ||
| 32583 | const new_decl = mod.declPtr(new_decl_index); | 33506 | const new_decl = mod.declPtr(new_decl_index); |
| 32584 | new_decl.owns_tv = true; | 33507 | new_decl.owns_tv = true; |
| 32585 | errdefer mod.abortAnonDecl(new_decl_index); | 33508 | new_decl.ty = Type.type; |
| 33509 | new_decl.val = enum_ty.toValue(); | ||
| 32586 | 33510 | ||
| 32587 | enum_obj.* = .{ | 33511 | try mod.finalizeAnonDecl(new_decl_index); |
| 32588 | .owner_decl = new_decl_index, | 33512 | return enum_ty.toType(); |
| 32589 | .fields = .{}, | ||
| 32590 | }; | ||
| 32591 | // Here we pre-allocate the maps using the decl arena. | ||
| 32592 | try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len); | ||
| 32593 | try new_decl.finalizeNewArena(&new_decl_arena); | ||
| 32594 | return enum_ty; | ||
| 32595 | } | 33513 | } |
| 32596 | 33514 | ||
| 32597 | fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { | 33515 | fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { |
| 32598 | var wip_captures = try WipCaptureScope.init(sema.gpa, sema.perm_arena, sema.owner_decl.src_scope); | 33516 | const gpa = sema.gpa; |
| 33517 | |||
| 33518 | var wip_captures = try WipCaptureScope.init(gpa, sema.owner_decl.src_scope); | ||
| 32599 | defer wip_captures.deinit(); | 33519 | defer wip_captures.deinit(); |
| 32600 | 33520 | ||
| 32601 | var block: Block = .{ | 33521 | var block: Block = .{ |
| ... | @@ -32609,19 +33529,20 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { | ... | @@ -32609,19 +33529,20 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { |
| 32609 | .is_comptime = true, | 33529 | .is_comptime = true, |
| 32610 | }; | 33530 | }; |
| 32611 | defer { | 33531 | defer { |
| 32612 | block.instructions.deinit(sema.gpa); | 33532 | block.instructions.deinit(gpa); |
| 32613 | block.params.deinit(sema.gpa); | 33533 | block.params.deinit(gpa); |
| 32614 | } | 33534 | } |
| 32615 | const src = LazySrcLoc.nodeOffset(0); | 33535 | const src = LazySrcLoc.nodeOffset(0); |
| 32616 | 33536 | ||
| 32617 | const mod = sema.mod; | 33537 | const mod = sema.mod; |
| 33538 | const ip = &mod.intern_pool; | ||
| 32618 | const std_pkg = mod.main_pkg.table.get("std").?; | 33539 | const std_pkg = mod.main_pkg.table.get("std").?; |
| 32619 | const std_file = (mod.importPkg(std_pkg) catch unreachable).file; | 33540 | const std_file = (mod.importPkg(std_pkg) catch unreachable).file; |
| 32620 | const opt_builtin_inst = (try sema.namespaceLookupRef( | 33541 | const opt_builtin_inst = (try sema.namespaceLookupRef( |
| 32621 | &block, | 33542 | &block, |
| 32622 | src, | 33543 | src, |
| 32623 | mod.declPtr(std_file.root_decl.unwrap().?).src_namespace, | 33544 | mod.declPtr(std_file.root_decl.unwrap().?).src_namespace, |
| 32624 | "builtin", | 33545 | try ip.getOrPutString(gpa, "builtin"), |
| 32625 | )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'"); | 33546 | )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'"); |
| 32626 | const builtin_inst = try sema.analyzeLoad(&block, src, opt_builtin_inst, src); | 33547 | const builtin_inst = try sema.analyzeLoad(&block, src, opt_builtin_inst, src); |
| 32627 | const builtin_ty = sema.analyzeAsType(&block, src, builtin_inst) catch |err| switch (err) { | 33548 | const builtin_ty = sema.analyzeAsType(&block, src, builtin_inst) catch |err| switch (err) { |
| ... | @@ -32631,8 +33552,8 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { | ... | @@ -32631,8 +33552,8 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { |
| 32631 | const opt_ty_decl = (try sema.namespaceLookup( | 33552 | const opt_ty_decl = (try sema.namespaceLookup( |
| 32632 | &block, | 33553 | &block, |
| 32633 | src, | 33554 | src, |
| 32634 | builtin_ty.getNamespace().?, | 33555 | builtin_ty.getNamespaceIndex(mod).unwrap().?, |
| 32635 | name, | 33556 | try ip.getOrPutString(gpa, name), |
| 32636 | )) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name}); | 33557 | )) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name}); |
| 32637 | return sema.analyzeDeclVal(&block, src, opt_ty_decl); | 33558 | return sema.analyzeDeclVal(&block, src, opt_ty_decl); |
| 32638 | } | 33559 | } |
| ... | @@ -32640,7 +33561,7 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { | ... | @@ -32640,7 +33561,7 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { |
| 32640 | fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type { | 33561 | fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type { |
| 32641 | const ty_inst = try sema.getBuiltin(name); | 33562 | const ty_inst = try sema.getBuiltin(name); |
| 32642 | 33563 | ||
| 32643 | var wip_captures = try WipCaptureScope.init(sema.gpa, sema.perm_arena, sema.owner_decl.src_scope); | 33564 | var wip_captures = try WipCaptureScope.init(sema.gpa, sema.owner_decl.src_scope); |
| 32644 | defer wip_captures.deinit(); | 33565 | defer wip_captures.deinit(); |
| 32645 | 33566 | ||
| 32646 | var block: Block = .{ | 33567 | var block: Block = .{ |
| ... | @@ -32673,341 +33594,287 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type { | ... | @@ -32673,341 +33594,287 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type { |
| 32673 | /// that the types are already resolved. | 33594 | /// that the types are already resolved. |
| 32674 | /// TODO assert the return value matches `ty.onePossibleValue` | 33595 | /// TODO assert the return value matches `ty.onePossibleValue` |
| 32675 | pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { | 33596 | pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 32676 | switch (ty.tag()) { | 33597 | const mod = sema.mod; |
| 32677 | .f16, | 33598 | return switch (ty.toIntern()) { |
| 32678 | .f32, | 33599 | .empty_struct_type => Value.empty_struct, |
| 32679 | .f64, | 33600 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 32680 | .f80, | 33601 | .int_type => |int_type| { |
| 32681 | .f128, | 33602 | if (int_type.bits == 0) { |
| 32682 | .c_longdouble, | 33603 | return try mod.intValue(ty, 0); |
| 32683 | .comptime_int, | 33604 | } else { |
| 32684 | .comptime_float, | 33605 | return null; |
| 32685 | .u1, | 33606 | } |
| 32686 | .u8, | 33607 | }, |
| 32687 | .i8, | 33608 | |
| 32688 | .u16, | 33609 | .ptr_type, |
| 32689 | .i16, | 33610 | .error_union_type, |
| 32690 | .u29, | 33611 | .func_type, |
| 32691 | .u32, | 33612 | .anyframe_type, |
| 32692 | .i32, | 33613 | .error_set_type, |
| 32693 | .u64, | 33614 | .inferred_error_set_type, |
| 32694 | .i64, | 33615 | => null, |
| 32695 | .u128, | 33616 | |
| 32696 | .i128, | 33617 | inline .array_type, .vector_type => |seq_type, seq_tag| { |
| 32697 | .usize, | 33618 | const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none; |
| 32698 | .isize, | 33619 | if (seq_type.len + @boolToInt(has_sentinel) == 0) return (try mod.intern(.{ .aggregate = .{ |
| 32699 | .c_char, | 33620 | .ty = ty.toIntern(), |
| 32700 | .c_short, | 33621 | .storage = .{ .elems = &.{} }, |
| 32701 | .c_ushort, | 33622 | } })).toValue(); |
| 32702 | .c_int, | 33623 | |
| 32703 | .c_uint, | 33624 | if (try sema.typeHasOnePossibleValue(seq_type.child.toType())) |opv| { |
| 32704 | .c_long, | 33625 | return (try mod.intern(.{ .aggregate = .{ |
| 32705 | .c_ulong, | 33626 | .ty = ty.toIntern(), |
| 32706 | .c_longlong, | 33627 | .storage = .{ .repeated_elem = opv.toIntern() }, |
| 32707 | .c_ulonglong, | 33628 | } })).toValue(); |
| 32708 | .bool, | 33629 | } |
| 32709 | .type, | ||
| 32710 | .anyerror, | ||
| 32711 | .error_set_single, | ||
| 32712 | .error_set, | ||
| 32713 | .error_set_merged, | ||
| 32714 | .error_union, | ||
| 32715 | .fn_noreturn_no_args, | ||
| 32716 | .fn_void_no_args, | ||
| 32717 | .fn_naked_noreturn_no_args, | ||
| 32718 | .fn_ccc_void_no_args, | ||
| 32719 | .function, | ||
| 32720 | .single_const_pointer_to_comptime_int, | ||
| 32721 | .array_sentinel, | ||
| 32722 | .array_u8_sentinel_0, | ||
| 32723 | .const_slice_u8, | ||
| 32724 | .const_slice_u8_sentinel_0, | ||
| 32725 | .const_slice, | ||
| 32726 | .mut_slice, | ||
| 32727 | .anyopaque, | ||
| 32728 | .optional_single_mut_pointer, | ||
| 32729 | .optional_single_const_pointer, | ||
| 32730 | .enum_literal, | ||
| 32731 | .anyerror_void_error_union, | ||
| 32732 | .error_set_inferred, | ||
| 32733 | .@"opaque", | ||
| 32734 | .manyptr_u8, | ||
| 32735 | .manyptr_const_u8, | ||
| 32736 | .manyptr_const_u8_sentinel_0, | ||
| 32737 | .atomic_order, | ||
| 32738 | .atomic_rmw_op, | ||
| 32739 | .calling_convention, | ||
| 32740 | .address_space, | ||
| 32741 | .float_mode, | ||
| 32742 | .reduce_op, | ||
| 32743 | .modifier, | ||
| 32744 | .prefetch_options, | ||
| 32745 | .export_options, | ||
| 32746 | .extern_options, | ||
| 32747 | .type_info, | ||
| 32748 | .@"anyframe", | ||
| 32749 | .anyframe_T, | ||
| 32750 | .many_const_pointer, | ||
| 32751 | .many_mut_pointer, | ||
| 32752 | .c_const_pointer, | ||
| 32753 | .c_mut_pointer, | ||
| 32754 | .single_const_pointer, | ||
| 32755 | .single_mut_pointer, | ||
| 32756 | .pointer, | ||
| 32757 | => return null, | ||
| 32758 | |||
| 32759 | .optional => { | ||
| 32760 | var buf: Type.Payload.ElemType = undefined; | ||
| 32761 | const child_ty = ty.optionalChild(&buf); | ||
| 32762 | if (child_ty.isNoReturn()) { | ||
| 32763 | return Value.null; | ||
| 32764 | } else { | ||
| 32765 | return null; | 33630 | return null; |
| 32766 | } | 33631 | }, |
| 32767 | }, | 33632 | .opt_type => |child| { |
| 33633 | if (child == .noreturn_type) { | ||
| 33634 | return try mod.nullValue(ty); | ||
| 33635 | } else { | ||
| 33636 | return null; | ||
| 33637 | } | ||
| 33638 | }, | ||
| 32768 | 33639 | ||
| 32769 | .@"struct" => { | 33640 | .simple_type => |t| switch (t) { |
| 32770 | const resolved_ty = try sema.resolveTypeFields(ty); | 33641 | .f16, |
| 32771 | const s = resolved_ty.castTag(.@"struct").?.data; | 33642 | .f32, |
| 32772 | for (s.fields.values(), 0..) |field, i| { | 33643 | .f64, |
| 32773 | if (field.is_comptime) continue; | 33644 | .f80, |
| 32774 | if (field.ty.eql(resolved_ty, sema.mod)) { | 33645 | .f128, |
| 33646 | .usize, | ||
| 33647 | .isize, | ||
| 33648 | .c_char, | ||
| 33649 | .c_short, | ||
| 33650 | .c_ushort, | ||
| 33651 | .c_int, | ||
| 33652 | .c_uint, | ||
| 33653 | .c_long, | ||
| 33654 | .c_ulong, | ||
| 33655 | .c_longlong, | ||
| 33656 | .c_ulonglong, | ||
| 33657 | .c_longdouble, | ||
| 33658 | .anyopaque, | ||
| 33659 | .bool, | ||
| 33660 | .type, | ||
| 33661 | .anyerror, | ||
| 33662 | .comptime_int, | ||
| 33663 | .comptime_float, | ||
| 33664 | .enum_literal, | ||
| 33665 | .atomic_order, | ||
| 33666 | .atomic_rmw_op, | ||
| 33667 | .calling_convention, | ||
| 33668 | .address_space, | ||
| 33669 | .float_mode, | ||
| 33670 | .reduce_op, | ||
| 33671 | .call_modifier, | ||
| 33672 | .prefetch_options, | ||
| 33673 | .export_options, | ||
| 33674 | .extern_options, | ||
| 33675 | .type_info, | ||
| 33676 | => null, | ||
| 33677 | |||
| 33678 | .void => Value.void, | ||
| 33679 | .noreturn => Value.@"unreachable", | ||
| 33680 | .null => Value.null, | ||
| 33681 | .undefined => Value.undef, | ||
| 33682 | |||
| 33683 | .generic_poison => return error.GenericPoison, | ||
| 33684 | }, | ||
| 33685 | .struct_type => |struct_type| { | ||
| 33686 | const resolved_ty = try sema.resolveTypeFields(ty); | ||
| 33687 | if (mod.structPtrUnwrap(struct_type.index)) |s| { | ||
| 33688 | const field_vals = try sema.arena.alloc(InternPool.Index, s.fields.count()); | ||
| 33689 | for (field_vals, s.fields.values(), 0..) |*field_val, field, i| { | ||
| 33690 | if (field.is_comptime) { | ||
| 33691 | field_val.* = field.default_val; | ||
| 33692 | continue; | ||
| 33693 | } | ||
| 33694 | if (field.ty.eql(resolved_ty, sema.mod)) { | ||
| 33695 | const msg = try Module.ErrorMsg.create( | ||
| 33696 | sema.gpa, | ||
| 33697 | s.srcLoc(sema.mod), | ||
| 33698 | "struct '{}' depends on itself", | ||
| 33699 | .{ty.fmt(sema.mod)}, | ||
| 33700 | ); | ||
| 33701 | try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{}); | ||
| 33702 | return sema.failWithOwnedErrorMsg(msg); | ||
| 33703 | } | ||
| 33704 | if (try sema.typeHasOnePossibleValue(field.ty)) |field_opv| { | ||
| 33705 | field_val.* = try field_opv.intern(field.ty, mod); | ||
| 33706 | } else return null; | ||
| 33707 | } | ||
| 33708 | |||
| 33709 | // In this case the struct has no runtime-known fields and | ||
| 33710 | // therefore has one possible value. | ||
| 33711 | return (try mod.intern(.{ .aggregate = .{ | ||
| 33712 | .ty = ty.toIntern(), | ||
| 33713 | .storage = .{ .elems = field_vals }, | ||
| 33714 | } })).toValue(); | ||
| 33715 | } | ||
| 33716 | |||
| 33717 | // In this case the struct has no fields at all and | ||
| 33718 | // therefore has one possible value. | ||
| 33719 | return (try mod.intern(.{ .aggregate = .{ | ||
| 33720 | .ty = ty.toIntern(), | ||
| 33721 | .storage = .{ .elems = &.{} }, | ||
| 33722 | } })).toValue(); | ||
| 33723 | }, | ||
| 33724 | |||
| 33725 | .anon_struct_type => |tuple| { | ||
| 33726 | for (tuple.values) |val| { | ||
| 33727 | if (val == .none) return null; | ||
| 33728 | } | ||
| 33729 | // In this case the struct has all comptime-known fields and | ||
| 33730 | // therefore has one possible value. | ||
| 33731 | // TODO: write something like getCoercedInts to avoid needing to dupe | ||
| 33732 | return (try mod.intern(.{ .aggregate = .{ | ||
| 33733 | .ty = ty.toIntern(), | ||
| 33734 | .storage = .{ .elems = try sema.arena.dupe(InternPool.Index, tuple.values) }, | ||
| 33735 | } })).toValue(); | ||
| 33736 | }, | ||
| 33737 | |||
| 33738 | .union_type => |union_type| { | ||
| 33739 | const resolved_ty = try sema.resolveTypeFields(ty); | ||
| 33740 | const union_obj = mod.unionPtr(union_type.index); | ||
| 33741 | const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse | ||
| 33742 | return null; | ||
| 33743 | const fields = union_obj.fields.values(); | ||
| 33744 | if (fields.len == 0) { | ||
| 33745 | const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); | ||
| 33746 | return only.toValue(); | ||
| 33747 | } | ||
| 33748 | const only_field = fields[0]; | ||
| 33749 | if (only_field.ty.eql(resolved_ty, sema.mod)) { | ||
| 32775 | const msg = try Module.ErrorMsg.create( | 33750 | const msg = try Module.ErrorMsg.create( |
| 32776 | sema.gpa, | 33751 | sema.gpa, |
| 32777 | s.srcLoc(sema.mod), | 33752 | union_obj.srcLoc(sema.mod), |
| 32778 | "struct '{}' depends on itself", | 33753 | "union '{}' depends on itself", |
| 32779 | .{ty.fmt(sema.mod)}, | 33754 | .{ty.fmt(sema.mod)}, |
| 32780 | ); | 33755 | ); |
| 32781 | try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{}); | 33756 | try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{}); |
| 32782 | return sema.failWithOwnedErrorMsg(msg); | 33757 | return sema.failWithOwnedErrorMsg(msg); |
| 32783 | } | 33758 | } |
| 32784 | if ((try sema.typeHasOnePossibleValue(field.ty)) == null) { | 33759 | const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse |
| 32785 | return null; | 33760 | return null; |
| 32786 | } | 33761 | const only = try mod.intern(.{ .un = .{ |
| 32787 | } | 33762 | .ty = resolved_ty.toIntern(), |
| 32788 | return Value.initTag(.empty_struct_value); | 33763 | .tag = tag_val.toIntern(), |
| 32789 | }, | 33764 | .val = val_val.toIntern(), |
| 32790 | 33765 | } }); | |
| 32791 | .tuple, .anon_struct => { | 33766 | return only.toValue(); |
| 32792 | const tuple = ty.tupleFields(); | 33767 | }, |
| 32793 | for (tuple.values, 0..) |val, i| { | 33768 | .opaque_type => null, |
| 32794 | const is_comptime = val.tag() != .unreachable_value; | 33769 | .enum_type => |enum_type| switch (enum_type.tag_mode) { |
| 32795 | if (is_comptime) continue; | 33770 | .nonexhaustive => { |
| 32796 | if ((try sema.typeHasOnePossibleValue(tuple.types[i])) != null) continue; | 33771 | if (enum_type.tag_ty == .comptime_int_type) return null; |
| 32797 | return null; | 33772 | |
| 32798 | } | 33773 | if (try sema.typeHasOnePossibleValue(enum_type.tag_ty.toType())) |int_opv| { |
| 32799 | return Value.initTag(.empty_struct_value); | 33774 | const only = try mod.intern(.{ .enum_tag = .{ |
| 32800 | }, | 33775 | .ty = ty.toIntern(), |
| 33776 | .int = int_opv.toIntern(), | ||
| 33777 | } }); | ||
| 33778 | return only.toValue(); | ||
| 33779 | } | ||
| 32801 | 33780 | ||
| 32802 | .enum_numbered => { | 33781 | return null; |
| 32803 | const resolved_ty = try sema.resolveTypeFields(ty); | ||
| 32804 | const enum_obj = resolved_ty.castTag(.enum_numbered).?.data; | ||
| 32805 | // An explicit tag type is always provided for enum_numbered. | ||
| 32806 | if (enum_obj.tag_ty.hasRuntimeBits()) { | ||
| 32807 | return null; | ||
| 32808 | } | ||
| 32809 | if (enum_obj.fields.count() == 1) { | ||
| 32810 | if (enum_obj.values.count() == 0) { | ||
| 32811 | return Value.zero; // auto-numbered | ||
| 32812 | } else { | ||
| 32813 | return enum_obj.values.keys()[0]; | ||
| 32814 | } | ||
| 32815 | } else { | ||
| 32816 | return null; | ||
| 32817 | } | ||
| 32818 | }, | ||
| 32819 | .enum_full => { | ||
| 32820 | const resolved_ty = try sema.resolveTypeFields(ty); | ||
| 32821 | const enum_obj = resolved_ty.castTag(.enum_full).?.data; | ||
| 32822 | if (enum_obj.tag_ty.hasRuntimeBits()) { | ||
| 32823 | return null; | ||
| 32824 | } | ||
| 32825 | switch (enum_obj.fields.count()) { | ||
| 32826 | 0 => return Value.initTag(.unreachable_value), | ||
| 32827 | 1 => if (enum_obj.values.count() == 0) { | ||
| 32828 | return Value.zero; // auto-numbered | ||
| 32829 | } else { | ||
| 32830 | return enum_obj.values.keys()[0]; | ||
| 32831 | }, | 33782 | }, |
| 32832 | else => return null, | 33783 | .auto, .explicit => { |
| 32833 | } | 33784 | if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null; |
| 32834 | }, | ||
| 32835 | .enum_simple => { | ||
| 32836 | const resolved_ty = try sema.resolveTypeFields(ty); | ||
| 32837 | const enum_simple = resolved_ty.castTag(.enum_simple).?.data; | ||
| 32838 | switch (enum_simple.fields.count()) { | ||
| 32839 | 0 => return Value.initTag(.unreachable_value), | ||
| 32840 | 1 => return Value.zero, | ||
| 32841 | else => return null, | ||
| 32842 | } | ||
| 32843 | }, | ||
| 32844 | .enum_nonexhaustive => { | ||
| 32845 | const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty; | ||
| 32846 | if (tag_ty.zigTypeTag() != .ComptimeInt and !(try sema.typeHasRuntimeBits(tag_ty))) { | ||
| 32847 | return Value.zero; | ||
| 32848 | } else { | ||
| 32849 | return null; | ||
| 32850 | } | ||
| 32851 | }, | ||
| 32852 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 32853 | const resolved_ty = try sema.resolveTypeFields(ty); | ||
| 32854 | const union_obj = resolved_ty.cast(Type.Payload.Union).?.data; | ||
| 32855 | const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse | ||
| 32856 | return null; | ||
| 32857 | const fields = union_obj.fields.values(); | ||
| 32858 | if (fields.len == 0) return Value.initTag(.unreachable_value); | ||
| 32859 | const only_field = fields[0]; | ||
| 32860 | if (only_field.ty.eql(resolved_ty, sema.mod)) { | ||
| 32861 | const msg = try Module.ErrorMsg.create( | ||
| 32862 | sema.gpa, | ||
| 32863 | union_obj.srcLoc(sema.mod), | ||
| 32864 | "union '{}' depends on itself", | ||
| 32865 | .{ty.fmt(sema.mod)}, | ||
| 32866 | ); | ||
| 32867 | try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{}); | ||
| 32868 | return sema.failWithOwnedErrorMsg(msg); | ||
| 32869 | } | ||
| 32870 | const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse | ||
| 32871 | return null; | ||
| 32872 | // TODO make this not allocate. The function in `Type.onePossibleValue` | ||
| 32873 | // currently returns `empty_struct_value` and we should do that here too. | ||
| 32874 | return try Value.Tag.@"union".create(sema.arena, .{ | ||
| 32875 | .tag = tag_val, | ||
| 32876 | .val = val_val, | ||
| 32877 | }); | ||
| 32878 | }, | ||
| 32879 | 33785 | ||
| 32880 | .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), | 33786 | switch (enum_type.names.len) { |
| 32881 | .void => return Value.void, | 33787 | 0 => { |
| 32882 | .noreturn => return Value.initTag(.unreachable_value), | 33788 | const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); |
| 32883 | .null => return Value.null, | 33789 | return only.toValue(); |
| 32884 | .undefined => return Value.initTag(.undef), | 33790 | }, |
| 33791 | 1 => return try mod.getCoerced((if (enum_type.values.len == 0) | ||
| 33792 | try mod.intern(.{ .int = .{ | ||
| 33793 | .ty = enum_type.tag_ty, | ||
| 33794 | .storage = .{ .u64 = 0 }, | ||
| 33795 | } }) | ||
| 33796 | else | ||
| 33797 | enum_type.values[0]).toValue(), ty), | ||
| 33798 | else => return null, | ||
| 33799 | } | ||
| 33800 | }, | ||
| 33801 | }, | ||
| 32885 | 33802 | ||
| 32886 | .int_unsigned, .int_signed => { | 33803 | // values, not types |
| 32887 | if (ty.cast(Type.Payload.Bits).?.data == 0) { | 33804 | .undef, |
| 32888 | return Value.zero; | 33805 | .runtime_value, |
| 32889 | } else { | 33806 | .simple_value, |
| 32890 | return null; | 33807 | .variable, |
| 32891 | } | 33808 | .extern_func, |
| 32892 | }, | 33809 | .func, |
| 32893 | .vector, .array, .array_u8 => { | 33810 | .int, |
| 32894 | if (ty.arrayLen() == 0) | 33811 | .err, |
| 32895 | return Value.initTag(.empty_array); | 33812 | .error_union, |
| 32896 | if ((try sema.typeHasOnePossibleValue(ty.elemType())) != null) { | 33813 | .enum_literal, |
| 32897 | return Value.initTag(.the_only_possible_value); | 33814 | .enum_tag, |
| 32898 | } | 33815 | .empty_enum_value, |
| 32899 | return null; | 33816 | .float, |
| 33817 | .ptr, | ||
| 33818 | .opt, | ||
| 33819 | .aggregate, | ||
| 33820 | .un, | ||
| 33821 | // memoization, not types | ||
| 33822 | .memoized_call, | ||
| 33823 | => unreachable, | ||
| 32900 | }, | 33824 | }, |
| 32901 | 33825 | }; | |
| 32902 | .inferred_alloc_const => unreachable, | ||
| 32903 | .inferred_alloc_mut => unreachable, | ||
| 32904 | .generic_poison => return error.GenericPoison, | ||
| 32905 | } | ||
| 32906 | } | 33826 | } |
| 32907 | 33827 | ||
| 32908 | /// Returns the type of the AIR instruction. | 33828 | /// Returns the type of the AIR instruction. |
| 32909 | fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type { | 33829 | fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type { |
| 32910 | return sema.getTmpAir().typeOf(inst); | 33830 | return sema.getTmpAir().typeOf(inst, &sema.mod.intern_pool); |
| 32911 | } | 33831 | } |
| 32912 | 33832 | ||
| 32913 | pub fn getTmpAir(sema: Sema) Air { | 33833 | pub fn getTmpAir(sema: Sema) Air { |
| 32914 | return .{ | 33834 | return .{ |
| 32915 | .instructions = sema.air_instructions.slice(), | 33835 | .instructions = sema.air_instructions.slice(), |
| 32916 | .extra = sema.air_extra.items, | 33836 | .extra = sema.air_extra.items, |
| 32917 | .values = sema.air_values.items, | ||
| 32918 | }; | 33837 | }; |
| 32919 | } | 33838 | } |
| 32920 | 33839 | ||
| 32921 | pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { | 33840 | pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref { |
| 32922 | switch (ty.tag()) { | 33841 | if (@enumToInt(ty.toIntern()) < Air.ref_start_index) |
| 32923 | .u1 => return .u1_type, | 33842 | return @intToEnum(Air.Inst.Ref, @enumToInt(ty.toIntern())); |
| 32924 | .u8 => return .u8_type, | ||
| 32925 | .i8 => return .i8_type, | ||
| 32926 | .u16 => return .u16_type, | ||
| 32927 | .u29 => return .u29_type, | ||
| 32928 | .i16 => return .i16_type, | ||
| 32929 | .u32 => return .u32_type, | ||
| 32930 | .i32 => return .i32_type, | ||
| 32931 | .u64 => return .u64_type, | ||
| 32932 | .i64 => return .i64_type, | ||
| 32933 | .u128 => return .u128_type, | ||
| 32934 | .i128 => return .i128_type, | ||
| 32935 | .usize => return .usize_type, | ||
| 32936 | .isize => return .isize_type, | ||
| 32937 | .c_short => return .c_short_type, | ||
| 32938 | .c_ushort => return .c_ushort_type, | ||
| 32939 | .c_int => return .c_int_type, | ||
| 32940 | .c_uint => return .c_uint_type, | ||
| 32941 | .c_long => return .c_long_type, | ||
| 32942 | .c_ulong => return .c_ulong_type, | ||
| 32943 | .c_longlong => return .c_longlong_type, | ||
| 32944 | .c_ulonglong => return .c_ulonglong_type, | ||
| 32945 | .c_longdouble => return .c_longdouble_type, | ||
| 32946 | .f16 => return .f16_type, | ||
| 32947 | .f32 => return .f32_type, | ||
| 32948 | .f64 => return .f64_type, | ||
| 32949 | .f80 => return .f80_type, | ||
| 32950 | .f128 => return .f128_type, | ||
| 32951 | .anyopaque => return .anyopaque_type, | ||
| 32952 | .bool => return .bool_type, | ||
| 32953 | .void => return .void_type, | ||
| 32954 | .type => return .type_type, | ||
| 32955 | .anyerror => return .anyerror_type, | ||
| 32956 | .comptime_int => return .comptime_int_type, | ||
| 32957 | .comptime_float => return .comptime_float_type, | ||
| 32958 | .noreturn => return .noreturn_type, | ||
| 32959 | .@"anyframe" => return .anyframe_type, | ||
| 32960 | .null => return .null_type, | ||
| 32961 | .undefined => return .undefined_type, | ||
| 32962 | .enum_literal => return .enum_literal_type, | ||
| 32963 | .atomic_order => return .atomic_order_type, | ||
| 32964 | .atomic_rmw_op => return .atomic_rmw_op_type, | ||
| 32965 | .calling_convention => return .calling_convention_type, | ||
| 32966 | .address_space => return .address_space_type, | ||
| 32967 | .float_mode => return .float_mode_type, | ||
| 32968 | .reduce_op => return .reduce_op_type, | ||
| 32969 | .modifier => return .modifier_type, | ||
| 32970 | .prefetch_options => return .prefetch_options_type, | ||
| 32971 | .export_options => return .export_options_type, | ||
| 32972 | .extern_options => return .extern_options_type, | ||
| 32973 | .type_info => return .type_info_type, | ||
| 32974 | .manyptr_u8 => return .manyptr_u8_type, | ||
| 32975 | .manyptr_const_u8 => return .manyptr_const_u8_type, | ||
| 32976 | .fn_noreturn_no_args => return .fn_noreturn_no_args_type, | ||
| 32977 | .fn_void_no_args => return .fn_void_no_args_type, | ||
| 32978 | .fn_naked_noreturn_no_args => return .fn_naked_noreturn_no_args_type, | ||
| 32979 | .fn_ccc_void_no_args => return .fn_ccc_void_no_args_type, | ||
| 32980 | .single_const_pointer_to_comptime_int => return .single_const_pointer_to_comptime_int_type, | ||
| 32981 | .const_slice_u8 => return .const_slice_u8_type, | ||
| 32982 | .anyerror_void_error_union => return .anyerror_void_error_union_type, | ||
| 32983 | .generic_poison => return .generic_poison_type, | ||
| 32984 | else => {}, | ||
| 32985 | } | ||
| 32986 | try sema.air_instructions.append(sema.gpa, .{ | 33843 | try sema.air_instructions.append(sema.gpa, .{ |
| 32987 | .tag = .const_ty, | 33844 | .tag = .interned, |
| 32988 | .data = .{ .ty = ty }, | 33845 | .data = .{ .interned = ty.toIntern() }, |
| 32989 | }); | 33846 | }); |
| 32990 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); | 33847 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); |
| 32991 | } | 33848 | } |
| 32992 | 33849 | ||
| 32993 | fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref { | 33850 | fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref { |
| 32994 | return sema.addConstant(ty, try Value.Tag.int_u64.create(sema.arena, int)); | 33851 | const mod = sema.mod; |
| 33852 | return sema.addConstant(ty, try mod.intValue(ty, int)); | ||
| 32995 | } | 33853 | } |
| 32996 | 33854 | ||
| 32997 | fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref { | 33855 | fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref { |
| 32998 | return sema.addConstant(ty, Value.undef); | 33856 | return sema.addConstant(ty, (try sema.mod.intern(.{ .undef = ty.toIntern() })).toValue()); |
| 32999 | } | 33857 | } |
| 33000 | 33858 | ||
| 33001 | pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref { | 33859 | pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref { |
| 33860 | const mod = sema.mod; | ||
| 33002 | const gpa = sema.gpa; | 33861 | const gpa = sema.gpa; |
| 33003 | const ty_inst = try sema.addType(ty); | 33862 | |
| 33004 | try sema.air_values.append(gpa, val); | 33863 | // This assertion can be removed when the `ty` parameter is removed from |
| 33864 | // this function thanks to the InternPool transition being complete. | ||
| 33865 | if (std.debug.runtime_safety) { | ||
| 33866 | const val_ty = mod.intern_pool.typeOf(val.toIntern()); | ||
| 33867 | if (ty.toIntern() != val_ty) { | ||
| 33868 | std.debug.panic("addConstant type mismatch: '{}' vs '{}'\n", .{ | ||
| 33869 | ty.fmt(mod), val_ty.toType().fmt(mod), | ||
| 33870 | }); | ||
| 33871 | } | ||
| 33872 | } | ||
| 33873 | if (@enumToInt(val.toIntern()) < Air.ref_start_index) | ||
| 33874 | return @intToEnum(Air.Inst.Ref, @enumToInt(val.toIntern())); | ||
| 33005 | try sema.air_instructions.append(gpa, .{ | 33875 | try sema.air_instructions.append(gpa, .{ |
| 33006 | .tag = .constant, | 33876 | .tag = .interned, |
| 33007 | .data = .{ .ty_pl = .{ | 33877 | .data = .{ .interned = val.toIntern() }, |
| 33008 | .ty = ty_inst, | ||
| 33009 | .payload = @intCast(u32, sema.air_values.items.len - 1), | ||
| 33010 | } }, | ||
| 33011 | }); | 33878 | }); |
| 33012 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); | 33879 | return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1)); |
| 33013 | } | 33880 | } |
| ... | @@ -33026,7 +33893,8 @@ pub fn addExtraAssumeCapacity(sema: *Sema, extra: anytype) u32 { | ... | @@ -33026,7 +33893,8 @@ pub fn addExtraAssumeCapacity(sema: *Sema, extra: anytype) u32 { |
| 33026 | u32 => @field(extra, field.name), | 33893 | u32 => @field(extra, field.name), |
| 33027 | Air.Inst.Ref => @enumToInt(@field(extra, field.name)), | 33894 | Air.Inst.Ref => @enumToInt(@field(extra, field.name)), |
| 33028 | i32 => @bitCast(u32, @field(extra, field.name)), | 33895 | i32 => @bitCast(u32, @field(extra, field.name)), |
| 33029 | else => @compileError("bad field type"), | 33896 | InternPool.Index => @enumToInt(@field(extra, field.name)), |
| 33897 | else => @compileError("bad field type: " ++ @typeName(field.type)), | ||
| 33030 | }); | 33898 | }); |
| 33031 | } | 33899 | } |
| 33032 | return result; | 33900 | return result; |
| ... | @@ -33072,21 +33940,25 @@ fn analyzeComptimeAlloc( | ... | @@ -33072,21 +33940,25 @@ fn analyzeComptimeAlloc( |
| 33072 | defer anon_decl.deinit(); | 33940 | defer anon_decl.deinit(); |
| 33073 | 33941 | ||
| 33074 | const decl_index = try anon_decl.finish( | 33942 | const decl_index = try anon_decl.finish( |
| 33075 | try var_type.copy(anon_decl.arena()), | 33943 | var_type, |
| 33076 | // There will be stores before the first load, but they may be to sub-elements or | 33944 | // There will be stores before the first load, but they may be to sub-elements or |
| 33077 | // sub-fields. So we need to initialize with undef to allow the mechanism to expand | 33945 | // sub-fields. So we need to initialize with undef to allow the mechanism to expand |
| 33078 | // into fields/elements and have those overridden with stored values. | 33946 | // into fields/elements and have those overridden with stored values. |
| 33079 | Value.undef, | 33947 | (try sema.mod.intern(.{ .undef = var_type.toIntern() })).toValue(), |
| 33080 | alignment, | 33948 | alignment, |
| 33081 | ); | 33949 | ); |
| 33082 | const decl = sema.mod.declPtr(decl_index); | 33950 | const decl = sema.mod.declPtr(decl_index); |
| 33083 | decl.@"align" = alignment; | 33951 | decl.@"align" = alignment; |
| 33084 | 33952 | ||
| 33953 | try sema.comptime_mutable_decls.append(decl_index); | ||
| 33085 | try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); | 33954 | try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); |
| 33086 | return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{ | 33955 | return sema.addConstant(ptr_type, (try sema.mod.intern(.{ .ptr = .{ |
| 33087 | .runtime_index = block.runtime_index, | 33956 | .ty = ptr_type.toIntern(), |
| 33088 | .decl_index = decl_index, | 33957 | .addr = .{ .mut_decl = .{ |
| 33089 | })); | 33958 | .decl = decl_index, |
| 33959 | .runtime_index = block.runtime_index, | ||
| 33960 | } }, | ||
| 33961 | } })).toValue()); | ||
| 33090 | } | 33962 | } |
| 33091 | 33963 | ||
| 33092 | /// The places where a user can specify an address space attribute | 33964 | /// The places where a user can specify an address space attribute |
| ... | @@ -33114,8 +33986,9 @@ pub fn analyzeAddressSpace( | ... | @@ -33114,8 +33986,9 @@ pub fn analyzeAddressSpace( |
| 33114 | zir_ref: Zir.Inst.Ref, | 33986 | zir_ref: Zir.Inst.Ref, |
| 33115 | ctx: AddressSpaceContext, | 33987 | ctx: AddressSpaceContext, |
| 33116 | ) !std.builtin.AddressSpace { | 33988 | ) !std.builtin.AddressSpace { |
| 33989 | const mod = sema.mod; | ||
| 33117 | const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, "addresspace must be comptime-known"); | 33990 | const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, "addresspace must be comptime-known"); |
| 33118 | const address_space = addrspace_tv.val.toEnum(std.builtin.AddressSpace); | 33991 | const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val); |
| 33119 | const target = sema.mod.getTarget(); | 33992 | const target = sema.mod.getTarget(); |
| 33120 | const arch = target.cpu.arch; | 33993 | const arch = target.cpu.arch; |
| 33121 | 33994 | ||
| ... | @@ -33158,8 +34031,9 @@ pub fn analyzeAddressSpace( | ... | @@ -33158,8 +34031,9 @@ pub fn analyzeAddressSpace( |
| 33158 | /// Asserts the value is a pointer and dereferences it. | 34031 | /// Asserts the value is a pointer and dereferences it. |
| 33159 | /// Returns `null` if the pointer contents cannot be loaded at comptime. | 34032 | /// Returns `null` if the pointer contents cannot be loaded at comptime. |
| 33160 | fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { | 34033 | fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value { |
| 33161 | const load_ty = ptr_ty.childType(); | 34034 | const mod = sema.mod; |
| 33162 | const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty, true); | 34035 | const load_ty = ptr_ty.childType(mod); |
| 34036 | const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty); | ||
| 33163 | switch (res) { | 34037 | switch (res) { |
| 33164 | .runtime_load => return null, | 34038 | .runtime_load => return null, |
| 33165 | .val => |v| return v, | 34039 | .val => |v| return v, |
| ... | @@ -33185,8 +34059,9 @@ const DerefResult = union(enum) { | ... | @@ -33185,8 +34059,9 @@ const DerefResult = union(enum) { |
| 33185 | out_of_bounds: Type, | 34059 | out_of_bounds: Type, |
| 33186 | }; | 34060 | }; |
| 33187 | 34061 | ||
| 33188 | fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type, want_mutable: bool) CompileError!DerefResult { | 34062 | fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type) CompileError!DerefResult { |
| 33189 | const target = sema.mod.getTarget(); | 34063 | const mod = sema.mod; |
| 34064 | const target = mod.getTarget(); | ||
| 33190 | const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) { | 34065 | const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) { |
| 33191 | error.RuntimeLoad => return DerefResult{ .runtime_load = {} }, | 34066 | error.RuntimeLoad => return DerefResult{ .runtime_load = {} }, |
| 33192 | else => |e| return e, | 34067 | else => |e| return e, |
| ... | @@ -33199,19 +34074,17 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value | ... | @@ -33199,19 +34074,17 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value |
| 33199 | if (coerce_in_mem_ok) { | 34074 | if (coerce_in_mem_ok) { |
| 33200 | // We have a Value that lines up in virtual memory exactly with what we want to load, | 34075 | // We have a Value that lines up in virtual memory exactly with what we want to load, |
| 33201 | // and it is in-memory coercible to load_ty. It may be returned without modifications. | 34076 | // and it is in-memory coercible to load_ty. It may be returned without modifications. |
| 33202 | if (deref.is_mutable and want_mutable) { | 34077 | // Move mutable decl values to the InternPool and assert other decls are already in |
| 33203 | // The decl whose value we are obtaining here may be overwritten with | 34078 | // the InternPool. |
| 33204 | // a different value upon further semantic analysis, which would | 34079 | const uncoerced_val = if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern(); |
| 33205 | // invalidate this memory. So we must copy here. | 34080 | const coerced_val = try sema.coerceValueInMemory(block, uncoerced_val.toValue(), tv.ty, load_ty, src); |
| 33206 | return DerefResult{ .val = try tv.val.copy(sema.arena) }; | 34081 | return .{ .val = coerced_val }; |
| 33207 | } | ||
| 33208 | return DerefResult{ .val = tv.val }; | ||
| 33209 | } | 34082 | } |
| 33210 | } | 34083 | } |
| 33211 | 34084 | ||
| 33212 | // The type is not in-memory coercible or the direct dereference failed, so it must | 34085 | // The type is not in-memory coercible or the direct dereference failed, so it must |
| 33213 | // be bitcast according to the pointer type we are performing the load through. | 34086 | // be bitcast according to the pointer type we are performing the load through. |
| 33214 | if (!load_ty.hasWellDefinedLayout()) { | 34087 | if (!load_ty.hasWellDefinedLayout(mod)) { |
| 33215 | return DerefResult{ .needed_well_defined = load_ty }; | 34088 | return DerefResult{ .needed_well_defined = load_ty }; |
| 33216 | } | 34089 | } |
| 33217 | 34090 | ||
| ... | @@ -33248,59 +34121,32 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError | ... | @@ -33248,59 +34121,32 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError |
| 33248 | /// This can return `error.AnalysisFail` because it sometimes requires resolving whether | 34121 | /// This can return `error.AnalysisFail` because it sometimes requires resolving whether |
| 33249 | /// a type has zero bits, which can cause a "foo depends on itself" compile error. | 34122 | /// a type has zero bits, which can cause a "foo depends on itself" compile error. |
| 33250 | /// This logic must be kept in sync with `Type.isPtrLikeOptional`. | 34123 | /// This logic must be kept in sync with `Type.isPtrLikeOptional`. |
| 33251 | fn typePtrOrOptionalPtrTy( | 34124 | fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type { |
| 33252 | sema: *Sema, | 34125 | const mod = sema.mod; |
| 33253 | ty: Type, | 34126 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 33254 | buf: *Type.Payload.ElemType, | 34127 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 33255 | ) !?Type { | 34128 | .One, .Many, .C => ty, |
| 33256 | switch (ty.tag()) { | 34129 | .Slice => null, |
| 33257 | .optional_single_const_pointer, | 34130 | }, |
| 33258 | .optional_single_mut_pointer, | 34131 | .opt_type => |opt_child| switch (mod.intern_pool.indexToKey(opt_child)) { |
| 33259 | .c_const_pointer, | 34132 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 33260 | .c_mut_pointer, | 34133 | .Slice, .C => null, |
| 33261 | => return ty.optionalChild(buf), | ||
| 33262 | |||
| 33263 | .single_const_pointer_to_comptime_int, | ||
| 33264 | .single_const_pointer, | ||
| 33265 | .single_mut_pointer, | ||
| 33266 | .many_const_pointer, | ||
| 33267 | .many_mut_pointer, | ||
| 33268 | .manyptr_u8, | ||
| 33269 | .manyptr_const_u8, | ||
| 33270 | .manyptr_const_u8_sentinel_0, | ||
| 33271 | => return ty, | ||
| 33272 | |||
| 33273 | .pointer => switch (ty.ptrSize()) { | ||
| 33274 | .Slice => return null, | ||
| 33275 | .C => return ty.optionalChild(buf), | ||
| 33276 | else => return ty, | ||
| 33277 | }, | ||
| 33278 | |||
| 33279 | .inferred_alloc_const => unreachable, | ||
| 33280 | .inferred_alloc_mut => unreachable, | ||
| 33281 | |||
| 33282 | .optional => { | ||
| 33283 | const child_type = ty.optionalChild(buf); | ||
| 33284 | if (child_type.zigTypeTag() != .Pointer) return null; | ||
| 33285 | |||
| 33286 | const info = child_type.ptrInfo().data; | ||
| 33287 | switch (info.size) { | ||
| 33288 | .Slice, .C => return null, | ||
| 33289 | .Many, .One => { | 34134 | .Many, .One => { |
| 33290 | if (info.@"allowzero") return null; | 34135 | if (ptr_type.flags.is_allowzero) return null; |
| 33291 | 34136 | ||
| 33292 | // optionals of zero sized types behave like bools, not pointers | 34137 | // optionals of zero sized types behave like bools, not pointers |
| 33293 | if ((try sema.typeHasOnePossibleValue(child_type)) != null) { | 34138 | const payload_ty = opt_child.toType(); |
| 34139 | if ((try sema.typeHasOnePossibleValue(payload_ty)) != null) { | ||
| 33294 | return null; | 34140 | return null; |
| 33295 | } | 34141 | } |
| 33296 | 34142 | ||
| 33297 | return child_type; | 34143 | return payload_ty; |
| 33298 | }, | 34144 | }, |
| 33299 | } | 34145 | }, |
| 34146 | else => null, | ||
| 33300 | }, | 34147 | }, |
| 33301 | 34148 | else => null, | |
| 33302 | else => return null, | 34149 | }; |
| 33303 | } | ||
| 33304 | } | 34150 | } |
| 33305 | 34151 | ||
| 33306 | /// `generic_poison` will return false. | 34152 | /// `generic_poison` will return false. |
| ... | @@ -33310,201 +34156,170 @@ fn typePtrOrOptionalPtrTy( | ... | @@ -33310,201 +34156,170 @@ fn typePtrOrOptionalPtrTy( |
| 33310 | /// TODO merge these implementations together with the "advanced"/opt_sema pattern seen | 34156 | /// TODO merge these implementations together with the "advanced"/opt_sema pattern seen |
| 33311 | /// elsewhere in value.zig | 34157 | /// elsewhere in value.zig |
| 33312 | pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { | 34158 | pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 33313 | return switch (ty.tag()) { | 34159 | const mod = sema.mod; |
| 33314 | .u1, | 34160 | return switch (ty.toIntern()) { |
| 33315 | .u8, | 34161 | .empty_struct_type => false, |
| 33316 | .i8, | 34162 | |
| 33317 | .u16, | 34163 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 33318 | .i16, | 34164 | .int_type => return false, |
| 33319 | .u29, | 34165 | .ptr_type => |ptr_type| { |
| 33320 | .u32, | 34166 | const child_ty = ptr_type.child.toType(); |
| 33321 | .i32, | 34167 | if (child_ty.zigTypeTag(mod) == .Fn) { |
| 33322 | .u64, | 34168 | return mod.typeToFunc(child_ty).?.is_generic; |
| 33323 | .i64, | 34169 | } else { |
| 33324 | .u128, | 34170 | return sema.typeRequiresComptime(child_ty); |
| 33325 | .i128, | ||
| 33326 | .usize, | ||
| 33327 | .isize, | ||
| 33328 | .c_char, | ||
| 33329 | .c_short, | ||
| 33330 | .c_ushort, | ||
| 33331 | .c_int, | ||
| 33332 | .c_uint, | ||
| 33333 | .c_long, | ||
| 33334 | .c_ulong, | ||
| 33335 | .c_longlong, | ||
| 33336 | .c_ulonglong, | ||
| 33337 | .c_longdouble, | ||
| 33338 | .f16, | ||
| 33339 | .f32, | ||
| 33340 | .f64, | ||
| 33341 | .f80, | ||
| 33342 | .f128, | ||
| 33343 | .anyopaque, | ||
| 33344 | .bool, | ||
| 33345 | .void, | ||
| 33346 | .anyerror, | ||
| 33347 | .noreturn, | ||
| 33348 | .@"anyframe", | ||
| 33349 | .null, | ||
| 33350 | .undefined, | ||
| 33351 | .atomic_order, | ||
| 33352 | .atomic_rmw_op, | ||
| 33353 | .calling_convention, | ||
| 33354 | .address_space, | ||
| 33355 | .float_mode, | ||
| 33356 | .reduce_op, | ||
| 33357 | .modifier, | ||
| 33358 | .prefetch_options, | ||
| 33359 | .export_options, | ||
| 33360 | .extern_options, | ||
| 33361 | .manyptr_u8, | ||
| 33362 | .manyptr_const_u8, | ||
| 33363 | .manyptr_const_u8_sentinel_0, | ||
| 33364 | .const_slice_u8, | ||
| 33365 | .const_slice_u8_sentinel_0, | ||
| 33366 | .anyerror_void_error_union, | ||
| 33367 | .empty_struct_literal, | ||
| 33368 | .empty_struct, | ||
| 33369 | .error_set, | ||
| 33370 | .error_set_single, | ||
| 33371 | .error_set_inferred, | ||
| 33372 | .error_set_merged, | ||
| 33373 | .@"opaque", | ||
| 33374 | .generic_poison, | ||
| 33375 | .array_u8, | ||
| 33376 | .array_u8_sentinel_0, | ||
| 33377 | .int_signed, | ||
| 33378 | .int_unsigned, | ||
| 33379 | .enum_simple, | ||
| 33380 | => false, | ||
| 33381 | |||
| 33382 | .single_const_pointer_to_comptime_int, | ||
| 33383 | .type, | ||
| 33384 | .comptime_int, | ||
| 33385 | .comptime_float, | ||
| 33386 | .enum_literal, | ||
| 33387 | .type_info, | ||
| 33388 | // These are function bodies, not function pointers. | ||
| 33389 | .fn_noreturn_no_args, | ||
| 33390 | .fn_void_no_args, | ||
| 33391 | .fn_naked_noreturn_no_args, | ||
| 33392 | .fn_ccc_void_no_args, | ||
| 33393 | .function, | ||
| 33394 | => true, | ||
| 33395 | |||
| 33396 | .inferred_alloc_mut => unreachable, | ||
| 33397 | .inferred_alloc_const => unreachable, | ||
| 33398 | |||
| 33399 | .array, | ||
| 33400 | .array_sentinel, | ||
| 33401 | .vector, | ||
| 33402 | => return sema.typeRequiresComptime(ty.childType()), | ||
| 33403 | |||
| 33404 | .pointer, | ||
| 33405 | .single_const_pointer, | ||
| 33406 | .single_mut_pointer, | ||
| 33407 | .many_const_pointer, | ||
| 33408 | .many_mut_pointer, | ||
| 33409 | .c_const_pointer, | ||
| 33410 | .c_mut_pointer, | ||
| 33411 | .const_slice, | ||
| 33412 | .mut_slice, | ||
| 33413 | => { | ||
| 33414 | const child_ty = ty.childType(); | ||
| 33415 | if (child_ty.zigTypeTag() == .Fn) { | ||
| 33416 | return child_ty.fnInfo().is_generic; | ||
| 33417 | } else { | ||
| 33418 | return sema.typeRequiresComptime(child_ty); | ||
| 33419 | } | ||
| 33420 | }, | ||
| 33421 | |||
| 33422 | .optional, | ||
| 33423 | .optional_single_mut_pointer, | ||
| 33424 | .optional_single_const_pointer, | ||
| 33425 | => { | ||
| 33426 | var buf: Type.Payload.ElemType = undefined; | ||
| 33427 | return sema.typeRequiresComptime(ty.optionalChild(&buf)); | ||
| 33428 | }, | ||
| 33429 | |||
| 33430 | .tuple, .anon_struct => { | ||
| 33431 | const tuple = ty.tupleFields(); | ||
| 33432 | for (tuple.types, 0..) |field_ty, i| { | ||
| 33433 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; | ||
| 33434 | if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) { | ||
| 33435 | return true; | ||
| 33436 | } | 34171 | } |
| 33437 | } | 34172 | }, |
| 33438 | return false; | 34173 | .anyframe_type => |child| { |
| 33439 | }, | 34174 | if (child == .none) return false; |
| 33440 | 34175 | return sema.typeRequiresComptime(child.toType()); | |
| 33441 | .@"struct" => { | 34176 | }, |
| 33442 | const struct_obj = ty.castTag(.@"struct").?.data; | 34177 | .array_type => |array_type| return sema.typeRequiresComptime(array_type.child.toType()), |
| 33443 | switch (struct_obj.requires_comptime) { | 34178 | .vector_type => |vector_type| return sema.typeRequiresComptime(vector_type.child.toType()), |
| 33444 | .no, .wip => return false, | 34179 | .opt_type => |child| return sema.typeRequiresComptime(child.toType()), |
| 33445 | .yes => return true, | ||
| 33446 | .unknown => { | ||
| 33447 | if (struct_obj.status == .field_types_wip) | ||
| 33448 | return false; | ||
| 33449 | 34180 | ||
| 33450 | try sema.resolveTypeFieldsStruct(ty, struct_obj); | 34181 | .error_union_type => |error_union_type| { |
| 34182 | return sema.typeRequiresComptime(error_union_type.payload_type.toType()); | ||
| 34183 | }, | ||
| 33451 | 34184 | ||
| 33452 | struct_obj.requires_comptime = .wip; | 34185 | .error_set_type, .inferred_error_set_type => false, |
| 33453 | for (struct_obj.fields.values()) |field| { | 34186 | |
| 33454 | if (field.is_comptime) continue; | 34187 | .func_type => true, |
| 33455 | if (try sema.typeRequiresComptime(field.ty)) { | 34188 | |
| 33456 | struct_obj.requires_comptime = .yes; | 34189 | .simple_type => |t| return switch (t) { |
| 33457 | return true; | 34190 | .f16, |
| 34191 | .f32, | ||
| 34192 | .f64, | ||
| 34193 | .f80, | ||
| 34194 | .f128, | ||
| 34195 | .usize, | ||
| 34196 | .isize, | ||
| 34197 | .c_char, | ||
| 34198 | .c_short, | ||
| 34199 | .c_ushort, | ||
| 34200 | .c_int, | ||
| 34201 | .c_uint, | ||
| 34202 | .c_long, | ||
| 34203 | .c_ulong, | ||
| 34204 | .c_longlong, | ||
| 34205 | .c_ulonglong, | ||
| 34206 | .c_longdouble, | ||
| 34207 | .anyopaque, | ||
| 34208 | .bool, | ||
| 34209 | .void, | ||
| 34210 | .anyerror, | ||
| 34211 | .noreturn, | ||
| 34212 | .generic_poison, | ||
| 34213 | .atomic_order, | ||
| 34214 | .atomic_rmw_op, | ||
| 34215 | .calling_convention, | ||
| 34216 | .address_space, | ||
| 34217 | .float_mode, | ||
| 34218 | .reduce_op, | ||
| 34219 | .call_modifier, | ||
| 34220 | .prefetch_options, | ||
| 34221 | .export_options, | ||
| 34222 | .extern_options, | ||
| 34223 | => false, | ||
| 34224 | |||
| 34225 | .type, | ||
| 34226 | .comptime_int, | ||
| 34227 | .comptime_float, | ||
| 34228 | .null, | ||
| 34229 | .undefined, | ||
| 34230 | .enum_literal, | ||
| 34231 | .type_info, | ||
| 34232 | => true, | ||
| 34233 | }, | ||
| 34234 | .struct_type => |struct_type| { | ||
| 34235 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | ||
| 34236 | switch (struct_obj.requires_comptime) { | ||
| 34237 | .no, .wip => return false, | ||
| 34238 | .yes => return true, | ||
| 34239 | .unknown => { | ||
| 34240 | if (struct_obj.status == .field_types_wip) | ||
| 34241 | return false; | ||
| 34242 | |||
| 34243 | try sema.resolveTypeFieldsStruct(ty, struct_obj); | ||
| 34244 | |||
| 34245 | struct_obj.requires_comptime = .wip; | ||
| 34246 | for (struct_obj.fields.values()) |field| { | ||
| 34247 | if (field.is_comptime) continue; | ||
| 34248 | if (try sema.typeRequiresComptime(field.ty)) { | ||
| 34249 | struct_obj.requires_comptime = .yes; | ||
| 34250 | return true; | ||
| 34251 | } | ||
| 33458 | } | 34252 | } |
| 33459 | } | 34253 | struct_obj.requires_comptime = .no; |
| 33460 | struct_obj.requires_comptime = .no; | ||
| 33461 | return false; | ||
| 33462 | }, | ||
| 33463 | } | ||
| 33464 | }, | ||
| 33465 | |||
| 33466 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 33467 | const union_obj = ty.cast(Type.Payload.Union).?.data; | ||
| 33468 | switch (union_obj.requires_comptime) { | ||
| 33469 | .no, .wip => return false, | ||
| 33470 | .yes => return true, | ||
| 33471 | .unknown => { | ||
| 33472 | if (union_obj.status == .field_types_wip) | ||
| 33473 | return false; | 34254 | return false; |
| 34255 | }, | ||
| 34256 | } | ||
| 34257 | }, | ||
| 34258 | .anon_struct_type => |tuple| { | ||
| 34259 | for (tuple.types, tuple.values) |field_ty, val| { | ||
| 34260 | const have_comptime_val = val != .none; | ||
| 34261 | if (!have_comptime_val and try sema.typeRequiresComptime(field_ty.toType())) { | ||
| 34262 | return true; | ||
| 34263 | } | ||
| 34264 | } | ||
| 34265 | return false; | ||
| 34266 | }, | ||
| 33474 | 34267 | ||
| 33475 | try sema.resolveTypeFieldsUnion(ty, union_obj); | 34268 | .union_type => |union_type| { |
| 33476 | 34269 | const union_obj = mod.unionPtr(union_type.index); | |
| 33477 | union_obj.requires_comptime = .wip; | 34270 | switch (union_obj.requires_comptime) { |
| 33478 | for (union_obj.fields.values()) |field| { | 34271 | .no, .wip => return false, |
| 33479 | if (try sema.typeRequiresComptime(field.ty)) { | 34272 | .yes => return true, |
| 33480 | union_obj.requires_comptime = .yes; | 34273 | .unknown => { |
| 33481 | return true; | 34274 | if (union_obj.status == .field_types_wip) |
| 34275 | return false; | ||
| 34276 | |||
| 34277 | try sema.resolveTypeFieldsUnion(ty, union_obj); | ||
| 34278 | |||
| 34279 | union_obj.requires_comptime = .wip; | ||
| 34280 | for (union_obj.fields.values()) |field| { | ||
| 34281 | if (try sema.typeRequiresComptime(field.ty)) { | ||
| 34282 | union_obj.requires_comptime = .yes; | ||
| 34283 | return true; | ||
| 34284 | } | ||
| 33482 | } | 34285 | } |
| 33483 | } | 34286 | union_obj.requires_comptime = .no; |
| 33484 | union_obj.requires_comptime = .no; | 34287 | return false; |
| 33485 | return false; | 34288 | }, |
| 33486 | }, | 34289 | } |
| 33487 | } | 34290 | }, |
| 33488 | }, | ||
| 33489 | 34291 | ||
| 33490 | .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()), | 34292 | .opaque_type => false, |
| 33491 | .anyframe_T => { | 34293 | .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()), |
| 33492 | const child_ty = ty.castTag(.anyframe_T).?.data; | 34294 | |
| 33493 | return sema.typeRequiresComptime(child_ty); | 34295 | // values, not types |
| 33494 | }, | 34296 | .undef, |
| 33495 | .enum_numbered => { | 34297 | .runtime_value, |
| 33496 | const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; | 34298 | .simple_value, |
| 33497 | return sema.typeRequiresComptime(tag_ty); | 34299 | .variable, |
| 33498 | }, | 34300 | .extern_func, |
| 33499 | .enum_full, .enum_nonexhaustive => { | 34301 | .func, |
| 33500 | const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; | 34302 | .int, |
| 33501 | return sema.typeRequiresComptime(tag_ty); | 34303 | .err, |
| 34304 | .error_union, | ||
| 34305 | .enum_literal, | ||
| 34306 | .enum_tag, | ||
| 34307 | .empty_enum_value, | ||
| 34308 | .float, | ||
| 34309 | .ptr, | ||
| 34310 | .opt, | ||
| 34311 | .aggregate, | ||
| 34312 | .un, | ||
| 34313 | // memoization, not types | ||
| 34314 | .memoized_call, | ||
| 34315 | => unreachable, | ||
| 33502 | }, | 34316 | }, |
| 33503 | }; | 34317 | }; |
| 33504 | } | 34318 | } |
| 33505 | 34319 | ||
| 33506 | pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { | 34320 | pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { |
| 33507 | return ty.hasRuntimeBitsAdvanced(false, .{ .sema = sema }) catch |err| switch (err) { | 34321 | const mod = sema.mod; |
| 34322 | return ty.hasRuntimeBitsAdvanced(mod, false, .{ .sema = sema }) catch |err| switch (err) { | ||
| 33508 | error.NeedLazy => unreachable, | 34323 | error.NeedLazy => unreachable, |
| 33509 | else => |e| return e, | 34324 | else => |e| return e, |
| 33510 | }; | 34325 | }; |
| ... | @@ -33512,19 +34327,18 @@ pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { | ... | @@ -33512,19 +34327,18 @@ pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { |
| 33512 | 34327 | ||
| 33513 | fn typeAbiSize(sema: *Sema, ty: Type) !u64 { | 34328 | fn typeAbiSize(sema: *Sema, ty: Type) !u64 { |
| 33514 | try sema.resolveTypeLayout(ty); | 34329 | try sema.resolveTypeLayout(ty); |
| 33515 | const target = sema.mod.getTarget(); | 34330 | return ty.abiSize(sema.mod); |
| 33516 | return ty.abiSize(target); | ||
| 33517 | } | 34331 | } |
| 33518 | 34332 | ||
| 33519 | fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 { | 34333 | fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 { |
| 33520 | const target = sema.mod.getTarget(); | 34334 | return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar; |
| 33521 | return (try ty.abiAlignmentAdvanced(target, .{ .sema = sema })).scalar; | ||
| 33522 | } | 34335 | } |
| 33523 | 34336 | ||
| 33524 | /// Not valid to call for packed unions. | 34337 | /// Not valid to call for packed unions. |
| 33525 | /// Keep implementation in sync with `Module.Union.Field.normalAlignment`. | 34338 | /// Keep implementation in sync with `Module.Union.Field.normalAlignment`. |
| 33526 | fn unionFieldAlignment(sema: *Sema, field: Module.Union.Field) !u32 { | 34339 | fn unionFieldAlignment(sema: *Sema, field: Module.Union.Field) !u32 { |
| 33527 | if (field.ty.zigTypeTag() == .NoReturn) { | 34340 | const mod = sema.mod; |
| 34341 | if (field.ty.zigTypeTag(mod) == .NoReturn) { | ||
| 33528 | return @as(u32, 0); | 34342 | return @as(u32, 0); |
| 33529 | } else if (field.abi_align == 0) { | 34343 | } else if (field.abi_align == 0) { |
| 33530 | return sema.typeAbiAlignment(field.ty); | 34344 | return sema.typeAbiAlignment(field.ty); |
| ... | @@ -33535,7 +34349,8 @@ fn unionFieldAlignment(sema: *Sema, field: Module.Union.Field) !u32 { | ... | @@ -33535,7 +34349,8 @@ fn unionFieldAlignment(sema: *Sema, field: Module.Union.Field) !u32 { |
| 33535 | 34349 | ||
| 33536 | /// Synchronize logic with `Type.isFnOrHasRuntimeBits`. | 34350 | /// Synchronize logic with `Type.isFnOrHasRuntimeBits`. |
| 33537 | pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { | 34351 | pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { |
| 33538 | const fn_info = ty.fnInfo(); | 34352 | const mod = sema.mod; |
| 34353 | const fn_info = mod.typeToFunc(ty).?; | ||
| 33539 | if (fn_info.is_generic) return false; | 34354 | if (fn_info.is_generic) return false; |
| 33540 | if (fn_info.is_var_args) return true; | 34355 | if (fn_info.is_var_args) return true; |
| 33541 | switch (fn_info.cc) { | 34356 | switch (fn_info.cc) { |
| ... | @@ -33543,7 +34358,7 @@ pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { | ... | @@ -33543,7 +34358,7 @@ pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { |
| 33543 | .Inline => return false, | 34358 | .Inline => return false, |
| 33544 | else => {}, | 34359 | else => {}, |
| 33545 | } | 34360 | } |
| 33546 | if (try sema.typeRequiresComptime(fn_info.return_type)) { | 34361 | if (try sema.typeRequiresComptime(fn_info.return_type.toType())) { |
| 33547 | return false; | 34362 | return false; |
| 33548 | } | 34363 | } |
| 33549 | return true; | 34364 | return true; |
| ... | @@ -33553,11 +34368,12 @@ fn unionFieldIndex( | ... | @@ -33553,11 +34368,12 @@ fn unionFieldIndex( |
| 33553 | sema: *Sema, | 34368 | sema: *Sema, |
| 33554 | block: *Block, | 34369 | block: *Block, |
| 33555 | unresolved_union_ty: Type, | 34370 | unresolved_union_ty: Type, |
| 33556 | field_name: []const u8, | 34371 | field_name: InternPool.NullTerminatedString, |
| 33557 | field_src: LazySrcLoc, | 34372 | field_src: LazySrcLoc, |
| 33558 | ) !u32 { | 34373 | ) !u32 { |
| 34374 | const mod = sema.mod; | ||
| 33559 | const union_ty = try sema.resolveTypeFields(unresolved_union_ty); | 34375 | const union_ty = try sema.resolveTypeFields(unresolved_union_ty); |
| 33560 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 34376 | const union_obj = mod.typeToUnion(union_ty).?; |
| 33561 | const field_index_usize = union_obj.fields.getIndex(field_name) orelse | 34377 | const field_index_usize = union_obj.fields.getIndex(field_name) orelse |
| 33562 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); | 34378 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); |
| 33563 | return @intCast(u32, field_index_usize); | 34379 | return @intCast(u32, field_index_usize); |
| ... | @@ -33567,14 +34383,15 @@ fn structFieldIndex( | ... | @@ -33567,14 +34383,15 @@ fn structFieldIndex( |
| 33567 | sema: *Sema, | 34383 | sema: *Sema, |
| 33568 | block: *Block, | 34384 | block: *Block, |
| 33569 | unresolved_struct_ty: Type, | 34385 | unresolved_struct_ty: Type, |
| 33570 | field_name: []const u8, | 34386 | field_name: InternPool.NullTerminatedString, |
| 33571 | field_src: LazySrcLoc, | 34387 | field_src: LazySrcLoc, |
| 33572 | ) !u32 { | 34388 | ) !u32 { |
| 34389 | const mod = sema.mod; | ||
| 33573 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); | 34390 | const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty); |
| 33574 | if (struct_ty.isAnonStruct()) { | 34391 | if (struct_ty.isAnonStruct(mod)) { |
| 33575 | return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); | 34392 | return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src); |
| 33576 | } else { | 34393 | } else { |
| 33577 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 34394 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| 33578 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse | 34395 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse |
| 33579 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); | 34396 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); |
| 33580 | return @intCast(u32, field_index_usize); | 34397 | return @intCast(u32, field_index_usize); |
| ... | @@ -33585,55 +34402,98 @@ fn anonStructFieldIndex( | ... | @@ -33585,55 +34402,98 @@ fn anonStructFieldIndex( |
| 33585 | sema: *Sema, | 34402 | sema: *Sema, |
| 33586 | block: *Block, | 34403 | block: *Block, |
| 33587 | struct_ty: Type, | 34404 | struct_ty: Type, |
| 33588 | field_name: []const u8, | 34405 | field_name: InternPool.NullTerminatedString, |
| 33589 | field_src: LazySrcLoc, | 34406 | field_src: LazySrcLoc, |
| 33590 | ) !u32 { | 34407 | ) !u32 { |
| 33591 | const anon_struct = struct_ty.castTag(.anon_struct).?.data; | 34408 | const mod = sema.mod; |
| 33592 | for (anon_struct.names, 0..) |name, i| { | 34409 | switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { |
| 33593 | if (mem.eql(u8, name, field_name)) { | 34410 | .anon_struct_type => |anon_struct_type| for (anon_struct_type.names, 0..) |name, i| { |
| 33594 | return @intCast(u32, i); | 34411 | if (name == field_name) return @intCast(u32, i); |
| 33595 | } | 34412 | }, |
| 34413 | .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { | ||
| 34414 | for (struct_obj.fields.keys(), 0..) |name, i| { | ||
| 34415 | if (name == field_name) { | ||
| 34416 | return @intCast(u32, i); | ||
| 34417 | } | ||
| 34418 | } | ||
| 34419 | }, | ||
| 34420 | else => unreachable, | ||
| 33596 | } | 34421 | } |
| 33597 | return sema.fail(block, field_src, "no field named '{s}' in anonymous struct '{}'", .{ | 34422 | return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{ |
| 33598 | field_name, struct_ty.fmt(sema.mod), | 34423 | field_name.fmt(&mod.intern_pool), struct_ty.fmt(sema.mod), |
| 33599 | }); | 34424 | }); |
| 33600 | } | 34425 | } |
| 33601 | 34426 | ||
| 33602 | fn queueFullTypeResolution(sema: *Sema, ty: Type) !void { | 34427 | fn queueFullTypeResolution(sema: *Sema, ty: Type) !void { |
| 33603 | const inst_ref = try sema.addType(ty); | 34428 | try sema.types_to_resolve.put(sema.gpa, ty.toIntern(), {}); |
| 33604 | try sema.types_to_resolve.append(sema.gpa, inst_ref); | 34429 | } |
| 34430 | |||
| 34431 | /// If the value overflowed the type, returns a comptime_int (or vector thereof) instead, setting | ||
| 34432 | /// overflow_idx to the vector index the overflow was at (or 0 for a scalar). | ||
| 34433 | fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *?usize) !Value { | ||
| 34434 | var overflow: usize = undefined; | ||
| 34435 | return sema.intAddInner(lhs, rhs, ty, &overflow) catch |err| switch (err) { | ||
| 34436 | error.Overflow => { | ||
| 34437 | const is_vec = ty.isVector(sema.mod); | ||
| 34438 | overflow_idx.* = if (is_vec) overflow else 0; | ||
| 34439 | const safe_ty = if (is_vec) try sema.mod.vectorType(.{ | ||
| 34440 | .len = ty.vectorLen(sema.mod), | ||
| 34441 | .child = .comptime_int_type, | ||
| 34442 | }) else Type.comptime_int; | ||
| 34443 | return sema.intAddInner(lhs, rhs, safe_ty, undefined) catch |err1| switch (err1) { | ||
| 34444 | error.Overflow => unreachable, | ||
| 34445 | else => |e| return e, | ||
| 34446 | }; | ||
| 34447 | }, | ||
| 34448 | else => |e| return e, | ||
| 34449 | }; | ||
| 33605 | } | 34450 | } |
| 33606 | 34451 | ||
| 33607 | fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { | 34452 | fn intAddInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize) !Value { |
| 33608 | if (ty.zigTypeTag() == .Vector) { | 34453 | const mod = sema.mod; |
| 33609 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | 34454 | if (ty.zigTypeTag(mod) == .Vector) { |
| 34455 | const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod)); | ||
| 34456 | const scalar_ty = ty.scalarType(mod); | ||
| 33610 | for (result_data, 0..) |*scalar, i| { | 34457 | for (result_data, 0..) |*scalar, i| { |
| 33611 | var lhs_buf: Value.ElemValueBuffer = undefined; | 34458 | const lhs_elem = try lhs.elemValue(mod, i); |
| 33612 | var rhs_buf: Value.ElemValueBuffer = undefined; | 34459 | const rhs_elem = try rhs.elemValue(mod, i); |
| 33613 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | 34460 | const val = sema.intAddScalar(lhs_elem, rhs_elem, scalar_ty) catch |err| switch (err) { |
| 33614 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | 34461 | error.Overflow => { |
| 33615 | scalar.* = try sema.intAddScalar(lhs_elem, rhs_elem); | 34462 | overflow_idx.* = i; |
| 34463 | return error.Overflow; | ||
| 34464 | }, | ||
| 34465 | else => |e| return e, | ||
| 34466 | }; | ||
| 34467 | scalar.* = try val.intern(scalar_ty, mod); | ||
| 33616 | } | 34468 | } |
| 33617 | return Value.Tag.aggregate.create(sema.arena, result_data); | 34469 | return (try mod.intern(.{ .aggregate = .{ |
| 34470 | .ty = ty.toIntern(), | ||
| 34471 | .storage = .{ .elems = result_data }, | ||
| 34472 | } })).toValue(); | ||
| 33618 | } | 34473 | } |
| 33619 | return sema.intAddScalar(lhs, rhs); | 34474 | return sema.intAddScalar(lhs, rhs, ty); |
| 33620 | } | 34475 | } |
| 33621 | 34476 | ||
| 33622 | fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value) !Value { | 34477 | fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value { |
| 34478 | const mod = sema.mod; | ||
| 34479 | if (scalar_ty.toIntern() != .comptime_int_type) { | ||
| 34480 | const res = try sema.intAddWithOverflowScalar(lhs, rhs, scalar_ty); | ||
| 34481 | if (res.overflow_bit.compareAllWithZero(.neq, mod)) return error.Overflow; | ||
| 34482 | return res.wrapped_result; | ||
| 34483 | } | ||
| 33623 | // TODO is this a performance issue? maybe we should try the operation without | 34484 | // TODO is this a performance issue? maybe we should try the operation without |
| 33624 | // resorting to BigInt first. | 34485 | // resorting to BigInt first. |
| 33625 | var lhs_space: Value.BigIntSpace = undefined; | 34486 | var lhs_space: Value.BigIntSpace = undefined; |
| 33626 | var rhs_space: Value.BigIntSpace = undefined; | 34487 | var rhs_space: Value.BigIntSpace = undefined; |
| 33627 | const target = sema.mod.getTarget(); | 34488 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); |
| 33628 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema); | 34489 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); |
| 33629 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema); | ||
| 33630 | const limbs = try sema.arena.alloc( | 34490 | const limbs = try sema.arena.alloc( |
| 33631 | std.math.big.Limb, | 34491 | std.math.big.Limb, |
| 33632 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, | 34492 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, |
| 33633 | ); | 34493 | ); |
| 33634 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 34494 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 33635 | result_bigint.add(lhs_bigint, rhs_bigint); | 34495 | result_bigint.add(lhs_bigint, rhs_bigint); |
| 33636 | return Value.fromBigInt(sema.arena, result_bigint.toConst()); | 34496 | return mod.intValue_big(scalar_ty, result_bigint.toConst()); |
| 33637 | } | 34497 | } |
| 33638 | 34498 | ||
| 33639 | /// Supports both floats and ints; handles undefined. | 34499 | /// Supports both floats and ints; handles undefined. |
| ... | @@ -33643,55 +34503,87 @@ fn numberAddWrapScalar( | ... | @@ -33643,55 +34503,87 @@ fn numberAddWrapScalar( |
| 33643 | rhs: Value, | 34503 | rhs: Value, |
| 33644 | ty: Type, | 34504 | ty: Type, |
| 33645 | ) !Value { | 34505 | ) !Value { |
| 33646 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | 34506 | const mod = sema.mod; |
| 34507 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef; | ||
| 33647 | 34508 | ||
| 33648 | if (ty.zigTypeTag() == .ComptimeInt) { | 34509 | if (ty.zigTypeTag(mod) == .ComptimeInt) { |
| 33649 | return sema.intAdd(lhs, rhs, ty); | 34510 | return sema.intAdd(lhs, rhs, ty, undefined); |
| 33650 | } | 34511 | } |
| 33651 | 34512 | ||
| 33652 | if (ty.isAnyFloat()) { | 34513 | if (ty.isAnyFloat()) { |
| 33653 | return sema.floatAdd(lhs, rhs, ty); | 34514 | return Value.floatAdd(lhs, rhs, ty, sema.arena, mod); |
| 33654 | } | 34515 | } |
| 33655 | 34516 | ||
| 33656 | const overflow_result = try sema.intAddWithOverflow(lhs, rhs, ty); | 34517 | const overflow_result = try sema.intAddWithOverflow(lhs, rhs, ty); |
| 33657 | return overflow_result.wrapped_result; | 34518 | return overflow_result.wrapped_result; |
| 33658 | } | 34519 | } |
| 33659 | 34520 | ||
| 33660 | fn intSub( | 34521 | /// If the value overflowed the type, returns a comptime_int (or vector thereof) instead, setting |
| 33661 | sema: *Sema, | 34522 | /// overflow_idx to the vector index the overflow was at (or 0 for a scalar). |
| 33662 | lhs: Value, | 34523 | fn intSub(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *?usize) !Value { |
| 33663 | rhs: Value, | 34524 | var overflow: usize = undefined; |
| 33664 | ty: Type, | 34525 | return sema.intSubInner(lhs, rhs, ty, &overflow) catch |err| switch (err) { |
| 33665 | ) !Value { | 34526 | error.Overflow => { |
| 33666 | if (ty.zigTypeTag() == .Vector) { | 34527 | const is_vec = ty.isVector(sema.mod); |
| 33667 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | 34528 | overflow_idx.* = if (is_vec) overflow else 0; |
| 34529 | const safe_ty = if (is_vec) try sema.mod.vectorType(.{ | ||
| 34530 | .len = ty.vectorLen(sema.mod), | ||
| 34531 | .child = .comptime_int_type, | ||
| 34532 | }) else Type.comptime_int; | ||
| 34533 | return sema.intSubInner(lhs, rhs, safe_ty, undefined) catch |err1| switch (err1) { | ||
| 34534 | error.Overflow => unreachable, | ||
| 34535 | else => |e| return e, | ||
| 34536 | }; | ||
| 34537 | }, | ||
| 34538 | else => |e| return e, | ||
| 34539 | }; | ||
| 34540 | } | ||
| 34541 | |||
| 34542 | fn intSubInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize) !Value { | ||
| 34543 | const mod = sema.mod; | ||
| 34544 | if (ty.zigTypeTag(mod) == .Vector) { | ||
| 34545 | const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod)); | ||
| 34546 | const scalar_ty = ty.scalarType(mod); | ||
| 33668 | for (result_data, 0..) |*scalar, i| { | 34547 | for (result_data, 0..) |*scalar, i| { |
| 33669 | var lhs_buf: Value.ElemValueBuffer = undefined; | 34548 | const lhs_elem = try lhs.elemValue(sema.mod, i); |
| 33670 | var rhs_buf: Value.ElemValueBuffer = undefined; | 34549 | const rhs_elem = try rhs.elemValue(sema.mod, i); |
| 33671 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | 34550 | const val = sema.intSubScalar(lhs_elem, rhs_elem, scalar_ty) catch |err| switch (err) { |
| 33672 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | 34551 | error.Overflow => { |
| 33673 | scalar.* = try sema.intSubScalar(lhs_elem, rhs_elem); | 34552 | overflow_idx.* = i; |
| 34553 | return error.Overflow; | ||
| 34554 | }, | ||
| 34555 | else => |e| return e, | ||
| 34556 | }; | ||
| 34557 | scalar.* = try val.intern(scalar_ty, mod); | ||
| 33674 | } | 34558 | } |
| 33675 | return Value.Tag.aggregate.create(sema.arena, result_data); | 34559 | return (try mod.intern(.{ .aggregate = .{ |
| 34560 | .ty = ty.toIntern(), | ||
| 34561 | .storage = .{ .elems = result_data }, | ||
| 34562 | } })).toValue(); | ||
| 33676 | } | 34563 | } |
| 33677 | return sema.intSubScalar(lhs, rhs); | 34564 | return sema.intSubScalar(lhs, rhs, ty); |
| 33678 | } | 34565 | } |
| 33679 | 34566 | ||
| 33680 | fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value) !Value { | 34567 | fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value { |
| 34568 | const mod = sema.mod; | ||
| 34569 | if (scalar_ty.toIntern() != .comptime_int_type) { | ||
| 34570 | const res = try sema.intSubWithOverflowScalar(lhs, rhs, scalar_ty); | ||
| 34571 | if (res.overflow_bit.compareAllWithZero(.neq, mod)) return error.Overflow; | ||
| 34572 | return res.wrapped_result; | ||
| 34573 | } | ||
| 33681 | // TODO is this a performance issue? maybe we should try the operation without | 34574 | // TODO is this a performance issue? maybe we should try the operation without |
| 33682 | // resorting to BigInt first. | 34575 | // resorting to BigInt first. |
| 33683 | var lhs_space: Value.BigIntSpace = undefined; | 34576 | var lhs_space: Value.BigIntSpace = undefined; |
| 33684 | var rhs_space: Value.BigIntSpace = undefined; | 34577 | var rhs_space: Value.BigIntSpace = undefined; |
| 33685 | const target = sema.mod.getTarget(); | 34578 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); |
| 33686 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema); | 34579 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); |
| 33687 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema); | ||
| 33688 | const limbs = try sema.arena.alloc( | 34580 | const limbs = try sema.arena.alloc( |
| 33689 | std.math.big.Limb, | 34581 | std.math.big.Limb, |
| 33690 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, | 34582 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, |
| 33691 | ); | 34583 | ); |
| 33692 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 34584 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 33693 | result_bigint.sub(lhs_bigint, rhs_bigint); | 34585 | result_bigint.sub(lhs_bigint, rhs_bigint); |
| 33694 | return Value.fromBigInt(sema.arena, result_bigint.toConst()); | 34586 | return mod.intValue_big(scalar_ty, result_bigint.toConst()); |
| 33695 | } | 34587 | } |
| 33696 | 34588 | ||
| 33697 | /// Supports both floats and ints; handles undefined. | 34589 | /// Supports both floats and ints; handles undefined. |
| ... | @@ -33701,155 +34593,49 @@ fn numberSubWrapScalar( | ... | @@ -33701,155 +34593,49 @@ fn numberSubWrapScalar( |
| 33701 | rhs: Value, | 34593 | rhs: Value, |
| 33702 | ty: Type, | 34594 | ty: Type, |
| 33703 | ) !Value { | 34595 | ) !Value { |
| 33704 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | 34596 | const mod = sema.mod; |
| 34597 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef; | ||
| 33705 | 34598 | ||
| 33706 | if (ty.zigTypeTag() == .ComptimeInt) { | 34599 | if (ty.zigTypeTag(mod) == .ComptimeInt) { |
| 33707 | return sema.intSub(lhs, rhs, ty); | 34600 | return sema.intSub(lhs, rhs, ty, undefined); |
| 33708 | } | 34601 | } |
| 33709 | 34602 | ||
| 33710 | if (ty.isAnyFloat()) { | 34603 | if (ty.isAnyFloat()) { |
| 33711 | return sema.floatSub(lhs, rhs, ty); | 34604 | return Value.floatSub(lhs, rhs, ty, sema.arena, mod); |
| 33712 | } | 34605 | } |
| 33713 | 34606 | ||
| 33714 | const overflow_result = try sema.intSubWithOverflow(lhs, rhs, ty); | 34607 | const overflow_result = try sema.intSubWithOverflow(lhs, rhs, ty); |
| 33715 | return overflow_result.wrapped_result; | 34608 | return overflow_result.wrapped_result; |
| 33716 | } | 34609 | } |
| 33717 | 34610 | ||
| 33718 | fn floatAdd( | ||
| 33719 | sema: *Sema, | ||
| 33720 | lhs: Value, | ||
| 33721 | rhs: Value, | ||
| 33722 | float_type: Type, | ||
| 33723 | ) !Value { | ||
| 33724 | if (float_type.zigTypeTag() == .Vector) { | ||
| 33725 | const result_data = try sema.arena.alloc(Value, float_type.vectorLen()); | ||
| 33726 | for (result_data, 0..) |*scalar, i| { | ||
| 33727 | var lhs_buf: Value.ElemValueBuffer = undefined; | ||
| 33728 | var rhs_buf: Value.ElemValueBuffer = undefined; | ||
| 33729 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | ||
| 33730 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | ||
| 33731 | scalar.* = try sema.floatAddScalar(lhs_elem, rhs_elem, float_type.scalarType()); | ||
| 33732 | } | ||
| 33733 | return Value.Tag.aggregate.create(sema.arena, result_data); | ||
| 33734 | } | ||
| 33735 | return sema.floatAddScalar(lhs, rhs, float_type); | ||
| 33736 | } | ||
| 33737 | |||
| 33738 | fn floatAddScalar( | ||
| 33739 | sema: *Sema, | ||
| 33740 | lhs: Value, | ||
| 33741 | rhs: Value, | ||
| 33742 | float_type: Type, | ||
| 33743 | ) !Value { | ||
| 33744 | const target = sema.mod.getTarget(); | ||
| 33745 | switch (float_type.floatBits(target)) { | ||
| 33746 | 16 => { | ||
| 33747 | const lhs_val = lhs.toFloat(f16); | ||
| 33748 | const rhs_val = rhs.toFloat(f16); | ||
| 33749 | return Value.Tag.float_16.create(sema.arena, lhs_val + rhs_val); | ||
| 33750 | }, | ||
| 33751 | 32 => { | ||
| 33752 | const lhs_val = lhs.toFloat(f32); | ||
| 33753 | const rhs_val = rhs.toFloat(f32); | ||
| 33754 | return Value.Tag.float_32.create(sema.arena, lhs_val + rhs_val); | ||
| 33755 | }, | ||
| 33756 | 64 => { | ||
| 33757 | const lhs_val = lhs.toFloat(f64); | ||
| 33758 | const rhs_val = rhs.toFloat(f64); | ||
| 33759 | return Value.Tag.float_64.create(sema.arena, lhs_val + rhs_val); | ||
| 33760 | }, | ||
| 33761 | 80 => { | ||
| 33762 | const lhs_val = lhs.toFloat(f80); | ||
| 33763 | const rhs_val = rhs.toFloat(f80); | ||
| 33764 | return Value.Tag.float_80.create(sema.arena, lhs_val + rhs_val); | ||
| 33765 | }, | ||
| 33766 | 128 => { | ||
| 33767 | const lhs_val = lhs.toFloat(f128); | ||
| 33768 | const rhs_val = rhs.toFloat(f128); | ||
| 33769 | return Value.Tag.float_128.create(sema.arena, lhs_val + rhs_val); | ||
| 33770 | }, | ||
| 33771 | else => unreachable, | ||
| 33772 | } | ||
| 33773 | } | ||
| 33774 | |||
| 33775 | fn floatSub( | ||
| 33776 | sema: *Sema, | ||
| 33777 | lhs: Value, | ||
| 33778 | rhs: Value, | ||
| 33779 | float_type: Type, | ||
| 33780 | ) !Value { | ||
| 33781 | if (float_type.zigTypeTag() == .Vector) { | ||
| 33782 | const result_data = try sema.arena.alloc(Value, float_type.vectorLen()); | ||
| 33783 | for (result_data, 0..) |*scalar, i| { | ||
| 33784 | var lhs_buf: Value.ElemValueBuffer = undefined; | ||
| 33785 | var rhs_buf: Value.ElemValueBuffer = undefined; | ||
| 33786 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | ||
| 33787 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | ||
| 33788 | scalar.* = try sema.floatSubScalar(lhs_elem, rhs_elem, float_type.scalarType()); | ||
| 33789 | } | ||
| 33790 | return Value.Tag.aggregate.create(sema.arena, result_data); | ||
| 33791 | } | ||
| 33792 | return sema.floatSubScalar(lhs, rhs, float_type); | ||
| 33793 | } | ||
| 33794 | |||
| 33795 | fn floatSubScalar( | ||
| 33796 | sema: *Sema, | ||
| 33797 | lhs: Value, | ||
| 33798 | rhs: Value, | ||
| 33799 | float_type: Type, | ||
| 33800 | ) !Value { | ||
| 33801 | const target = sema.mod.getTarget(); | ||
| 33802 | switch (float_type.floatBits(target)) { | ||
| 33803 | 16 => { | ||
| 33804 | const lhs_val = lhs.toFloat(f16); | ||
| 33805 | const rhs_val = rhs.toFloat(f16); | ||
| 33806 | return Value.Tag.float_16.create(sema.arena, lhs_val - rhs_val); | ||
| 33807 | }, | ||
| 33808 | 32 => { | ||
| 33809 | const lhs_val = lhs.toFloat(f32); | ||
| 33810 | const rhs_val = rhs.toFloat(f32); | ||
| 33811 | return Value.Tag.float_32.create(sema.arena, lhs_val - rhs_val); | ||
| 33812 | }, | ||
| 33813 | 64 => { | ||
| 33814 | const lhs_val = lhs.toFloat(f64); | ||
| 33815 | const rhs_val = rhs.toFloat(f64); | ||
| 33816 | return Value.Tag.float_64.create(sema.arena, lhs_val - rhs_val); | ||
| 33817 | }, | ||
| 33818 | 80 => { | ||
| 33819 | const lhs_val = lhs.toFloat(f80); | ||
| 33820 | const rhs_val = rhs.toFloat(f80); | ||
| 33821 | return Value.Tag.float_80.create(sema.arena, lhs_val - rhs_val); | ||
| 33822 | }, | ||
| 33823 | 128 => { | ||
| 33824 | const lhs_val = lhs.toFloat(f128); | ||
| 33825 | const rhs_val = rhs.toFloat(f128); | ||
| 33826 | return Value.Tag.float_128.create(sema.arena, lhs_val - rhs_val); | ||
| 33827 | }, | ||
| 33828 | else => unreachable, | ||
| 33829 | } | ||
| 33830 | } | ||
| 33831 | |||
| 33832 | fn intSubWithOverflow( | 34611 | fn intSubWithOverflow( |
| 33833 | sema: *Sema, | 34612 | sema: *Sema, |
| 33834 | lhs: Value, | 34613 | lhs: Value, |
| 33835 | rhs: Value, | 34614 | rhs: Value, |
| 33836 | ty: Type, | 34615 | ty: Type, |
| 33837 | ) !Value.OverflowArithmeticResult { | 34616 | ) !Value.OverflowArithmeticResult { |
| 33838 | if (ty.zigTypeTag() == .Vector) { | 34617 | const mod = sema.mod; |
| 33839 | const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen()); | 34618 | if (ty.zigTypeTag(mod) == .Vector) { |
| 33840 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | 34619 | const vec_len = ty.vectorLen(mod); |
| 33841 | for (result_data, 0..) |*scalar, i| { | 34620 | const overflowed_data = try sema.arena.alloc(InternPool.Index, vec_len); |
| 33842 | var lhs_buf: Value.ElemValueBuffer = undefined; | 34621 | const result_data = try sema.arena.alloc(InternPool.Index, vec_len); |
| 33843 | var rhs_buf: Value.ElemValueBuffer = undefined; | 34622 | const scalar_ty = ty.scalarType(mod); |
| 33844 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | 34623 | for (overflowed_data, result_data, 0..) |*of, *scalar, i| { |
| 33845 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | 34624 | const lhs_elem = try lhs.elemValue(sema.mod, i); |
| 33846 | const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType()); | 34625 | const rhs_elem = try rhs.elemValue(sema.mod, i); |
| 33847 | overflowed_data[i] = of_math_result.overflow_bit; | 34626 | const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty); |
| 33848 | scalar.* = of_math_result.wrapped_result; | 34627 | of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); |
| 34628 | scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); | ||
| 33849 | } | 34629 | } |
| 33850 | return Value.OverflowArithmeticResult{ | 34630 | return Value.OverflowArithmeticResult{ |
| 33851 | .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data), | 34631 | .overflow_bit = (try mod.intern(.{ .aggregate = .{ |
| 33852 | .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data), | 34632 | .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(), |
| 34633 | .storage = .{ .elems = overflowed_data }, | ||
| 34634 | } })).toValue(), | ||
| 34635 | .wrapped_result = (try mod.intern(.{ .aggregate = .{ | ||
| 34636 | .ty = ty.toIntern(), | ||
| 34637 | .storage = .{ .elems = result_data }, | ||
| 34638 | } })).toValue(), | ||
| 33853 | }; | 34639 | }; |
| 33854 | } | 34640 | } |
| 33855 | return sema.intSubWithOverflowScalar(lhs, rhs, ty); | 34641 | return sema.intSubWithOverflowScalar(lhs, rhs, ty); |
| ... | @@ -33861,22 +34647,22 @@ fn intSubWithOverflowScalar( | ... | @@ -33861,22 +34647,22 @@ fn intSubWithOverflowScalar( |
| 33861 | rhs: Value, | 34647 | rhs: Value, |
| 33862 | ty: Type, | 34648 | ty: Type, |
| 33863 | ) !Value.OverflowArithmeticResult { | 34649 | ) !Value.OverflowArithmeticResult { |
| 33864 | const target = sema.mod.getTarget(); | 34650 | const mod = sema.mod; |
| 33865 | const info = ty.intInfo(target); | 34651 | const info = ty.intInfo(mod); |
| 33866 | 34652 | ||
| 33867 | var lhs_space: Value.BigIntSpace = undefined; | 34653 | var lhs_space: Value.BigIntSpace = undefined; |
| 33868 | var rhs_space: Value.BigIntSpace = undefined; | 34654 | var rhs_space: Value.BigIntSpace = undefined; |
| 33869 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema); | 34655 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); |
| 33870 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema); | 34656 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); |
| 33871 | const limbs = try sema.arena.alloc( | 34657 | const limbs = try sema.arena.alloc( |
| 33872 | std.math.big.Limb, | 34658 | std.math.big.Limb, |
| 33873 | std.math.big.int.calcTwosCompLimbCount(info.bits), | 34659 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| 33874 | ); | 34660 | ); |
| 33875 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 34661 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 33876 | const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); | 34662 | const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); |
| 33877 | const wrapped_result = try Value.fromBigInt(sema.arena, result_bigint.toConst()); | 34663 | const wrapped_result = try mod.intValue_big(ty, result_bigint.toConst()); |
| 33878 | return Value.OverflowArithmeticResult{ | 34664 | return Value.OverflowArithmeticResult{ |
| 33879 | .overflow_bit = Value.boolToInt(overflowed), | 34665 | .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)), |
| 33880 | .wrapped_result = wrapped_result, | 34666 | .wrapped_result = wrapped_result, |
| 33881 | }; | 34667 | }; |
| 33882 | } | 34668 | } |
| ... | @@ -33889,15 +34675,19 @@ fn floatToInt( | ... | @@ -33889,15 +34675,19 @@ fn floatToInt( |
| 33889 | float_ty: Type, | 34675 | float_ty: Type, |
| 33890 | int_ty: Type, | 34676 | int_ty: Type, |
| 33891 | ) CompileError!Value { | 34677 | ) CompileError!Value { |
| 33892 | if (float_ty.zigTypeTag() == .Vector) { | 34678 | const mod = sema.mod; |
| 33893 | const elem_ty = float_ty.childType(); | 34679 | if (float_ty.zigTypeTag(mod) == .Vector) { |
| 33894 | const result_data = try sema.arena.alloc(Value, float_ty.vectorLen()); | 34680 | const elem_ty = float_ty.scalarType(mod); |
| 34681 | const result_data = try sema.arena.alloc(InternPool.Index, float_ty.vectorLen(mod)); | ||
| 34682 | const scalar_ty = int_ty.scalarType(mod); | ||
| 33895 | for (result_data, 0..) |*scalar, i| { | 34683 | for (result_data, 0..) |*scalar, i| { |
| 33896 | var buf: Value.ElemValueBuffer = undefined; | 34684 | const elem_val = try val.elemValue(sema.mod, i); |
| 33897 | const elem_val = val.elemValueBuffer(sema.mod, i, &buf); | 34685 | scalar.* = try (try sema.floatToIntScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod))).intern(scalar_ty, mod); |
| 33898 | scalar.* = try sema.floatToIntScalar(block, src, elem_val, elem_ty, int_ty.scalarType()); | ||
| 33899 | } | 34686 | } |
| 33900 | return Value.Tag.aggregate.create(sema.arena, result_data); | 34687 | return (try mod.intern(.{ .aggregate = .{ |
| 34688 | .ty = int_ty.toIntern(), | ||
| 34689 | .storage = .{ .elems = result_data }, | ||
| 34690 | } })).toValue(); | ||
| 33901 | } | 34691 | } |
| 33902 | return sema.floatToIntScalar(block, src, val, float_ty, int_ty); | 34692 | return sema.floatToIntScalar(block, src, val, float_ty, int_ty); |
| 33903 | } | 34693 | } |
| ... | @@ -33935,9 +34725,9 @@ fn floatToIntScalar( | ... | @@ -33935,9 +34725,9 @@ fn floatToIntScalar( |
| 33935 | float_ty: Type, | 34725 | float_ty: Type, |
| 33936 | int_ty: Type, | 34726 | int_ty: Type, |
| 33937 | ) CompileError!Value { | 34727 | ) CompileError!Value { |
| 33938 | const Limb = std.math.big.Limb; | 34728 | const mod = sema.mod; |
| 33939 | 34729 | ||
| 33940 | const float = val.toFloat(f128); | 34730 | const float = val.toFloat(f128, mod); |
| 33941 | if (std.math.isNan(float)) { | 34731 | if (std.math.isNan(float)) { |
| 33942 | return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{ | 34732 | return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{ |
| 33943 | int_ty.fmt(sema.mod), | 34733 | int_ty.fmt(sema.mod), |
| ... | @@ -33952,18 +34742,14 @@ fn floatToIntScalar( | ... | @@ -33952,18 +34742,14 @@ fn floatToIntScalar( |
| 33952 | var big_int = try float128IntPartToBigInt(sema.arena, float); | 34742 | var big_int = try float128IntPartToBigInt(sema.arena, float); |
| 33953 | defer big_int.deinit(); | 34743 | defer big_int.deinit(); |
| 33954 | 34744 | ||
| 33955 | const result_limbs = try sema.arena.dupe(Limb, big_int.toConst().limbs); | 34745 | const cti_result = try mod.intValue_big(Type.comptime_int, big_int.toConst()); |
| 33956 | const result = if (!big_int.isPositive()) | ||
| 33957 | try Value.Tag.int_big_negative.create(sema.arena, result_limbs) | ||
| 33958 | else | ||
| 33959 | try Value.Tag.int_big_positive.create(sema.arena, result_limbs); | ||
| 33960 | 34746 | ||
| 33961 | if (!(try sema.intFitsInType(result, int_ty, null))) { | 34747 | if (!(try sema.intFitsInType(cti_result, int_ty, null))) { |
| 33962 | return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{ | 34748 | return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{ |
| 33963 | val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod), | 34749 | val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod), |
| 33964 | }); | 34750 | }); |
| 33965 | } | 34751 | } |
| 33966 | return result; | 34752 | return mod.getCoerced(cti_result, int_ty); |
| 33967 | } | 34753 | } |
| 33968 | 34754 | ||
| 33969 | /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. | 34755 | /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. |
| ... | @@ -33976,208 +34762,91 @@ fn intFitsInType( | ... | @@ -33976,208 +34762,91 @@ fn intFitsInType( |
| 33976 | ty: Type, | 34762 | ty: Type, |
| 33977 | vector_index: ?*usize, | 34763 | vector_index: ?*usize, |
| 33978 | ) CompileError!bool { | 34764 | ) CompileError!bool { |
| 33979 | const target = sema.mod.getTarget(); | 34765 | const mod = sema.mod; |
| 33980 | switch (val.tag()) { | 34766 | if (ty.toIntern() == .comptime_int_type) return true; |
| 33981 | .zero, | 34767 | const info = ty.intInfo(mod); |
| 33982 | .undef, | 34768 | switch (val.toIntern()) { |
| 33983 | .bool_false, | 34769 | .zero_usize, .zero_u8 => return true, |
| 33984 | => return true, | 34770 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 33985 | 34771 | .undef => return true, | |
| 33986 | .one, | 34772 | .variable, .extern_func, .func, .ptr => { |
| 33987 | .bool_true, | 34773 | const target = mod.getTarget(); |
| 33988 | => switch (ty.zigTypeTag()) { | ||
| 33989 | .Int => { | ||
| 33990 | const info = ty.intInfo(target); | ||
| 33991 | return switch (info.signedness) { | ||
| 33992 | .signed => info.bits >= 2, | ||
| 33993 | .unsigned => info.bits >= 1, | ||
| 33994 | }; | ||
| 33995 | }, | ||
| 33996 | .ComptimeInt => return true, | ||
| 33997 | else => unreachable, | ||
| 33998 | }, | ||
| 33999 | |||
| 34000 | .lazy_align => switch (ty.zigTypeTag()) { | ||
| 34001 | .Int => { | ||
| 34002 | const info = ty.intInfo(target); | ||
| 34003 | const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed); | ||
| 34004 | // If it is u16 or bigger we know the alignment fits without resolving it. | ||
| 34005 | if (info.bits >= max_needed_bits) return true; | ||
| 34006 | const x = try sema.typeAbiAlignment(val.castTag(.lazy_align).?.data); | ||
| 34007 | if (x == 0) return true; | ||
| 34008 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | ||
| 34009 | return info.bits >= actual_needed_bits; | ||
| 34010 | }, | ||
| 34011 | .ComptimeInt => return true, | ||
| 34012 | else => unreachable, | ||
| 34013 | }, | ||
| 34014 | .lazy_size => switch (ty.zigTypeTag()) { | ||
| 34015 | .Int => { | ||
| 34016 | const info = ty.intInfo(target); | ||
| 34017 | const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed); | ||
| 34018 | // If it is u64 or bigger we know the size fits without resolving it. | ||
| 34019 | if (info.bits >= max_needed_bits) return true; | ||
| 34020 | const x = try sema.typeAbiSize(val.castTag(.lazy_size).?.data); | ||
| 34021 | if (x == 0) return true; | ||
| 34022 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | ||
| 34023 | return info.bits >= actual_needed_bits; | ||
| 34024 | }, | ||
| 34025 | .ComptimeInt => return true, | ||
| 34026 | else => unreachable, | ||
| 34027 | }, | ||
| 34028 | |||
| 34029 | .int_u64 => switch (ty.zigTypeTag()) { | ||
| 34030 | .Int => { | ||
| 34031 | const x = val.castTag(.int_u64).?.data; | ||
| 34032 | if (x == 0) return true; | ||
| 34033 | const info = ty.intInfo(target); | ||
| 34034 | const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | ||
| 34035 | return info.bits >= needed_bits; | ||
| 34036 | }, | ||
| 34037 | .ComptimeInt => return true, | ||
| 34038 | else => unreachable, | ||
| 34039 | }, | ||
| 34040 | .int_i64 => switch (ty.zigTypeTag()) { | ||
| 34041 | .Int => { | ||
| 34042 | const x = val.castTag(.int_i64).?.data; | ||
| 34043 | if (x == 0) return true; | ||
| 34044 | const info = ty.intInfo(target); | ||
| 34045 | if (info.signedness == .unsigned and x < 0) | ||
| 34046 | return false; | ||
| 34047 | var buffer: Value.BigIntSpace = undefined; | ||
| 34048 | return (try val.toBigIntAdvanced(&buffer, target, sema)).fitsInTwosComp(info.signedness, info.bits); | ||
| 34049 | }, | ||
| 34050 | .ComptimeInt => return true, | ||
| 34051 | else => unreachable, | ||
| 34052 | }, | ||
| 34053 | .int_big_positive => switch (ty.zigTypeTag()) { | ||
| 34054 | .Int => { | ||
| 34055 | const info = ty.intInfo(target); | ||
| 34056 | return val.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); | ||
| 34057 | }, | ||
| 34058 | .ComptimeInt => return true, | ||
| 34059 | else => unreachable, | ||
| 34060 | }, | ||
| 34061 | .int_big_negative => switch (ty.zigTypeTag()) { | ||
| 34062 | .Int => { | ||
| 34063 | const info = ty.intInfo(target); | ||
| 34064 | return val.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); | ||
| 34065 | }, | ||
| 34066 | .ComptimeInt => return true, | ||
| 34067 | else => unreachable, | ||
| 34068 | }, | ||
| 34069 | |||
| 34070 | .the_only_possible_value => { | ||
| 34071 | assert(ty.intInfo(target).bits == 0); | ||
| 34072 | return true; | ||
| 34073 | }, | ||
| 34074 | |||
| 34075 | .decl_ref_mut, | ||
| 34076 | .extern_fn, | ||
| 34077 | .decl_ref, | ||
| 34078 | .function, | ||
| 34079 | .variable, | ||
| 34080 | => switch (ty.zigTypeTag()) { | ||
| 34081 | .Int => { | ||
| 34082 | const info = ty.intInfo(target); | ||
| 34083 | const ptr_bits = target.ptrBitWidth(); | 34774 | const ptr_bits = target.ptrBitWidth(); |
| 34084 | return switch (info.signedness) { | 34775 | return switch (info.signedness) { |
| 34085 | .signed => info.bits > ptr_bits, | 34776 | .signed => info.bits > ptr_bits, |
| 34086 | .unsigned => info.bits >= ptr_bits, | 34777 | .unsigned => info.bits >= ptr_bits, |
| 34087 | }; | 34778 | }; |
| 34088 | }, | 34779 | }, |
| 34089 | .ComptimeInt => return true, | 34780 | .int => |int| switch (int.storage) { |
| 34781 | .u64, .i64, .big_int => { | ||
| 34782 | var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; | ||
| 34783 | const big_int = int.storage.toBigInt(&buffer); | ||
| 34784 | return big_int.fitsInTwosComp(info.signedness, info.bits); | ||
| 34785 | }, | ||
| 34786 | .lazy_align => |lazy_ty| { | ||
| 34787 | const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed); | ||
| 34788 | // If it is u16 or bigger we know the alignment fits without resolving it. | ||
| 34789 | if (info.bits >= max_needed_bits) return true; | ||
| 34790 | const x = try sema.typeAbiAlignment(lazy_ty.toType()); | ||
| 34791 | if (x == 0) return true; | ||
| 34792 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | ||
| 34793 | return info.bits >= actual_needed_bits; | ||
| 34794 | }, | ||
| 34795 | .lazy_size => |lazy_ty| { | ||
| 34796 | const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed); | ||
| 34797 | // If it is u64 or bigger we know the size fits without resolving it. | ||
| 34798 | if (info.bits >= max_needed_bits) return true; | ||
| 34799 | const x = try sema.typeAbiSize(lazy_ty.toType()); | ||
| 34800 | if (x == 0) return true; | ||
| 34801 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | ||
| 34802 | return info.bits >= actual_needed_bits; | ||
| 34803 | }, | ||
| 34804 | }, | ||
| 34805 | .aggregate => |aggregate| { | ||
| 34806 | assert(ty.zigTypeTag(mod) == .Vector); | ||
| 34807 | return switch (aggregate.storage) { | ||
| 34808 | .bytes => |bytes| for (bytes, 0..) |byte, i| { | ||
| 34809 | if (byte == 0) continue; | ||
| 34810 | const actual_needed_bits = std.math.log2(byte) + 1 + @boolToInt(info.signedness == .signed); | ||
| 34811 | if (info.bits >= actual_needed_bits) continue; | ||
| 34812 | if (vector_index) |vi| vi.* = i; | ||
| 34813 | break false; | ||
| 34814 | } else true, | ||
| 34815 | .elems, .repeated_elem => for (switch (aggregate.storage) { | ||
| 34816 | .bytes => unreachable, | ||
| 34817 | .elems => |elems| elems, | ||
| 34818 | .repeated_elem => |elem| @as(*const [1]InternPool.Index, &elem), | ||
| 34819 | }, 0..) |elem, i| { | ||
| 34820 | if (try sema.intFitsInType(elem.toValue(), ty.scalarType(mod), null)) continue; | ||
| 34821 | if (vector_index) |vi| vi.* = i; | ||
| 34822 | break false; | ||
| 34823 | } else true, | ||
| 34824 | }; | ||
| 34825 | }, | ||
| 34090 | else => unreachable, | 34826 | else => unreachable, |
| 34091 | }, | 34827 | }, |
| 34092 | |||
| 34093 | .aggregate => { | ||
| 34094 | assert(ty.zigTypeTag() == .Vector); | ||
| 34095 | for (val.castTag(.aggregate).?.data, 0..) |elem, i| { | ||
| 34096 | if (!(try sema.intFitsInType(elem, ty.scalarType(), null))) { | ||
| 34097 | if (vector_index) |some| some.* = i; | ||
| 34098 | return false; | ||
| 34099 | } | ||
| 34100 | } | ||
| 34101 | return true; | ||
| 34102 | }, | ||
| 34103 | |||
| 34104 | else => unreachable, | ||
| 34105 | } | 34828 | } |
| 34106 | } | 34829 | } |
| 34107 | 34830 | ||
| 34108 | fn intInRange( | 34831 | fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool { |
| 34109 | sema: *Sema, | 34832 | const mod = sema.mod; |
| 34110 | tag_ty: Type, | ||
| 34111 | int_val: Value, | ||
| 34112 | end: usize, | ||
| 34113 | ) !bool { | ||
| 34114 | if (!(try int_val.compareAllWithZeroAdvanced(.gte, sema))) return false; | 34833 | if (!(try int_val.compareAllWithZeroAdvanced(.gte, sema))) return false; |
| 34115 | var end_payload: Value.Payload.U64 = .{ | 34834 | const end_val = try mod.intValue(tag_ty, end); |
| 34116 | .base = .{ .tag = .int_u64 }, | ||
| 34117 | .data = end, | ||
| 34118 | }; | ||
| 34119 | const end_val = Value.initPayload(&end_payload.base); | ||
| 34120 | if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false; | 34835 | if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false; |
| 34121 | return true; | 34836 | return true; |
| 34122 | } | 34837 | } |
| 34123 | 34838 | ||
| 34124 | /// Asserts the type is an enum. | 34839 | /// Asserts the type is an enum. |
| 34125 | fn enumHasInt( | 34840 | fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool { |
| 34126 | sema: *Sema, | 34841 | const mod = sema.mod; |
| 34127 | ty: Type, | 34842 | const enum_type = mod.intern_pool.indexToKey(ty.toIntern()).enum_type; |
| 34128 | int: Value, | 34843 | assert(enum_type.tag_mode != .nonexhaustive); |
| 34129 | ) CompileError!bool { | 34844 | // The `tagValueIndex` function call below relies on the type being the integer tag type. |
| 34130 | switch (ty.tag()) { | 34845 | // `getCoerced` assumes the value will fit the new type. |
| 34131 | .enum_nonexhaustive => unreachable, | 34846 | if (!(try sema.intFitsInType(int, enum_type.tag_ty.toType(), null))) return false; |
| 34132 | .enum_full => { | 34847 | const int_coerced = try mod.getCoerced(int, enum_type.tag_ty.toType()); |
| 34133 | const enum_full = ty.castTag(.enum_full).?.data; | ||
| 34134 | const tag_ty = enum_full.tag_ty; | ||
| 34135 | if (enum_full.values.count() == 0) { | ||
| 34136 | return sema.intInRange(tag_ty, int, enum_full.fields.count()); | ||
| 34137 | } else { | ||
| 34138 | return enum_full.values.containsContext(int, .{ | ||
| 34139 | .ty = tag_ty, | ||
| 34140 | .mod = sema.mod, | ||
| 34141 | }); | ||
| 34142 | } | ||
| 34143 | }, | ||
| 34144 | .enum_numbered => { | ||
| 34145 | const enum_obj = ty.castTag(.enum_numbered).?.data; | ||
| 34146 | const tag_ty = enum_obj.tag_ty; | ||
| 34147 | if (enum_obj.values.count() == 0) { | ||
| 34148 | return sema.intInRange(tag_ty, int, enum_obj.fields.count()); | ||
| 34149 | } else { | ||
| 34150 | return enum_obj.values.containsContext(int, .{ | ||
| 34151 | .ty = tag_ty, | ||
| 34152 | .mod = sema.mod, | ||
| 34153 | }); | ||
| 34154 | } | ||
| 34155 | }, | ||
| 34156 | .enum_simple => { | ||
| 34157 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 34158 | const fields_len = enum_simple.fields.count(); | ||
| 34159 | const bits = std.math.log2_int_ceil(usize, fields_len); | ||
| 34160 | var buffer: Type.Payload.Bits = .{ | ||
| 34161 | .base = .{ .tag = .int_unsigned }, | ||
| 34162 | .data = bits, | ||
| 34163 | }; | ||
| 34164 | const tag_ty = Type.initPayload(&buffer.base); | ||
| 34165 | return sema.intInRange(tag_ty, int, fields_len); | ||
| 34166 | }, | ||
| 34167 | .atomic_order, | ||
| 34168 | .atomic_rmw_op, | ||
| 34169 | .calling_convention, | ||
| 34170 | .address_space, | ||
| 34171 | .float_mode, | ||
| 34172 | .reduce_op, | ||
| 34173 | .modifier, | ||
| 34174 | .prefetch_options, | ||
| 34175 | .export_options, | ||
| 34176 | .extern_options, | ||
| 34177 | => unreachable, | ||
| 34178 | 34848 | ||
| 34179 | else => unreachable, | 34849 | return enum_type.tagValueIndex(&mod.intern_pool, int_coerced.toIntern()) != null; |
| 34180 | } | ||
| 34181 | } | 34850 | } |
| 34182 | 34851 | ||
| 34183 | fn intAddWithOverflow( | 34852 | fn intAddWithOverflow( |
| ... | @@ -34186,21 +34855,28 @@ fn intAddWithOverflow( | ... | @@ -34186,21 +34855,28 @@ fn intAddWithOverflow( |
| 34186 | rhs: Value, | 34855 | rhs: Value, |
| 34187 | ty: Type, | 34856 | ty: Type, |
| 34188 | ) !Value.OverflowArithmeticResult { | 34857 | ) !Value.OverflowArithmeticResult { |
| 34189 | if (ty.zigTypeTag() == .Vector) { | 34858 | const mod = sema.mod; |
| 34190 | const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen()); | 34859 | if (ty.zigTypeTag(mod) == .Vector) { |
| 34191 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | 34860 | const vec_len = ty.vectorLen(mod); |
| 34192 | for (result_data, 0..) |*scalar, i| { | 34861 | const overflowed_data = try sema.arena.alloc(InternPool.Index, vec_len); |
| 34193 | var lhs_buf: Value.ElemValueBuffer = undefined; | 34862 | const result_data = try sema.arena.alloc(InternPool.Index, vec_len); |
| 34194 | var rhs_buf: Value.ElemValueBuffer = undefined; | 34863 | const scalar_ty = ty.scalarType(mod); |
| 34195 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | 34864 | for (overflowed_data, result_data, 0..) |*of, *scalar, i| { |
| 34196 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | 34865 | const lhs_elem = try lhs.elemValue(sema.mod, i); |
| 34197 | const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType()); | 34866 | const rhs_elem = try rhs.elemValue(sema.mod, i); |
| 34198 | overflowed_data[i] = of_math_result.overflow_bit; | 34867 | const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty); |
| 34199 | scalar.* = of_math_result.wrapped_result; | 34868 | of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); |
| 34869 | scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); | ||
| 34200 | } | 34870 | } |
| 34201 | return Value.OverflowArithmeticResult{ | 34871 | return Value.OverflowArithmeticResult{ |
| 34202 | .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data), | 34872 | .overflow_bit = (try mod.intern(.{ .aggregate = .{ |
| 34203 | .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data), | 34873 | .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(), |
| 34874 | .storage = .{ .elems = overflowed_data }, | ||
| 34875 | } })).toValue(), | ||
| 34876 | .wrapped_result = (try mod.intern(.{ .aggregate = .{ | ||
| 34877 | .ty = ty.toIntern(), | ||
| 34878 | .storage = .{ .elems = result_data }, | ||
| 34879 | } })).toValue(), | ||
| 34204 | }; | 34880 | }; |
| 34205 | } | 34881 | } |
| 34206 | return sema.intAddWithOverflowScalar(lhs, rhs, ty); | 34882 | return sema.intAddWithOverflowScalar(lhs, rhs, ty); |
| ... | @@ -34212,22 +34888,22 @@ fn intAddWithOverflowScalar( | ... | @@ -34212,22 +34888,22 @@ fn intAddWithOverflowScalar( |
| 34212 | rhs: Value, | 34888 | rhs: Value, |
| 34213 | ty: Type, | 34889 | ty: Type, |
| 34214 | ) !Value.OverflowArithmeticResult { | 34890 | ) !Value.OverflowArithmeticResult { |
| 34215 | const target = sema.mod.getTarget(); | 34891 | const mod = sema.mod; |
| 34216 | const info = ty.intInfo(target); | 34892 | const info = ty.intInfo(mod); |
| 34217 | 34893 | ||
| 34218 | var lhs_space: Value.BigIntSpace = undefined; | 34894 | var lhs_space: Value.BigIntSpace = undefined; |
| 34219 | var rhs_space: Value.BigIntSpace = undefined; | 34895 | var rhs_space: Value.BigIntSpace = undefined; |
| 34220 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema); | 34896 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema); |
| 34221 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema); | 34897 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema); |
| 34222 | const limbs = try sema.arena.alloc( | 34898 | const limbs = try sema.arena.alloc( |
| 34223 | std.math.big.Limb, | 34899 | std.math.big.Limb, |
| 34224 | std.math.big.int.calcTwosCompLimbCount(info.bits), | 34900 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| 34225 | ); | 34901 | ); |
| 34226 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 34902 | var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 34227 | const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); | 34903 | const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); |
| 34228 | const result = try Value.fromBigInt(sema.arena, result_bigint.toConst()); | 34904 | const result = try mod.intValue_big(ty, result_bigint.toConst()); |
| 34229 | return Value.OverflowArithmeticResult{ | 34905 | return Value.OverflowArithmeticResult{ |
| 34230 | .overflow_bit = Value.boolToInt(overflowed), | 34906 | .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)), |
| 34231 | .wrapped_result = result, | 34907 | .wrapped_result = result, |
| 34232 | }; | 34908 | }; |
| 34233 | } | 34909 | } |
| ... | @@ -34243,14 +34919,13 @@ fn compareAll( | ... | @@ -34243,14 +34919,13 @@ fn compareAll( |
| 34243 | rhs: Value, | 34919 | rhs: Value, |
| 34244 | ty: Type, | 34920 | ty: Type, |
| 34245 | ) CompileError!bool { | 34921 | ) CompileError!bool { |
| 34246 | if (ty.zigTypeTag() == .Vector) { | 34922 | const mod = sema.mod; |
| 34923 | if (ty.zigTypeTag(mod) == .Vector) { | ||
| 34247 | var i: usize = 0; | 34924 | var i: usize = 0; |
| 34248 | while (i < ty.vectorLen()) : (i += 1) { | 34925 | while (i < ty.vectorLen(mod)) : (i += 1) { |
| 34249 | var lhs_buf: Value.ElemValueBuffer = undefined; | 34926 | const lhs_elem = try lhs.elemValue(sema.mod, i); |
| 34250 | var rhs_buf: Value.ElemValueBuffer = undefined; | 34927 | const rhs_elem = try rhs.elemValue(sema.mod, i); |
| 34251 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | 34928 | if (!(try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod)))) { |
| 34252 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | ||
| 34253 | if (!(try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType()))) { | ||
| 34254 | return false; | 34929 | return false; |
| 34255 | } | 34930 | } |
| 34256 | } | 34931 | } |
| ... | @@ -34267,10 +34942,13 @@ fn compareScalar( | ... | @@ -34267,10 +34942,13 @@ fn compareScalar( |
| 34267 | rhs: Value, | 34942 | rhs: Value, |
| 34268 | ty: Type, | 34943 | ty: Type, |
| 34269 | ) CompileError!bool { | 34944 | ) CompileError!bool { |
| 34945 | const mod = sema.mod; | ||
| 34946 | const coerced_lhs = try mod.getCoerced(lhs, ty); | ||
| 34947 | const coerced_rhs = try mod.getCoerced(rhs, ty); | ||
| 34270 | switch (op) { | 34948 | switch (op) { |
| 34271 | .eq => return sema.valuesEqual(lhs, rhs, ty), | 34949 | .eq => return sema.valuesEqual(coerced_lhs, coerced_rhs, ty), |
| 34272 | .neq => return !(try sema.valuesEqual(lhs, rhs, ty)), | 34950 | .neq => return !(try sema.valuesEqual(coerced_lhs, coerced_rhs, ty)), |
| 34273 | else => return Value.compareHeteroAdvanced(lhs, op, rhs, sema.mod.getTarget(), sema), | 34951 | else => return Value.compareHeteroAdvanced(coerced_lhs, op, coerced_rhs, mod, sema), |
| 34274 | } | 34952 | } |
| 34275 | } | 34953 | } |
| 34276 | 34954 | ||
| ... | @@ -34291,17 +34969,19 @@ fn compareVector( | ... | @@ -34291,17 +34969,19 @@ fn compareVector( |
| 34291 | rhs: Value, | 34969 | rhs: Value, |
| 34292 | ty: Type, | 34970 | ty: Type, |
| 34293 | ) !Value { | 34971 | ) !Value { |
| 34294 | assert(ty.zigTypeTag() == .Vector); | 34972 | const mod = sema.mod; |
| 34295 | const result_data = try sema.arena.alloc(Value, ty.vectorLen()); | 34973 | assert(ty.zigTypeTag(mod) == .Vector); |
| 34974 | const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod)); | ||
| 34296 | for (result_data, 0..) |*scalar, i| { | 34975 | for (result_data, 0..) |*scalar, i| { |
| 34297 | var lhs_buf: Value.ElemValueBuffer = undefined; | 34976 | const lhs_elem = try lhs.elemValue(sema.mod, i); |
| 34298 | var rhs_buf: Value.ElemValueBuffer = undefined; | 34977 | const rhs_elem = try rhs.elemValue(sema.mod, i); |
| 34299 | const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf); | 34978 | const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod)); |
| 34300 | const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf); | 34979 | scalar.* = try Value.makeBool(res_bool).intern(Type.bool, mod); |
| 34301 | const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType()); | ||
| 34302 | scalar.* = Value.makeBool(res_bool); | ||
| 34303 | } | 34980 | } |
| 34304 | return Value.Tag.aggregate.create(sema.arena, result_data); | 34981 | return (try mod.intern(.{ .aggregate = .{ |
| 34982 | .ty = (try mod.vectorType(.{ .len = ty.vectorLen(mod), .child = .bool_type })).toIntern(), | ||
| 34983 | .storage = .{ .elems = result_data }, | ||
| 34984 | } })).toValue(); | ||
| 34305 | } | 34985 | } |
| 34306 | 34986 | ||
| 34307 | /// Returns the type of a pointer to an element. | 34987 | /// Returns the type of a pointer to an element. |
| ... | @@ -34312,11 +34992,11 @@ fn compareVector( | ... | @@ -34312,11 +34992,11 @@ fn compareVector( |
| 34312 | /// Handles const-ness and address spaces in particular. | 34992 | /// Handles const-ness and address spaces in particular. |
| 34313 | /// This code is duplicated in `analyzePtrArithmetic`. | 34993 | /// This code is duplicated in `analyzePtrArithmetic`. |
| 34314 | fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { | 34994 | fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 34315 | const ptr_info = ptr_ty.ptrInfo().data; | 34995 | const mod = sema.mod; |
| 34316 | const elem_ty = ptr_ty.elemType2(); | 34996 | const ptr_info = ptr_ty.ptrInfo(mod); |
| 34997 | const elem_ty = ptr_ty.elemType2(mod); | ||
| 34317 | const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0; | 34998 | const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0; |
| 34318 | const target = sema.mod.getTarget(); | 34999 | const parent_ty = ptr_ty.childType(mod); |
| 34319 | const parent_ty = ptr_ty.childType(); | ||
| 34320 | 35000 | ||
| 34321 | const VI = Type.Payload.Pointer.Data.VectorIndex; | 35001 | const VI = Type.Payload.Pointer.Data.VectorIndex; |
| 34322 | 35002 | ||
| ... | @@ -34324,15 +35004,15 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { | ... | @@ -34324,15 +35004,15 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 34324 | host_size: u16 = 0, | 35004 | host_size: u16 = 0, |
| 34325 | alignment: u32 = 0, | 35005 | alignment: u32 = 0, |
| 34326 | vector_index: VI = .none, | 35006 | vector_index: VI = .none, |
| 34327 | } = if (parent_ty.tag() == .vector and ptr_info.size == .One) blk: { | 35007 | } = if (parent_ty.isVector(mod) and ptr_info.size == .One) blk: { |
| 34328 | const elem_bits = elem_ty.bitSize(target); | 35008 | const elem_bits = elem_ty.bitSize(mod); |
| 34329 | if (elem_bits == 0) break :blk .{}; | 35009 | if (elem_bits == 0) break :blk .{}; |
| 34330 | const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits); | 35010 | const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits); |
| 34331 | if (!is_packed) break :blk .{}; | 35011 | if (!is_packed) break :blk .{}; |
| 34332 | 35012 | ||
| 34333 | break :blk .{ | 35013 | break :blk .{ |
| 34334 | .host_size = @intCast(u16, parent_ty.arrayLen()), | 35014 | .host_size = @intCast(u16, parent_ty.arrayLen(mod)), |
| 34335 | .alignment = @intCast(u16, parent_ty.abiAlignment(target)), | 35015 | .alignment = @intCast(u16, parent_ty.abiAlignment(mod)), |
| 34336 | .vector_index = if (offset) |some| @intToEnum(VI, some) else .runtime, | 35016 | .vector_index = if (offset) |some| @intToEnum(VI, some) else .runtime, |
| 34337 | }; | 35017 | }; |
| 34338 | } else .{}; | 35018 | } else .{}; |
| ... | @@ -34366,3 +35046,42 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { | ... | @@ -34366,3 +35046,42 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type { |
| 34366 | .vector_index = vector_info.vector_index, | 35046 | .vector_index = vector_info.vector_index, |
| 34367 | }); | 35047 | }); |
| 34368 | } | 35048 | } |
| 35049 | |||
| 35050 | /// Merge lhs with rhs. | ||
| 35051 | /// Asserts that lhs and rhs are both error sets and are resolved. | ||
| 35052 | fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type { | ||
| 35053 | const mod = sema.mod; | ||
| 35054 | const arena = sema.arena; | ||
| 35055 | const lhs_names = lhs.errorSetNames(mod); | ||
| 35056 | const rhs_names = rhs.errorSetNames(mod); | ||
| 35057 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; | ||
| 35058 | try names.ensureUnusedCapacity(arena, lhs_names.len); | ||
| 35059 | |||
| 35060 | for (lhs_names) |name| { | ||
| 35061 | names.putAssumeCapacityNoClobber(name, {}); | ||
| 35062 | } | ||
| 35063 | for (rhs_names) |name| { | ||
| 35064 | try names.put(arena, name, {}); | ||
| 35065 | } | ||
| 35066 | |||
| 35067 | return mod.errorSetFromUnsortedNames(names.keys()); | ||
| 35068 | } | ||
| 35069 | |||
| 35070 | /// Avoids crashing the compiler when asking if inferred allocations are noreturn. | ||
| 35071 | fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool { | ||
| 35072 | if (ref == .unreachable_value) return true; | ||
| 35073 | if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) { | ||
| 35074 | .inferred_alloc, .inferred_alloc_comptime => return false, | ||
| 35075 | else => {}, | ||
| 35076 | }; | ||
| 35077 | return sema.typeOf(ref).isNoReturn(sema.mod); | ||
| 35078 | } | ||
| 35079 | |||
| 35080 | /// Avoids crashing the compiler when asking if inferred allocations are known to be a certain zig type. | ||
| 35081 | fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool { | ||
| 35082 | if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) { | ||
| 35083 | .inferred_alloc, .inferred_alloc_comptime => return false, | ||
| 35084 | else => {}, | ||
| 35085 | }; | ||
| 35086 | return sema.typeOf(ref).zigTypeTag(sema.mod) == tag; | ||
| 35087 | } |
src/TypedValue.zig+358-378| ... | @@ -27,13 +27,13 @@ pub const Managed = struct { | ... | @@ -27,13 +27,13 @@ pub const Managed = struct { |
| 27 | /// Assumes arena allocation. Does a recursive copy. | 27 | /// Assumes arena allocation. Does a recursive copy. |
| 28 | pub fn copy(self: TypedValue, arena: Allocator) error{OutOfMemory}!TypedValue { | 28 | pub fn copy(self: TypedValue, arena: Allocator) error{OutOfMemory}!TypedValue { |
| 29 | return TypedValue{ | 29 | return TypedValue{ |
| 30 | .ty = try self.ty.copy(arena), | 30 | .ty = self.ty, |
| 31 | .val = try self.val.copy(arena), | 31 | .val = try self.val.copy(arena), |
| 32 | }; | 32 | }; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | pub fn eql(a: TypedValue, b: TypedValue, mod: *Module) bool { | 35 | pub fn eql(a: TypedValue, b: TypedValue, mod: *Module) bool { |
| 36 | if (!a.ty.eql(b.ty, mod)) return false; | 36 | if (a.ty.toIntern() != b.ty.toIntern()) return false; |
| 37 | return a.val.eql(b.val, a.ty, mod); | 37 | return a.val.eql(b.val, a.ty, mod); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| ... | @@ -41,8 +41,8 @@ pub fn hash(tv: TypedValue, hasher: *std.hash.Wyhash, mod: *Module) void { | ... | @@ -41,8 +41,8 @@ pub fn hash(tv: TypedValue, hasher: *std.hash.Wyhash, mod: *Module) void { |
| 41 | return tv.val.hash(tv.ty, hasher, mod); | 41 | return tv.val.hash(tv.ty, hasher, mod); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | pub fn enumToInt(tv: TypedValue, buffer: *Value.Payload.U64) Value { | 44 | pub fn enumToInt(tv: TypedValue, mod: *Module) Allocator.Error!Value { |
| 45 | return tv.val.enumToInt(tv.ty, buffer); | 45 | return tv.val.enumToInt(tv.ty, mod); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | const max_aggregate_items = 100; | 48 | const max_aggregate_items = 100; |
| ... | @@ -61,7 +61,10 @@ pub fn format( | ... | @@ -61,7 +61,10 @@ pub fn format( |
| 61 | ) !void { | 61 | ) !void { |
| 62 | _ = options; | 62 | _ = options; |
| 63 | comptime std.debug.assert(fmt.len == 0); | 63 | comptime std.debug.assert(fmt.len == 0); |
| 64 | return ctx.tv.print(writer, 3, ctx.mod); | 64 | return ctx.tv.print(writer, 3, ctx.mod) catch |err| switch (err) { |
| 65 | error.OutOfMemory => @panic("OOM"), // We're not allowed to return this from a format function | ||
| 66 | else => |e| return e, | ||
| 67 | }; | ||
| 65 | } | 68 | } |
| 66 | 69 | ||
| 67 | /// Prints the Value according to the Type, not according to the Value Tag. | 70 | /// Prints the Value according to the Type, not according to the Value Tag. |
| ... | @@ -70,106 +73,61 @@ pub fn print( | ... | @@ -70,106 +73,61 @@ pub fn print( |
| 70 | writer: anytype, | 73 | writer: anytype, |
| 71 | level: u8, | 74 | level: u8, |
| 72 | mod: *Module, | 75 | mod: *Module, |
| 73 | ) @TypeOf(writer).Error!void { | 76 | ) (@TypeOf(writer).Error || Allocator.Error)!void { |
| 74 | const target = mod.getTarget(); | ||
| 75 | var val = tv.val; | 77 | var val = tv.val; |
| 76 | var ty = tv.ty; | 78 | var ty = tv.ty; |
| 77 | if (val.isVariable(mod)) | 79 | const ip = &mod.intern_pool; |
| 78 | return writer.writeAll("(variable)"); | 80 | while (true) switch (val.ip_index) { |
| 79 | 81 | .none => switch (val.tag()) { | |
| 80 | while (true) switch (val.tag()) { | 82 | .aggregate => return printAggregate(ty, val, writer, level, mod), |
| 81 | .u1_type => return writer.writeAll("u1"), | 83 | .@"union" => { |
| 82 | .u8_type => return writer.writeAll("u8"), | 84 | if (level == 0) { |
| 83 | .i8_type => return writer.writeAll("i8"), | 85 | return writer.writeAll(".{ ... }"); |
| 84 | .u16_type => return writer.writeAll("u16"), | 86 | } |
| 85 | .i16_type => return writer.writeAll("i16"), | 87 | const union_val = val.castTag(.@"union").?.data; |
| 86 | .u29_type => return writer.writeAll("u29"), | 88 | try writer.writeAll(".{ "); |
| 87 | .u32_type => return writer.writeAll("u32"), | ||
| 88 | .i32_type => return writer.writeAll("i32"), | ||
| 89 | .u64_type => return writer.writeAll("u64"), | ||
| 90 | .i64_type => return writer.writeAll("i64"), | ||
| 91 | .u128_type => return writer.writeAll("u128"), | ||
| 92 | .i128_type => return writer.writeAll("i128"), | ||
| 93 | .isize_type => return writer.writeAll("isize"), | ||
| 94 | .usize_type => return writer.writeAll("usize"), | ||
| 95 | .c_char_type => return writer.writeAll("c_char"), | ||
| 96 | .c_short_type => return writer.writeAll("c_short"), | ||
| 97 | .c_ushort_type => return writer.writeAll("c_ushort"), | ||
| 98 | .c_int_type => return writer.writeAll("c_int"), | ||
| 99 | .c_uint_type => return writer.writeAll("c_uint"), | ||
| 100 | .c_long_type => return writer.writeAll("c_long"), | ||
| 101 | .c_ulong_type => return writer.writeAll("c_ulong"), | ||
| 102 | .c_longlong_type => return writer.writeAll("c_longlong"), | ||
| 103 | .c_ulonglong_type => return writer.writeAll("c_ulonglong"), | ||
| 104 | .c_longdouble_type => return writer.writeAll("c_longdouble"), | ||
| 105 | .f16_type => return writer.writeAll("f16"), | ||
| 106 | .f32_type => return writer.writeAll("f32"), | ||
| 107 | .f64_type => return writer.writeAll("f64"), | ||
| 108 | .f80_type => return writer.writeAll("f80"), | ||
| 109 | .f128_type => return writer.writeAll("f128"), | ||
| 110 | .anyopaque_type => return writer.writeAll("anyopaque"), | ||
| 111 | .bool_type => return writer.writeAll("bool"), | ||
| 112 | .void_type => return writer.writeAll("void"), | ||
| 113 | .type_type => return writer.writeAll("type"), | ||
| 114 | .anyerror_type => return writer.writeAll("anyerror"), | ||
| 115 | .comptime_int_type => return writer.writeAll("comptime_int"), | ||
| 116 | .comptime_float_type => return writer.writeAll("comptime_float"), | ||
| 117 | .noreturn_type => return writer.writeAll("noreturn"), | ||
| 118 | .null_type => return writer.writeAll("@Type(.Null)"), | ||
| 119 | .undefined_type => return writer.writeAll("@Type(.Undefined)"), | ||
| 120 | .fn_noreturn_no_args_type => return writer.writeAll("fn() noreturn"), | ||
| 121 | .fn_void_no_args_type => return writer.writeAll("fn() void"), | ||
| 122 | .fn_naked_noreturn_no_args_type => return writer.writeAll("fn() callconv(.Naked) noreturn"), | ||
| 123 | .fn_ccc_void_no_args_type => return writer.writeAll("fn() callconv(.C) void"), | ||
| 124 | .single_const_pointer_to_comptime_int_type => return writer.writeAll("*const comptime_int"), | ||
| 125 | .anyframe_type => return writer.writeAll("anyframe"), | ||
| 126 | .const_slice_u8_type => return writer.writeAll("[]const u8"), | ||
| 127 | .const_slice_u8_sentinel_0_type => return writer.writeAll("[:0]const u8"), | ||
| 128 | .anyerror_void_error_union_type => return writer.writeAll("anyerror!void"), | ||
| 129 | |||
| 130 | .enum_literal_type => return writer.writeAll("@Type(.EnumLiteral)"), | ||
| 131 | .manyptr_u8_type => return writer.writeAll("[*]u8"), | ||
| 132 | .manyptr_const_u8_type => return writer.writeAll("[*]const u8"), | ||
| 133 | .manyptr_const_u8_sentinel_0_type => return writer.writeAll("[*:0]const u8"), | ||
| 134 | .atomic_order_type => return writer.writeAll("std.builtin.AtomicOrder"), | ||
| 135 | .atomic_rmw_op_type => return writer.writeAll("std.builtin.AtomicRmwOp"), | ||
| 136 | .calling_convention_type => return writer.writeAll("std.builtin.CallingConvention"), | ||
| 137 | .address_space_type => return writer.writeAll("std.builtin.AddressSpace"), | ||
| 138 | .float_mode_type => return writer.writeAll("std.builtin.FloatMode"), | ||
| 139 | .reduce_op_type => return writer.writeAll("std.builtin.ReduceOp"), | ||
| 140 | .modifier_type => return writer.writeAll("std.builtin.CallModifier"), | ||
| 141 | .prefetch_options_type => return writer.writeAll("std.builtin.PrefetchOptions"), | ||
| 142 | .export_options_type => return writer.writeAll("std.builtin.ExportOptions"), | ||
| 143 | .extern_options_type => return writer.writeAll("std.builtin.ExternOptions"), | ||
| 144 | .type_info_type => return writer.writeAll("std.builtin.Type"), | ||
| 145 | 89 | ||
| 146 | .empty_struct_value, .aggregate => { | 90 | try print(.{ |
| 147 | if (level == 0) { | 91 | .ty = mod.unionPtr(ip.indexToKey(ty.toIntern()).union_type.index).tag_ty, |
| 148 | return writer.writeAll(".{ ... }"); | 92 | .val = union_val.tag, |
| 149 | } | 93 | }, writer, level - 1, mod); |
| 150 | if (ty.zigTypeTag() == .Struct) { | 94 | try writer.writeAll(" = "); |
| 151 | try writer.writeAll(".{"); | 95 | try print(.{ |
| 152 | const max_len = std.math.min(ty.structFieldCount(), max_aggregate_items); | 96 | .ty = ty.unionFieldType(union_val.tag, mod), |
| 97 | .val = union_val.val, | ||
| 98 | }, writer, level - 1, mod); | ||
| 153 | 99 | ||
| 100 | return writer.writeAll(" }"); | ||
| 101 | }, | ||
| 102 | .bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}), | ||
| 103 | .repeated => { | ||
| 104 | if (level == 0) { | ||
| 105 | return writer.writeAll(".{ ... }"); | ||
| 106 | } | ||
| 154 | var i: u32 = 0; | 107 | var i: u32 = 0; |
| 108 | try writer.writeAll(".{ "); | ||
| 109 | const elem_tv = TypedValue{ | ||
| 110 | .ty = ty.elemType2(mod), | ||
| 111 | .val = val.castTag(.repeated).?.data, | ||
| 112 | }; | ||
| 113 | const len = ty.arrayLen(mod); | ||
| 114 | const max_len = std.math.min(len, max_aggregate_items); | ||
| 155 | while (i < max_len) : (i += 1) { | 115 | while (i < max_len) : (i += 1) { |
| 156 | if (i != 0) try writer.writeAll(", "); | 116 | if (i != 0) try writer.writeAll(", "); |
| 157 | switch (ty.tag()) { | 117 | try print(elem_tv, writer, level - 1, mod); |
| 158 | .anon_struct, .@"struct" => try writer.print(".{s} = ", .{ty.structFieldName(i)}), | ||
| 159 | else => {}, | ||
| 160 | } | ||
| 161 | try print(.{ | ||
| 162 | .ty = ty.structFieldType(i), | ||
| 163 | .val = val.fieldValue(ty, i), | ||
| 164 | }, writer, level - 1, mod); | ||
| 165 | } | 118 | } |
| 166 | if (ty.structFieldCount() > max_aggregate_items) { | 119 | if (len > max_aggregate_items) { |
| 167 | try writer.writeAll(", ..."); | 120 | try writer.writeAll(", ..."); |
| 168 | } | 121 | } |
| 169 | return writer.writeAll("}"); | 122 | return writer.writeAll(" }"); |
| 170 | } else { | 123 | }, |
| 171 | const elem_ty = ty.elemType2(); | 124 | .slice => { |
| 172 | const len = ty.arrayLen(); | 125 | if (level == 0) { |
| 126 | return writer.writeAll(".{ ... }"); | ||
| 127 | } | ||
| 128 | const payload = val.castTag(.slice).?.data; | ||
| 129 | const elem_ty = ty.elemType2(mod); | ||
| 130 | const len = payload.len.toUnsignedInt(mod); | ||
| 173 | 131 | ||
| 174 | if (elem_ty.eql(Type.u8, mod)) str: { | 132 | if (elem_ty.eql(Type.u8, mod)) str: { |
| 175 | const max_len = @intCast(usize, std.math.min(len, max_string_len)); | 133 | const max_len = @intCast(usize, std.math.min(len, max_string_len)); |
| ... | @@ -177,11 +135,14 @@ pub fn print( | ... | @@ -177,11 +135,14 @@ pub fn print( |
| 177 | 135 | ||
| 178 | var i: u32 = 0; | 136 | var i: u32 = 0; |
| 179 | while (i < max_len) : (i += 1) { | 137 | while (i < max_len) : (i += 1) { |
| 180 | const elem = val.fieldValue(ty, i); | 138 | const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) { |
| 181 | if (elem.isUndef()) break :str; | 139 | error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic |
| 182 | buf[i] = std.math.cast(u8, elem.toUnsignedInt(target)) orelse break :str; | 140 | }; |
| 141 | if (elem_val.isUndef(mod)) break :str; | ||
| 142 | buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str; | ||
| 183 | } | 143 | } |
| 184 | 144 | ||
| 145 | // TODO would be nice if this had a bit of unicode awareness. | ||
| 185 | const truncated = if (len > max_string_len) " (truncated)" else ""; | 146 | const truncated = if (len > max_string_len) " (truncated)" else ""; |
| 186 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | 147 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); |
| 187 | } | 148 | } |
| ... | @@ -192,315 +153,334 @@ pub fn print( | ... | @@ -192,315 +153,334 @@ pub fn print( |
| 192 | var i: u32 = 0; | 153 | var i: u32 = 0; |
| 193 | while (i < max_len) : (i += 1) { | 154 | while (i < max_len) : (i += 1) { |
| 194 | if (i != 0) try writer.writeAll(", "); | 155 | if (i != 0) try writer.writeAll(", "); |
| 156 | const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) { | ||
| 157 | error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic | ||
| 158 | }; | ||
| 195 | try print(.{ | 159 | try print(.{ |
| 196 | .ty = elem_ty, | 160 | .ty = elem_ty, |
| 197 | .val = val.fieldValue(ty, i), | 161 | .val = elem_val, |
| 198 | }, writer, level - 1, mod); | 162 | }, writer, level - 1, mod); |
| 199 | } | 163 | } |
| 200 | if (len > max_aggregate_items) { | 164 | if (len > max_aggregate_items) { |
| 201 | try writer.writeAll(", ..."); | 165 | try writer.writeAll(", ..."); |
| 202 | } | 166 | } |
| 203 | return writer.writeAll(" }"); | 167 | return writer.writeAll(" }"); |
| 204 | } | 168 | }, |
| 205 | }, | 169 | .eu_payload => { |
| 206 | .@"union" => { | 170 | val = val.castTag(.eu_payload).?.data; |
| 207 | if (level == 0) { | 171 | ty = ty.errorUnionPayload(mod); |
| 208 | return writer.writeAll(".{ ... }"); | 172 | }, |
| 209 | } | 173 | .opt_payload => { |
| 210 | const union_val = val.castTag(.@"union").?.data; | 174 | val = val.castTag(.opt_payload).?.data; |
| 211 | try writer.writeAll(".{ "); | 175 | ty = ty.optionalChild(mod); |
| 212 | 176 | }, | |
| 213 | try print(.{ | ||
| 214 | .ty = ty.cast(Type.Payload.Union).?.data.tag_ty, | ||
| 215 | .val = union_val.tag, | ||
| 216 | }, writer, level - 1, mod); | ||
| 217 | try writer.writeAll(" = "); | ||
| 218 | try print(.{ | ||
| 219 | .ty = ty.unionFieldType(union_val.tag, mod), | ||
| 220 | .val = union_val.val, | ||
| 221 | }, writer, level - 1, mod); | ||
| 222 | |||
| 223 | return writer.writeAll(" }"); | ||
| 224 | }, | ||
| 225 | .null_value => return writer.writeAll("null"), | ||
| 226 | .undef => return writer.writeAll("undefined"), | ||
| 227 | .zero => return writer.writeAll("0"), | ||
| 228 | .one => return writer.writeAll("1"), | ||
| 229 | .void_value => return writer.writeAll("{}"), | ||
| 230 | .unreachable_value => return writer.writeAll("unreachable"), | ||
| 231 | .the_only_possible_value => return writer.writeAll("0"), | ||
| 232 | .bool_true => return writer.writeAll("true"), | ||
| 233 | .bool_false => return writer.writeAll("false"), | ||
| 234 | .ty => return val.castTag(.ty).?.data.print(writer, mod), | ||
| 235 | .int_type => { | ||
| 236 | const int_type = val.castTag(.int_type).?.data; | ||
| 237 | return writer.print("{s}{d}", .{ | ||
| 238 | if (int_type.signed) "s" else "u", | ||
| 239 | int_type.bits, | ||
| 240 | }); | ||
| 241 | }, | ||
| 242 | .int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", .{}, writer), | ||
| 243 | .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", .{}, writer), | ||
| 244 | .int_big_positive => return writer.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}), | ||
| 245 | .int_big_negative => return writer.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}), | ||
| 246 | .lazy_align => { | ||
| 247 | const sub_ty = val.castTag(.lazy_align).?.data; | ||
| 248 | const x = sub_ty.abiAlignment(target); | ||
| 249 | return writer.print("{d}", .{x}); | ||
| 250 | }, | 177 | }, |
| 251 | .lazy_size => { | 178 | else => switch (ip.indexToKey(val.toIntern())) { |
| 252 | const sub_ty = val.castTag(.lazy_size).?.data; | 179 | .int_type, |
| 253 | const x = sub_ty.abiSize(target); | 180 | .ptr_type, |
| 254 | return writer.print("{d}", .{x}); | 181 | .array_type, |
| 255 | }, | 182 | .vector_type, |
| 256 | .function => return writer.print("(function '{s}')", .{ | 183 | .opt_type, |
| 257 | mod.declPtr(val.castTag(.function).?.data.owner_decl).name, | 184 | .anyframe_type, |
| 258 | }), | 185 | .error_union_type, |
| 259 | .extern_fn => return writer.writeAll("(extern function)"), | 186 | .simple_type, |
| 260 | .variable => unreachable, | 187 | .struct_type, |
| 261 | .decl_ref_mut => { | 188 | .anon_struct_type, |
| 262 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | 189 | .union_type, |
| 263 | const decl = mod.declPtr(decl_index); | 190 | .opaque_type, |
| 264 | if (level == 0) { | 191 | .enum_type, |
| 265 | return writer.print("(decl ref mut '{s}')", .{decl.name}); | 192 | .func_type, |
| 266 | } | 193 | .error_set_type, |
| 267 | return print(.{ | 194 | .inferred_error_set_type, |
| 268 | .ty = decl.ty, | 195 | => return Type.print(val.toType(), writer, mod), |
| 269 | .val = decl.val, | 196 | .undef => return writer.writeAll("undefined"), |
| 270 | }, writer, level - 1, mod); | 197 | .runtime_value => return writer.writeAll("(runtime value)"), |
| 271 | }, | 198 | .simple_value => |simple_value| switch (simple_value) { |
| 272 | .decl_ref => { | 199 | .empty_struct => return printAggregate(ty, val, writer, level, mod), |
| 273 | const decl_index = val.castTag(.decl_ref).?.data; | 200 | .generic_poison => return writer.writeAll("(generic poison)"), |
| 274 | const decl = mod.declPtr(decl_index); | 201 | else => return writer.writeAll(@tagName(simple_value)), |
| 275 | if (level == 0) { | 202 | }, |
| 276 | return writer.print("(decl ref '{s}')", .{decl.name}); | 203 | .variable => return writer.writeAll("(variable)"), |
| 277 | } | 204 | .extern_func => |extern_func| return writer.print("(extern function '{}')", .{ |
| 278 | return print(.{ | 205 | mod.declPtr(extern_func.decl).name.fmt(ip), |
| 279 | .ty = decl.ty, | 206 | }), |
| 280 | .val = decl.val, | 207 | .func => |func| return writer.print("(function '{}')", .{ |
| 281 | }, writer, level - 1, mod); | 208 | mod.declPtr(mod.funcPtr(func.index).owner_decl).name.fmt(ip), |
| 282 | }, | 209 | }), |
| 283 | .comptime_field_ptr => { | 210 | .int => |int| switch (int.storage) { |
| 284 | const payload = val.castTag(.comptime_field_ptr).?.data; | 211 | inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}), |
| 285 | if (level == 0) { | 212 | .lazy_align => |lazy_ty| return writer.print("{d}", .{ |
| 286 | return writer.writeAll("(comptime field ptr)"); | 213 | lazy_ty.toType().abiAlignment(mod), |
| 287 | } | 214 | }), |
| 288 | return print(.{ | 215 | .lazy_size => |lazy_ty| return writer.print("{d}", .{ |
| 289 | .ty = payload.field_ty, | 216 | lazy_ty.toType().abiSize(mod), |
| 290 | .val = payload.field_val, | 217 | }), |
| 291 | }, writer, level - 1, mod); | 218 | }, |
| 292 | }, | 219 | .err => |err| return writer.print("error.{}", .{ |
| 293 | .elem_ptr => { | 220 | err.name.fmt(ip), |
| 294 | const elem_ptr = val.castTag(.elem_ptr).?.data; | 221 | }), |
| 295 | try writer.writeAll("&"); | 222 | .error_union => |error_union| switch (error_union.val) { |
| 296 | if (level == 0) { | 223 | .err_name => |err_name| return writer.print("error.{}", .{ |
| 297 | try writer.writeAll("(ptr)"); | 224 | err_name.fmt(ip), |
| 298 | } else { | 225 | }), |
| 226 | .payload => |payload| { | ||
| 227 | val = payload.toValue(); | ||
| 228 | ty = ty.errorUnionPayload(mod); | ||
| 229 | }, | ||
| 230 | }, | ||
| 231 | .enum_literal => |enum_literal| return writer.print(".{}", .{ | ||
| 232 | enum_literal.fmt(ip), | ||
| 233 | }), | ||
| 234 | .enum_tag => |enum_tag| { | ||
| 235 | if (level == 0) { | ||
| 236 | return writer.writeAll("(enum)"); | ||
| 237 | } | ||
| 238 | const enum_type = ip.indexToKey(ty.toIntern()).enum_type; | ||
| 239 | if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| { | ||
| 240 | try writer.print(".{i}", .{enum_type.names[tag_index].fmt(ip)}); | ||
| 241 | return; | ||
| 242 | } | ||
| 243 | try writer.writeAll("@intToEnum("); | ||
| 299 | try print(.{ | 244 | try print(.{ |
| 300 | .ty = elem_ptr.elem_ty, | 245 | .ty = Type.type, |
| 301 | .val = elem_ptr.array_ptr, | 246 | .val = enum_tag.ty.toValue(), |
| 302 | }, writer, level - 1, mod); | 247 | }, writer, level - 1, mod); |
| 303 | } | 248 | try writer.writeAll(", "); |
| 304 | return writer.print("[{}]", .{elem_ptr.index}); | ||
| 305 | }, | ||
| 306 | .field_ptr => { | ||
| 307 | const field_ptr = val.castTag(.field_ptr).?.data; | ||
| 308 | try writer.writeAll("&"); | ||
| 309 | if (level == 0) { | ||
| 310 | try writer.writeAll("(ptr)"); | ||
| 311 | } else { | ||
| 312 | try print(.{ | 249 | try print(.{ |
| 313 | .ty = field_ptr.container_ty, | 250 | .ty = ip.typeOf(enum_tag.int).toType(), |
| 314 | .val = field_ptr.container_ptr, | 251 | .val = enum_tag.int.toValue(), |
| 315 | }, writer, level - 1, mod); | 252 | }, writer, level - 1, mod); |
| 316 | } | 253 | try writer.writeAll(")"); |
| 317 | 254 | return; | |
| 318 | if (field_ptr.container_ty.zigTypeTag() == .Struct) { | 255 | }, |
| 319 | switch (field_ptr.container_ty.tag()) { | 256 | .empty_enum_value => return writer.writeAll("(empty enum value)"), |
| 320 | .tuple => return writer.print(".@\"{d}\"", .{field_ptr.field_index}), | 257 | .float => |float| switch (float.storage) { |
| 321 | else => { | 258 | inline else => |x| return writer.print("{d}", .{@floatCast(f64, x)}), |
| 322 | const field_name = field_ptr.container_ty.structFieldName(field_ptr.field_index); | 259 | }, |
| 323 | return writer.print(".{s}", .{field_name}); | 260 | .ptr => |ptr| { |
| 324 | }, | 261 | if (ptr.addr == .int) { |
| 325 | } | 262 | const i = ip.indexToKey(ptr.addr.int).int; |
| 326 | } else if (field_ptr.container_ty.zigTypeTag() == .Union) { | 263 | switch (i.storage) { |
| 327 | const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index]; | 264 | inline else => |addr| return writer.print("{x:0>8}", .{addr}), |
| 328 | return writer.print(".{s}", .{field_name}); | 265 | } |
| 329 | } else if (field_ptr.container_ty.isSlice()) { | ||
| 330 | switch (field_ptr.field_index) { | ||
| 331 | Value.Payload.Slice.ptr_index => return writer.writeAll(".ptr"), | ||
| 332 | Value.Payload.Slice.len_index => return writer.writeAll(".len"), | ||
| 333 | else => unreachable, | ||
| 334 | } | 266 | } |
| 335 | } | ||
| 336 | }, | ||
| 337 | .empty_array => return writer.writeAll(".{}"), | ||
| 338 | .enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}), | ||
| 339 | .enum_field_index => { | ||
| 340 | return writer.print(".{s}", .{ty.enumFieldName(val.castTag(.enum_field_index).?.data)}); | ||
| 341 | }, | ||
| 342 | .bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}), | ||
| 343 | .str_lit => { | ||
| 344 | const str_lit = val.castTag(.str_lit).?.data; | ||
| 345 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | ||
| 346 | return writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)}); | ||
| 347 | }, | ||
| 348 | .repeated => { | ||
| 349 | if (level == 0) { | ||
| 350 | return writer.writeAll(".{ ... }"); | ||
| 351 | } | ||
| 352 | var i: u32 = 0; | ||
| 353 | try writer.writeAll(".{ "); | ||
| 354 | const elem_tv = TypedValue{ | ||
| 355 | .ty = ty.elemType2(), | ||
| 356 | .val = val.castTag(.repeated).?.data, | ||
| 357 | }; | ||
| 358 | const len = ty.arrayLen(); | ||
| 359 | const max_len = std.math.min(len, max_aggregate_items); | ||
| 360 | while (i < max_len) : (i += 1) { | ||
| 361 | if (i != 0) try writer.writeAll(", "); | ||
| 362 | try print(elem_tv, writer, level - 1, mod); | ||
| 363 | } | ||
| 364 | if (len > max_aggregate_items) { | ||
| 365 | try writer.writeAll(", ..."); | ||
| 366 | } | ||
| 367 | return writer.writeAll(" }"); | ||
| 368 | }, | ||
| 369 | .empty_array_sentinel => { | ||
| 370 | if (level == 0) { | ||
| 371 | return writer.writeAll(".{ (sentinel) }"); | ||
| 372 | } | ||
| 373 | try writer.writeAll(".{ "); | ||
| 374 | try print(.{ | ||
| 375 | .ty = ty.elemType2(), | ||
| 376 | .val = ty.sentinel().?, | ||
| 377 | }, writer, level - 1, mod); | ||
| 378 | return writer.writeAll(" }"); | ||
| 379 | }, | ||
| 380 | .slice => { | ||
| 381 | if (level == 0) { | ||
| 382 | return writer.writeAll(".{ ... }"); | ||
| 383 | } | ||
| 384 | const payload = val.castTag(.slice).?.data; | ||
| 385 | const elem_ty = ty.elemType2(); | ||
| 386 | const len = payload.len.toUnsignedInt(target); | ||
| 387 | 267 | ||
| 388 | if (elem_ty.eql(Type.u8, mod)) str: { | 268 | const ptr_ty = ip.indexToKey(ty.toIntern()).ptr_type; |
| 389 | const max_len = @intCast(usize, std.math.min(len, max_string_len)); | 269 | if (ptr_ty.flags.size == .Slice) { |
| 390 | var buf: [max_string_len]u8 = undefined; | 270 | if (level == 0) { |
| 391 | 271 | return writer.writeAll(".{ ... }"); | |
| 392 | var i: u32 = 0; | 272 | } |
| 393 | while (i < max_len) : (i += 1) { | 273 | const elem_ty = ptr_ty.child.toType(); |
| 394 | var elem_buf: Value.ElemValueBuffer = undefined; | 274 | const len = ptr.len.toValue().toUnsignedInt(mod); |
| 395 | const elem_val = payload.ptr.elemValueBuffer(mod, i, &elem_buf); | 275 | if (elem_ty.eql(Type.u8, mod)) str: { |
| 396 | if (elem_val.isUndef()) break :str; | 276 | const max_len = @min(len, max_string_len); |
| 397 | buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(target)) orelse break :str; | 277 | var buf: [max_string_len]u8 = undefined; |
| 278 | for (buf[0..max_len], 0..) |*c, i| { | ||
| 279 | const elem = try val.elemValue(mod, i); | ||
| 280 | if (elem.isUndef(mod)) break :str; | ||
| 281 | c.* = @intCast(u8, elem.toUnsignedInt(mod)); | ||
| 282 | } | ||
| 283 | const truncated = if (len > max_string_len) " (truncated)" else ""; | ||
| 284 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | ||
| 285 | } | ||
| 286 | try writer.writeAll(".{ "); | ||
| 287 | const max_len = @min(len, max_aggregate_items); | ||
| 288 | for (0..max_len) |i| { | ||
| 289 | if (i != 0) try writer.writeAll(", "); | ||
| 290 | try print(.{ | ||
| 291 | .ty = elem_ty, | ||
| 292 | .val = try val.elemValue(mod, i), | ||
| 293 | }, writer, level - 1, mod); | ||
| 294 | } | ||
| 295 | if (len > max_aggregate_items) { | ||
| 296 | try writer.writeAll(", ..."); | ||
| 297 | } | ||
| 298 | return writer.writeAll(" }"); | ||
| 398 | } | 299 | } |
| 399 | 300 | ||
| 400 | // TODO would be nice if this had a bit of unicode awareness. | 301 | switch (ptr.addr) { |
| 401 | const truncated = if (len > max_string_len) " (truncated)" else ""; | 302 | .decl => |decl_index| { |
| 402 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | 303 | const decl = mod.declPtr(decl_index); |
| 403 | } | 304 | if (level == 0) return writer.print("(decl '{}')", .{decl.name.fmt(ip)}); |
| 404 | 305 | return print(.{ | |
| 405 | try writer.writeAll(".{ "); | 306 | .ty = decl.ty, |
| 406 | 307 | .val = decl.val, | |
| 407 | const max_len = std.math.min(len, max_aggregate_items); | 308 | }, writer, level - 1, mod); |
| 408 | var i: u32 = 0; | 309 | }, |
| 409 | while (i < max_len) : (i += 1) { | 310 | .mut_decl => |mut_decl| { |
| 410 | if (i != 0) try writer.writeAll(", "); | 311 | const decl = mod.declPtr(mut_decl.decl); |
| 411 | var buf: Value.ElemValueBuffer = undefined; | 312 | if (level == 0) return writer.print("(mut decl '{}')", .{decl.name.fmt(ip)}); |
| 412 | try print(.{ | 313 | return print(.{ |
| 413 | .ty = elem_ty, | 314 | .ty = decl.ty, |
| 414 | .val = payload.ptr.elemValueBuffer(mod, i, &buf), | 315 | .val = decl.val, |
| 415 | }, writer, level - 1, mod); | 316 | }, writer, level - 1, mod); |
| 416 | } | 317 | }, |
| 417 | if (len > max_aggregate_items) { | 318 | .comptime_field => |field_val_ip| { |
| 418 | try writer.writeAll(", ..."); | 319 | return print(.{ |
| 419 | } | 320 | .ty = ip.typeOf(field_val_ip).toType(), |
| 420 | return writer.writeAll(" }"); | 321 | .val = field_val_ip.toValue(), |
| 421 | }, | 322 | }, writer, level - 1, mod); |
| 422 | .float_16 => return writer.print("{d}", .{val.castTag(.float_16).?.data}), | 323 | }, |
| 423 | .float_32 => return writer.print("{d}", .{val.castTag(.float_32).?.data}), | 324 | .int => unreachable, |
| 424 | .float_64 => return writer.print("{d}", .{val.castTag(.float_64).?.data}), | 325 | .eu_payload => |eu_ip| { |
| 425 | .float_80 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_80).?.data)}), | 326 | try writer.writeAll("(payload of "); |
| 426 | .float_128 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_128).?.data)}), | 327 | try print(.{ |
| 427 | .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}), | 328 | .ty = ip.typeOf(eu_ip).toType(), |
| 428 | .eu_payload => { | 329 | .val = eu_ip.toValue(), |
| 429 | val = val.castTag(.eu_payload).?.data; | 330 | }, writer, level - 1, mod); |
| 430 | ty = ty.errorUnionPayload(); | 331 | try writer.writeAll(")"); |
| 431 | }, | 332 | }, |
| 432 | .opt_payload => { | 333 | .opt_payload => |opt_ip| { |
| 433 | val = val.castTag(.opt_payload).?.data; | 334 | try print(.{ |
| 434 | var buf: Type.Payload.ElemType = undefined; | 335 | .ty = ip.typeOf(opt_ip).toType(), |
| 435 | ty = ty.optionalChild(&buf); | 336 | .val = opt_ip.toValue(), |
| 436 | return print(.{ .ty = ty, .val = val }, writer, level, mod); | 337 | }, writer, level - 1, mod); |
| 338 | try writer.writeAll(".?"); | ||
| 339 | }, | ||
| 340 | .elem => |elem| { | ||
| 341 | try print(.{ | ||
| 342 | .ty = ip.typeOf(elem.base).toType(), | ||
| 343 | .val = elem.base.toValue(), | ||
| 344 | }, writer, level - 1, mod); | ||
| 345 | try writer.print("[{}]", .{elem.index}); | ||
| 346 | }, | ||
| 347 | .field => |field| { | ||
| 348 | const container_ty = ip.typeOf(field.base).toType(); | ||
| 349 | try print(.{ | ||
| 350 | .ty = container_ty, | ||
| 351 | .val = field.base.toValue(), | ||
| 352 | }, writer, level - 1, mod); | ||
| 353 | |||
| 354 | switch (container_ty.zigTypeTag(mod)) { | ||
| 355 | .Struct => { | ||
| 356 | if (container_ty.isTuple(mod)) { | ||
| 357 | try writer.print("[{d}]", .{field.index}); | ||
| 358 | } | ||
| 359 | const field_name = container_ty.structFieldName(@intCast(usize, field.index), mod); | ||
| 360 | try writer.print(".{i}", .{field_name.fmt(ip)}); | ||
| 361 | }, | ||
| 362 | .Union => { | ||
| 363 | const field_name = container_ty.unionFields(mod).keys()[@intCast(usize, field.index)]; | ||
| 364 | try writer.print(".{i}", .{field_name.fmt(ip)}); | ||
| 365 | }, | ||
| 366 | .Pointer => { | ||
| 367 | std.debug.assert(container_ty.isSlice(mod)); | ||
| 368 | try writer.writeAll(switch (field.index) { | ||
| 369 | Value.slice_ptr_index => ".ptr", | ||
| 370 | Value.slice_len_index => ".len", | ||
| 371 | else => unreachable, | ||
| 372 | }); | ||
| 373 | }, | ||
| 374 | else => unreachable, | ||
| 375 | } | ||
| 376 | }, | ||
| 377 | } | ||
| 378 | }, | ||
| 379 | .opt => |opt| switch (opt.val) { | ||
| 380 | .none => return writer.writeAll("null"), | ||
| 381 | else => |payload| { | ||
| 382 | val = payload.toValue(); | ||
| 383 | ty = ty.optionalChild(mod); | ||
| 384 | }, | ||
| 385 | }, | ||
| 386 | .aggregate => |aggregate| switch (aggregate.storage) { | ||
| 387 | .bytes => |bytes| { | ||
| 388 | // Strip the 0 sentinel off of strings before printing | ||
| 389 | const zero_sent = blk: { | ||
| 390 | const sent = ty.sentinel(mod) orelse break :blk false; | ||
| 391 | break :blk sent.eql(Value.zero_u8, Type.u8, mod); | ||
| 392 | }; | ||
| 393 | const str = if (zero_sent) bytes[0 .. bytes.len - 1] else bytes; | ||
| 394 | return writer.print("\"{}\"", .{std.zig.fmtEscapes(str)}); | ||
| 395 | }, | ||
| 396 | .elems, .repeated_elem => return printAggregate(ty, val, writer, level, mod), | ||
| 397 | }, | ||
| 398 | .un => |un| { | ||
| 399 | try writer.writeAll(".{ "); | ||
| 400 | if (level > 0) { | ||
| 401 | try print(.{ | ||
| 402 | .ty = ty.unionTagTypeHypothetical(mod), | ||
| 403 | .val = un.tag.toValue(), | ||
| 404 | }, writer, level - 1, mod); | ||
| 405 | try writer.writeAll(" = "); | ||
| 406 | try print(.{ | ||
| 407 | .ty = ty.unionFieldType(un.tag.toValue(), mod), | ||
| 408 | .val = un.val.toValue(), | ||
| 409 | }, writer, level - 1, mod); | ||
| 410 | } else try writer.writeAll("..."); | ||
| 411 | return writer.writeAll(" }"); | ||
| 412 | }, | ||
| 413 | .memoized_call => unreachable, | ||
| 437 | }, | 414 | }, |
| 438 | .eu_payload_ptr => { | 415 | }; |
| 439 | try writer.writeAll("&"); | 416 | } |
| 440 | |||
| 441 | const data = val.castTag(.eu_payload_ptr).?.data; | ||
| 442 | |||
| 443 | var ty_val: Value.Payload.Ty = .{ | ||
| 444 | .base = .{ .tag = .ty }, | ||
| 445 | .data = ty, | ||
| 446 | }; | ||
| 447 | 417 | ||
| 448 | try writer.writeAll("@as("); | 418 | fn printAggregate( |
| 449 | try print(.{ | 419 | ty: Type, |
| 450 | .ty = Type.type, | 420 | val: Value, |
| 451 | .val = Value.initPayload(&ty_val.base), | 421 | writer: anytype, |
| 452 | }, writer, level - 1, mod); | 422 | level: u8, |
| 423 | mod: *Module, | ||
| 424 | ) (@TypeOf(writer).Error || Allocator.Error)!void { | ||
| 425 | if (level == 0) { | ||
| 426 | return writer.writeAll(".{ ... }"); | ||
| 427 | } | ||
| 428 | if (ty.zigTypeTag(mod) == .Struct) { | ||
| 429 | try writer.writeAll(".{"); | ||
| 430 | const max_len = @min(ty.structFieldCount(mod), max_aggregate_items); | ||
| 453 | 431 | ||
| 454 | try writer.writeAll(", &(payload of "); | 432 | for (0..max_len) |i| { |
| 433 | if (i != 0) try writer.writeAll(", "); | ||
| 455 | 434 | ||
| 456 | var ptr_ty: Type.Payload.ElemType = .{ | 435 | const field_name = switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 457 | .base = .{ .tag = .single_mut_pointer }, | 436 | .struct_type => |x| mod.structPtrUnwrap(x.index).?.fields.keys()[i].toOptional(), |
| 458 | .data = data.container_ty, | 437 | .anon_struct_type => |x| if (x.isTuple()) .none else x.names[i].toOptional(), |
| 438 | else => unreachable, | ||
| 459 | }; | 439 | }; |
| 460 | 440 | ||
| 441 | if (field_name.unwrap()) |name| try writer.print(".{} = ", .{name.fmt(&mod.intern_pool)}); | ||
| 461 | try print(.{ | 442 | try print(.{ |
| 462 | .ty = Type.initPayload(&ptr_ty.base), | 443 | .ty = ty.structFieldType(i, mod), |
| 463 | .val = data.container_ptr, | 444 | .val = try val.fieldValue(mod, i), |
| 464 | }, writer, level - 1, mod); | 445 | }, writer, level - 1, mod); |
| 446 | } | ||
| 447 | if (ty.structFieldCount(mod) > max_aggregate_items) { | ||
| 448 | try writer.writeAll(", ..."); | ||
| 449 | } | ||
| 450 | return writer.writeAll("}"); | ||
| 451 | } else { | ||
| 452 | const elem_ty = ty.elemType2(mod); | ||
| 453 | const len = ty.arrayLen(mod); | ||
| 454 | |||
| 455 | if (elem_ty.eql(Type.u8, mod)) str: { | ||
| 456 | const max_len = @intCast(usize, std.math.min(len, max_string_len)); | ||
| 457 | var buf: [max_string_len]u8 = undefined; | ||
| 465 | 458 | ||
| 466 | try writer.writeAll("))"); | 459 | var i: u32 = 0; |
| 467 | return; | 460 | while (i < max_len) : (i += 1) { |
| 468 | }, | 461 | const elem = try val.fieldValue(mod, i); |
| 469 | .opt_payload_ptr => { | 462 | if (elem.isUndef(mod)) break :str; |
| 470 | const data = val.castTag(.opt_payload_ptr).?.data; | 463 | buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str; |
| 471 | 464 | } | |
| 472 | var ty_val: Value.Payload.Ty = .{ | ||
| 473 | .base = .{ .tag = .ty }, | ||
| 474 | .data = ty, | ||
| 475 | }; | ||
| 476 | |||
| 477 | try writer.writeAll("@as("); | ||
| 478 | try print(.{ | ||
| 479 | .ty = Type.type, | ||
| 480 | .val = Value.initPayload(&ty_val.base), | ||
| 481 | }, writer, level - 1, mod); | ||
| 482 | 465 | ||
| 483 | try writer.writeAll(", &(payload of "); | 466 | const truncated = if (len > max_string_len) " (truncated)" else ""; |
| 467 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | ||
| 468 | } | ||
| 484 | 469 | ||
| 485 | var ptr_ty: Type.Payload.ElemType = .{ | 470 | try writer.writeAll(".{ "); |
| 486 | .base = .{ .tag = .single_mut_pointer }, | ||
| 487 | .data = data.container_ty, | ||
| 488 | }; | ||
| 489 | 471 | ||
| 472 | const max_len = std.math.min(len, max_aggregate_items); | ||
| 473 | var i: u32 = 0; | ||
| 474 | while (i < max_len) : (i += 1) { | ||
| 475 | if (i != 0) try writer.writeAll(", "); | ||
| 490 | try print(.{ | 476 | try print(.{ |
| 491 | .ty = Type.initPayload(&ptr_ty.base), | 477 | .ty = elem_ty, |
| 492 | .val = data.container_ptr, | 478 | .val = try val.fieldValue(mod, i), |
| 493 | }, writer, level - 1, mod); | 479 | }, writer, level - 1, mod); |
| 494 | 480 | } | |
| 495 | try writer.writeAll("))"); | 481 | if (len > max_aggregate_items) { |
| 496 | return; | 482 | try writer.writeAll(", ..."); |
| 497 | }, | 483 | } |
| 498 | 484 | return writer.writeAll(" }"); | |
| 499 | // TODO these should not appear in this function | 485 | } |
| 500 | .inferred_alloc => return writer.writeAll("(inferred allocation value)"), | ||
| 501 | .inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"), | ||
| 502 | .generic_poison_type => return writer.writeAll("(generic poison type)"), | ||
| 503 | .generic_poison => return writer.writeAll("(generic poison)"), | ||
| 504 | .runtime_value => return writer.writeAll("[runtime value]"), | ||
| 505 | }; | ||
| 506 | } | 486 | } |
src/Zir.zig+97-435| ... | @@ -19,6 +19,7 @@ const BigIntConst = std.math.big.int.Const; | ... | @@ -19,6 +19,7 @@ const BigIntConst = std.math.big.int.Const; |
| 19 | const BigIntMutable = std.math.big.int.Mutable; | 19 | const BigIntMutable = std.math.big.int.Mutable; |
| 20 | const Ast = std.zig.Ast; | 20 | const Ast = std.zig.Ast; |
| 21 | 21 | ||
| 22 | const InternPool = @import("InternPool.zig"); | ||
| 22 | const Zir = @This(); | 23 | const Zir = @This(); |
| 23 | const Type = @import("type.zig").Type; | 24 | const Type = @import("type.zig").Type; |
| 24 | const Value = @import("value.zig").Value; | 25 | const Value = @import("value.zig").Value; |
| ... | @@ -2041,448 +2042,103 @@ pub const Inst = struct { | ... | @@ -2041,448 +2042,103 @@ pub const Inst = struct { |
| 2041 | /// The position of a ZIR instruction within the `Zir` instructions array. | 2042 | /// The position of a ZIR instruction within the `Zir` instructions array. |
| 2042 | pub const Index = u32; | 2043 | pub const Index = u32; |
| 2043 | 2044 | ||
| 2044 | /// A reference to a TypedValue or ZIR instruction. | 2045 | /// A reference to ZIR instruction, or to an InternPool index, or neither. |
| 2045 | /// | 2046 | /// |
| 2046 | /// If the Ref has a tag in this enum, it refers to a TypedValue. | 2047 | /// If the integer tag value is < InternPool.static_len, then it |
| 2047 | /// | 2048 | /// corresponds to an InternPool index. Otherwise, this refers to a ZIR |
| 2048 | /// If the value of a Ref does not have a tag, it refers to a ZIR instruction. | 2049 | /// instruction. |
| 2049 | /// | ||
| 2050 | /// The first values after the the last tag refer to ZIR instructions which may | ||
| 2051 | /// be derived by subtracting `typed_value_map.len`. | ||
| 2052 | /// | ||
| 2053 | /// When adding a tag to this enum, consider adding a corresponding entry to | ||
| 2054 | /// `primitives` in astgen. | ||
| 2055 | /// | 2050 | /// |
| 2056 | /// The tag type is specified so that it is safe to bitcast between `[]u32` | 2051 | /// The tag type is specified so that it is safe to bitcast between `[]u32` |
| 2057 | /// and `[]Ref`. | 2052 | /// and `[]Ref`. |
| 2058 | pub const Ref = enum(u32) { | 2053 | pub const Ref = enum(u32) { |
| 2054 | u1_type = @enumToInt(InternPool.Index.u1_type), | ||
| 2055 | u8_type = @enumToInt(InternPool.Index.u8_type), | ||
| 2056 | i8_type = @enumToInt(InternPool.Index.i8_type), | ||
| 2057 | u16_type = @enumToInt(InternPool.Index.u16_type), | ||
| 2058 | i16_type = @enumToInt(InternPool.Index.i16_type), | ||
| 2059 | u29_type = @enumToInt(InternPool.Index.u29_type), | ||
| 2060 | u32_type = @enumToInt(InternPool.Index.u32_type), | ||
| 2061 | i32_type = @enumToInt(InternPool.Index.i32_type), | ||
| 2062 | u64_type = @enumToInt(InternPool.Index.u64_type), | ||
| 2063 | i64_type = @enumToInt(InternPool.Index.i64_type), | ||
| 2064 | u80_type = @enumToInt(InternPool.Index.u80_type), | ||
| 2065 | u128_type = @enumToInt(InternPool.Index.u128_type), | ||
| 2066 | i128_type = @enumToInt(InternPool.Index.i128_type), | ||
| 2067 | usize_type = @enumToInt(InternPool.Index.usize_type), | ||
| 2068 | isize_type = @enumToInt(InternPool.Index.isize_type), | ||
| 2069 | c_char_type = @enumToInt(InternPool.Index.c_char_type), | ||
| 2070 | c_short_type = @enumToInt(InternPool.Index.c_short_type), | ||
| 2071 | c_ushort_type = @enumToInt(InternPool.Index.c_ushort_type), | ||
| 2072 | c_int_type = @enumToInt(InternPool.Index.c_int_type), | ||
| 2073 | c_uint_type = @enumToInt(InternPool.Index.c_uint_type), | ||
| 2074 | c_long_type = @enumToInt(InternPool.Index.c_long_type), | ||
| 2075 | c_ulong_type = @enumToInt(InternPool.Index.c_ulong_type), | ||
| 2076 | c_longlong_type = @enumToInt(InternPool.Index.c_longlong_type), | ||
| 2077 | c_ulonglong_type = @enumToInt(InternPool.Index.c_ulonglong_type), | ||
| 2078 | c_longdouble_type = @enumToInt(InternPool.Index.c_longdouble_type), | ||
| 2079 | f16_type = @enumToInt(InternPool.Index.f16_type), | ||
| 2080 | f32_type = @enumToInt(InternPool.Index.f32_type), | ||
| 2081 | f64_type = @enumToInt(InternPool.Index.f64_type), | ||
| 2082 | f80_type = @enumToInt(InternPool.Index.f80_type), | ||
| 2083 | f128_type = @enumToInt(InternPool.Index.f128_type), | ||
| 2084 | anyopaque_type = @enumToInt(InternPool.Index.anyopaque_type), | ||
| 2085 | bool_type = @enumToInt(InternPool.Index.bool_type), | ||
| 2086 | void_type = @enumToInt(InternPool.Index.void_type), | ||
| 2087 | type_type = @enumToInt(InternPool.Index.type_type), | ||
| 2088 | anyerror_type = @enumToInt(InternPool.Index.anyerror_type), | ||
| 2089 | comptime_int_type = @enumToInt(InternPool.Index.comptime_int_type), | ||
| 2090 | comptime_float_type = @enumToInt(InternPool.Index.comptime_float_type), | ||
| 2091 | noreturn_type = @enumToInt(InternPool.Index.noreturn_type), | ||
| 2092 | anyframe_type = @enumToInt(InternPool.Index.anyframe_type), | ||
| 2093 | null_type = @enumToInt(InternPool.Index.null_type), | ||
| 2094 | undefined_type = @enumToInt(InternPool.Index.undefined_type), | ||
| 2095 | enum_literal_type = @enumToInt(InternPool.Index.enum_literal_type), | ||
| 2096 | atomic_order_type = @enumToInt(InternPool.Index.atomic_order_type), | ||
| 2097 | atomic_rmw_op_type = @enumToInt(InternPool.Index.atomic_rmw_op_type), | ||
| 2098 | calling_convention_type = @enumToInt(InternPool.Index.calling_convention_type), | ||
| 2099 | address_space_type = @enumToInt(InternPool.Index.address_space_type), | ||
| 2100 | float_mode_type = @enumToInt(InternPool.Index.float_mode_type), | ||
| 2101 | reduce_op_type = @enumToInt(InternPool.Index.reduce_op_type), | ||
| 2102 | call_modifier_type = @enumToInt(InternPool.Index.call_modifier_type), | ||
| 2103 | prefetch_options_type = @enumToInt(InternPool.Index.prefetch_options_type), | ||
| 2104 | export_options_type = @enumToInt(InternPool.Index.export_options_type), | ||
| 2105 | extern_options_type = @enumToInt(InternPool.Index.extern_options_type), | ||
| 2106 | type_info_type = @enumToInt(InternPool.Index.type_info_type), | ||
| 2107 | manyptr_u8_type = @enumToInt(InternPool.Index.manyptr_u8_type), | ||
| 2108 | manyptr_const_u8_type = @enumToInt(InternPool.Index.manyptr_const_u8_type), | ||
| 2109 | manyptr_const_u8_sentinel_0_type = @enumToInt(InternPool.Index.manyptr_const_u8_sentinel_0_type), | ||
| 2110 | single_const_pointer_to_comptime_int_type = @enumToInt(InternPool.Index.single_const_pointer_to_comptime_int_type), | ||
| 2111 | slice_const_u8_type = @enumToInt(InternPool.Index.slice_const_u8_type), | ||
| 2112 | slice_const_u8_sentinel_0_type = @enumToInt(InternPool.Index.slice_const_u8_sentinel_0_type), | ||
| 2113 | anyerror_void_error_union_type = @enumToInt(InternPool.Index.anyerror_void_error_union_type), | ||
| 2114 | generic_poison_type = @enumToInt(InternPool.Index.generic_poison_type), | ||
| 2115 | empty_struct_type = @enumToInt(InternPool.Index.empty_struct_type), | ||
| 2116 | undef = @enumToInt(InternPool.Index.undef), | ||
| 2117 | zero = @enumToInt(InternPool.Index.zero), | ||
| 2118 | zero_usize = @enumToInt(InternPool.Index.zero_usize), | ||
| 2119 | zero_u8 = @enumToInt(InternPool.Index.zero_u8), | ||
| 2120 | one = @enumToInt(InternPool.Index.one), | ||
| 2121 | one_usize = @enumToInt(InternPool.Index.one_usize), | ||
| 2122 | one_u8 = @enumToInt(InternPool.Index.one_u8), | ||
| 2123 | four_u8 = @enumToInt(InternPool.Index.four_u8), | ||
| 2124 | negative_one = @enumToInt(InternPool.Index.negative_one), | ||
| 2125 | calling_convention_c = @enumToInt(InternPool.Index.calling_convention_c), | ||
| 2126 | calling_convention_inline = @enumToInt(InternPool.Index.calling_convention_inline), | ||
| 2127 | void_value = @enumToInt(InternPool.Index.void_value), | ||
| 2128 | unreachable_value = @enumToInt(InternPool.Index.unreachable_value), | ||
| 2129 | null_value = @enumToInt(InternPool.Index.null_value), | ||
| 2130 | bool_true = @enumToInt(InternPool.Index.bool_true), | ||
| 2131 | bool_false = @enumToInt(InternPool.Index.bool_false), | ||
| 2132 | empty_struct = @enumToInt(InternPool.Index.empty_struct), | ||
| 2133 | generic_poison = @enumToInt(InternPool.Index.generic_poison), | ||
| 2134 | |||
| 2135 | /// This tag is here to match Air and InternPool, however it is unused | ||
| 2136 | /// for ZIR purposes. | ||
| 2137 | var_args_param_type = @enumToInt(InternPool.Index.var_args_param_type), | ||
| 2059 | /// This Ref does not correspond to any ZIR instruction or constant | 2138 | /// This Ref does not correspond to any ZIR instruction or constant |
| 2060 | /// value and may instead be used as a sentinel to indicate null. | 2139 | /// value and may instead be used as a sentinel to indicate null. |
| 2061 | none, | 2140 | none = @enumToInt(InternPool.Index.none), |
| 2062 | |||
| 2063 | u1_type, | ||
| 2064 | u8_type, | ||
| 2065 | i8_type, | ||
| 2066 | u16_type, | ||
| 2067 | i16_type, | ||
| 2068 | u29_type, | ||
| 2069 | u32_type, | ||
| 2070 | i32_type, | ||
| 2071 | u64_type, | ||
| 2072 | i64_type, | ||
| 2073 | u128_type, | ||
| 2074 | i128_type, | ||
| 2075 | usize_type, | ||
| 2076 | isize_type, | ||
| 2077 | c_char_type, | ||
| 2078 | c_short_type, | ||
| 2079 | c_ushort_type, | ||
| 2080 | c_int_type, | ||
| 2081 | c_uint_type, | ||
| 2082 | c_long_type, | ||
| 2083 | c_ulong_type, | ||
| 2084 | c_longlong_type, | ||
| 2085 | c_ulonglong_type, | ||
| 2086 | c_longdouble_type, | ||
| 2087 | f16_type, | ||
| 2088 | f32_type, | ||
| 2089 | f64_type, | ||
| 2090 | f80_type, | ||
| 2091 | f128_type, | ||
| 2092 | anyopaque_type, | ||
| 2093 | bool_type, | ||
| 2094 | void_type, | ||
| 2095 | type_type, | ||
| 2096 | anyerror_type, | ||
| 2097 | comptime_int_type, | ||
| 2098 | comptime_float_type, | ||
| 2099 | noreturn_type, | ||
| 2100 | anyframe_type, | ||
| 2101 | null_type, | ||
| 2102 | undefined_type, | ||
| 2103 | enum_literal_type, | ||
| 2104 | atomic_order_type, | ||
| 2105 | atomic_rmw_op_type, | ||
| 2106 | calling_convention_type, | ||
| 2107 | address_space_type, | ||
| 2108 | float_mode_type, | ||
| 2109 | reduce_op_type, | ||
| 2110 | modifier_type, | ||
| 2111 | prefetch_options_type, | ||
| 2112 | export_options_type, | ||
| 2113 | extern_options_type, | ||
| 2114 | type_info_type, | ||
| 2115 | manyptr_u8_type, | ||
| 2116 | manyptr_const_u8_type, | ||
| 2117 | fn_noreturn_no_args_type, | ||
| 2118 | fn_void_no_args_type, | ||
| 2119 | fn_naked_noreturn_no_args_type, | ||
| 2120 | fn_ccc_void_no_args_type, | ||
| 2121 | single_const_pointer_to_comptime_int_type, | ||
| 2122 | const_slice_u8_type, | ||
| 2123 | anyerror_void_error_union_type, | ||
| 2124 | generic_poison_type, | ||
| 2125 | |||
| 2126 | /// `undefined` (untyped) | ||
| 2127 | undef, | ||
| 2128 | /// `0` (comptime_int) | ||
| 2129 | zero, | ||
| 2130 | /// `1` (comptime_int) | ||
| 2131 | one, | ||
| 2132 | /// `{}` | ||
| 2133 | void_value, | ||
| 2134 | /// `unreachable` (noreturn type) | ||
| 2135 | unreachable_value, | ||
| 2136 | /// `null` (untyped) | ||
| 2137 | null_value, | ||
| 2138 | /// `true` | ||
| 2139 | bool_true, | ||
| 2140 | /// `false` | ||
| 2141 | bool_false, | ||
| 2142 | /// `.{}` (untyped) | ||
| 2143 | empty_struct, | ||
| 2144 | /// `0` (usize) | ||
| 2145 | zero_usize, | ||
| 2146 | /// `1` (usize) | ||
| 2147 | one_usize, | ||
| 2148 | /// `std.builtin.CallingConvention.C` | ||
| 2149 | calling_convention_c, | ||
| 2150 | /// `std.builtin.CallingConvention.Inline` | ||
| 2151 | calling_convention_inline, | ||
| 2152 | /// Used for generic parameters where the type and value | ||
| 2153 | /// is not known until generic function instantiation. | ||
| 2154 | generic_poison, | ||
| 2155 | /// This is a special type for variadic parameters of a function call. | ||
| 2156 | /// Casts to it will validate that the type can be passed to a c | ||
| 2157 | /// calling convention function. | ||
| 2158 | var_args_param, | ||
| 2159 | |||
| 2160 | _, | 2141 | _, |
| 2161 | |||
| 2162 | pub const typed_value_map = std.enums.directEnumArray(Ref, TypedValue, 0, .{ | ||
| 2163 | .none = undefined, | ||
| 2164 | |||
| 2165 | .u1_type = .{ | ||
| 2166 | .ty = Type.initTag(.type), | ||
| 2167 | .val = Value.initTag(.u1_type), | ||
| 2168 | }, | ||
| 2169 | .u8_type = .{ | ||
| 2170 | .ty = Type.initTag(.type), | ||
| 2171 | .val = Value.initTag(.u8_type), | ||
| 2172 | }, | ||
| 2173 | .i8_type = .{ | ||
| 2174 | .ty = Type.initTag(.type), | ||
| 2175 | .val = Value.initTag(.i8_type), | ||
| 2176 | }, | ||
| 2177 | .u16_type = .{ | ||
| 2178 | .ty = Type.initTag(.type), | ||
| 2179 | .val = Value.initTag(.u16_type), | ||
| 2180 | }, | ||
| 2181 | .i16_type = .{ | ||
| 2182 | .ty = Type.initTag(.type), | ||
| 2183 | .val = Value.initTag(.i16_type), | ||
| 2184 | }, | ||
| 2185 | .u29_type = .{ | ||
| 2186 | .ty = Type.initTag(.type), | ||
| 2187 | .val = Value.initTag(.u29_type), | ||
| 2188 | }, | ||
| 2189 | .u32_type = .{ | ||
| 2190 | .ty = Type.initTag(.type), | ||
| 2191 | .val = Value.initTag(.u32_type), | ||
| 2192 | }, | ||
| 2193 | .i32_type = .{ | ||
| 2194 | .ty = Type.initTag(.type), | ||
| 2195 | .val = Value.initTag(.i32_type), | ||
| 2196 | }, | ||
| 2197 | .u64_type = .{ | ||
| 2198 | .ty = Type.initTag(.type), | ||
| 2199 | .val = Value.initTag(.u64_type), | ||
| 2200 | }, | ||
| 2201 | .i64_type = .{ | ||
| 2202 | .ty = Type.initTag(.type), | ||
| 2203 | .val = Value.initTag(.i64_type), | ||
| 2204 | }, | ||
| 2205 | .u128_type = .{ | ||
| 2206 | .ty = Type.initTag(.type), | ||
| 2207 | .val = Value.initTag(.u128_type), | ||
| 2208 | }, | ||
| 2209 | .i128_type = .{ | ||
| 2210 | .ty = Type.initTag(.type), | ||
| 2211 | .val = Value.initTag(.i128_type), | ||
| 2212 | }, | ||
| 2213 | .usize_type = .{ | ||
| 2214 | .ty = Type.initTag(.type), | ||
| 2215 | .val = Value.initTag(.usize_type), | ||
| 2216 | }, | ||
| 2217 | .isize_type = .{ | ||
| 2218 | .ty = Type.initTag(.type), | ||
| 2219 | .val = Value.initTag(.isize_type), | ||
| 2220 | }, | ||
| 2221 | .c_char_type = .{ | ||
| 2222 | .ty = Type.initTag(.type), | ||
| 2223 | .val = Value.initTag(.c_char_type), | ||
| 2224 | }, | ||
| 2225 | .c_short_type = .{ | ||
| 2226 | .ty = Type.initTag(.type), | ||
| 2227 | .val = Value.initTag(.c_short_type), | ||
| 2228 | }, | ||
| 2229 | .c_ushort_type = .{ | ||
| 2230 | .ty = Type.initTag(.type), | ||
| 2231 | .val = Value.initTag(.c_ushort_type), | ||
| 2232 | }, | ||
| 2233 | .c_int_type = .{ | ||
| 2234 | .ty = Type.initTag(.type), | ||
| 2235 | .val = Value.initTag(.c_int_type), | ||
| 2236 | }, | ||
| 2237 | .c_uint_type = .{ | ||
| 2238 | .ty = Type.initTag(.type), | ||
| 2239 | .val = Value.initTag(.c_uint_type), | ||
| 2240 | }, | ||
| 2241 | .c_long_type = .{ | ||
| 2242 | .ty = Type.initTag(.type), | ||
| 2243 | .val = Value.initTag(.c_long_type), | ||
| 2244 | }, | ||
| 2245 | .c_ulong_type = .{ | ||
| 2246 | .ty = Type.initTag(.type), | ||
| 2247 | .val = Value.initTag(.c_ulong_type), | ||
| 2248 | }, | ||
| 2249 | .c_longlong_type = .{ | ||
| 2250 | .ty = Type.initTag(.type), | ||
| 2251 | .val = Value.initTag(.c_longlong_type), | ||
| 2252 | }, | ||
| 2253 | .c_ulonglong_type = .{ | ||
| 2254 | .ty = Type.initTag(.type), | ||
| 2255 | .val = Value.initTag(.c_ulonglong_type), | ||
| 2256 | }, | ||
| 2257 | .c_longdouble_type = .{ | ||
| 2258 | .ty = Type.initTag(.type), | ||
| 2259 | .val = Value.initTag(.c_longdouble_type), | ||
| 2260 | }, | ||
| 2261 | .f16_type = .{ | ||
| 2262 | .ty = Type.initTag(.type), | ||
| 2263 | .val = Value.initTag(.f16_type), | ||
| 2264 | }, | ||
| 2265 | .f32_type = .{ | ||
| 2266 | .ty = Type.initTag(.type), | ||
| 2267 | .val = Value.initTag(.f32_type), | ||
| 2268 | }, | ||
| 2269 | .f64_type = .{ | ||
| 2270 | .ty = Type.initTag(.type), | ||
| 2271 | .val = Value.initTag(.f64_type), | ||
| 2272 | }, | ||
| 2273 | .f80_type = .{ | ||
| 2274 | .ty = Type.initTag(.type), | ||
| 2275 | .val = Value.initTag(.f80_type), | ||
| 2276 | }, | ||
| 2277 | .f128_type = .{ | ||
| 2278 | .ty = Type.initTag(.type), | ||
| 2279 | .val = Value.initTag(.f128_type), | ||
| 2280 | }, | ||
| 2281 | .anyopaque_type = .{ | ||
| 2282 | .ty = Type.initTag(.type), | ||
| 2283 | .val = Value.initTag(.anyopaque_type), | ||
| 2284 | }, | ||
| 2285 | .bool_type = .{ | ||
| 2286 | .ty = Type.initTag(.type), | ||
| 2287 | .val = Value.initTag(.bool_type), | ||
| 2288 | }, | ||
| 2289 | .void_type = .{ | ||
| 2290 | .ty = Type.initTag(.type), | ||
| 2291 | .val = Value.initTag(.void_type), | ||
| 2292 | }, | ||
| 2293 | .type_type = .{ | ||
| 2294 | .ty = Type.initTag(.type), | ||
| 2295 | .val = Value.initTag(.type_type), | ||
| 2296 | }, | ||
| 2297 | .anyerror_type = .{ | ||
| 2298 | .ty = Type.initTag(.type), | ||
| 2299 | .val = Value.initTag(.anyerror_type), | ||
| 2300 | }, | ||
| 2301 | .comptime_int_type = .{ | ||
| 2302 | .ty = Type.initTag(.type), | ||
| 2303 | .val = Value.initTag(.comptime_int_type), | ||
| 2304 | }, | ||
| 2305 | .comptime_float_type = .{ | ||
| 2306 | .ty = Type.initTag(.type), | ||
| 2307 | .val = Value.initTag(.comptime_float_type), | ||
| 2308 | }, | ||
| 2309 | .noreturn_type = .{ | ||
| 2310 | .ty = Type.initTag(.type), | ||
| 2311 | .val = Value.initTag(.noreturn_type), | ||
| 2312 | }, | ||
| 2313 | .anyframe_type = .{ | ||
| 2314 | .ty = Type.initTag(.type), | ||
| 2315 | .val = Value.initTag(.anyframe_type), | ||
| 2316 | }, | ||
| 2317 | .null_type = .{ | ||
| 2318 | .ty = Type.initTag(.type), | ||
| 2319 | .val = Value.initTag(.null_type), | ||
| 2320 | }, | ||
| 2321 | .undefined_type = .{ | ||
| 2322 | .ty = Type.initTag(.type), | ||
| 2323 | .val = Value.initTag(.undefined_type), | ||
| 2324 | }, | ||
| 2325 | .fn_noreturn_no_args_type = .{ | ||
| 2326 | .ty = Type.initTag(.type), | ||
| 2327 | .val = Value.initTag(.fn_noreturn_no_args_type), | ||
| 2328 | }, | ||
| 2329 | .fn_void_no_args_type = .{ | ||
| 2330 | .ty = Type.initTag(.type), | ||
| 2331 | .val = Value.initTag(.fn_void_no_args_type), | ||
| 2332 | }, | ||
| 2333 | .fn_naked_noreturn_no_args_type = .{ | ||
| 2334 | .ty = Type.initTag(.type), | ||
| 2335 | .val = Value.initTag(.fn_naked_noreturn_no_args_type), | ||
| 2336 | }, | ||
| 2337 | .fn_ccc_void_no_args_type = .{ | ||
| 2338 | .ty = Type.initTag(.type), | ||
| 2339 | .val = Value.initTag(.fn_ccc_void_no_args_type), | ||
| 2340 | }, | ||
| 2341 | .single_const_pointer_to_comptime_int_type = .{ | ||
| 2342 | .ty = Type.initTag(.type), | ||
| 2343 | .val = Value.initTag(.single_const_pointer_to_comptime_int_type), | ||
| 2344 | }, | ||
| 2345 | .const_slice_u8_type = .{ | ||
| 2346 | .ty = Type.initTag(.type), | ||
| 2347 | .val = Value.initTag(.const_slice_u8_type), | ||
| 2348 | }, | ||
| 2349 | .anyerror_void_error_union_type = .{ | ||
| 2350 | .ty = Type.initTag(.type), | ||
| 2351 | .val = Value.initTag(.anyerror_void_error_union_type), | ||
| 2352 | }, | ||
| 2353 | .generic_poison_type = .{ | ||
| 2354 | .ty = Type.initTag(.type), | ||
| 2355 | .val = Value.initTag(.generic_poison_type), | ||
| 2356 | }, | ||
| 2357 | .enum_literal_type = .{ | ||
| 2358 | .ty = Type.initTag(.type), | ||
| 2359 | .val = Value.initTag(.enum_literal_type), | ||
| 2360 | }, | ||
| 2361 | .manyptr_u8_type = .{ | ||
| 2362 | .ty = Type.initTag(.type), | ||
| 2363 | .val = Value.initTag(.manyptr_u8_type), | ||
| 2364 | }, | ||
| 2365 | .manyptr_const_u8_type = .{ | ||
| 2366 | .ty = Type.initTag(.type), | ||
| 2367 | .val = Value.initTag(.manyptr_const_u8_type), | ||
| 2368 | }, | ||
| 2369 | .atomic_order_type = .{ | ||
| 2370 | .ty = Type.initTag(.type), | ||
| 2371 | .val = Value.initTag(.atomic_order_type), | ||
| 2372 | }, | ||
| 2373 | .atomic_rmw_op_type = .{ | ||
| 2374 | .ty = Type.initTag(.type), | ||
| 2375 | .val = Value.initTag(.atomic_rmw_op_type), | ||
| 2376 | }, | ||
| 2377 | .calling_convention_type = .{ | ||
| 2378 | .ty = Type.initTag(.type), | ||
| 2379 | .val = Value.initTag(.calling_convention_type), | ||
| 2380 | }, | ||
| 2381 | .address_space_type = .{ | ||
| 2382 | .ty = Type.initTag(.type), | ||
| 2383 | .val = Value.initTag(.address_space_type), | ||
| 2384 | }, | ||
| 2385 | .float_mode_type = .{ | ||
| 2386 | .ty = Type.initTag(.type), | ||
| 2387 | .val = Value.initTag(.float_mode_type), | ||
| 2388 | }, | ||
| 2389 | .reduce_op_type = .{ | ||
| 2390 | .ty = Type.initTag(.type), | ||
| 2391 | .val = Value.initTag(.reduce_op_type), | ||
| 2392 | }, | ||
| 2393 | .modifier_type = .{ | ||
| 2394 | .ty = Type.initTag(.type), | ||
| 2395 | .val = Value.initTag(.modifier_type), | ||
| 2396 | }, | ||
| 2397 | .prefetch_options_type = .{ | ||
| 2398 | .ty = Type.initTag(.type), | ||
| 2399 | .val = Value.initTag(.prefetch_options_type), | ||
| 2400 | }, | ||
| 2401 | .export_options_type = .{ | ||
| 2402 | .ty = Type.initTag(.type), | ||
| 2403 | .val = Value.initTag(.export_options_type), | ||
| 2404 | }, | ||
| 2405 | .extern_options_type = .{ | ||
| 2406 | .ty = Type.initTag(.type), | ||
| 2407 | .val = Value.initTag(.extern_options_type), | ||
| 2408 | }, | ||
| 2409 | .type_info_type = .{ | ||
| 2410 | .ty = Type.initTag(.type), | ||
| 2411 | .val = Value.initTag(.type_info_type), | ||
| 2412 | }, | ||
| 2413 | |||
| 2414 | .undef = .{ | ||
| 2415 | .ty = Type.initTag(.undefined), | ||
| 2416 | .val = Value.initTag(.undef), | ||
| 2417 | }, | ||
| 2418 | .zero = .{ | ||
| 2419 | .ty = Type.initTag(.comptime_int), | ||
| 2420 | .val = Value.initTag(.zero), | ||
| 2421 | }, | ||
| 2422 | .zero_usize = .{ | ||
| 2423 | .ty = Type.initTag(.usize), | ||
| 2424 | .val = Value.initTag(.zero), | ||
| 2425 | }, | ||
| 2426 | .one = .{ | ||
| 2427 | .ty = Type.initTag(.comptime_int), | ||
| 2428 | .val = Value.initTag(.one), | ||
| 2429 | }, | ||
| 2430 | .one_usize = .{ | ||
| 2431 | .ty = Type.initTag(.usize), | ||
| 2432 | .val = Value.initTag(.one), | ||
| 2433 | }, | ||
| 2434 | .void_value = .{ | ||
| 2435 | .ty = Type.initTag(.void), | ||
| 2436 | .val = Value.initTag(.void_value), | ||
| 2437 | }, | ||
| 2438 | .unreachable_value = .{ | ||
| 2439 | .ty = Type.initTag(.noreturn), | ||
| 2440 | .val = Value.initTag(.unreachable_value), | ||
| 2441 | }, | ||
| 2442 | .null_value = .{ | ||
| 2443 | .ty = Type.initTag(.null), | ||
| 2444 | .val = Value.initTag(.null_value), | ||
| 2445 | }, | ||
| 2446 | .bool_true = .{ | ||
| 2447 | .ty = Type.initTag(.bool), | ||
| 2448 | .val = Value.initTag(.bool_true), | ||
| 2449 | }, | ||
| 2450 | .bool_false = .{ | ||
| 2451 | .ty = Type.initTag(.bool), | ||
| 2452 | .val = Value.initTag(.bool_false), | ||
| 2453 | }, | ||
| 2454 | .empty_struct = .{ | ||
| 2455 | .ty = Type.initTag(.empty_struct_literal), | ||
| 2456 | .val = Value.initTag(.empty_struct_value), | ||
| 2457 | }, | ||
| 2458 | .calling_convention_c = .{ | ||
| 2459 | .ty = Type.initTag(.calling_convention), | ||
| 2460 | .val = .{ .ptr_otherwise = &calling_convention_c_payload.base }, | ||
| 2461 | }, | ||
| 2462 | .calling_convention_inline = .{ | ||
| 2463 | .ty = Type.initTag(.calling_convention), | ||
| 2464 | .val = .{ .ptr_otherwise = &calling_convention_inline_payload.base }, | ||
| 2465 | }, | ||
| 2466 | .generic_poison = .{ | ||
| 2467 | .ty = Type.initTag(.generic_poison), | ||
| 2468 | .val = Value.initTag(.generic_poison), | ||
| 2469 | }, | ||
| 2470 | .var_args_param = undefined, | ||
| 2471 | }); | ||
| 2472 | }; | ||
| 2473 | |||
| 2474 | /// We would like this to be const but `Value` wants a mutable pointer for | ||
| 2475 | /// its payload field. Nothing should mutate this though. | ||
| 2476 | var calling_convention_c_payload: Value.Payload.U32 = .{ | ||
| 2477 | .base = .{ .tag = .enum_field_index }, | ||
| 2478 | .data = @enumToInt(std.builtin.CallingConvention.C), | ||
| 2479 | }; | ||
| 2480 | |||
| 2481 | /// We would like this to be const but `Value` wants a mutable pointer for | ||
| 2482 | /// its payload field. Nothing should mutate this though. | ||
| 2483 | var calling_convention_inline_payload: Value.Payload.U32 = .{ | ||
| 2484 | .base = .{ .tag = .enum_field_index }, | ||
| 2485 | .data = @enumToInt(std.builtin.CallingConvention.Inline), | ||
| 2486 | }; | 2142 | }; |
| 2487 | 2143 | ||
| 2488 | /// All instructions have an 8-byte payload, which is contained within | 2144 | /// All instructions have an 8-byte payload, which is contained within |
| ... | @@ -4163,13 +3819,14 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { | ... | @@ -4163,13 +3819,14 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { |
| 4163 | }; | 3819 | }; |
| 4164 | } | 3820 | } |
| 4165 | 3821 | ||
| 4166 | const ref_start_index: u32 = Inst.Ref.typed_value_map.len; | 3822 | pub const ref_start_index: u32 = InternPool.static_len; |
| 4167 | 3823 | ||
| 4168 | pub fn indexToRef(inst: Inst.Index) Inst.Ref { | 3824 | pub fn indexToRef(inst: Inst.Index) Inst.Ref { |
| 4169 | return @intToEnum(Inst.Ref, ref_start_index + inst); | 3825 | return @intToEnum(Inst.Ref, ref_start_index + inst); |
| 4170 | } | 3826 | } |
| 4171 | 3827 | ||
| 4172 | pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { | 3828 | pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { |
| 3829 | assert(inst != .none); | ||
| 4173 | const ref_int = @enumToInt(inst); | 3830 | const ref_int = @enumToInt(inst); |
| 4174 | if (ref_int >= ref_start_index) { | 3831 | if (ref_int >= ref_start_index) { |
| 4175 | return ref_int - ref_start_index; | 3832 | return ref_int - ref_start_index; |
| ... | @@ -4177,3 +3834,8 @@ pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { | ... | @@ -4177,3 +3834,8 @@ pub fn refToIndex(inst: Inst.Ref) ?Inst.Index { |
| 4177 | return null; | 3834 | return null; |
| 4178 | } | 3835 | } |
| 4179 | } | 3836 | } |
| 3837 | |||
| 3838 | pub fn refToIndexAllowNone(inst: Inst.Ref) ?Inst.Index { | ||
| 3839 | if (inst == .none) return null; | ||
| 3840 | return refToIndex(inst); | ||
| 3841 | } |
src/arch/aarch64/CodeGen.zig+372-350| ... | @@ -328,7 +328,7 @@ const Self = @This(); | ... | @@ -328,7 +328,7 @@ const Self = @This(); |
| 328 | pub fn generate( | 328 | pub fn generate( |
| 329 | bin_file: *link.File, | 329 | bin_file: *link.File, |
| 330 | src_loc: Module.SrcLoc, | 330 | src_loc: Module.SrcLoc, |
| 331 | module_fn: *Module.Fn, | 331 | module_fn_index: Module.Fn.Index, |
| 332 | air: Air, | 332 | air: Air, |
| 333 | liveness: Liveness, | 333 | liveness: Liveness, |
| 334 | code: *std.ArrayList(u8), | 334 | code: *std.ArrayList(u8), |
| ... | @@ -339,6 +339,7 @@ pub fn generate( | ... | @@ -339,6 +339,7 @@ pub fn generate( |
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | const mod = bin_file.options.module.?; | 341 | const mod = bin_file.options.module.?; |
| 342 | const module_fn = mod.funcPtr(module_fn_index); | ||
| 342 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); | 343 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 343 | assert(fn_owner_decl.has_tv); | 344 | assert(fn_owner_decl.has_tv); |
| 344 | const fn_type = fn_owner_decl.ty; | 345 | const fn_type = fn_owner_decl.ty; |
| ... | @@ -471,7 +472,8 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { | ... | @@ -471,7 +472,8 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 471 | } | 472 | } |
| 472 | 473 | ||
| 473 | fn gen(self: *Self) !void { | 474 | fn gen(self: *Self) !void { |
| 474 | const cc = self.fn_type.fnCallingConvention(); | 475 | const mod = self.bin_file.options.module.?; |
| 476 | const cc = self.fn_type.fnCallingConvention(mod); | ||
| 475 | if (cc != .Naked) { | 477 | if (cc != .Naked) { |
| 476 | // stp fp, lr, [sp, #-16]! | 478 | // stp fp, lr, [sp, #-16]! |
| 477 | _ = try self.addInst(.{ | 479 | _ = try self.addInst(.{ |
| ... | @@ -520,10 +522,10 @@ fn gen(self: *Self) !void { | ... | @@ -520,10 +522,10 @@ fn gen(self: *Self) !void { |
| 520 | const inst = self.air.getMainBody()[arg_index]; | 522 | const inst = self.air.getMainBody()[arg_index]; |
| 521 | assert(self.air.instructions.items(.tag)[inst] == .arg); | 523 | assert(self.air.instructions.items(.tag)[inst] == .arg); |
| 522 | 524 | ||
| 523 | const ty = self.air.typeOfIndex(inst); | 525 | const ty = self.typeOfIndex(inst); |
| 524 | 526 | ||
| 525 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 527 | const abi_size = @intCast(u32, ty.abiSize(mod)); |
| 526 | const abi_align = ty.abiAlignment(self.target.*); | 528 | const abi_align = ty.abiAlignment(mod); |
| 527 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); | 529 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| 528 | try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 530 | try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 529 | 531 | ||
| ... | @@ -652,13 +654,14 @@ fn gen(self: *Self) !void { | ... | @@ -652,13 +654,14 @@ fn gen(self: *Self) !void { |
| 652 | } | 654 | } |
| 653 | 655 | ||
| 654 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | 656 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 657 | const mod = self.bin_file.options.module.?; | ||
| 658 | const ip = &mod.intern_pool; | ||
| 655 | const air_tags = self.air.instructions.items(.tag); | 659 | const air_tags = self.air.instructions.items(.tag); |
| 656 | 660 | ||
| 657 | for (body) |inst| { | 661 | for (body) |inst| { |
| 658 | // TODO: remove now-redundant isUnused calls from AIR handler functions | 662 | // TODO: remove now-redundant isUnused calls from AIR handler functions |
| 659 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) { | 663 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) |
| 660 | continue; | 664 | continue; |
| 661 | } | ||
| 662 | 665 | ||
| 663 | const old_air_bookkeeping = self.air_bookkeeping; | 666 | const old_air_bookkeeping = self.air_bookkeeping; |
| 664 | try self.ensureProcessDeathCapacity(Liveness.bpi); | 667 | try self.ensureProcessDeathCapacity(Liveness.bpi); |
| ... | @@ -842,8 +845,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -842,8 +845,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 842 | .ptr_elem_val => try self.airPtrElemVal(inst), | 845 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 843 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), | 846 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 844 | 847 | ||
| 845 | .constant => unreachable, // excluded from function bodies | 848 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, |
| 846 | .const_ty => unreachable, // excluded from function bodies | ||
| 847 | .unreach => self.finishAirBookkeeping(), | 849 | .unreach => self.finishAirBookkeeping(), |
| 848 | 850 | ||
| 849 | .optional_payload => try self.airOptionalPayload(inst), | 851 | .optional_payload => try self.airOptionalPayload(inst), |
| ... | @@ -916,8 +918,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -916,8 +918,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 916 | 918 | ||
| 917 | /// Asserts there is already capacity to insert into top branch inst_table. | 919 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 918 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { | 920 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 919 | const air_tags = self.air.instructions.items(.tag); | 921 | assert(self.air.instructions.items(.tag)[inst] != .interned); |
| 920 | if (air_tags[inst] == .constant) return; // Constants are immortal. | ||
| 921 | // When editing this function, note that the logic must synchronize with `reuseOperand`. | 922 | // When editing this function, note that the logic must synchronize with `reuseOperand`. |
| 922 | const prev_value = self.getResolvedInstValue(inst); | 923 | const prev_value = self.getResolvedInstValue(inst); |
| 923 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 924 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | @@ -951,8 +952,8 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -951,8 +952,8 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 951 | tomb_bits >>= 1; | 952 | tomb_bits >>= 1; |
| 952 | if (!dies) continue; | 953 | if (!dies) continue; |
| 953 | const op_int = @enumToInt(op); | 954 | const op_int = @enumToInt(op); |
| 954 | if (op_int < Air.Inst.Ref.typed_value_map.len) continue; | 955 | if (op_int < Air.ref_start_index) continue; |
| 955 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | 956 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); |
| 956 | self.processDeath(op_index); | 957 | self.processDeath(op_index); |
| 957 | } | 958 | } |
| 958 | const is_used = @truncate(u1, tomb_bits) == 0; | 959 | const is_used = @truncate(u1, tomb_bits) == 0; |
| ... | @@ -1026,31 +1027,31 @@ fn allocMem( | ... | @@ -1026,31 +1027,31 @@ fn allocMem( |
| 1026 | 1027 | ||
| 1027 | /// Use a pointer instruction as the basis for allocating stack memory. | 1028 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 1028 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | 1029 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 1029 | const elem_ty = self.air.typeOfIndex(inst).elemType(); | 1030 | const mod = self.bin_file.options.module.?; |
| 1031 | const elem_ty = self.typeOfIndex(inst).childType(mod); | ||
| 1030 | 1032 | ||
| 1031 | if (!elem_ty.hasRuntimeBits()) { | 1033 | if (!elem_ty.hasRuntimeBits(mod)) { |
| 1032 | // return the stack offset 0. Stack offset 0 will be where all | 1034 | // return the stack offset 0. Stack offset 0 will be where all |
| 1033 | // zero-sized stack allocations live as non-zero-sized | 1035 | // zero-sized stack allocations live as non-zero-sized |
| 1034 | // allocations will always have an offset > 0. | 1036 | // allocations will always have an offset > 0. |
| 1035 | return @as(u32, 0); | 1037 | return @as(u32, 0); |
| 1036 | } | 1038 | } |
| 1037 | 1039 | ||
| 1038 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | 1040 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { |
| 1039 | const mod = self.bin_file.options.module.?; | ||
| 1040 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 1041 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 1041 | }; | 1042 | }; |
| 1042 | // TODO swap this for inst.ty.ptrAlign | 1043 | // TODO swap this for inst.ty.ptrAlign |
| 1043 | const abi_align = elem_ty.abiAlignment(self.target.*); | 1044 | const abi_align = elem_ty.abiAlignment(mod); |
| 1044 | 1045 | ||
| 1045 | return self.allocMem(abi_size, abi_align, inst); | 1046 | return self.allocMem(abi_size, abi_align, inst); |
| 1046 | } | 1047 | } |
| 1047 | 1048 | ||
| 1048 | fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue { | 1049 | fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue { |
| 1049 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | 1050 | const mod = self.bin_file.options.module.?; |
| 1050 | const mod = self.bin_file.options.module.?; | 1051 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { |
| 1051 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 1052 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 1052 | }; | 1053 | }; |
| 1053 | const abi_align = elem_ty.abiAlignment(self.target.*); | 1054 | const abi_align = elem_ty.abiAlignment(mod); |
| 1054 | 1055 | ||
| 1055 | if (reg_ok) { | 1056 | if (reg_ok) { |
| 1056 | // Make sure the type can fit in a register before we try to allocate one. | 1057 | // Make sure the type can fit in a register before we try to allocate one. |
| ... | @@ -1066,7 +1067,7 @@ fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst | ... | @@ -1066,7 +1067,7 @@ fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst |
| 1066 | } | 1067 | } |
| 1067 | 1068 | ||
| 1068 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { | 1069 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 1069 | const stack_mcv = try self.allocRegOrMem(self.air.typeOfIndex(inst), false, inst); | 1070 | const stack_mcv = try self.allocRegOrMem(self.typeOfIndex(inst), false, inst); |
| 1070 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); | 1071 | log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); |
| 1071 | 1072 | ||
| 1072 | const reg_mcv = self.getResolvedInstValue(inst); | 1073 | const reg_mcv = self.getResolvedInstValue(inst); |
| ... | @@ -1078,14 +1079,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -1078,14 +1079,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 1078 | 1079 | ||
| 1079 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 1080 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1080 | try branch.inst_table.put(self.gpa, inst, stack_mcv); | 1081 | try branch.inst_table.put(self.gpa, inst, stack_mcv); |
| 1081 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); | 1082 | try self.genSetStack(self.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); |
| 1082 | } | 1083 | } |
| 1083 | 1084 | ||
| 1084 | /// Save the current instruction stored in the compare flags if | 1085 | /// Save the current instruction stored in the compare flags if |
| 1085 | /// occupied | 1086 | /// occupied |
| 1086 | fn spillCompareFlagsIfOccupied(self: *Self) !void { | 1087 | fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 1087 | if (self.compare_flags_inst) |inst_to_save| { | 1088 | if (self.compare_flags_inst) |inst_to_save| { |
| 1088 | const ty = self.air.typeOfIndex(inst_to_save); | 1089 | const ty = self.typeOfIndex(inst_to_save); |
| 1089 | const mcv = self.getResolvedInstValue(inst_to_save); | 1090 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 1090 | const new_mcv = switch (mcv) { | 1091 | const new_mcv = switch (mcv) { |
| 1091 | .compare_flags => try self.allocRegOrMem(ty, true, inst_to_save), | 1092 | .compare_flags => try self.allocRegOrMem(ty, true, inst_to_save), |
| ... | @@ -1093,7 +1094,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { | ... | @@ -1093,7 +1094,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 1093 | else => unreachable, // mcv doesn't occupy the compare flags | 1094 | else => unreachable, // mcv doesn't occupy the compare flags |
| 1094 | }; | 1095 | }; |
| 1095 | 1096 | ||
| 1096 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); | 1097 | try self.setRegOrMem(self.typeOfIndex(inst_to_save), new_mcv, mcv); |
| 1097 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); | 1098 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); |
| 1098 | 1099 | ||
| 1099 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 1100 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | @@ -1125,9 +1126,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | ... | @@ -1125,9 +1126,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 1125 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 1126 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 1126 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 1127 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { |
| 1127 | const raw_reg = try self.register_manager.allocReg(reg_owner, gp); | 1128 | const raw_reg = try self.register_manager.allocReg(reg_owner, gp); |
| 1128 | const ty = self.air.typeOfIndex(reg_owner); | 1129 | const ty = self.typeOfIndex(reg_owner); |
| 1129 | const reg = self.registerAlias(raw_reg, ty); | 1130 | const reg = self.registerAlias(raw_reg, ty); |
| 1130 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); | 1131 | try self.genSetReg(self.typeOfIndex(reg_owner), reg, mcv); |
| 1131 | return MCValue{ .register = reg }; | 1132 | return MCValue{ .register = reg }; |
| 1132 | } | 1133 | } |
| 1133 | 1134 | ||
| ... | @@ -1137,17 +1138,14 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1137,17 +1138,14 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 1137 | } | 1138 | } |
| 1138 | 1139 | ||
| 1139 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { | 1140 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1141 | const mod = self.bin_file.options.module.?; | ||
| 1140 | const result: MCValue = switch (self.ret_mcv) { | 1142 | const result: MCValue = switch (self.ret_mcv) { |
| 1141 | .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) }, | 1143 | .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) }, |
| 1142 | .stack_offset => blk: { | 1144 | .stack_offset => blk: { |
| 1143 | // self.ret_mcv is an address to where this function | 1145 | // self.ret_mcv is an address to where this function |
| 1144 | // should store its result into | 1146 | // should store its result into |
| 1145 | const ret_ty = self.fn_type.fnReturnType(); | 1147 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 1146 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 1148 | const ptr_ty = try mod.singleMutPtrType(ret_ty); |
| 1147 | .base = .{ .tag = .single_mut_pointer }, | ||
| 1148 | .data = ret_ty, | ||
| 1149 | }; | ||
| 1150 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 1151 | 1149 | ||
| 1152 | // addr_reg will contain the address of where to store the | 1150 | // addr_reg will contain the address of where to store the |
| 1153 | // result into | 1151 | // result into |
| ... | @@ -1177,13 +1175,14 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1177,13 +1175,14 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1177 | if (self.liveness.isUnused(inst)) | 1175 | if (self.liveness.isUnused(inst)) |
| 1178 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | 1176 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1179 | 1177 | ||
| 1178 | const mod = self.bin_file.options.module.?; | ||
| 1180 | const operand = ty_op.operand; | 1179 | const operand = ty_op.operand; |
| 1181 | const operand_mcv = try self.resolveInst(operand); | 1180 | const operand_mcv = try self.resolveInst(operand); |
| 1182 | const operand_ty = self.air.typeOf(operand); | 1181 | const operand_ty = self.typeOf(operand); |
| 1183 | const operand_info = operand_ty.intInfo(self.target.*); | 1182 | const operand_info = operand_ty.intInfo(mod); |
| 1184 | 1183 | ||
| 1185 | const dest_ty = self.air.typeOfIndex(inst); | 1184 | const dest_ty = self.typeOfIndex(inst); |
| 1186 | const dest_info = dest_ty.intInfo(self.target.*); | 1185 | const dest_info = dest_ty.intInfo(mod); |
| 1187 | 1186 | ||
| 1188 | const result: MCValue = result: { | 1187 | const result: MCValue = result: { |
| 1189 | const operand_lock: ?RegisterLock = switch (operand_mcv) { | 1188 | const operand_lock: ?RegisterLock = switch (operand_mcv) { |
| ... | @@ -1199,14 +1198,14 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1199,14 +1198,14 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1199 | 1198 | ||
| 1200 | if (dest_info.bits > operand_info.bits) { | 1199 | if (dest_info.bits > operand_info.bits) { |
| 1201 | const dest_mcv = try self.allocRegOrMem(dest_ty, true, inst); | 1200 | const dest_mcv = try self.allocRegOrMem(dest_ty, true, inst); |
| 1202 | try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated); | 1201 | try self.setRegOrMem(self.typeOfIndex(inst), dest_mcv, truncated); |
| 1203 | break :result dest_mcv; | 1202 | break :result dest_mcv; |
| 1204 | } else { | 1203 | } else { |
| 1205 | if (self.reuseOperand(inst, operand, 0, truncated)) { | 1204 | if (self.reuseOperand(inst, operand, 0, truncated)) { |
| 1206 | break :result truncated; | 1205 | break :result truncated; |
| 1207 | } else { | 1206 | } else { |
| 1208 | const dest_mcv = try self.allocRegOrMem(dest_ty, true, inst); | 1207 | const dest_mcv = try self.allocRegOrMem(dest_ty, true, inst); |
| 1209 | try self.setRegOrMem(self.air.typeOfIndex(inst), dest_mcv, truncated); | 1208 | try self.setRegOrMem(self.typeOfIndex(inst), dest_mcv, truncated); |
| 1210 | break :result dest_mcv; | 1209 | break :result dest_mcv; |
| 1211 | } | 1210 | } |
| 1212 | } | 1211 | } |
| ... | @@ -1257,8 +1256,9 @@ fn trunc( | ... | @@ -1257,8 +1256,9 @@ fn trunc( |
| 1257 | operand_ty: Type, | 1256 | operand_ty: Type, |
| 1258 | dest_ty: Type, | 1257 | dest_ty: Type, |
| 1259 | ) !MCValue { | 1258 | ) !MCValue { |
| 1260 | const info_a = operand_ty.intInfo(self.target.*); | 1259 | const mod = self.bin_file.options.module.?; |
| 1261 | const info_b = dest_ty.intInfo(self.target.*); | 1260 | const info_a = operand_ty.intInfo(mod); |
| 1261 | const info_b = dest_ty.intInfo(mod); | ||
| 1262 | 1262 | ||
| 1263 | if (info_b.bits <= 64) { | 1263 | if (info_b.bits <= 64) { |
| 1264 | const operand_reg = switch (operand) { | 1264 | const operand_reg = switch (operand) { |
| ... | @@ -1300,8 +1300,8 @@ fn trunc( | ... | @@ -1300,8 +1300,8 @@ fn trunc( |
| 1300 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 1300 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1301 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1301 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1302 | const operand = try self.resolveInst(ty_op.operand); | 1302 | const operand = try self.resolveInst(ty_op.operand); |
| 1303 | const operand_ty = self.air.typeOf(ty_op.operand); | 1303 | const operand_ty = self.typeOf(ty_op.operand); |
| 1304 | const dest_ty = self.air.typeOfIndex(inst); | 1304 | const dest_ty = self.typeOfIndex(inst); |
| 1305 | 1305 | ||
| 1306 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { | 1306 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 1307 | break :blk try self.trunc(inst, operand, operand_ty, dest_ty); | 1307 | break :blk try self.trunc(inst, operand, operand_ty, dest_ty); |
| ... | @@ -1319,15 +1319,16 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1319,15 +1319,16 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 1319 | 1319 | ||
| 1320 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { | 1320 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1321 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1321 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1322 | const mod = self.bin_file.options.module.?; | ||
| 1322 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1323 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1323 | const operand = try self.resolveInst(ty_op.operand); | 1324 | const operand = try self.resolveInst(ty_op.operand); |
| 1324 | const operand_ty = self.air.typeOf(ty_op.operand); | 1325 | const operand_ty = self.typeOf(ty_op.operand); |
| 1325 | switch (operand) { | 1326 | switch (operand) { |
| 1326 | .dead => unreachable, | 1327 | .dead => unreachable, |
| 1327 | .unreach => unreachable, | 1328 | .unreach => unreachable, |
| 1328 | .compare_flags => |cond| break :result MCValue{ .compare_flags = cond.negate() }, | 1329 | .compare_flags => |cond| break :result MCValue{ .compare_flags = cond.negate() }, |
| 1329 | else => { | 1330 | else => { |
| 1330 | switch (operand_ty.zigTypeTag()) { | 1331 | switch (operand_ty.zigTypeTag(mod)) { |
| 1331 | .Bool => { | 1332 | .Bool => { |
| 1332 | // TODO convert this to mvn + and | 1333 | // TODO convert this to mvn + and |
| 1333 | const op_reg = switch (operand) { | 1334 | const op_reg = switch (operand) { |
| ... | @@ -1361,7 +1362,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1361,7 +1362,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1361 | }, | 1362 | }, |
| 1362 | .Vector => return self.fail("TODO bitwise not for vectors", .{}), | 1363 | .Vector => return self.fail("TODO bitwise not for vectors", .{}), |
| 1363 | .Int => { | 1364 | .Int => { |
| 1364 | const int_info = operand_ty.intInfo(self.target.*); | 1365 | const int_info = operand_ty.intInfo(mod); |
| 1365 | if (int_info.bits <= 64) { | 1366 | if (int_info.bits <= 64) { |
| 1366 | const op_reg = switch (operand) { | 1367 | const op_reg = switch (operand) { |
| 1367 | .register => |r| r, | 1368 | .register => |r| r, |
| ... | @@ -1413,13 +1414,13 @@ fn minMax( | ... | @@ -1413,13 +1414,13 @@ fn minMax( |
| 1413 | rhs_ty: Type, | 1414 | rhs_ty: Type, |
| 1414 | maybe_inst: ?Air.Inst.Index, | 1415 | maybe_inst: ?Air.Inst.Index, |
| 1415 | ) !MCValue { | 1416 | ) !MCValue { |
| 1416 | switch (lhs_ty.zigTypeTag()) { | 1417 | const mod = self.bin_file.options.module.?; |
| 1418 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 1417 | .Float => return self.fail("TODO ARM min/max on floats", .{}), | 1419 | .Float => return self.fail("TODO ARM min/max on floats", .{}), |
| 1418 | .Vector => return self.fail("TODO ARM min/max on vectors", .{}), | 1420 | .Vector => return self.fail("TODO ARM min/max on vectors", .{}), |
| 1419 | .Int => { | 1421 | .Int => { |
| 1420 | const mod = self.bin_file.options.module.?; | ||
| 1421 | assert(lhs_ty.eql(rhs_ty, mod)); | 1422 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1422 | const int_info = lhs_ty.intInfo(self.target.*); | 1423 | const int_info = lhs_ty.intInfo(mod); |
| 1423 | if (int_info.bits <= 64) { | 1424 | if (int_info.bits <= 64) { |
| 1424 | var lhs_reg: Register = undefined; | 1425 | var lhs_reg: Register = undefined; |
| 1425 | var rhs_reg: Register = undefined; | 1426 | var rhs_reg: Register = undefined; |
| ... | @@ -1488,8 +1489,8 @@ fn minMax( | ... | @@ -1488,8 +1489,8 @@ fn minMax( |
| 1488 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { | 1489 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1489 | const tag = self.air.instructions.items(.tag)[inst]; | 1490 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1490 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1491 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1491 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1492 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1492 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1493 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1493 | 1494 | ||
| 1494 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1495 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1495 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; | 1496 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| ... | @@ -1508,9 +1509,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1508,9 +1509,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1508 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1509 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1509 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1510 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1510 | const ptr = try self.resolveInst(bin_op.lhs); | 1511 | const ptr = try self.resolveInst(bin_op.lhs); |
| 1511 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 1512 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 1512 | const len = try self.resolveInst(bin_op.rhs); | 1513 | const len = try self.resolveInst(bin_op.rhs); |
| 1513 | const len_ty = self.air.typeOf(bin_op.rhs); | 1514 | const len_ty = self.typeOf(bin_op.rhs); |
| 1514 | 1515 | ||
| 1515 | const ptr_bits = self.target.ptrBitWidth(); | 1516 | const ptr_bits = self.target.ptrBitWidth(); |
| 1516 | const ptr_bytes = @divExact(ptr_bits, 8); | 1517 | const ptr_bytes = @divExact(ptr_bits, 8); |
| ... | @@ -1907,12 +1908,12 @@ fn addSub( | ... | @@ -1907,12 +1908,12 @@ fn addSub( |
| 1907 | maybe_inst: ?Air.Inst.Index, | 1908 | maybe_inst: ?Air.Inst.Index, |
| 1908 | ) InnerError!MCValue { | 1909 | ) InnerError!MCValue { |
| 1909 | const mod = self.bin_file.options.module.?; | 1910 | const mod = self.bin_file.options.module.?; |
| 1910 | switch (lhs_ty.zigTypeTag()) { | 1911 | switch (lhs_ty.zigTypeTag(mod)) { |
| 1911 | .Float => return self.fail("TODO binary operations on floats", .{}), | 1912 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| 1912 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 1913 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 1913 | .Int => { | 1914 | .Int => { |
| 1914 | assert(lhs_ty.eql(rhs_ty, mod)); | 1915 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1915 | const int_info = lhs_ty.intInfo(self.target.*); | 1916 | const int_info = lhs_ty.intInfo(mod); |
| 1916 | if (int_info.bits <= 64) { | 1917 | if (int_info.bits <= 64) { |
| 1917 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); | 1918 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 1918 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); | 1919 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| ... | @@ -1968,11 +1969,11 @@ fn mul( | ... | @@ -1968,11 +1969,11 @@ fn mul( |
| 1968 | maybe_inst: ?Air.Inst.Index, | 1969 | maybe_inst: ?Air.Inst.Index, |
| 1969 | ) InnerError!MCValue { | 1970 | ) InnerError!MCValue { |
| 1970 | const mod = self.bin_file.options.module.?; | 1971 | const mod = self.bin_file.options.module.?; |
| 1971 | switch (lhs_ty.zigTypeTag()) { | 1972 | switch (lhs_ty.zigTypeTag(mod)) { |
| 1972 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 1973 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 1973 | .Int => { | 1974 | .Int => { |
| 1974 | assert(lhs_ty.eql(rhs_ty, mod)); | 1975 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1975 | const int_info = lhs_ty.intInfo(self.target.*); | 1976 | const int_info = lhs_ty.intInfo(mod); |
| 1976 | if (int_info.bits <= 64) { | 1977 | if (int_info.bits <= 64) { |
| 1977 | // TODO add optimisations for multiplication | 1978 | // TODO add optimisations for multiplication |
| 1978 | // with immediates, for example a * 2 can be | 1979 | // with immediates, for example a * 2 can be |
| ... | @@ -1999,7 +2000,8 @@ fn divFloat( | ... | @@ -1999,7 +2000,8 @@ fn divFloat( |
| 1999 | _ = rhs_ty; | 2000 | _ = rhs_ty; |
| 2000 | _ = maybe_inst; | 2001 | _ = maybe_inst; |
| 2001 | 2002 | ||
| 2002 | switch (lhs_ty.zigTypeTag()) { | 2003 | const mod = self.bin_file.options.module.?; |
| 2004 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 2003 | .Float => return self.fail("TODO div_float", .{}), | 2005 | .Float => return self.fail("TODO div_float", .{}), |
| 2004 | .Vector => return self.fail("TODO div_float on vectors", .{}), | 2006 | .Vector => return self.fail("TODO div_float on vectors", .{}), |
| 2005 | else => unreachable, | 2007 | else => unreachable, |
| ... | @@ -2015,12 +2017,12 @@ fn divTrunc( | ... | @@ -2015,12 +2017,12 @@ fn divTrunc( |
| 2015 | maybe_inst: ?Air.Inst.Index, | 2017 | maybe_inst: ?Air.Inst.Index, |
| 2016 | ) InnerError!MCValue { | 2018 | ) InnerError!MCValue { |
| 2017 | const mod = self.bin_file.options.module.?; | 2019 | const mod = self.bin_file.options.module.?; |
| 2018 | switch (lhs_ty.zigTypeTag()) { | 2020 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2019 | .Float => return self.fail("TODO div on floats", .{}), | 2021 | .Float => return self.fail("TODO div on floats", .{}), |
| 2020 | .Vector => return self.fail("TODO div on vectors", .{}), | 2022 | .Vector => return self.fail("TODO div on vectors", .{}), |
| 2021 | .Int => { | 2023 | .Int => { |
| 2022 | assert(lhs_ty.eql(rhs_ty, mod)); | 2024 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2023 | const int_info = lhs_ty.intInfo(self.target.*); | 2025 | const int_info = lhs_ty.intInfo(mod); |
| 2024 | if (int_info.bits <= 64) { | 2026 | if (int_info.bits <= 64) { |
| 2025 | switch (int_info.signedness) { | 2027 | switch (int_info.signedness) { |
| 2026 | .signed => { | 2028 | .signed => { |
| ... | @@ -2049,12 +2051,12 @@ fn divFloor( | ... | @@ -2049,12 +2051,12 @@ fn divFloor( |
| 2049 | maybe_inst: ?Air.Inst.Index, | 2051 | maybe_inst: ?Air.Inst.Index, |
| 2050 | ) InnerError!MCValue { | 2052 | ) InnerError!MCValue { |
| 2051 | const mod = self.bin_file.options.module.?; | 2053 | const mod = self.bin_file.options.module.?; |
| 2052 | switch (lhs_ty.zigTypeTag()) { | 2054 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2053 | .Float => return self.fail("TODO div on floats", .{}), | 2055 | .Float => return self.fail("TODO div on floats", .{}), |
| 2054 | .Vector => return self.fail("TODO div on vectors", .{}), | 2056 | .Vector => return self.fail("TODO div on vectors", .{}), |
| 2055 | .Int => { | 2057 | .Int => { |
| 2056 | assert(lhs_ty.eql(rhs_ty, mod)); | 2058 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2057 | const int_info = lhs_ty.intInfo(self.target.*); | 2059 | const int_info = lhs_ty.intInfo(mod); |
| 2058 | if (int_info.bits <= 64) { | 2060 | if (int_info.bits <= 64) { |
| 2059 | switch (int_info.signedness) { | 2061 | switch (int_info.signedness) { |
| 2060 | .signed => { | 2062 | .signed => { |
| ... | @@ -2082,12 +2084,12 @@ fn divExact( | ... | @@ -2082,12 +2084,12 @@ fn divExact( |
| 2082 | maybe_inst: ?Air.Inst.Index, | 2084 | maybe_inst: ?Air.Inst.Index, |
| 2083 | ) InnerError!MCValue { | 2085 | ) InnerError!MCValue { |
| 2084 | const mod = self.bin_file.options.module.?; | 2086 | const mod = self.bin_file.options.module.?; |
| 2085 | switch (lhs_ty.zigTypeTag()) { | 2087 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2086 | .Float => return self.fail("TODO div on floats", .{}), | 2088 | .Float => return self.fail("TODO div on floats", .{}), |
| 2087 | .Vector => return self.fail("TODO div on vectors", .{}), | 2089 | .Vector => return self.fail("TODO div on vectors", .{}), |
| 2088 | .Int => { | 2090 | .Int => { |
| 2089 | assert(lhs_ty.eql(rhs_ty, mod)); | 2091 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2090 | const int_info = lhs_ty.intInfo(self.target.*); | 2092 | const int_info = lhs_ty.intInfo(mod); |
| 2091 | if (int_info.bits <= 64) { | 2093 | if (int_info.bits <= 64) { |
| 2092 | switch (int_info.signedness) { | 2094 | switch (int_info.signedness) { |
| 2093 | .signed => { | 2095 | .signed => { |
| ... | @@ -2118,12 +2120,12 @@ fn rem( | ... | @@ -2118,12 +2120,12 @@ fn rem( |
| 2118 | _ = maybe_inst; | 2120 | _ = maybe_inst; |
| 2119 | 2121 | ||
| 2120 | const mod = self.bin_file.options.module.?; | 2122 | const mod = self.bin_file.options.module.?; |
| 2121 | switch (lhs_ty.zigTypeTag()) { | 2123 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2122 | .Float => return self.fail("TODO rem/mod on floats", .{}), | 2124 | .Float => return self.fail("TODO rem/mod on floats", .{}), |
| 2123 | .Vector => return self.fail("TODO rem/mod on vectors", .{}), | 2125 | .Vector => return self.fail("TODO rem/mod on vectors", .{}), |
| 2124 | .Int => { | 2126 | .Int => { |
| 2125 | assert(lhs_ty.eql(rhs_ty, mod)); | 2127 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2126 | const int_info = lhs_ty.intInfo(self.target.*); | 2128 | const int_info = lhs_ty.intInfo(mod); |
| 2127 | if (int_info.bits <= 64) { | 2129 | if (int_info.bits <= 64) { |
| 2128 | var lhs_reg: Register = undefined; | 2130 | var lhs_reg: Register = undefined; |
| 2129 | var rhs_reg: Register = undefined; | 2131 | var rhs_reg: Register = undefined; |
| ... | @@ -2188,7 +2190,8 @@ fn modulo( | ... | @@ -2188,7 +2190,8 @@ fn modulo( |
| 2188 | _ = rhs_ty; | 2190 | _ = rhs_ty; |
| 2189 | _ = maybe_inst; | 2191 | _ = maybe_inst; |
| 2190 | 2192 | ||
| 2191 | switch (lhs_ty.zigTypeTag()) { | 2193 | const mod = self.bin_file.options.module.?; |
| 2194 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 2192 | .Float => return self.fail("TODO mod on floats", .{}), | 2195 | .Float => return self.fail("TODO mod on floats", .{}), |
| 2193 | .Vector => return self.fail("TODO mod on vectors", .{}), | 2196 | .Vector => return self.fail("TODO mod on vectors", .{}), |
| 2194 | .Int => return self.fail("TODO mod on ints", .{}), | 2197 | .Int => return self.fail("TODO mod on ints", .{}), |
| ... | @@ -2205,10 +2208,11 @@ fn wrappingArithmetic( | ... | @@ -2205,10 +2208,11 @@ fn wrappingArithmetic( |
| 2205 | rhs_ty: Type, | 2208 | rhs_ty: Type, |
| 2206 | maybe_inst: ?Air.Inst.Index, | 2209 | maybe_inst: ?Air.Inst.Index, |
| 2207 | ) InnerError!MCValue { | 2210 | ) InnerError!MCValue { |
| 2208 | switch (lhs_ty.zigTypeTag()) { | 2211 | const mod = self.bin_file.options.module.?; |
| 2212 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 2209 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2213 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2210 | .Int => { | 2214 | .Int => { |
| 2211 | const int_info = lhs_ty.intInfo(self.target.*); | 2215 | const int_info = lhs_ty.intInfo(mod); |
| 2212 | if (int_info.bits <= 64) { | 2216 | if (int_info.bits <= 64) { |
| 2213 | // Generate an add/sub/mul | 2217 | // Generate an add/sub/mul |
| 2214 | const result: MCValue = switch (tag) { | 2218 | const result: MCValue = switch (tag) { |
| ... | @@ -2240,11 +2244,11 @@ fn bitwise( | ... | @@ -2240,11 +2244,11 @@ fn bitwise( |
| 2240 | maybe_inst: ?Air.Inst.Index, | 2244 | maybe_inst: ?Air.Inst.Index, |
| 2241 | ) InnerError!MCValue { | 2245 | ) InnerError!MCValue { |
| 2242 | const mod = self.bin_file.options.module.?; | 2246 | const mod = self.bin_file.options.module.?; |
| 2243 | switch (lhs_ty.zigTypeTag()) { | 2247 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2244 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2248 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2245 | .Int => { | 2249 | .Int => { |
| 2246 | assert(lhs_ty.eql(rhs_ty, mod)); | 2250 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2247 | const int_info = lhs_ty.intInfo(self.target.*); | 2251 | const int_info = lhs_ty.intInfo(mod); |
| 2248 | if (int_info.bits <= 64) { | 2252 | if (int_info.bits <= 64) { |
| 2249 | // TODO implement bitwise operations with immediates | 2253 | // TODO implement bitwise operations with immediates |
| 2250 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 2254 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| ... | @@ -2274,10 +2278,11 @@ fn shiftExact( | ... | @@ -2274,10 +2278,11 @@ fn shiftExact( |
| 2274 | ) InnerError!MCValue { | 2278 | ) InnerError!MCValue { |
| 2275 | _ = rhs_ty; | 2279 | _ = rhs_ty; |
| 2276 | 2280 | ||
| 2277 | switch (lhs_ty.zigTypeTag()) { | 2281 | const mod = self.bin_file.options.module.?; |
| 2282 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 2278 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2283 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2279 | .Int => { | 2284 | .Int => { |
| 2280 | const int_info = lhs_ty.intInfo(self.target.*); | 2285 | const int_info = lhs_ty.intInfo(mod); |
| 2281 | if (int_info.bits <= 64) { | 2286 | if (int_info.bits <= 64) { |
| 2282 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); | 2287 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 2283 | 2288 | ||
| ... | @@ -2323,10 +2328,11 @@ fn shiftNormal( | ... | @@ -2323,10 +2328,11 @@ fn shiftNormal( |
| 2323 | rhs_ty: Type, | 2328 | rhs_ty: Type, |
| 2324 | maybe_inst: ?Air.Inst.Index, | 2329 | maybe_inst: ?Air.Inst.Index, |
| 2325 | ) InnerError!MCValue { | 2330 | ) InnerError!MCValue { |
| 2326 | switch (lhs_ty.zigTypeTag()) { | 2331 | const mod = self.bin_file.options.module.?; |
| 2332 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 2327 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2333 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2328 | .Int => { | 2334 | .Int => { |
| 2329 | const int_info = lhs_ty.intInfo(self.target.*); | 2335 | const int_info = lhs_ty.intInfo(mod); |
| 2330 | if (int_info.bits <= 64) { | 2336 | if (int_info.bits <= 64) { |
| 2331 | // Generate a shl_exact/shr_exact | 2337 | // Generate a shl_exact/shr_exact |
| 2332 | const result: MCValue = switch (tag) { | 2338 | const result: MCValue = switch (tag) { |
| ... | @@ -2362,7 +2368,8 @@ fn booleanOp( | ... | @@ -2362,7 +2368,8 @@ fn booleanOp( |
| 2362 | rhs_ty: Type, | 2368 | rhs_ty: Type, |
| 2363 | maybe_inst: ?Air.Inst.Index, | 2369 | maybe_inst: ?Air.Inst.Index, |
| 2364 | ) InnerError!MCValue { | 2370 | ) InnerError!MCValue { |
| 2365 | switch (lhs_ty.zigTypeTag()) { | 2371 | const mod = self.bin_file.options.module.?; |
| 2372 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 2366 | .Bool => { | 2373 | .Bool => { |
| 2367 | assert((try lhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema | 2374 | assert((try lhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema |
| 2368 | assert((try rhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema | 2375 | assert((try rhs_bind.resolveToImmediate(self)) == null); // should have been handled by Sema |
| ... | @@ -2388,17 +2395,17 @@ fn ptrArithmetic( | ... | @@ -2388,17 +2395,17 @@ fn ptrArithmetic( |
| 2388 | rhs_ty: Type, | 2395 | rhs_ty: Type, |
| 2389 | maybe_inst: ?Air.Inst.Index, | 2396 | maybe_inst: ?Air.Inst.Index, |
| 2390 | ) InnerError!MCValue { | 2397 | ) InnerError!MCValue { |
| 2391 | switch (lhs_ty.zigTypeTag()) { | 2398 | const mod = self.bin_file.options.module.?; |
| 2399 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 2392 | .Pointer => { | 2400 | .Pointer => { |
| 2393 | const mod = self.bin_file.options.module.?; | ||
| 2394 | assert(rhs_ty.eql(Type.usize, mod)); | 2401 | assert(rhs_ty.eql(Type.usize, mod)); |
| 2395 | 2402 | ||
| 2396 | const ptr_ty = lhs_ty; | 2403 | const ptr_ty = lhs_ty; |
| 2397 | const elem_ty = switch (ptr_ty.ptrSize()) { | 2404 | const elem_ty = switch (ptr_ty.ptrSize(mod)) { |
| 2398 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type | 2405 | .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type |
| 2399 | else => ptr_ty.childType(), | 2406 | else => ptr_ty.childType(mod), |
| 2400 | }; | 2407 | }; |
| 2401 | const elem_size = elem_ty.abiSize(self.target.*); | 2408 | const elem_size = elem_ty.abiSize(mod); |
| 2402 | 2409 | ||
| 2403 | const base_tag: Air.Inst.Tag = switch (tag) { | 2410 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 2404 | .ptr_add => .add, | 2411 | .ptr_add => .add, |
| ... | @@ -2426,8 +2433,8 @@ fn ptrArithmetic( | ... | @@ -2426,8 +2433,8 @@ fn ptrArithmetic( |
| 2426 | 2433 | ||
| 2427 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 2434 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 2428 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2435 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2429 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 2436 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 2430 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 2437 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 2431 | 2438 | ||
| 2432 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2439 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2433 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; | 2440 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| ... | @@ -2477,8 +2484,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | ... | @@ -2477,8 +2484,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 2477 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 2484 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 2478 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2485 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2479 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2486 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2480 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 2487 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 2481 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 2488 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 2482 | 2489 | ||
| 2483 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2490 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2484 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; | 2491 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| ... | @@ -2511,23 +2518,23 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2511,23 +2518,23 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2511 | const tag = self.air.instructions.items(.tag)[inst]; | 2518 | const tag = self.air.instructions.items(.tag)[inst]; |
| 2512 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2519 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2513 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2520 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2521 | const mod = self.bin_file.options.module.?; | ||
| 2514 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2522 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2515 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; | 2523 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2516 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; | 2524 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2517 | const lhs_ty = self.air.typeOf(extra.lhs); | 2525 | const lhs_ty = self.typeOf(extra.lhs); |
| 2518 | const rhs_ty = self.air.typeOf(extra.rhs); | 2526 | const rhs_ty = self.typeOf(extra.rhs); |
| 2519 | 2527 | ||
| 2520 | const tuple_ty = self.air.typeOfIndex(inst); | 2528 | const tuple_ty = self.typeOfIndex(inst); |
| 2521 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | 2529 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); |
| 2522 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | 2530 | const tuple_align = tuple_ty.abiAlignment(mod); |
| 2523 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | 2531 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, mod)); |
| 2524 | 2532 | ||
| 2525 | switch (lhs_ty.zigTypeTag()) { | 2533 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2526 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), | 2534 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), |
| 2527 | .Int => { | 2535 | .Int => { |
| 2528 | const mod = self.bin_file.options.module.?; | ||
| 2529 | assert(lhs_ty.eql(rhs_ty, mod)); | 2536 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2530 | const int_info = lhs_ty.intInfo(self.target.*); | 2537 | const int_info = lhs_ty.intInfo(mod); |
| 2531 | switch (int_info.bits) { | 2538 | switch (int_info.bits) { |
| 2532 | 1...31, 33...63 => { | 2539 | 1...31, 33...63 => { |
| 2533 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); | 2540 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| ... | @@ -2565,7 +2572,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2565,7 +2572,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2565 | }); | 2572 | }); |
| 2566 | 2573 | ||
| 2567 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2574 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2568 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); | 2575 | try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2569 | 2576 | ||
| 2570 | break :result MCValue{ .stack_offset = stack_offset }; | 2577 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2571 | }, | 2578 | }, |
| ... | @@ -2639,24 +2646,23 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2639,24 +2646,23 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2639 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2646 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2640 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2647 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2641 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); | 2648 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 2649 | const mod = self.bin_file.options.module.?; | ||
| 2642 | const result: MCValue = result: { | 2650 | const result: MCValue = result: { |
| 2643 | const mod = self.bin_file.options.module.?; | ||
| 2644 | |||
| 2645 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; | 2651 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2646 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; | 2652 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2647 | const lhs_ty = self.air.typeOf(extra.lhs); | 2653 | const lhs_ty = self.typeOf(extra.lhs); |
| 2648 | const rhs_ty = self.air.typeOf(extra.rhs); | 2654 | const rhs_ty = self.typeOf(extra.rhs); |
| 2649 | 2655 | ||
| 2650 | const tuple_ty = self.air.typeOfIndex(inst); | 2656 | const tuple_ty = self.typeOfIndex(inst); |
| 2651 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | 2657 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); |
| 2652 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | 2658 | const tuple_align = tuple_ty.abiAlignment(mod); |
| 2653 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | 2659 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, mod)); |
| 2654 | 2660 | ||
| 2655 | switch (lhs_ty.zigTypeTag()) { | 2661 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2656 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), | 2662 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| 2657 | .Int => { | 2663 | .Int => { |
| 2658 | assert(lhs_ty.eql(rhs_ty, mod)); | 2664 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2659 | const int_info = lhs_ty.intInfo(self.target.*); | 2665 | const int_info = lhs_ty.intInfo(mod); |
| 2660 | if (int_info.bits <= 32) { | 2666 | if (int_info.bits <= 32) { |
| 2661 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); | 2667 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 2662 | 2668 | ||
| ... | @@ -2709,7 +2715,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2709,7 +2715,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2709 | } | 2715 | } |
| 2710 | 2716 | ||
| 2711 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2717 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2712 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); | 2718 | try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2713 | 2719 | ||
| 2714 | break :result MCValue{ .stack_offset = stack_offset }; | 2720 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2715 | } else if (int_info.bits <= 64) { | 2721 | } else if (int_info.bits <= 64) { |
| ... | @@ -2849,7 +2855,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2849,7 +2855,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2849 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); | 2855 | try self.truncRegister(dest_reg, truncated_reg, int_info.signedness, int_info.bits); |
| 2850 | 2856 | ||
| 2851 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 2857 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 2852 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); | 2858 | try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2853 | 2859 | ||
| 2854 | break :result MCValue{ .stack_offset = stack_offset }; | 2860 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2855 | } else return self.fail("TODO implement mul_with_overflow for integers > u64/i64", .{}); | 2861 | } else return self.fail("TODO implement mul_with_overflow for integers > u64/i64", .{}); |
| ... | @@ -2864,21 +2870,22 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2864,21 +2870,22 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2864 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2870 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2865 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2871 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2866 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); | 2872 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 2873 | const mod = self.bin_file.options.module.?; | ||
| 2867 | const result: MCValue = result: { | 2874 | const result: MCValue = result: { |
| 2868 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; | 2875 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2869 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; | 2876 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2870 | const lhs_ty = self.air.typeOf(extra.lhs); | 2877 | const lhs_ty = self.typeOf(extra.lhs); |
| 2871 | const rhs_ty = self.air.typeOf(extra.rhs); | 2878 | const rhs_ty = self.typeOf(extra.rhs); |
| 2872 | 2879 | ||
| 2873 | const tuple_ty = self.air.typeOfIndex(inst); | 2880 | const tuple_ty = self.typeOfIndex(inst); |
| 2874 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | 2881 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); |
| 2875 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | 2882 | const tuple_align = tuple_ty.abiAlignment(mod); |
| 2876 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | 2883 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, mod)); |
| 2877 | 2884 | ||
| 2878 | switch (lhs_ty.zigTypeTag()) { | 2885 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2879 | .Vector => return self.fail("TODO implement shl_with_overflow for vectors", .{}), | 2886 | .Vector => return self.fail("TODO implement shl_with_overflow for vectors", .{}), |
| 2880 | .Int => { | 2887 | .Int => { |
| 2881 | const int_info = lhs_ty.intInfo(self.target.*); | 2888 | const int_info = lhs_ty.intInfo(mod); |
| 2882 | if (int_info.bits <= 64) { | 2889 | if (int_info.bits <= 64) { |
| 2883 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); | 2890 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 2884 | 2891 | ||
| ... | @@ -2981,7 +2988,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2981,7 +2988,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2981 | }); | 2988 | }); |
| 2982 | 2989 | ||
| 2983 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg }); | 2990 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg }); |
| 2984 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); | 2991 | try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{ .compare_flags = .ne }); |
| 2985 | 2992 | ||
| 2986 | break :result MCValue{ .stack_offset = stack_offset }; | 2993 | break :result MCValue{ .stack_offset = stack_offset }; |
| 2987 | } else { | 2994 | } else { |
| ... | @@ -3003,7 +3010,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3003,7 +3010,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3003 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { | 3010 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3004 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3011 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3005 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3012 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3006 | const optional_ty = self.air.typeOf(ty_op.operand); | 3013 | const optional_ty = self.typeOf(ty_op.operand); |
| 3007 | const mcv = try self.resolveInst(ty_op.operand); | 3014 | const mcv = try self.resolveInst(ty_op.operand); |
| 3008 | break :result try self.optionalPayload(inst, mcv, optional_ty); | 3015 | break :result try self.optionalPayload(inst, mcv, optional_ty); |
| 3009 | }; | 3016 | }; |
| ... | @@ -3011,10 +3018,10 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3011,10 +3018,10 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3011 | } | 3018 | } |
| 3012 | 3019 | ||
| 3013 | fn optionalPayload(self: *Self, inst: Air.Inst.Index, mcv: MCValue, optional_ty: Type) !MCValue { | 3020 | fn optionalPayload(self: *Self, inst: Air.Inst.Index, mcv: MCValue, optional_ty: Type) !MCValue { |
| 3014 | var opt_buf: Type.Payload.ElemType = undefined; | 3021 | const mod = self.bin_file.options.module.?; |
| 3015 | const payload_ty = optional_ty.optionalChild(&opt_buf); | 3022 | const payload_ty = optional_ty.optionalChild(mod); |
| 3016 | if (!payload_ty.hasRuntimeBits()) return MCValue.none; | 3023 | if (!payload_ty.hasRuntimeBits(mod)) return MCValue.none; |
| 3017 | if (optional_ty.isPtrLikeOptional()) { | 3024 | if (optional_ty.isPtrLikeOptional(mod)) { |
| 3018 | // TODO should we reuse the operand here? | 3025 | // TODO should we reuse the operand here? |
| 3019 | const raw_reg = try self.register_manager.allocReg(inst, gp); | 3026 | const raw_reg = try self.register_manager.allocReg(inst, gp); |
| 3020 | const reg = self.registerAlias(raw_reg, payload_ty); | 3027 | const reg = self.registerAlias(raw_reg, payload_ty); |
| ... | @@ -3055,16 +3062,17 @@ fn errUnionErr( | ... | @@ -3055,16 +3062,17 @@ fn errUnionErr( |
| 3055 | error_union_ty: Type, | 3062 | error_union_ty: Type, |
| 3056 | maybe_inst: ?Air.Inst.Index, | 3063 | maybe_inst: ?Air.Inst.Index, |
| 3057 | ) !MCValue { | 3064 | ) !MCValue { |
| 3058 | const err_ty = error_union_ty.errorUnionSet(); | 3065 | const mod = self.bin_file.options.module.?; |
| 3059 | const payload_ty = error_union_ty.errorUnionPayload(); | 3066 | const err_ty = error_union_ty.errorUnionSet(mod); |
| 3060 | if (err_ty.errorSetIsEmpty()) { | 3067 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 3068 | if (err_ty.errorSetIsEmpty(mod)) { | ||
| 3061 | return MCValue{ .immediate = 0 }; | 3069 | return MCValue{ .immediate = 0 }; |
| 3062 | } | 3070 | } |
| 3063 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3071 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3064 | return try error_union_bind.resolveToMcv(self); | 3072 | return try error_union_bind.resolveToMcv(self); |
| 3065 | } | 3073 | } |
| 3066 | 3074 | ||
| 3067 | const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*)); | 3075 | const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, mod)); |
| 3068 | switch (try error_union_bind.resolveToMcv(self)) { | 3076 | switch (try error_union_bind.resolveToMcv(self)) { |
| 3069 | .register => { | 3077 | .register => { |
| 3070 | var operand_reg: Register = undefined; | 3078 | var operand_reg: Register = undefined; |
| ... | @@ -3086,7 +3094,7 @@ fn errUnionErr( | ... | @@ -3086,7 +3094,7 @@ fn errUnionErr( |
| 3086 | ); | 3094 | ); |
| 3087 | 3095 | ||
| 3088 | const err_bit_offset = err_offset * 8; | 3096 | const err_bit_offset = err_offset * 8; |
| 3089 | const err_bit_size = @intCast(u32, err_ty.abiSize(self.target.*)) * 8; | 3097 | const err_bit_size = @intCast(u32, err_ty.abiSize(mod)) * 8; |
| 3090 | 3098 | ||
| 3091 | _ = try self.addInst(.{ | 3099 | _ = try self.addInst(.{ |
| 3092 | .tag = .ubfx, // errors are unsigned integers | 3100 | .tag = .ubfx, // errors are unsigned integers |
| ... | @@ -3120,7 +3128,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3120,7 +3128,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 3120 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3128 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3121 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3129 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3122 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; | 3130 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 3123 | const error_union_ty = self.air.typeOf(ty_op.operand); | 3131 | const error_union_ty = self.typeOf(ty_op.operand); |
| 3124 | 3132 | ||
| 3125 | break :result try self.errUnionErr(error_union_bind, error_union_ty, inst); | 3133 | break :result try self.errUnionErr(error_union_bind, error_union_ty, inst); |
| 3126 | }; | 3134 | }; |
| ... | @@ -3134,16 +3142,17 @@ fn errUnionPayload( | ... | @@ -3134,16 +3142,17 @@ fn errUnionPayload( |
| 3134 | error_union_ty: Type, | 3142 | error_union_ty: Type, |
| 3135 | maybe_inst: ?Air.Inst.Index, | 3143 | maybe_inst: ?Air.Inst.Index, |
| 3136 | ) !MCValue { | 3144 | ) !MCValue { |
| 3137 | const err_ty = error_union_ty.errorUnionSet(); | 3145 | const mod = self.bin_file.options.module.?; |
| 3138 | const payload_ty = error_union_ty.errorUnionPayload(); | 3146 | const err_ty = error_union_ty.errorUnionSet(mod); |
| 3139 | if (err_ty.errorSetIsEmpty()) { | 3147 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 3148 | if (err_ty.errorSetIsEmpty(mod)) { | ||
| 3140 | return try error_union_bind.resolveToMcv(self); | 3149 | return try error_union_bind.resolveToMcv(self); |
| 3141 | } | 3150 | } |
| 3142 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3151 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3143 | return MCValue.none; | 3152 | return MCValue.none; |
| 3144 | } | 3153 | } |
| 3145 | 3154 | ||
| 3146 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*)); | 3155 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, mod)); |
| 3147 | switch (try error_union_bind.resolveToMcv(self)) { | 3156 | switch (try error_union_bind.resolveToMcv(self)) { |
| 3148 | .register => { | 3157 | .register => { |
| 3149 | var operand_reg: Register = undefined; | 3158 | var operand_reg: Register = undefined; |
| ... | @@ -3165,10 +3174,10 @@ fn errUnionPayload( | ... | @@ -3165,10 +3174,10 @@ fn errUnionPayload( |
| 3165 | ); | 3174 | ); |
| 3166 | 3175 | ||
| 3167 | const payload_bit_offset = payload_offset * 8; | 3176 | const payload_bit_offset = payload_offset * 8; |
| 3168 | const payload_bit_size = @intCast(u32, payload_ty.abiSize(self.target.*)) * 8; | 3177 | const payload_bit_size = @intCast(u32, payload_ty.abiSize(mod)) * 8; |
| 3169 | 3178 | ||
| 3170 | _ = try self.addInst(.{ | 3179 | _ = try self.addInst(.{ |
| 3171 | .tag = if (payload_ty.isSignedInt()) Mir.Inst.Tag.sbfx else .ubfx, | 3180 | .tag = if (payload_ty.isSignedInt(mod)) Mir.Inst.Tag.sbfx else .ubfx, |
| 3172 | .data = .{ | 3181 | .data = .{ |
| 3173 | .rr_lsb_width = .{ | 3182 | .rr_lsb_width = .{ |
| 3174 | // Set both registers to the X variant to get the full width | 3183 | // Set both registers to the X variant to get the full width |
| ... | @@ -3199,7 +3208,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3199,7 +3208,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3199 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3208 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3200 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3209 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3201 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; | 3210 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 3202 | const error_union_ty = self.air.typeOf(ty_op.operand); | 3211 | const error_union_ty = self.typeOf(ty_op.operand); |
| 3203 | 3212 | ||
| 3204 | break :result try self.errUnionPayload(error_union_bind, error_union_ty, inst); | 3213 | break :result try self.errUnionPayload(error_union_bind, error_union_ty, inst); |
| 3205 | }; | 3214 | }; |
| ... | @@ -3245,6 +3254,7 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3245,6 +3254,7 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { |
| 3245 | } | 3254 | } |
| 3246 | 3255 | ||
| 3247 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | 3256 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3257 | const mod = self.bin_file.options.module.?; | ||
| 3248 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3258 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3249 | 3259 | ||
| 3250 | if (self.liveness.isUnused(inst)) { | 3260 | if (self.liveness.isUnused(inst)) { |
| ... | @@ -3252,12 +3262,12 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3252,12 +3262,12 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3252 | } | 3262 | } |
| 3253 | 3263 | ||
| 3254 | const result: MCValue = result: { | 3264 | const result: MCValue = result: { |
| 3255 | const payload_ty = self.air.typeOf(ty_op.operand); | 3265 | const payload_ty = self.typeOf(ty_op.operand); |
| 3256 | if (!payload_ty.hasRuntimeBits()) { | 3266 | if (!payload_ty.hasRuntimeBits(mod)) { |
| 3257 | break :result MCValue{ .immediate = 1 }; | 3267 | break :result MCValue{ .immediate = 1 }; |
| 3258 | } | 3268 | } |
| 3259 | 3269 | ||
| 3260 | const optional_ty = self.air.typeOfIndex(inst); | 3270 | const optional_ty = self.typeOfIndex(inst); |
| 3261 | const operand = try self.resolveInst(ty_op.operand); | 3271 | const operand = try self.resolveInst(ty_op.operand); |
| 3262 | const operand_lock: ?RegisterLock = switch (operand) { | 3272 | const operand_lock: ?RegisterLock = switch (operand) { |
| 3263 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 3273 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -3265,7 +3275,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3265,7 +3275,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3265 | }; | 3275 | }; |
| 3266 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | 3276 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 3267 | 3277 | ||
| 3268 | if (optional_ty.isPtrLikeOptional()) { | 3278 | if (optional_ty.isPtrLikeOptional(mod)) { |
| 3269 | // TODO should we check if we can reuse the operand? | 3279 | // TODO should we check if we can reuse the operand? |
| 3270 | const raw_reg = try self.register_manager.allocReg(inst, gp); | 3280 | const raw_reg = try self.register_manager.allocReg(inst, gp); |
| 3271 | const reg = self.registerAlias(raw_reg, payload_ty); | 3281 | const reg = self.registerAlias(raw_reg, payload_ty); |
| ... | @@ -3273,9 +3283,9 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3273,9 +3283,9 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3273 | break :result MCValue{ .register = reg }; | 3283 | break :result MCValue{ .register = reg }; |
| 3274 | } | 3284 | } |
| 3275 | 3285 | ||
| 3276 | const optional_abi_size = @intCast(u32, optional_ty.abiSize(self.target.*)); | 3286 | const optional_abi_size = @intCast(u32, optional_ty.abiSize(mod)); |
| 3277 | const optional_abi_align = optional_ty.abiAlignment(self.target.*); | 3287 | const optional_abi_align = optional_ty.abiAlignment(mod); |
| 3278 | const offset = @intCast(u32, payload_ty.abiSize(self.target.*)); | 3288 | const offset = @intCast(u32, payload_ty.abiSize(mod)); |
| 3279 | 3289 | ||
| 3280 | const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst); | 3290 | const stack_offset = try self.allocMem(optional_abi_size, optional_abi_align, inst); |
| 3281 | try self.genSetStack(payload_ty, stack_offset, operand); | 3291 | try self.genSetStack(payload_ty, stack_offset, operand); |
| ... | @@ -3289,19 +3299,20 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3289,19 +3299,20 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3289 | 3299 | ||
| 3290 | /// T to E!T | 3300 | /// T to E!T |
| 3291 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | 3301 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3302 | const mod = self.bin_file.options.module.?; | ||
| 3292 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3303 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3293 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3304 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3294 | const error_union_ty = self.air.getRefType(ty_op.ty); | 3305 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 3295 | const error_ty = error_union_ty.errorUnionSet(); | 3306 | const error_ty = error_union_ty.errorUnionSet(mod); |
| 3296 | const payload_ty = error_union_ty.errorUnionPayload(); | 3307 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 3297 | const operand = try self.resolveInst(ty_op.operand); | 3308 | const operand = try self.resolveInst(ty_op.operand); |
| 3298 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; | 3309 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result operand; |
| 3299 | 3310 | ||
| 3300 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | 3311 | const abi_size = @intCast(u32, error_union_ty.abiSize(mod)); |
| 3301 | const abi_align = error_union_ty.abiAlignment(self.target.*); | 3312 | const abi_align = error_union_ty.abiAlignment(mod); |
| 3302 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); | 3313 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| 3303 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | 3314 | const payload_off = errUnionPayloadOffset(payload_ty, mod); |
| 3304 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | 3315 | const err_off = errUnionErrorOffset(payload_ty, mod); |
| 3305 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand); | 3316 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand); |
| 3306 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 }); | 3317 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 }); |
| 3307 | 3318 | ||
| ... | @@ -3314,17 +3325,18 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3314,17 +3325,18 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3314 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | 3325 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 3315 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3326 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3316 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 3327 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 3328 | const mod = self.bin_file.options.module.?; | ||
| 3317 | const error_union_ty = self.air.getRefType(ty_op.ty); | 3329 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 3318 | const error_ty = error_union_ty.errorUnionSet(); | 3330 | const error_ty = error_union_ty.errorUnionSet(mod); |
| 3319 | const payload_ty = error_union_ty.errorUnionPayload(); | 3331 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 3320 | const operand = try self.resolveInst(ty_op.operand); | 3332 | const operand = try self.resolveInst(ty_op.operand); |
| 3321 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; | 3333 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result operand; |
| 3322 | 3334 | ||
| 3323 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | 3335 | const abi_size = @intCast(u32, error_union_ty.abiSize(mod)); |
| 3324 | const abi_align = error_union_ty.abiAlignment(self.target.*); | 3336 | const abi_align = error_union_ty.abiAlignment(mod); |
| 3325 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); | 3337 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| 3326 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | 3338 | const payload_off = errUnionPayloadOffset(payload_ty, mod); |
| 3327 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | 3339 | const err_off = errUnionErrorOffset(payload_ty, mod); |
| 3328 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), operand); | 3340 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), operand); |
| 3329 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef); | 3341 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef); |
| 3330 | 3342 | ||
| ... | @@ -3416,11 +3428,11 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3416,11 +3428,11 @@ fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3416 | } | 3428 | } |
| 3417 | 3429 | ||
| 3418 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 3430 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3431 | const mod = self.bin_file.options.module.?; | ||
| 3419 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 3432 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3420 | const slice_ty = self.air.typeOf(bin_op.lhs); | 3433 | const slice_ty = self.typeOf(bin_op.lhs); |
| 3421 | const result: MCValue = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: { | 3434 | const result: MCValue = if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { |
| 3422 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 3435 | const ptr_ty = slice_ty.slicePtrFieldType(mod); |
| 3423 | const ptr_ty = slice_ty.slicePtrFieldType(&buf); | ||
| 3424 | 3436 | ||
| 3425 | const slice_mcv = try self.resolveInst(bin_op.lhs); | 3437 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 3426 | const base_mcv = slicePtr(slice_mcv); | 3438 | const base_mcv = slicePtr(slice_mcv); |
| ... | @@ -3440,8 +3452,9 @@ fn ptrElemVal( | ... | @@ -3440,8 +3452,9 @@ fn ptrElemVal( |
| 3440 | ptr_ty: Type, | 3452 | ptr_ty: Type, |
| 3441 | maybe_inst: ?Air.Inst.Index, | 3453 | maybe_inst: ?Air.Inst.Index, |
| 3442 | ) !MCValue { | 3454 | ) !MCValue { |
| 3443 | const elem_ty = ptr_ty.childType(); | 3455 | const mod = self.bin_file.options.module.?; |
| 3444 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | 3456 | const elem_ty = ptr_ty.childType(mod); |
| 3457 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); | ||
| 3445 | 3458 | ||
| 3446 | // TODO optimize for elem_sizes of 1, 2, 4, 8 | 3459 | // TODO optimize for elem_sizes of 1, 2, 4, 8 |
| 3447 | switch (elem_size) { | 3460 | switch (elem_size) { |
| ... | @@ -3465,8 +3478,8 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3465,8 +3478,8 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3465 | const base_bind: ReadArg.Bind = .{ .mcv = base_mcv }; | 3478 | const base_bind: ReadArg.Bind = .{ .mcv = base_mcv }; |
| 3466 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; | 3479 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 3467 | 3480 | ||
| 3468 | const slice_ty = self.air.typeOf(extra.lhs); | 3481 | const slice_ty = self.typeOf(extra.lhs); |
| 3469 | const index_ty = self.air.typeOf(extra.rhs); | 3482 | const index_ty = self.typeOf(extra.rhs); |
| 3470 | 3483 | ||
| 3471 | const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ty, index_ty, null); | 3484 | const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ty, index_ty, null); |
| 3472 | break :result addr; | 3485 | break :result addr; |
| ... | @@ -3481,9 +3494,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3481,9 +3494,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3481 | } | 3494 | } |
| 3482 | 3495 | ||
| 3483 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { | 3496 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3497 | const mod = self.bin_file.options.module.?; | ||
| 3484 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 3498 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3485 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 3499 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 3486 | const result: MCValue = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: { | 3500 | const result: MCValue = if (!ptr_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { |
| 3487 | const base_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; | 3501 | const base_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 3488 | const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; | 3502 | const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; |
| 3489 | 3503 | ||
| ... | @@ -3499,8 +3513,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3499,8 +3513,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3499 | const ptr_bind: ReadArg.Bind = .{ .inst = extra.lhs }; | 3513 | const ptr_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 3500 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; | 3514 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 3501 | 3515 | ||
| 3502 | const ptr_ty = self.air.typeOf(extra.lhs); | 3516 | const ptr_ty = self.typeOf(extra.lhs); |
| 3503 | const index_ty = self.air.typeOf(extra.rhs); | 3517 | const index_ty = self.typeOf(extra.rhs); |
| 3504 | 3518 | ||
| 3505 | const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, index_ty, null); | 3519 | const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, index_ty, null); |
| 3506 | break :result addr; | 3520 | break :result addr; |
| ... | @@ -3597,8 +3611,9 @@ fn reuseOperand( | ... | @@ -3597,8 +3611,9 @@ fn reuseOperand( |
| 3597 | } | 3611 | } |
| 3598 | 3612 | ||
| 3599 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { | 3613 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 3600 | const elem_ty = ptr_ty.elemType(); | 3614 | const mod = self.bin_file.options.module.?; |
| 3601 | const elem_size = elem_ty.abiSize(self.target.*); | 3615 | const elem_ty = ptr_ty.childType(mod); |
| 3616 | const elem_size = elem_ty.abiSize(mod); | ||
| 3602 | 3617 | ||
| 3603 | switch (ptr) { | 3618 | switch (ptr) { |
| 3604 | .none => unreachable, | 3619 | .none => unreachable, |
| ... | @@ -3753,14 +3768,14 @@ fn genInlineMemset( | ... | @@ -3753,14 +3768,14 @@ fn genInlineMemset( |
| 3753 | ) !void { | 3768 | ) !void { |
| 3754 | const dst_reg = switch (dst) { | 3769 | const dst_reg = switch (dst) { |
| 3755 | .register => |r| r, | 3770 | .register => |r| r, |
| 3756 | else => try self.copyToTmpRegister(Type.initTag(.manyptr_u8), dst), | 3771 | else => try self.copyToTmpRegister(Type.manyptr_u8, dst), |
| 3757 | }; | 3772 | }; |
| 3758 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); | 3773 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 3759 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); | 3774 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 3760 | 3775 | ||
| 3761 | const val_reg = switch (val) { | 3776 | const val_reg = switch (val) { |
| 3762 | .register => |r| r, | 3777 | .register => |r| r, |
| 3763 | else => try self.copyToTmpRegister(Type.initTag(.u8), val), | 3778 | else => try self.copyToTmpRegister(Type.u8, val), |
| 3764 | }; | 3779 | }; |
| 3765 | const val_reg_lock = self.register_manager.lockReg(val_reg); | 3780 | const val_reg_lock = self.register_manager.lockReg(val_reg); |
| 3766 | defer if (val_reg_lock) |lock| self.register_manager.unlockReg(lock); | 3781 | defer if (val_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | @@ -3844,15 +3859,16 @@ fn genInlineMemsetCode( | ... | @@ -3844,15 +3859,16 @@ fn genInlineMemsetCode( |
| 3844 | } | 3859 | } |
| 3845 | 3860 | ||
| 3846 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | 3861 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3862 | const mod = self.bin_file.options.module.?; | ||
| 3847 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3863 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3848 | const elem_ty = self.air.typeOfIndex(inst); | 3864 | const elem_ty = self.typeOfIndex(inst); |
| 3849 | const elem_size = elem_ty.abiSize(self.target.*); | 3865 | const elem_size = elem_ty.abiSize(mod); |
| 3850 | const result: MCValue = result: { | 3866 | const result: MCValue = result: { |
| 3851 | if (!elem_ty.hasRuntimeBits()) | 3867 | if (!elem_ty.hasRuntimeBits(mod)) |
| 3852 | break :result MCValue.none; | 3868 | break :result MCValue.none; |
| 3853 | 3869 | ||
| 3854 | const ptr = try self.resolveInst(ty_op.operand); | 3870 | const ptr = try self.resolveInst(ty_op.operand); |
| 3855 | const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr(); | 3871 | const is_volatile = self.typeOf(ty_op.operand).isVolatilePtr(mod); |
| 3856 | if (self.liveness.isUnused(inst) and !is_volatile) | 3872 | if (self.liveness.isUnused(inst) and !is_volatile) |
| 3857 | break :result MCValue.dead; | 3873 | break :result MCValue.dead; |
| 3858 | 3874 | ||
| ... | @@ -3867,18 +3883,19 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3867,18 +3883,19 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 3867 | break :blk try self.allocRegOrMem(elem_ty, true, inst); | 3883 | break :blk try self.allocRegOrMem(elem_ty, true, inst); |
| 3868 | } | 3884 | } |
| 3869 | }; | 3885 | }; |
| 3870 | try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand)); | 3886 | try self.load(dst_mcv, ptr, self.typeOf(ty_op.operand)); |
| 3871 | break :result dst_mcv; | 3887 | break :result dst_mcv; |
| 3872 | }; | 3888 | }; |
| 3873 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3889 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3874 | } | 3890 | } |
| 3875 | 3891 | ||
| 3876 | fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { | 3892 | fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { |
| 3877 | const abi_size = ty.abiSize(self.target.*); | 3893 | const mod = self.bin_file.options.module.?; |
| 3894 | const abi_size = ty.abiSize(mod); | ||
| 3878 | 3895 | ||
| 3879 | const tag: Mir.Inst.Tag = switch (abi_size) { | 3896 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3880 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_immediate else .ldrb_immediate, | 3897 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb_immediate else .ldrb_immediate, |
| 3881 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_immediate else .ldrh_immediate, | 3898 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh_immediate else .ldrh_immediate, |
| 3882 | 4 => .ldr_immediate, | 3899 | 4 => .ldr_immediate, |
| 3883 | 8 => .ldr_immediate, | 3900 | 8 => .ldr_immediate, |
| 3884 | 3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}), | 3901 | 3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}), |
| ... | @@ -3896,7 +3913,8 @@ fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type | ... | @@ -3896,7 +3913,8 @@ fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type |
| 3896 | } | 3913 | } |
| 3897 | 3914 | ||
| 3898 | fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { | 3915 | fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void { |
| 3899 | const abi_size = ty.abiSize(self.target.*); | 3916 | const mod = self.bin_file.options.module.?; |
| 3917 | const abi_size = ty.abiSize(mod); | ||
| 3900 | 3918 | ||
| 3901 | const tag: Mir.Inst.Tag = switch (abi_size) { | 3919 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3902 | 1 => .strb_immediate, | 3920 | 1 => .strb_immediate, |
| ... | @@ -3917,8 +3935,9 @@ fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type | ... | @@ -3917,8 +3935,9 @@ fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type |
| 3917 | } | 3935 | } |
| 3918 | 3936 | ||
| 3919 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { | 3937 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| 3938 | const mod = self.bin_file.options.module.?; | ||
| 3920 | log.debug("store: storing {} to {}", .{ value, ptr }); | 3939 | log.debug("store: storing {} to {}", .{ value, ptr }); |
| 3921 | const abi_size = value_ty.abiSize(self.target.*); | 3940 | const abi_size = value_ty.abiSize(mod); |
| 3922 | 3941 | ||
| 3923 | switch (ptr) { | 3942 | switch (ptr) { |
| 3924 | .none => unreachable, | 3943 | .none => unreachable, |
| ... | @@ -4046,8 +4065,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -4046,8 +4065,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 4046 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 4065 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4047 | const ptr = try self.resolveInst(bin_op.lhs); | 4066 | const ptr = try self.resolveInst(bin_op.lhs); |
| 4048 | const value = try self.resolveInst(bin_op.rhs); | 4067 | const value = try self.resolveInst(bin_op.rhs); |
| 4049 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 4068 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 4050 | const value_ty = self.air.typeOf(bin_op.rhs); | 4069 | const value_ty = self.typeOf(bin_op.rhs); |
| 4051 | 4070 | ||
| 4052 | try self.store(ptr, value, ptr_ty, value_ty); | 4071 | try self.store(ptr, value, ptr_ty, value_ty); |
| 4053 | 4072 | ||
| ... | @@ -4069,10 +4088,11 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { | ... | @@ -4069,10 +4088,11 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 4069 | 4088 | ||
| 4070 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { | 4089 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 4071 | return if (self.liveness.isUnused(inst)) .dead else result: { | 4090 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 4091 | const mod = self.bin_file.options.module.?; | ||
| 4072 | const mcv = try self.resolveInst(operand); | 4092 | const mcv = try self.resolveInst(operand); |
| 4073 | const ptr_ty = self.air.typeOf(operand); | 4093 | const ptr_ty = self.typeOf(operand); |
| 4074 | const struct_ty = ptr_ty.childType(); | 4094 | const struct_ty = ptr_ty.childType(mod); |
| 4075 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | 4095 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); |
| 4076 | switch (mcv) { | 4096 | switch (mcv) { |
| 4077 | .ptr_stack_offset => |off| { | 4097 | .ptr_stack_offset => |off| { |
| 4078 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; | 4098 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; |
| ... | @@ -4093,10 +4113,11 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4093,10 +4113,11 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4093 | const operand = extra.struct_operand; | 4113 | const operand = extra.struct_operand; |
| 4094 | const index = extra.field_index; | 4114 | const index = extra.field_index; |
| 4095 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4115 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4116 | const mod = self.bin_file.options.module.?; | ||
| 4096 | const mcv = try self.resolveInst(operand); | 4117 | const mcv = try self.resolveInst(operand); |
| 4097 | const struct_ty = self.air.typeOf(operand); | 4118 | const struct_ty = self.typeOf(operand); |
| 4098 | const struct_field_ty = struct_ty.structFieldType(index); | 4119 | const struct_field_ty = struct_ty.structFieldType(index, mod); |
| 4099 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | 4120 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); |
| 4100 | 4121 | ||
| 4101 | switch (mcv) { | 4122 | switch (mcv) { |
| 4102 | .dead, .unreach => unreachable, | 4123 | .dead, .unreach => unreachable, |
| ... | @@ -4142,12 +4163,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4142,12 +4163,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4142 | } | 4163 | } |
| 4143 | 4164 | ||
| 4144 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | 4165 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4166 | const mod = self.bin_file.options.module.?; | ||
| 4145 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 4167 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 4146 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; | 4168 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 4147 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4169 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4148 | const field_ptr = try self.resolveInst(extra.field_ptr); | 4170 | const field_ptr = try self.resolveInst(extra.field_ptr); |
| 4149 | const struct_ty = self.air.getRefType(ty_pl.ty).childType(); | 4171 | const struct_ty = self.air.getRefType(ty_pl.ty).childType(mod); |
| 4150 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(extra.field_index, self.target.*)); | 4172 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(extra.field_index, mod)); |
| 4151 | switch (field_ptr) { | 4173 | switch (field_ptr) { |
| 4152 | .ptr_stack_offset => |off| { | 4174 | .ptr_stack_offset => |off| { |
| 4153 | break :result MCValue{ .ptr_stack_offset = off + struct_field_offset }; | 4175 | break :result MCValue{ .ptr_stack_offset = off + struct_field_offset }; |
| ... | @@ -4169,7 +4191,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4169,7 +4191,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 4169 | while (self.args[arg_index] == .none) arg_index += 1; | 4191 | while (self.args[arg_index] == .none) arg_index += 1; |
| 4170 | self.arg_index = arg_index + 1; | 4192 | self.arg_index = arg_index + 1; |
| 4171 | 4193 | ||
| 4172 | const ty = self.air.typeOfIndex(inst); | 4194 | const ty = self.typeOfIndex(inst); |
| 4173 | const tag = self.air.instructions.items(.tag)[inst]; | 4195 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4174 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; | 4196 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 4175 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index); | 4197 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index); |
| ... | @@ -4222,11 +4244,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4222,11 +4244,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4222 | const callee = pl_op.operand; | 4244 | const callee = pl_op.operand; |
| 4223 | const extra = self.air.extraData(Air.Call, pl_op.payload); | 4245 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 4224 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); | 4246 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); |
| 4225 | const ty = self.air.typeOf(callee); | 4247 | const ty = self.typeOf(callee); |
| 4248 | const mod = self.bin_file.options.module.?; | ||
| 4226 | 4249 | ||
| 4227 | const fn_ty = switch (ty.zigTypeTag()) { | 4250 | const fn_ty = switch (ty.zigTypeTag(mod)) { |
| 4228 | .Fn => ty, | 4251 | .Fn => ty, |
| 4229 | .Pointer => ty.childType(), | 4252 | .Pointer => ty.childType(mod), |
| 4230 | else => unreachable, | 4253 | else => unreachable, |
| 4231 | }; | 4254 | }; |
| 4232 | 4255 | ||
| ... | @@ -4245,18 +4268,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4245,18 +4268,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4245 | 4268 | ||
| 4246 | if (info.return_value == .stack_offset) { | 4269 | if (info.return_value == .stack_offset) { |
| 4247 | log.debug("airCall: return by reference", .{}); | 4270 | log.debug("airCall: return by reference", .{}); |
| 4248 | const ret_ty = fn_ty.fnReturnType(); | 4271 | const ret_ty = fn_ty.fnReturnType(mod); |
| 4249 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 4272 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(mod)); |
| 4250 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); | 4273 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(mod)); |
| 4251 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); | 4274 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 4252 | 4275 | ||
| 4253 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); | 4276 | const ret_ptr_reg = self.registerAlias(.x0, Type.usize); |
| 4254 | 4277 | ||
| 4255 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 4278 | const ptr_ty = try mod.singleMutPtrType(ret_ty); |
| 4256 | .base = .{ .tag = .single_mut_pointer }, | ||
| 4257 | .data = ret_ty, | ||
| 4258 | }; | ||
| 4259 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 4260 | try self.register_manager.getReg(ret_ptr_reg, null); | 4279 | try self.register_manager.getReg(ret_ptr_reg, null); |
| 4261 | try self.genSetReg(ptr_ty, ret_ptr_reg, .{ .ptr_stack_offset = stack_offset }); | 4280 | try self.genSetReg(ptr_ty, ret_ptr_reg, .{ .ptr_stack_offset = stack_offset }); |
| 4262 | 4281 | ||
| ... | @@ -4268,7 +4287,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4268,7 +4287,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4268 | 4287 | ||
| 4269 | for (info.args, 0..) |mc_arg, arg_i| { | 4288 | for (info.args, 0..) |mc_arg, arg_i| { |
| 4270 | const arg = args[arg_i]; | 4289 | const arg = args[arg_i]; |
| 4271 | const arg_ty = self.air.typeOf(arg); | 4290 | const arg_ty = self.typeOf(arg); |
| 4272 | const arg_mcv = try self.resolveInst(args[arg_i]); | 4291 | const arg_mcv = try self.resolveInst(args[arg_i]); |
| 4273 | 4292 | ||
| 4274 | switch (mc_arg) { | 4293 | switch (mc_arg) { |
| ... | @@ -4289,21 +4308,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4289,21 +4308,18 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4289 | 4308 | ||
| 4290 | // Due to incremental compilation, how function calls are generated depends | 4309 | // Due to incremental compilation, how function calls are generated depends |
| 4291 | // on linking. | 4310 | // on linking. |
| 4292 | const mod = self.bin_file.options.module.?; | 4311 | if (try self.air.value(callee, mod)) |func_value| { |
| 4293 | if (self.air.value(callee)) |func_value| { | 4312 | if (func_value.getFunction(mod)) |func| { |
| 4294 | if (func_value.castTag(.function)) |func_payload| { | ||
| 4295 | const func = func_payload.data; | ||
| 4296 | |||
| 4297 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | 4313 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 4298 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); | 4314 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 4299 | const atom = elf_file.getAtom(atom_index); | 4315 | const atom = elf_file.getAtom(atom_index); |
| 4300 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); | 4316 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); |
| 4301 | const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file)); | 4317 | const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file)); |
| 4302 | try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr }); | 4318 | try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr }); |
| 4303 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | 4319 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 4304 | const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl); | 4320 | const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl); |
| 4305 | const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; | 4321 | const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; |
| 4306 | try self.genSetReg(Type.initTag(.u64), .x30, .{ | 4322 | try self.genSetReg(Type.u64, .x30, .{ |
| 4307 | .linker_load = .{ | 4323 | .linker_load = .{ |
| 4308 | .type = .got, | 4324 | .type = .got, |
| 4309 | .sym_index = sym_index, | 4325 | .sym_index = sym_index, |
| ... | @@ -4312,7 +4328,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4312,7 +4328,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4312 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | 4328 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 4313 | const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl); | 4329 | const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl); |
| 4314 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; | 4330 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; |
| 4315 | try self.genSetReg(Type.initTag(.u64), .x30, .{ | 4331 | try self.genSetReg(Type.u64, .x30, .{ |
| 4316 | .linker_load = .{ | 4332 | .linker_load = .{ |
| 4317 | .type = .got, | 4333 | .type = .got, |
| 4318 | .sym_index = sym_index, | 4334 | .sym_index = sym_index, |
| ... | @@ -4326,17 +4342,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4326,17 +4342,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4326 | const got_addr = p9.bases.data; | 4342 | const got_addr = p9.bases.data; |
| 4327 | const got_index = decl_block.got_index.?; | 4343 | const got_index = decl_block.got_index.?; |
| 4328 | const fn_got_addr = got_addr + got_index * ptr_bytes; | 4344 | const fn_got_addr = got_addr + got_index * ptr_bytes; |
| 4329 | try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = fn_got_addr }); | 4345 | try self.genSetReg(Type.usize, .x30, .{ .memory = fn_got_addr }); |
| 4330 | } else unreachable; | 4346 | } else unreachable; |
| 4331 | 4347 | ||
| 4332 | _ = try self.addInst(.{ | 4348 | _ = try self.addInst(.{ |
| 4333 | .tag = .blr, | 4349 | .tag = .blr, |
| 4334 | .data = .{ .reg = .x30 }, | 4350 | .data = .{ .reg = .x30 }, |
| 4335 | }); | 4351 | }); |
| 4336 | } else if (func_value.castTag(.extern_fn)) |func_payload| { | 4352 | } else if (func_value.getExternFunc(mod)) |extern_func| { |
| 4337 | const extern_fn = func_payload.data; | 4353 | const decl_name = mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name); |
| 4338 | const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); | 4354 | const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name); |
| 4339 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); | ||
| 4340 | if (self.bin_file.cast(link.File.MachO)) |macho_file| { | 4355 | if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 4341 | const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name); | 4356 | const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name); |
| 4342 | const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); | 4357 | const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); |
| ... | @@ -4352,7 +4367,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4352,7 +4367,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4352 | }); | 4367 | }); |
| 4353 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | 4368 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 4354 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); | 4369 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); |
| 4355 | try self.genSetReg(Type.initTag(.u64), .x30, .{ | 4370 | try self.genSetReg(Type.u64, .x30, .{ |
| 4356 | .linker_load = .{ | 4371 | .linker_load = .{ |
| 4357 | .type = .import, | 4372 | .type = .import, |
| 4358 | .sym_index = sym_index, | 4373 | .sym_index = sym_index, |
| ... | @@ -4369,7 +4384,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4369,7 +4384,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4369 | return self.fail("TODO implement calling bitcasted functions", .{}); | 4384 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 4370 | } | 4385 | } |
| 4371 | } else { | 4386 | } else { |
| 4372 | assert(ty.zigTypeTag() == .Pointer); | 4387 | assert(ty.zigTypeTag(mod) == .Pointer); |
| 4373 | const mcv = try self.resolveInst(callee); | 4388 | const mcv = try self.resolveInst(callee); |
| 4374 | try self.genSetReg(ty, .x30, mcv); | 4389 | try self.genSetReg(ty, .x30, mcv); |
| 4375 | 4390 | ||
| ... | @@ -4407,14 +4422,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4407,14 +4422,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4407 | } | 4422 | } |
| 4408 | 4423 | ||
| 4409 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { | 4424 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4425 | const mod = self.bin_file.options.module.?; | ||
| 4410 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4426 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4411 | const operand = try self.resolveInst(un_op); | 4427 | const operand = try self.resolveInst(un_op); |
| 4412 | const ret_ty = self.fn_type.fnReturnType(); | 4428 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 4413 | 4429 | ||
| 4414 | switch (self.ret_mcv) { | 4430 | switch (self.ret_mcv) { |
| 4415 | .none => {}, | 4431 | .none => {}, |
| 4416 | .immediate => { | 4432 | .immediate => { |
| 4417 | assert(ret_ty.isError()); | 4433 | assert(ret_ty.isError(mod)); |
| 4418 | }, | 4434 | }, |
| 4419 | .register => |reg| { | 4435 | .register => |reg| { |
| 4420 | // Return result by value | 4436 | // Return result by value |
| ... | @@ -4425,11 +4441,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4425,11 +4441,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4425 | // | 4441 | // |
| 4426 | // self.ret_mcv is an address to where this function | 4442 | // self.ret_mcv is an address to where this function |
| 4427 | // should store its result into | 4443 | // should store its result into |
| 4428 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 4444 | const ptr_ty = try mod.singleMutPtrType(ret_ty); |
| 4429 | .base = .{ .tag = .single_mut_pointer }, | ||
| 4430 | .data = ret_ty, | ||
| 4431 | }; | ||
| 4432 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 4433 | try self.store(self.ret_mcv, operand, ptr_ty, ret_ty); | 4445 | try self.store(self.ret_mcv, operand, ptr_ty, ret_ty); |
| 4434 | }, | 4446 | }, |
| 4435 | else => unreachable, | 4447 | else => unreachable, |
| ... | @@ -4442,10 +4454,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4442,10 +4454,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4442 | } | 4454 | } |
| 4443 | 4455 | ||
| 4444 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | 4456 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4457 | const mod = self.bin_file.options.module.?; | ||
| 4445 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4458 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4446 | const ptr = try self.resolveInst(un_op); | 4459 | const ptr = try self.resolveInst(un_op); |
| 4447 | const ptr_ty = self.air.typeOf(un_op); | 4460 | const ptr_ty = self.typeOf(un_op); |
| 4448 | const ret_ty = self.fn_type.fnReturnType(); | 4461 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 4449 | 4462 | ||
| 4450 | switch (self.ret_mcv) { | 4463 | switch (self.ret_mcv) { |
| 4451 | .none => {}, | 4464 | .none => {}, |
| ... | @@ -4465,8 +4478,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4465,8 +4478,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4465 | // location. | 4478 | // location. |
| 4466 | const op_inst = Air.refToIndex(un_op).?; | 4479 | const op_inst = Air.refToIndex(un_op).?; |
| 4467 | if (self.air.instructions.items(.tag)[op_inst] != .ret_ptr) { | 4480 | if (self.air.instructions.items(.tag)[op_inst] != .ret_ptr) { |
| 4468 | const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 4481 | const abi_size = @intCast(u32, ret_ty.abiSize(mod)); |
| 4469 | const abi_align = ret_ty.abiAlignment(self.target.*); | 4482 | const abi_align = ret_ty.abiAlignment(mod); |
| 4470 | 4483 | ||
| 4471 | const offset = try self.allocMem(abi_size, abi_align, null); | 4484 | const offset = try self.allocMem(abi_size, abi_align, null); |
| 4472 | 4485 | ||
| ... | @@ -4485,7 +4498,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4485,7 +4498,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4485 | 4498 | ||
| 4486 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 4499 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 4487 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 4500 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4488 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 4501 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 4489 | 4502 | ||
| 4490 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { | 4503 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 4491 | break :blk try self.cmp(.{ .inst = bin_op.lhs }, .{ .inst = bin_op.rhs }, lhs_ty, op); | 4504 | break :blk try self.cmp(.{ .inst = bin_op.lhs }, .{ .inst = bin_op.rhs }, lhs_ty, op); |
| ... | @@ -4501,29 +4514,28 @@ fn cmp( | ... | @@ -4501,29 +4514,28 @@ fn cmp( |
| 4501 | lhs_ty: Type, | 4514 | lhs_ty: Type, |
| 4502 | op: math.CompareOperator, | 4515 | op: math.CompareOperator, |
| 4503 | ) !MCValue { | 4516 | ) !MCValue { |
| 4504 | var int_buffer: Type.Payload.Bits = undefined; | 4517 | const mod = self.bin_file.options.module.?; |
| 4505 | const int_ty = switch (lhs_ty.zigTypeTag()) { | 4518 | const int_ty = switch (lhs_ty.zigTypeTag(mod)) { |
| 4506 | .Optional => blk: { | 4519 | .Optional => blk: { |
| 4507 | var opt_buffer: Type.Payload.ElemType = undefined; | 4520 | const payload_ty = lhs_ty.optionalChild(mod); |
| 4508 | const payload_ty = lhs_ty.optionalChild(&opt_buffer); | 4521 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4509 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 4522 | break :blk Type.u1; |
| 4510 | break :blk Type.initTag(.u1); | 4523 | } else if (lhs_ty.isPtrLikeOptional(mod)) { |
| 4511 | } else if (lhs_ty.isPtrLikeOptional()) { | ||
| 4512 | break :blk Type.usize; | 4524 | break :blk Type.usize; |
| 4513 | } else { | 4525 | } else { |
| 4514 | return self.fail("TODO ARM cmp non-pointer optionals", .{}); | 4526 | return self.fail("TODO ARM cmp non-pointer optionals", .{}); |
| 4515 | } | 4527 | } |
| 4516 | }, | 4528 | }, |
| 4517 | .Float => return self.fail("TODO ARM cmp floats", .{}), | 4529 | .Float => return self.fail("TODO ARM cmp floats", .{}), |
| 4518 | .Enum => lhs_ty.intTagType(&int_buffer), | 4530 | .Enum => lhs_ty.intTagType(mod), |
| 4519 | .Int => lhs_ty, | 4531 | .Int => lhs_ty, |
| 4520 | .Bool => Type.initTag(.u1), | 4532 | .Bool => Type.u1, |
| 4521 | .Pointer => Type.usize, | 4533 | .Pointer => Type.usize, |
| 4522 | .ErrorSet => Type.initTag(.u16), | 4534 | .ErrorSet => Type.u16, |
| 4523 | else => unreachable, | 4535 | else => unreachable, |
| 4524 | }; | 4536 | }; |
| 4525 | 4537 | ||
| 4526 | const int_info = int_ty.intInfo(self.target.*); | 4538 | const int_info = int_ty.intInfo(mod); |
| 4527 | if (int_info.bits <= 64) { | 4539 | if (int_info.bits <= 64) { |
| 4528 | try self.spillCompareFlagsIfOccupied(); | 4540 | try self.spillCompareFlagsIfOccupied(); |
| 4529 | 4541 | ||
| ... | @@ -4609,8 +4621,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4609,8 +4621,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 4609 | } | 4621 | } |
| 4610 | 4622 | ||
| 4611 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { | 4623 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 4612 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 4624 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; |
| 4613 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | 4625 | const mod = self.bin_file.options.module.?; |
| 4626 | const function = mod.funcPtr(ty_fn.func); | ||
| 4614 | // TODO emit debug info for function change | 4627 | // TODO emit debug info for function change |
| 4615 | _ = function; | 4628 | _ = function; |
| 4616 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); | 4629 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| ... | @@ -4625,7 +4638,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4625,7 +4638,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4625 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 4638 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4626 | const operand = pl_op.operand; | 4639 | const operand = pl_op.operand; |
| 4627 | const tag = self.air.instructions.items(.tag)[inst]; | 4640 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4628 | const ty = self.air.typeOf(operand); | 4641 | const ty = self.typeOf(operand); |
| 4629 | const mcv = try self.resolveInst(operand); | 4642 | const mcv = try self.resolveInst(operand); |
| 4630 | const name = self.air.nullTerminatedString(pl_op.payload); | 4643 | const name = self.air.nullTerminatedString(pl_op.payload); |
| 4631 | 4644 | ||
| ... | @@ -4687,8 +4700,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4687,8 +4700,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4687 | // whether it needs to be spilled in the branches | 4700 | // whether it needs to be spilled in the branches |
| 4688 | if (self.liveness.operandDies(inst, 0)) { | 4701 | if (self.liveness.operandDies(inst, 0)) { |
| 4689 | const op_int = @enumToInt(pl_op.operand); | 4702 | const op_int = @enumToInt(pl_op.operand); |
| 4690 | if (op_int >= Air.Inst.Ref.typed_value_map.len) { | 4703 | if (op_int >= Air.ref_start_index) { |
| 4691 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | 4704 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); |
| 4692 | self.processDeath(op_index); | 4705 | self.processDeath(op_index); |
| 4693 | } | 4706 | } |
| 4694 | } | 4707 | } |
| ... | @@ -4777,7 +4790,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4777,7 +4790,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4777 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); | 4790 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); |
| 4778 | // TODO make sure the destination stack offset / register does not already have something | 4791 | // TODO make sure the destination stack offset / register does not already have something |
| 4779 | // going on there. | 4792 | // going on there. |
| 4780 | try self.setRegOrMem(self.air.typeOfIndex(else_key), canon_mcv, else_value); | 4793 | try self.setRegOrMem(self.typeOfIndex(else_key), canon_mcv, else_value); |
| 4781 | // TODO track the new register / stack allocation | 4794 | // TODO track the new register / stack allocation |
| 4782 | } | 4795 | } |
| 4783 | try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, saved_then_branch.inst_table.count()); | 4796 | try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, saved_then_branch.inst_table.count()); |
| ... | @@ -4804,7 +4817,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4804,7 +4817,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4804 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); | 4817 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); |
| 4805 | // TODO make sure the destination stack offset / register does not already have something | 4818 | // TODO make sure the destination stack offset / register does not already have something |
| 4806 | // going on there. | 4819 | // going on there. |
| 4807 | try self.setRegOrMem(self.air.typeOfIndex(then_key), parent_mcv, then_value); | 4820 | try self.setRegOrMem(self.typeOfIndex(then_key), parent_mcv, then_value); |
| 4808 | // TODO track the new register / stack allocation | 4821 | // TODO track the new register / stack allocation |
| 4809 | } | 4822 | } |
| 4810 | 4823 | ||
| ... | @@ -4819,13 +4832,13 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4819,13 +4832,13 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4819 | } | 4832 | } |
| 4820 | 4833 | ||
| 4821 | fn isNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue { | 4834 | fn isNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue { |
| 4822 | const sentinel: struct { ty: Type, bind: ReadArg.Bind } = if (!operand_ty.isPtrLikeOptional()) blk: { | 4835 | const mod = self.bin_file.options.module.?; |
| 4823 | var buf: Type.Payload.ElemType = undefined; | 4836 | const sentinel: struct { ty: Type, bind: ReadArg.Bind } = if (!operand_ty.isPtrLikeOptional(mod)) blk: { |
| 4824 | const payload_ty = operand_ty.optionalChild(&buf); | 4837 | const payload_ty = operand_ty.optionalChild(mod); |
| 4825 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) | 4838 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 4826 | break :blk .{ .ty = operand_ty, .bind = operand_bind }; | 4839 | break :blk .{ .ty = operand_ty, .bind = operand_bind }; |
| 4827 | 4840 | ||
| 4828 | const offset = @intCast(u32, payload_ty.abiSize(self.target.*)); | 4841 | const offset = @intCast(u32, payload_ty.abiSize(mod)); |
| 4829 | const operand_mcv = try operand_bind.resolveToMcv(self); | 4842 | const operand_mcv = try operand_bind.resolveToMcv(self); |
| 4830 | const new_mcv: MCValue = switch (operand_mcv) { | 4843 | const new_mcv: MCValue = switch (operand_mcv) { |
| 4831 | .register => |source_reg| new: { | 4844 | .register => |source_reg| new: { |
| ... | @@ -4838,7 +4851,7 @@ fn isNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue { | ... | @@ -4838,7 +4851,7 @@ fn isNull(self: *Self, operand_bind: ReadArg.Bind, operand_ty: Type) !MCValue { |
| 4838 | try self.genSetReg(payload_ty, dest_reg, operand_mcv); | 4851 | try self.genSetReg(payload_ty, dest_reg, operand_mcv); |
| 4839 | } else { | 4852 | } else { |
| 4840 | _ = try self.addInst(.{ | 4853 | _ = try self.addInst(.{ |
| 4841 | .tag = if (payload_ty.isSignedInt()) | 4854 | .tag = if (payload_ty.isSignedInt(mod)) |
| 4842 | Mir.Inst.Tag.asr_immediate | 4855 | Mir.Inst.Tag.asr_immediate |
| 4843 | else | 4856 | else |
| 4844 | Mir.Inst.Tag.lsr_immediate, | 4857 | Mir.Inst.Tag.lsr_immediate, |
| ... | @@ -4875,9 +4888,10 @@ fn isErr( | ... | @@ -4875,9 +4888,10 @@ fn isErr( |
| 4875 | error_union_bind: ReadArg.Bind, | 4888 | error_union_bind: ReadArg.Bind, |
| 4876 | error_union_ty: Type, | 4889 | error_union_ty: Type, |
| 4877 | ) !MCValue { | 4890 | ) !MCValue { |
| 4878 | const error_type = error_union_ty.errorUnionSet(); | 4891 | const mod = self.bin_file.options.module.?; |
| 4892 | const error_type = error_union_ty.errorUnionSet(mod); | ||
| 4879 | 4893 | ||
| 4880 | if (error_type.errorSetIsEmpty()) { | 4894 | if (error_type.errorSetIsEmpty(mod)) { |
| 4881 | return MCValue{ .immediate = 0 }; // always false | 4895 | return MCValue{ .immediate = 0 }; // always false |
| 4882 | } | 4896 | } |
| 4883 | 4897 | ||
| ... | @@ -4908,7 +4922,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4908,7 +4922,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4908 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4922 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4909 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4923 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4910 | const operand = try self.resolveInst(un_op); | 4924 | const operand = try self.resolveInst(un_op); |
| 4911 | const operand_ty = self.air.typeOf(un_op); | 4925 | const operand_ty = self.typeOf(un_op); |
| 4912 | 4926 | ||
| 4913 | break :result try self.isNull(.{ .mcv = operand }, operand_ty); | 4927 | break :result try self.isNull(.{ .mcv = operand }, operand_ty); |
| 4914 | }; | 4928 | }; |
| ... | @@ -4916,11 +4930,12 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4916,11 +4930,12 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4916 | } | 4930 | } |
| 4917 | 4931 | ||
| 4918 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 4932 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4933 | const mod = self.bin_file.options.module.?; | ||
| 4919 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4934 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4920 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4935 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4921 | const operand_ptr = try self.resolveInst(un_op); | 4936 | const operand_ptr = try self.resolveInst(un_op); |
| 4922 | const ptr_ty = self.air.typeOf(un_op); | 4937 | const ptr_ty = self.typeOf(un_op); |
| 4923 | const elem_ty = ptr_ty.elemType(); | 4938 | const elem_ty = ptr_ty.childType(mod); |
| 4924 | 4939 | ||
| 4925 | const operand = try self.allocRegOrMem(elem_ty, true, null); | 4940 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4926 | try self.load(operand, operand_ptr, ptr_ty); | 4941 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | @@ -4934,7 +4949,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4934,7 +4949,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4934 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4949 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4935 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4950 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4936 | const operand = try self.resolveInst(un_op); | 4951 | const operand = try self.resolveInst(un_op); |
| 4937 | const operand_ty = self.air.typeOf(un_op); | 4952 | const operand_ty = self.typeOf(un_op); |
| 4938 | 4953 | ||
| 4939 | break :result try self.isNonNull(.{ .mcv = operand }, operand_ty); | 4954 | break :result try self.isNonNull(.{ .mcv = operand }, operand_ty); |
| 4940 | }; | 4955 | }; |
| ... | @@ -4942,11 +4957,12 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4942,11 +4957,12 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4942 | } | 4957 | } |
| 4943 | 4958 | ||
| 4944 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 4959 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4960 | const mod = self.bin_file.options.module.?; | ||
| 4945 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4961 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4946 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4962 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4947 | const operand_ptr = try self.resolveInst(un_op); | 4963 | const operand_ptr = try self.resolveInst(un_op); |
| 4948 | const ptr_ty = self.air.typeOf(un_op); | 4964 | const ptr_ty = self.typeOf(un_op); |
| 4949 | const elem_ty = ptr_ty.elemType(); | 4965 | const elem_ty = ptr_ty.childType(mod); |
| 4950 | 4966 | ||
| 4951 | const operand = try self.allocRegOrMem(elem_ty, true, null); | 4967 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4952 | try self.load(operand, operand_ptr, ptr_ty); | 4968 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | @@ -4960,7 +4976,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4960,7 +4976,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4960 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4976 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4961 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4977 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4962 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; | 4978 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; |
| 4963 | const error_union_ty = self.air.typeOf(un_op); | 4979 | const error_union_ty = self.typeOf(un_op); |
| 4964 | 4980 | ||
| 4965 | break :result try self.isErr(error_union_bind, error_union_ty); | 4981 | break :result try self.isErr(error_union_bind, error_union_ty); |
| 4966 | }; | 4982 | }; |
| ... | @@ -4968,11 +4984,12 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4968,11 +4984,12 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4968 | } | 4984 | } |
| 4969 | 4985 | ||
| 4970 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 4986 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4987 | const mod = self.bin_file.options.module.?; | ||
| 4971 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4988 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4972 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4989 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4973 | const operand_ptr = try self.resolveInst(un_op); | 4990 | const operand_ptr = try self.resolveInst(un_op); |
| 4974 | const ptr_ty = self.air.typeOf(un_op); | 4991 | const ptr_ty = self.typeOf(un_op); |
| 4975 | const elem_ty = ptr_ty.elemType(); | 4992 | const elem_ty = ptr_ty.childType(mod); |
| 4976 | 4993 | ||
| 4977 | const operand = try self.allocRegOrMem(elem_ty, true, null); | 4994 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4978 | try self.load(operand, operand_ptr, ptr_ty); | 4995 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | @@ -4986,7 +5003,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4986,7 +5003,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4986 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 5003 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4987 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 5004 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4988 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; | 5005 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; |
| 4989 | const error_union_ty = self.air.typeOf(un_op); | 5006 | const error_union_ty = self.typeOf(un_op); |
| 4990 | 5007 | ||
| 4991 | break :result try self.isNonErr(error_union_bind, error_union_ty); | 5008 | break :result try self.isNonErr(error_union_bind, error_union_ty); |
| 4992 | }; | 5009 | }; |
| ... | @@ -4994,11 +5011,12 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4994,11 +5011,12 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4994 | } | 5011 | } |
| 4995 | 5012 | ||
| 4996 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 5013 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5014 | const mod = self.bin_file.options.module.?; | ||
| 4997 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 5015 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4998 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 5016 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4999 | const operand_ptr = try self.resolveInst(un_op); | 5017 | const operand_ptr = try self.resolveInst(un_op); |
| 5000 | const ptr_ty = self.air.typeOf(un_op); | 5018 | const ptr_ty = self.typeOf(un_op); |
| 5001 | const elem_ty = ptr_ty.elemType(); | 5019 | const elem_ty = ptr_ty.childType(mod); |
| 5002 | 5020 | ||
| 5003 | const operand = try self.allocRegOrMem(elem_ty, true, null); | 5021 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 5004 | try self.load(operand, operand_ptr, ptr_ty); | 5022 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | @@ -5065,7 +5083,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5065,7 +5083,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 5065 | 5083 | ||
| 5066 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | 5084 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 5067 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 5085 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 5068 | const condition_ty = self.air.typeOf(pl_op.operand); | 5086 | const condition_ty = self.typeOf(pl_op.operand); |
| 5069 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); | 5087 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 5070 | const liveness = try self.liveness.getSwitchBr( | 5088 | const liveness = try self.liveness.getSwitchBr( |
| 5071 | self.gpa, | 5089 | self.gpa, |
| ... | @@ -5210,9 +5228,10 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5210,9 +5228,10 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 5210 | } | 5228 | } |
| 5211 | 5229 | ||
| 5212 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | 5230 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5231 | const mod = self.bin_file.options.module.?; | ||
| 5213 | const block_data = self.blocks.getPtr(block).?; | 5232 | const block_data = self.blocks.getPtr(block).?; |
| 5214 | 5233 | ||
| 5215 | if (self.air.typeOf(operand).hasRuntimeBits()) { | 5234 | if (self.typeOf(operand).hasRuntimeBits(mod)) { |
| 5216 | const operand_mcv = try self.resolveInst(operand); | 5235 | const operand_mcv = try self.resolveInst(operand); |
| 5217 | const block_mcv = block_data.mcv; | 5236 | const block_mcv = block_data.mcv; |
| 5218 | if (block_mcv == .none) { | 5237 | if (block_mcv == .none) { |
| ... | @@ -5220,14 +5239,14 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | ... | @@ -5220,14 +5239,14 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5220 | .none, .dead, .unreach => unreachable, | 5239 | .none, .dead, .unreach => unreachable, |
| 5221 | .register, .stack_offset, .memory => operand_mcv, | 5240 | .register, .stack_offset, .memory => operand_mcv, |
| 5222 | .immediate, .stack_argument_offset, .compare_flags => blk: { | 5241 | .immediate, .stack_argument_offset, .compare_flags => blk: { |
| 5223 | const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block); | 5242 | const new_mcv = try self.allocRegOrMem(self.typeOfIndex(block), true, block); |
| 5224 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | 5243 | try self.setRegOrMem(self.typeOfIndex(block), new_mcv, operand_mcv); |
| 5225 | break :blk new_mcv; | 5244 | break :blk new_mcv; |
| 5226 | }, | 5245 | }, |
| 5227 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), | 5246 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), |
| 5228 | }; | 5247 | }; |
| 5229 | } else { | 5248 | } else { |
| 5230 | try self.setRegOrMem(self.air.typeOfIndex(block), block_mcv, operand_mcv); | 5249 | try self.setRegOrMem(self.typeOfIndex(block), block_mcv, operand_mcv); |
| 5231 | } | 5250 | } |
| 5232 | } | 5251 | } |
| 5233 | return self.brVoid(block); | 5252 | return self.brVoid(block); |
| ... | @@ -5293,7 +5312,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5293,7 +5312,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 5293 | 5312 | ||
| 5294 | const arg_mcv = try self.resolveInst(input); | 5313 | const arg_mcv = try self.resolveInst(input); |
| 5295 | try self.register_manager.getReg(reg, null); | 5314 | try self.register_manager.getReg(reg, null); |
| 5296 | try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); | 5315 | try self.genSetReg(self.typeOf(input), reg, arg_mcv); |
| 5297 | } | 5316 | } |
| 5298 | 5317 | ||
| 5299 | { | 5318 | { |
| ... | @@ -5386,7 +5405,8 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { | ... | @@ -5386,7 +5405,8 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { |
| 5386 | } | 5405 | } |
| 5387 | 5406 | ||
| 5388 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { | 5407 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 5389 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 5408 | const mod = self.bin_file.options.module.?; |
| 5409 | const abi_size = @intCast(u32, ty.abiSize(mod)); | ||
| 5390 | switch (mcv) { | 5410 | switch (mcv) { |
| 5391 | .dead => unreachable, | 5411 | .dead => unreachable, |
| 5392 | .unreach, .none => return, // Nothing to do. | 5412 | .unreach, .none => return, // Nothing to do. |
| ... | @@ -5441,11 +5461,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5441,11 +5461,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5441 | const reg_lock = self.register_manager.lockReg(rwo.reg); | 5461 | const reg_lock = self.register_manager.lockReg(rwo.reg); |
| 5442 | defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg); | 5462 | defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg); |
| 5443 | 5463 | ||
| 5444 | const wrapped_ty = ty.structFieldType(0); | 5464 | const wrapped_ty = ty.structFieldType(0, mod); |
| 5445 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = rwo.reg }); | 5465 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = rwo.reg }); |
| 5446 | 5466 | ||
| 5447 | const overflow_bit_ty = ty.structFieldType(1); | 5467 | const overflow_bit_ty = ty.structFieldType(1, mod); |
| 5448 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*)); | 5468 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, mod)); |
| 5449 | const raw_cond_reg = try self.register_manager.allocReg(null, gp); | 5469 | const raw_cond_reg = try self.register_manager.allocReg(null, gp); |
| 5450 | const cond_reg = self.registerAlias(raw_cond_reg, overflow_bit_ty); | 5470 | const cond_reg = self.registerAlias(raw_cond_reg, overflow_bit_ty); |
| 5451 | 5471 | ||
| ... | @@ -5478,11 +5498,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5478,11 +5498,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5478 | const reg = try self.copyToTmpRegister(ty, mcv); | 5498 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 5479 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 5499 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 5480 | } else { | 5500 | } else { |
| 5481 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 5501 | const ptr_ty = try mod.singleMutPtrType(ty); |
| 5482 | .base = .{ .tag = .single_mut_pointer }, | ||
| 5483 | .data = ty, | ||
| 5484 | }; | ||
| 5485 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 5486 | 5502 | ||
| 5487 | // TODO call extern memcpy | 5503 | // TODO call extern memcpy |
| 5488 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp); | 5504 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp); |
| ... | @@ -5559,6 +5575,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5559,6 +5575,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5559 | } | 5575 | } |
| 5560 | 5576 | ||
| 5561 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { | 5577 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 5578 | const mod = self.bin_file.options.module.?; | ||
| 5562 | switch (mcv) { | 5579 | switch (mcv) { |
| 5563 | .dead => unreachable, | 5580 | .dead => unreachable, |
| 5564 | .unreach, .none => return, // Nothing to do. | 5581 | .unreach, .none => return, // Nothing to do. |
| ... | @@ -5669,13 +5686,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5669,13 +5686,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5669 | try self.genLdrRegister(reg, reg.toX(), ty); | 5686 | try self.genLdrRegister(reg, reg.toX(), ty); |
| 5670 | }, | 5687 | }, |
| 5671 | .stack_offset => |off| { | 5688 | .stack_offset => |off| { |
| 5672 | const abi_size = ty.abiSize(self.target.*); | 5689 | const abi_size = ty.abiSize(mod); |
| 5673 | 5690 | ||
| 5674 | switch (abi_size) { | 5691 | switch (abi_size) { |
| 5675 | 1, 2, 4, 8 => { | 5692 | 1, 2, 4, 8 => { |
| 5676 | const tag: Mir.Inst.Tag = switch (abi_size) { | 5693 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5677 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack else .ldrb_stack, | 5694 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb_stack else .ldrb_stack, |
| 5678 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack else .ldrh_stack, | 5695 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh_stack else .ldrh_stack, |
| 5679 | 4, 8 => .ldr_stack, | 5696 | 4, 8 => .ldr_stack, |
| 5680 | else => unreachable, // unexpected abi size | 5697 | else => unreachable, // unexpected abi size |
| 5681 | }; | 5698 | }; |
| ... | @@ -5693,13 +5710,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5693,13 +5710,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5693 | } | 5710 | } |
| 5694 | }, | 5711 | }, |
| 5695 | .stack_argument_offset => |off| { | 5712 | .stack_argument_offset => |off| { |
| 5696 | const abi_size = ty.abiSize(self.target.*); | 5713 | const abi_size = ty.abiSize(mod); |
| 5697 | 5714 | ||
| 5698 | switch (abi_size) { | 5715 | switch (abi_size) { |
| 5699 | 1, 2, 4, 8 => { | 5716 | 1, 2, 4, 8 => { |
| 5700 | const tag: Mir.Inst.Tag = switch (abi_size) { | 5717 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5701 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument, | 5718 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument, |
| 5702 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument, | 5719 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument, |
| 5703 | 4, 8 => .ldr_stack_argument, | 5720 | 4, 8 => .ldr_stack_argument, |
| 5704 | else => unreachable, // unexpected abi size | 5721 | else => unreachable, // unexpected abi size |
| 5705 | }; | 5722 | }; |
| ... | @@ -5720,7 +5737,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5720,7 +5737,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5720 | } | 5737 | } |
| 5721 | 5738 | ||
| 5722 | fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { | 5739 | fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 5723 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 5740 | const mod = self.bin_file.options.module.?; |
| 5741 | const abi_size = @intCast(u32, ty.abiSize(mod)); | ||
| 5724 | switch (mcv) { | 5742 | switch (mcv) { |
| 5725 | .dead => unreachable, | 5743 | .dead => unreachable, |
| 5726 | .none, .unreach => return, | 5744 | .none, .unreach => return, |
| ... | @@ -5728,7 +5746,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -5728,7 +5746,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5728 | if (!self.wantSafety()) | 5746 | if (!self.wantSafety()) |
| 5729 | return; // The already existing value will do just fine. | 5747 | return; // The already existing value will do just fine. |
| 5730 | // TODO Upgrade this to a memset call when we have that available. | 5748 | // TODO Upgrade this to a memset call when we have that available. |
| 5731 | switch (ty.abiSize(self.target.*)) { | 5749 | switch (ty.abiSize(mod)) { |
| 5732 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), | 5750 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 5733 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), | 5751 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 5734 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 5752 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| ... | @@ -5798,11 +5816,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -5798,11 +5816,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5798 | const reg = try self.copyToTmpRegister(ty, mcv); | 5816 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 5799 | return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg }); | 5817 | return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg }); |
| 5800 | } else { | 5818 | } else { |
| 5801 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 5819 | const ptr_ty = try mod.singleMutPtrType(ty); |
| 5802 | .base = .{ .tag = .single_mut_pointer }, | ||
| 5803 | .data = ty, | ||
| 5804 | }; | ||
| 5805 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 5806 | 5820 | ||
| 5807 | // TODO call extern memcpy | 5821 | // TODO call extern memcpy |
| 5808 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp); | 5822 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp); |
| ... | @@ -5913,7 +5927,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5913,7 +5927,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 5913 | }; | 5927 | }; |
| 5914 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | 5928 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 5915 | 5929 | ||
| 5916 | const dest_ty = self.air.typeOfIndex(inst); | 5930 | const dest_ty = self.typeOfIndex(inst); |
| 5917 | const dest = try self.allocRegOrMem(dest_ty, true, inst); | 5931 | const dest = try self.allocRegOrMem(dest_ty, true, inst); |
| 5918 | try self.setRegOrMem(dest_ty, dest, operand); | 5932 | try self.setRegOrMem(dest_ty, dest, operand); |
| 5919 | break :result dest; | 5933 | break :result dest; |
| ... | @@ -5922,19 +5936,20 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5922,19 +5936,20 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 5922 | } | 5936 | } |
| 5923 | 5937 | ||
| 5924 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | 5938 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5939 | const mod = self.bin_file.options.module.?; | ||
| 5925 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5940 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5926 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 5941 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 5927 | const ptr_ty = self.air.typeOf(ty_op.operand); | 5942 | const ptr_ty = self.typeOf(ty_op.operand); |
| 5928 | const ptr = try self.resolveInst(ty_op.operand); | 5943 | const ptr = try self.resolveInst(ty_op.operand); |
| 5929 | const array_ty = ptr_ty.childType(); | 5944 | const array_ty = ptr_ty.childType(mod); |
| 5930 | const array_len = @intCast(u32, array_ty.arrayLen()); | 5945 | const array_len = @intCast(u32, array_ty.arrayLen(mod)); |
| 5931 | 5946 | ||
| 5932 | const ptr_bits = self.target.ptrBitWidth(); | 5947 | const ptr_bits = self.target.ptrBitWidth(); |
| 5933 | const ptr_bytes = @divExact(ptr_bits, 8); | 5948 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 5934 | 5949 | ||
| 5935 | const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst); | 5950 | const stack_offset = try self.allocMem(ptr_bytes * 2, ptr_bytes * 2, inst); |
| 5936 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 5951 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 5937 | try self.genSetStack(Type.initTag(.usize), stack_offset - ptr_bytes, .{ .immediate = array_len }); | 5952 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 5938 | break :result MCValue{ .stack_offset = stack_offset }; | 5953 | break :result MCValue{ .stack_offset = stack_offset }; |
| 5939 | }; | 5954 | }; |
| 5940 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 5955 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -6044,8 +6059,9 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6044,8 +6059,9 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { |
| 6044 | } | 6059 | } |
| 6045 | 6060 | ||
| 6046 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | 6061 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 6047 | const vector_ty = self.air.typeOfIndex(inst); | 6062 | const mod = self.bin_file.options.module.?; |
| 6048 | const len = vector_ty.vectorLen(); | 6063 | const vector_ty = self.typeOfIndex(inst); |
| 6064 | const len = vector_ty.vectorLen(mod); | ||
| 6049 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 6065 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 6050 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); | 6066 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 6051 | const result: MCValue = res: { | 6067 | const result: MCValue = res: { |
| ... | @@ -6087,14 +6103,15 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6087,14 +6103,15 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 6087 | } | 6103 | } |
| 6088 | 6104 | ||
| 6089 | fn airTry(self: *Self, inst: Air.Inst.Index) !void { | 6105 | fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 6106 | const mod = self.bin_file.options.module.?; | ||
| 6090 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 6107 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 6091 | const extra = self.air.extraData(Air.Try, pl_op.payload); | 6108 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 6092 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 6109 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 6093 | const result: MCValue = result: { | 6110 | const result: MCValue = result: { |
| 6094 | const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand }; | 6111 | const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand }; |
| 6095 | const error_union_ty = self.air.typeOf(pl_op.operand); | 6112 | const error_union_ty = self.typeOf(pl_op.operand); |
| 6096 | const error_union_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | 6113 | const error_union_size = @intCast(u32, error_union_ty.abiSize(mod)); |
| 6097 | const error_union_align = error_union_ty.abiAlignment(self.target.*); | 6114 | const error_union_align = error_union_ty.abiAlignment(mod); |
| 6098 | 6115 | ||
| 6099 | // The error union will die in the body. However, we need the | 6116 | // The error union will die in the body. However, we need the |
| 6100 | // error union after the body in order to extract the payload | 6117 | // error union after the body in order to extract the payload |
| ... | @@ -6123,37 +6140,32 @@ fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6123,37 +6140,32 @@ fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6123 | } | 6140 | } |
| 6124 | 6141 | ||
| 6125 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | 6142 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 6126 | // First section of indexes correspond to a set number of constant values. | 6143 | const mod = self.bin_file.options.module.?; |
| 6127 | const ref_int = @enumToInt(inst); | ||
| 6128 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | ||
| 6129 | const tv = Air.Inst.Ref.typed_value_map[ref_int]; | ||
| 6130 | if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) { | ||
| 6131 | return MCValue{ .none = {} }; | ||
| 6132 | } | ||
| 6133 | return self.genTypedValue(tv); | ||
| 6134 | } | ||
| 6135 | 6144 | ||
| 6136 | // If the type has no codegen bits, no need to store it. | 6145 | // If the type has no codegen bits, no need to store it. |
| 6137 | const inst_ty = self.air.typeOf(inst); | 6146 | const inst_ty = self.typeOf(inst); |
| 6138 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError()) | 6147 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod) and !inst_ty.isError(mod)) |
| 6139 | return MCValue{ .none = {} }; | 6148 | return MCValue{ .none = {} }; |
| 6140 | 6149 | ||
| 6141 | const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); | 6150 | const inst_index = Air.refToIndex(inst) orelse return self.genTypedValue(.{ |
| 6151 | .ty = inst_ty, | ||
| 6152 | .val = (try self.air.value(inst, mod)).?, | ||
| 6153 | }); | ||
| 6154 | |||
| 6142 | switch (self.air.instructions.items(.tag)[inst_index]) { | 6155 | switch (self.air.instructions.items(.tag)[inst_index]) { |
| 6143 | .constant => { | 6156 | .interned => { |
| 6144 | // Constants have static lifetimes, so they are always memoized in the outer most table. | 6157 | // Constants have static lifetimes, so they are always memoized in the outer most table. |
| 6145 | const branch = &self.branch_stack.items[0]; | 6158 | const branch = &self.branch_stack.items[0]; |
| 6146 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); | 6159 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); |
| 6147 | if (!gop.found_existing) { | 6160 | if (!gop.found_existing) { |
| 6148 | const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl; | 6161 | const interned = self.air.instructions.items(.data)[inst_index].interned; |
| 6149 | gop.value_ptr.* = try self.genTypedValue(.{ | 6162 | gop.value_ptr.* = try self.genTypedValue(.{ |
| 6150 | .ty = inst_ty, | 6163 | .ty = inst_ty, |
| 6151 | .val = self.air.values[ty_pl.payload], | 6164 | .val = interned.toValue(), |
| 6152 | }); | 6165 | }); |
| 6153 | } | 6166 | } |
| 6154 | return gop.value_ptr.*; | 6167 | return gop.value_ptr.*; |
| 6155 | }, | 6168 | }, |
| 6156 | .const_ty => unreachable, | ||
| 6157 | else => return self.getResolvedInstValue(inst_index), | 6169 | else => return self.getResolvedInstValue(inst_index), |
| 6158 | } | 6170 | } |
| 6159 | } | 6171 | } |
| ... | @@ -6208,12 +6220,11 @@ const CallMCValues = struct { | ... | @@ -6208,12 +6220,11 @@ const CallMCValues = struct { |
| 6208 | 6220 | ||
| 6209 | /// Caller must call `CallMCValues.deinit`. | 6221 | /// Caller must call `CallMCValues.deinit`. |
| 6210 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | 6222 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6211 | const cc = fn_ty.fnCallingConvention(); | 6223 | const mod = self.bin_file.options.module.?; |
| 6212 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | 6224 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 6213 | defer self.gpa.free(param_types); | 6225 | const cc = fn_info.cc; |
| 6214 | fn_ty.fnParamTypes(param_types); | ||
| 6215 | var result: CallMCValues = .{ | 6226 | var result: CallMCValues = .{ |
| 6216 | .args = try self.gpa.alloc(MCValue, param_types.len), | 6227 | .args = try self.gpa.alloc(MCValue, fn_info.param_types.len), |
| 6217 | // These undefined values must be populated before returning from this function. | 6228 | // These undefined values must be populated before returning from this function. |
| 6218 | .return_value = undefined, | 6229 | .return_value = undefined, |
| 6219 | .stack_byte_count = undefined, | 6230 | .stack_byte_count = undefined, |
| ... | @@ -6221,7 +6232,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6221,7 +6232,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6221 | }; | 6232 | }; |
| 6222 | errdefer self.gpa.free(result.args); | 6233 | errdefer self.gpa.free(result.args); |
| 6223 | 6234 | ||
| 6224 | const ret_ty = fn_ty.fnReturnType(); | 6235 | const ret_ty = fn_ty.fnReturnType(mod); |
| 6225 | 6236 | ||
| 6226 | switch (cc) { | 6237 | switch (cc) { |
| 6227 | .Naked => { | 6238 | .Naked => { |
| ... | @@ -6236,14 +6247,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6236,14 +6247,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6236 | var ncrn: usize = 0; // Next Core Register Number | 6247 | var ncrn: usize = 0; // Next Core Register Number |
| 6237 | var nsaa: u32 = 0; // Next stacked argument address | 6248 | var nsaa: u32 = 0; // Next stacked argument address |
| 6238 | 6249 | ||
| 6239 | if (ret_ty.zigTypeTag() == .NoReturn) { | 6250 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 6240 | result.return_value = .{ .unreach = {} }; | 6251 | result.return_value = .{ .unreach = {} }; |
| 6241 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { | 6252 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod) and !ret_ty.isError(mod)) { |
| 6242 | result.return_value = .{ .none = {} }; | 6253 | result.return_value = .{ .none = {} }; |
| 6243 | } else { | 6254 | } else { |
| 6244 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 6255 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(mod)); |
| 6245 | if (ret_ty_size == 0) { | 6256 | if (ret_ty_size == 0) { |
| 6246 | assert(ret_ty.isError()); | 6257 | assert(ret_ty.isError(mod)); |
| 6247 | result.return_value = .{ .immediate = 0 }; | 6258 | result.return_value = .{ .immediate = 0 }; |
| 6248 | } else if (ret_ty_size <= 8) { | 6259 | } else if (ret_ty_size <= 8) { |
| 6249 | result.return_value = .{ .register = self.registerAlias(c_abi_int_return_regs[0], ret_ty) }; | 6260 | result.return_value = .{ .register = self.registerAlias(c_abi_int_return_regs[0], ret_ty) }; |
| ... | @@ -6252,8 +6263,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6252,8 +6263,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6252 | } | 6263 | } |
| 6253 | } | 6264 | } |
| 6254 | 6265 | ||
| 6255 | for (param_types, 0..) |ty, i| { | 6266 | for (fn_info.param_types, 0..) |ty, i| { |
| 6256 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 6267 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); |
| 6257 | if (param_size == 0) { | 6268 | if (param_size == 0) { |
| 6258 | result.args[i] = .{ .none = {} }; | 6269 | result.args[i] = .{ .none = {} }; |
| 6259 | continue; | 6270 | continue; |
| ... | @@ -6261,14 +6272,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6261,14 +6272,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6261 | 6272 | ||
| 6262 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned | 6273 | // We round up NCRN only for non-Apple platforms which allow the 16-byte aligned |
| 6263 | // values to spread across odd-numbered registers. | 6274 | // values to spread across odd-numbered registers. |
| 6264 | if (ty.abiAlignment(self.target.*) == 16 and !self.target.isDarwin()) { | 6275 | if (ty.toType().abiAlignment(mod) == 16 and !self.target.isDarwin()) { |
| 6265 | // Round up NCRN to the next even number | 6276 | // Round up NCRN to the next even number |
| 6266 | ncrn += ncrn % 2; | 6277 | ncrn += ncrn % 2; |
| 6267 | } | 6278 | } |
| 6268 | 6279 | ||
| 6269 | if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) { | 6280 | if (std.math.divCeil(u32, param_size, 8) catch unreachable <= 8 - ncrn) { |
| 6270 | if (param_size <= 8) { | 6281 | if (param_size <= 8) { |
| 6271 | result.args[i] = .{ .register = self.registerAlias(c_abi_int_param_regs[ncrn], ty) }; | 6282 | result.args[i] = .{ .register = self.registerAlias(c_abi_int_param_regs[ncrn], ty.toType()) }; |
| 6272 | ncrn += 1; | 6283 | ncrn += 1; |
| 6273 | } else { | 6284 | } else { |
| 6274 | return self.fail("TODO MCValues with multiple registers", .{}); | 6285 | return self.fail("TODO MCValues with multiple registers", .{}); |
| ... | @@ -6279,7 +6290,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6279,7 +6290,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6279 | ncrn = 8; | 6290 | ncrn = 8; |
| 6280 | // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided | 6291 | // TODO Apple allows the arguments on the stack to be non-8-byte aligned provided |
| 6281 | // that the entire stack space consumed by the arguments is 8-byte aligned. | 6292 | // that the entire stack space consumed by the arguments is 8-byte aligned. |
| 6282 | if (ty.abiAlignment(self.target.*) == 8) { | 6293 | if (ty.toType().abiAlignment(mod) == 8) { |
| 6283 | if (nsaa % 8 != 0) { | 6294 | if (nsaa % 8 != 0) { |
| 6284 | nsaa += 8 - (nsaa % 8); | 6295 | nsaa += 8 - (nsaa % 8); |
| 6285 | } | 6296 | } |
| ... | @@ -6294,14 +6305,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6294,14 +6305,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6294 | result.stack_align = 16; | 6305 | result.stack_align = 16; |
| 6295 | }, | 6306 | }, |
| 6296 | .Unspecified => { | 6307 | .Unspecified => { |
| 6297 | if (ret_ty.zigTypeTag() == .NoReturn) { | 6308 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 6298 | result.return_value = .{ .unreach = {} }; | 6309 | result.return_value = .{ .unreach = {} }; |
| 6299 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { | 6310 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod) and !ret_ty.isError(mod)) { |
| 6300 | result.return_value = .{ .none = {} }; | 6311 | result.return_value = .{ .none = {} }; |
| 6301 | } else { | 6312 | } else { |
| 6302 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 6313 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(mod)); |
| 6303 | if (ret_ty_size == 0) { | 6314 | if (ret_ty_size == 0) { |
| 6304 | assert(ret_ty.isError()); | 6315 | assert(ret_ty.isError(mod)); |
| 6305 | result.return_value = .{ .immediate = 0 }; | 6316 | result.return_value = .{ .immediate = 0 }; |
| 6306 | } else if (ret_ty_size <= 8) { | 6317 | } else if (ret_ty_size <= 8) { |
| 6307 | result.return_value = .{ .register = self.registerAlias(.x0, ret_ty) }; | 6318 | result.return_value = .{ .register = self.registerAlias(.x0, ret_ty) }; |
| ... | @@ -6317,10 +6328,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6317,10 +6328,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6317 | 6328 | ||
| 6318 | var stack_offset: u32 = 0; | 6329 | var stack_offset: u32 = 0; |
| 6319 | 6330 | ||
| 6320 | for (param_types, 0..) |ty, i| { | 6331 | for (fn_info.param_types, 0..) |ty, i| { |
| 6321 | if (ty.abiSize(self.target.*) > 0) { | 6332 | if (ty.toType().abiSize(mod) > 0) { |
| 6322 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 6333 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); |
| 6323 | const param_alignment = ty.abiAlignment(self.target.*); | 6334 | const param_alignment = ty.toType().abiAlignment(mod); |
| 6324 | 6335 | ||
| 6325 | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment); | 6336 | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment); |
| 6326 | result.args[i] = .{ .stack_argument_offset = stack_offset }; | 6337 | result.args[i] = .{ .stack_argument_offset = stack_offset }; |
| ... | @@ -6371,7 +6382,8 @@ fn parseRegName(name: []const u8) ?Register { | ... | @@ -6371,7 +6382,8 @@ fn parseRegName(name: []const u8) ?Register { |
| 6371 | } | 6382 | } |
| 6372 | 6383 | ||
| 6373 | fn registerAlias(self: *Self, reg: Register, ty: Type) Register { | 6384 | fn registerAlias(self: *Self, reg: Register, ty: Type) Register { |
| 6374 | const abi_size = ty.abiSize(self.target.*); | 6385 | const mod = self.bin_file.options.module.?; |
| 6386 | const abi_size = ty.abiSize(mod); | ||
| 6375 | 6387 | ||
| 6376 | switch (reg.class()) { | 6388 | switch (reg.class()) { |
| 6377 | .general_purpose => { | 6389 | .general_purpose => { |
| ... | @@ -6397,3 +6409,13 @@ fn registerAlias(self: *Self, reg: Register, ty: Type) Register { | ... | @@ -6397,3 +6409,13 @@ fn registerAlias(self: *Self, reg: Register, ty: Type) Register { |
| 6397 | }, | 6409 | }, |
| 6398 | } | 6410 | } |
| 6399 | } | 6411 | } |
| 6412 | |||
| 6413 | fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { | ||
| 6414 | const mod = self.bin_file.options.module.?; | ||
| 6415 | return self.air.typeOf(inst, &mod.intern_pool); | ||
| 6416 | } | ||
| 6417 | |||
| 6418 | fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { | ||
| 6419 | const mod = self.bin_file.options.module.?; | ||
| 6420 | return self.air.typeOfIndex(inst, &mod.intern_pool); | ||
| 6421 | } |
src/arch/aarch64/abi.zig+28-26| ... | @@ -4,6 +4,7 @@ const bits = @import("bits.zig"); | ... | @@ -4,6 +4,7 @@ const bits = @import("bits.zig"); |
| 4 | const Register = bits.Register; | 4 | const Register = bits.Register; |
| 5 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | 5 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 6 | const Type = @import("../../type.zig").Type; | 6 | const Type = @import("../../type.zig").Type; |
| 7 | const Module = @import("../../Module.zig"); | ||
| 7 | 8 | ||
| 8 | pub const Class = union(enum) { | 9 | pub const Class = union(enum) { |
| 9 | memory, | 10 | memory, |
| ... | @@ -14,44 +15,44 @@ pub const Class = union(enum) { | ... | @@ -14,44 +15,44 @@ pub const Class = union(enum) { |
| 14 | }; | 15 | }; |
| 15 | 16 | ||
| 16 | /// For `float_array` the second element will be the amount of floats. | 17 | /// For `float_array` the second element will be the amount of floats. |
| 17 | pub fn classifyType(ty: Type, target: std.Target) Class { | 18 | pub fn classifyType(ty: Type, mod: *Module) Class { |
| 18 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime()); | 19 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 19 | 20 | ||
| 20 | var maybe_float_bits: ?u16 = null; | 21 | var maybe_float_bits: ?u16 = null; |
| 21 | switch (ty.zigTypeTag()) { | 22 | switch (ty.zigTypeTag(mod)) { |
| 22 | .Struct => { | 23 | .Struct => { |
| 23 | if (ty.containerLayout() == .Packed) return .byval; | 24 | if (ty.containerLayout(mod) == .Packed) return .byval; |
| 24 | const float_count = countFloats(ty, target, &maybe_float_bits); | 25 | const float_count = countFloats(ty, mod, &maybe_float_bits); |
| 25 | if (float_count <= sret_float_count) return .{ .float_array = float_count }; | 26 | if (float_count <= sret_float_count) return .{ .float_array = float_count }; |
| 26 | 27 | ||
| 27 | const bit_size = ty.bitSize(target); | 28 | const bit_size = ty.bitSize(mod); |
| 28 | if (bit_size > 128) return .memory; | 29 | if (bit_size > 128) return .memory; |
| 29 | if (bit_size > 64) return .double_integer; | 30 | if (bit_size > 64) return .double_integer; |
| 30 | return .integer; | 31 | return .integer; |
| 31 | }, | 32 | }, |
| 32 | .Union => { | 33 | .Union => { |
| 33 | if (ty.containerLayout() == .Packed) return .byval; | 34 | if (ty.containerLayout(mod) == .Packed) return .byval; |
| 34 | const float_count = countFloats(ty, target, &maybe_float_bits); | 35 | const float_count = countFloats(ty, mod, &maybe_float_bits); |
| 35 | if (float_count <= sret_float_count) return .{ .float_array = float_count }; | 36 | if (float_count <= sret_float_count) return .{ .float_array = float_count }; |
| 36 | 37 | ||
| 37 | const bit_size = ty.bitSize(target); | 38 | const bit_size = ty.bitSize(mod); |
| 38 | if (bit_size > 128) return .memory; | 39 | if (bit_size > 128) return .memory; |
| 39 | if (bit_size > 64) return .double_integer; | 40 | if (bit_size > 64) return .double_integer; |
| 40 | return .integer; | 41 | return .integer; |
| 41 | }, | 42 | }, |
| 42 | .Int, .Enum, .ErrorSet, .Float, .Bool => return .byval, | 43 | .Int, .Enum, .ErrorSet, .Float, .Bool => return .byval, |
| 43 | .Vector => { | 44 | .Vector => { |
| 44 | const bit_size = ty.bitSize(target); | 45 | const bit_size = ty.bitSize(mod); |
| 45 | // TODO is this controlled by a cpu feature? | 46 | // TODO is this controlled by a cpu feature? |
| 46 | if (bit_size > 128) return .memory; | 47 | if (bit_size > 128) return .memory; |
| 47 | return .byval; | 48 | return .byval; |
| 48 | }, | 49 | }, |
| 49 | .Optional => { | 50 | .Optional => { |
| 50 | std.debug.assert(ty.isPtrLikeOptional()); | 51 | std.debug.assert(ty.isPtrLikeOptional(mod)); |
| 51 | return .byval; | 52 | return .byval; |
| 52 | }, | 53 | }, |
| 53 | .Pointer => { | 54 | .Pointer => { |
| 54 | std.debug.assert(!ty.isSlice()); | 55 | std.debug.assert(!ty.isSlice(mod)); |
| 55 | return .byval; | 56 | return .byval; |
| 56 | }, | 57 | }, |
| 57 | .ErrorUnion, | 58 | .ErrorUnion, |
| ... | @@ -73,14 +74,15 @@ pub fn classifyType(ty: Type, target: std.Target) Class { | ... | @@ -73,14 +74,15 @@ pub fn classifyType(ty: Type, target: std.Target) Class { |
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | const sret_float_count = 4; | 76 | const sret_float_count = 4; |
| 76 | fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u8 { | 77 | fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u8 { |
| 78 | const target = mod.getTarget(); | ||
| 77 | const invalid = std.math.maxInt(u8); | 79 | const invalid = std.math.maxInt(u8); |
| 78 | switch (ty.zigTypeTag()) { | 80 | switch (ty.zigTypeTag(mod)) { |
| 79 | .Union => { | 81 | .Union => { |
| 80 | const fields = ty.unionFields(); | 82 | const fields = ty.unionFields(mod); |
| 81 | var max_count: u8 = 0; | 83 | var max_count: u8 = 0; |
| 82 | for (fields.values()) |field| { | 84 | for (fields.values()) |field| { |
| 83 | const field_count = countFloats(field.ty, target, maybe_float_bits); | 85 | const field_count = countFloats(field.ty, mod, maybe_float_bits); |
| 84 | if (field_count == invalid) return invalid; | 86 | if (field_count == invalid) return invalid; |
| 85 | if (field_count > max_count) max_count = field_count; | 87 | if (field_count > max_count) max_count = field_count; |
| 86 | if (max_count > sret_float_count) return invalid; | 88 | if (max_count > sret_float_count) return invalid; |
| ... | @@ -88,12 +90,12 @@ fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u8 { | ... | @@ -88,12 +90,12 @@ fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u8 { |
| 88 | return max_count; | 90 | return max_count; |
| 89 | }, | 91 | }, |
| 90 | .Struct => { | 92 | .Struct => { |
| 91 | const fields_len = ty.structFieldCount(); | 93 | const fields_len = ty.structFieldCount(mod); |
| 92 | var count: u8 = 0; | 94 | var count: u8 = 0; |
| 93 | var i: u32 = 0; | 95 | var i: u32 = 0; |
| 94 | while (i < fields_len) : (i += 1) { | 96 | while (i < fields_len) : (i += 1) { |
| 95 | const field_ty = ty.structFieldType(i); | 97 | const field_ty = ty.structFieldType(i, mod); |
| 96 | const field_count = countFloats(field_ty, target, maybe_float_bits); | 98 | const field_count = countFloats(field_ty, mod, maybe_float_bits); |
| 97 | if (field_count == invalid) return invalid; | 99 | if (field_count == invalid) return invalid; |
| 98 | count += field_count; | 100 | count += field_count; |
| 99 | if (count > sret_float_count) return invalid; | 101 | if (count > sret_float_count) return invalid; |
| ... | @@ -113,21 +115,21 @@ fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u8 { | ... | @@ -113,21 +115,21 @@ fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u8 { |
| 113 | } | 115 | } |
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | pub fn getFloatArrayType(ty: Type) ?Type { | 118 | pub fn getFloatArrayType(ty: Type, mod: *Module) ?Type { |
| 117 | switch (ty.zigTypeTag()) { | 119 | switch (ty.zigTypeTag(mod)) { |
| 118 | .Union => { | 120 | .Union => { |
| 119 | const fields = ty.unionFields(); | 121 | const fields = ty.unionFields(mod); |
| 120 | for (fields.values()) |field| { | 122 | for (fields.values()) |field| { |
| 121 | if (getFloatArrayType(field.ty)) |some| return some; | 123 | if (getFloatArrayType(field.ty, mod)) |some| return some; |
| 122 | } | 124 | } |
| 123 | return null; | 125 | return null; |
| 124 | }, | 126 | }, |
| 125 | .Struct => { | 127 | .Struct => { |
| 126 | const fields_len = ty.structFieldCount(); | 128 | const fields_len = ty.structFieldCount(mod); |
| 127 | var i: u32 = 0; | 129 | var i: u32 = 0; |
| 128 | while (i < fields_len) : (i += 1) { | 130 | while (i < fields_len) : (i += 1) { |
| 129 | const field_ty = ty.structFieldType(i); | 131 | const field_ty = ty.structFieldType(i, mod); |
| 130 | if (getFloatArrayType(field_ty)) |some| return some; | 132 | if (getFloatArrayType(field_ty, mod)) |some| return some; |
| 131 | } | 133 | } |
| 132 | return null; | 134 | return null; |
| 133 | }, | 135 | }, |
src/arch/arm/CodeGen.zig+365-342| ... | @@ -334,7 +334,7 @@ const Self = @This(); | ... | @@ -334,7 +334,7 @@ const Self = @This(); |
| 334 | pub fn generate( | 334 | pub fn generate( |
| 335 | bin_file: *link.File, | 335 | bin_file: *link.File, |
| 336 | src_loc: Module.SrcLoc, | 336 | src_loc: Module.SrcLoc, |
| 337 | module_fn: *Module.Fn, | 337 | module_fn_index: Module.Fn.Index, |
| 338 | air: Air, | 338 | air: Air, |
| 339 | liveness: Liveness, | 339 | liveness: Liveness, |
| 340 | code: *std.ArrayList(u8), | 340 | code: *std.ArrayList(u8), |
| ... | @@ -345,6 +345,7 @@ pub fn generate( | ... | @@ -345,6 +345,7 @@ pub fn generate( |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | const mod = bin_file.options.module.?; | 347 | const mod = bin_file.options.module.?; |
| 348 | const module_fn = mod.funcPtr(module_fn_index); | ||
| 348 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); | 349 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 349 | assert(fn_owner_decl.has_tv); | 350 | assert(fn_owner_decl.has_tv); |
| 350 | const fn_type = fn_owner_decl.ty; | 351 | const fn_type = fn_owner_decl.ty; |
| ... | @@ -477,7 +478,8 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { | ... | @@ -477,7 +478,8 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 477 | } | 478 | } |
| 478 | 479 | ||
| 479 | fn gen(self: *Self) !void { | 480 | fn gen(self: *Self) !void { |
| 480 | const cc = self.fn_type.fnCallingConvention(); | 481 | const mod = self.bin_file.options.module.?; |
| 482 | const cc = self.fn_type.fnCallingConvention(mod); | ||
| 481 | if (cc != .Naked) { | 483 | if (cc != .Naked) { |
| 482 | // push {fp, lr} | 484 | // push {fp, lr} |
| 483 | const push_reloc = try self.addNop(); | 485 | const push_reloc = try self.addNop(); |
| ... | @@ -518,10 +520,10 @@ fn gen(self: *Self) !void { | ... | @@ -518,10 +520,10 @@ fn gen(self: *Self) !void { |
| 518 | const inst = self.air.getMainBody()[arg_index]; | 520 | const inst = self.air.getMainBody()[arg_index]; |
| 519 | assert(self.air.instructions.items(.tag)[inst] == .arg); | 521 | assert(self.air.instructions.items(.tag)[inst] == .arg); |
| 520 | 522 | ||
| 521 | const ty = self.air.typeOfIndex(inst); | 523 | const ty = self.typeOfIndex(inst); |
| 522 | 524 | ||
| 523 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 525 | const abi_size = @intCast(u32, ty.abiSize(mod)); |
| 524 | const abi_align = ty.abiAlignment(self.target.*); | 526 | const abi_align = ty.abiAlignment(mod); |
| 525 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); | 527 | const stack_offset = try self.allocMem(abi_size, abi_align, inst); |
| 526 | try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 528 | try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 527 | 529 | ||
| ... | @@ -636,13 +638,14 @@ fn gen(self: *Self) !void { | ... | @@ -636,13 +638,14 @@ fn gen(self: *Self) !void { |
| 636 | } | 638 | } |
| 637 | 639 | ||
| 638 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | 640 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 641 | const mod = self.bin_file.options.module.?; | ||
| 642 | const ip = &mod.intern_pool; | ||
| 639 | const air_tags = self.air.instructions.items(.tag); | 643 | const air_tags = self.air.instructions.items(.tag); |
| 640 | 644 | ||
| 641 | for (body) |inst| { | 645 | for (body) |inst| { |
| 642 | // TODO: remove now-redundant isUnused calls from AIR handler functions | 646 | // TODO: remove now-redundant isUnused calls from AIR handler functions |
| 643 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) { | 647 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) |
| 644 | continue; | 648 | continue; |
| 645 | } | ||
| 646 | 649 | ||
| 647 | const old_air_bookkeeping = self.air_bookkeeping; | 650 | const old_air_bookkeeping = self.air_bookkeeping; |
| 648 | try self.ensureProcessDeathCapacity(Liveness.bpi); | 651 | try self.ensureProcessDeathCapacity(Liveness.bpi); |
| ... | @@ -826,8 +829,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -826,8 +829,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 826 | .ptr_elem_val => try self.airPtrElemVal(inst), | 829 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 827 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), | 830 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 828 | 831 | ||
| 829 | .constant => unreachable, // excluded from function bodies | 832 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, |
| 830 | .const_ty => unreachable, // excluded from function bodies | ||
| 831 | .unreach => self.finishAirBookkeeping(), | 833 | .unreach => self.finishAirBookkeeping(), |
| 832 | 834 | ||
| 833 | .optional_payload => try self.airOptionalPayload(inst), | 835 | .optional_payload => try self.airOptionalPayload(inst), |
| ... | @@ -900,8 +902,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -900,8 +902,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 900 | 902 | ||
| 901 | /// Asserts there is already capacity to insert into top branch inst_table. | 903 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 902 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { | 904 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 903 | const air_tags = self.air.instructions.items(.tag); | 905 | assert(self.air.instructions.items(.tag)[inst] != .interned); |
| 904 | if (air_tags[inst] == .constant) return; // Constants are immortal. | ||
| 905 | // When editing this function, note that the logic must synchronize with `reuseOperand`. | 906 | // When editing this function, note that the logic must synchronize with `reuseOperand`. |
| 906 | const prev_value = self.getResolvedInstValue(inst); | 907 | const prev_value = self.getResolvedInstValue(inst); |
| 907 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 908 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | @@ -937,8 +938,8 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -937,8 +938,8 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 937 | tomb_bits >>= 1; | 938 | tomb_bits >>= 1; |
| 938 | if (!dies) continue; | 939 | if (!dies) continue; |
| 939 | const op_int = @enumToInt(op); | 940 | const op_int = @enumToInt(op); |
| 940 | if (op_int < Air.Inst.Ref.typed_value_map.len) continue; | 941 | if (op_int < Air.ref_start_index) continue; |
| 941 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | 942 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); |
| 942 | self.processDeath(op_index); | 943 | self.processDeath(op_index); |
| 943 | } | 944 | } |
| 944 | const is_used = @truncate(u1, tomb_bits) == 0; | 945 | const is_used = @truncate(u1, tomb_bits) == 0; |
| ... | @@ -1006,9 +1007,10 @@ fn allocMem( | ... | @@ -1006,9 +1007,10 @@ fn allocMem( |
| 1006 | 1007 | ||
| 1007 | /// Use a pointer instruction as the basis for allocating stack memory. | 1008 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 1008 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | 1009 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 1009 | const elem_ty = self.air.typeOfIndex(inst).elemType(); | 1010 | const mod = self.bin_file.options.module.?; |
| 1011 | const elem_ty = self.typeOfIndex(inst).childType(mod); | ||
| 1010 | 1012 | ||
| 1011 | if (!elem_ty.hasRuntimeBits()) { | 1013 | if (!elem_ty.hasRuntimeBits(mod)) { |
| 1012 | // As this stack item will never be dereferenced at runtime, | 1014 | // As this stack item will never be dereferenced at runtime, |
| 1013 | // return the stack offset 0. Stack offset 0 will be where all | 1015 | // return the stack offset 0. Stack offset 0 will be where all |
| 1014 | // zero-sized stack allocations live as non-zero-sized | 1016 | // zero-sized stack allocations live as non-zero-sized |
| ... | @@ -1016,22 +1018,21 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | ... | @@ -1016,22 +1018,21 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 1016 | return @as(u32, 0); | 1018 | return @as(u32, 0); |
| 1017 | } | 1019 | } |
| 1018 | 1020 | ||
| 1019 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | 1021 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { |
| 1020 | const mod = self.bin_file.options.module.?; | ||
| 1021 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 1022 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 1022 | }; | 1023 | }; |
| 1023 | // TODO swap this for inst.ty.ptrAlign | 1024 | // TODO swap this for inst.ty.ptrAlign |
| 1024 | const abi_align = elem_ty.abiAlignment(self.target.*); | 1025 | const abi_align = elem_ty.abiAlignment(mod); |
| 1025 | 1026 | ||
| 1026 | return self.allocMem(abi_size, abi_align, inst); | 1027 | return self.allocMem(abi_size, abi_align, inst); |
| 1027 | } | 1028 | } |
| 1028 | 1029 | ||
| 1029 | fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue { | 1030 | fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst.Index) !MCValue { |
| 1030 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | 1031 | const mod = self.bin_file.options.module.?; |
| 1031 | const mod = self.bin_file.options.module.?; | 1032 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { |
| 1032 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 1033 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 1033 | }; | 1034 | }; |
| 1034 | const abi_align = elem_ty.abiAlignment(self.target.*); | 1035 | const abi_align = elem_ty.abiAlignment(mod); |
| 1035 | 1036 | ||
| 1036 | if (reg_ok) { | 1037 | if (reg_ok) { |
| 1037 | // Make sure the type can fit in a register before we try to allocate one. | 1038 | // Make sure the type can fit in a register before we try to allocate one. |
| ... | @@ -1049,7 +1050,7 @@ fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst | ... | @@ -1049,7 +1050,7 @@ fn allocRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool, maybe_inst: ?Air.Inst |
| 1049 | } | 1050 | } |
| 1050 | 1051 | ||
| 1051 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { | 1052 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 1052 | const stack_mcv = try self.allocRegOrMem(self.air.typeOfIndex(inst), false, inst); | 1053 | const stack_mcv = try self.allocRegOrMem(self.typeOfIndex(inst), false, inst); |
| 1053 | log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv }); | 1054 | log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv }); |
| 1054 | 1055 | ||
| 1055 | const reg_mcv = self.getResolvedInstValue(inst); | 1056 | const reg_mcv = self.getResolvedInstValue(inst); |
| ... | @@ -1063,14 +1064,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -1063,14 +1064,14 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 1063 | 1064 | ||
| 1064 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 1065 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 1065 | try branch.inst_table.put(self.gpa, inst, stack_mcv); | 1066 | try branch.inst_table.put(self.gpa, inst, stack_mcv); |
| 1066 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); | 1067 | try self.genSetStack(self.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); |
| 1067 | } | 1068 | } |
| 1068 | 1069 | ||
| 1069 | /// Save the current instruction stored in the compare flags if | 1070 | /// Save the current instruction stored in the compare flags if |
| 1070 | /// occupied | 1071 | /// occupied |
| 1071 | fn spillCompareFlagsIfOccupied(self: *Self) !void { | 1072 | fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 1072 | if (self.cpsr_flags_inst) |inst_to_save| { | 1073 | if (self.cpsr_flags_inst) |inst_to_save| { |
| 1073 | const ty = self.air.typeOfIndex(inst_to_save); | 1074 | const ty = self.typeOfIndex(inst_to_save); |
| 1074 | const mcv = self.getResolvedInstValue(inst_to_save); | 1075 | const mcv = self.getResolvedInstValue(inst_to_save); |
| 1075 | const new_mcv = switch (mcv) { | 1076 | const new_mcv = switch (mcv) { |
| 1076 | .cpsr_flags => try self.allocRegOrMem(ty, true, inst_to_save), | 1077 | .cpsr_flags => try self.allocRegOrMem(ty, true, inst_to_save), |
| ... | @@ -1080,7 +1081,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { | ... | @@ -1080,7 +1081,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void { |
| 1080 | else => unreachable, // mcv doesn't occupy the compare flags | 1081 | else => unreachable, // mcv doesn't occupy the compare flags |
| 1081 | }; | 1082 | }; |
| 1082 | 1083 | ||
| 1083 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); | 1084 | try self.setRegOrMem(self.typeOfIndex(inst_to_save), new_mcv, mcv); |
| 1084 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); | 1085 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); |
| 1085 | 1086 | ||
| 1086 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 1087 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | @@ -1114,17 +1115,14 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1114,17 +1115,14 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) !void { |
| 1114 | } | 1115 | } |
| 1115 | 1116 | ||
| 1116 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { | 1117 | fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1118 | const mod = self.bin_file.options.module.?; | ||
| 1117 | const result: MCValue = switch (self.ret_mcv) { | 1119 | const result: MCValue = switch (self.ret_mcv) { |
| 1118 | .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) }, | 1120 | .none, .register => .{ .ptr_stack_offset = try self.allocMemPtr(inst) }, |
| 1119 | .stack_offset => blk: { | 1121 | .stack_offset => blk: { |
| 1120 | // self.ret_mcv is an address to where this function | 1122 | // self.ret_mcv is an address to where this function |
| 1121 | // should store its result into | 1123 | // should store its result into |
| 1122 | const ret_ty = self.fn_type.fnReturnType(); | 1124 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 1123 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 1125 | const ptr_ty = try mod.singleMutPtrType(ret_ty); |
| 1124 | .base = .{ .tag = .single_mut_pointer }, | ||
| 1125 | .data = ret_ty, | ||
| 1126 | }; | ||
| 1127 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 1128 | 1126 | ||
| 1129 | // addr_reg will contain the address of where to store the | 1127 | // addr_reg will contain the address of where to store the |
| 1130 | // result into | 1128 | // result into |
| ... | @@ -1150,18 +1148,19 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1150,18 +1148,19 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 1150 | } | 1148 | } |
| 1151 | 1149 | ||
| 1152 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | 1150 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1151 | const mod = self.bin_file.options.module.?; | ||
| 1153 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1152 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1154 | if (self.liveness.isUnused(inst)) | 1153 | if (self.liveness.isUnused(inst)) |
| 1155 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | 1154 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1156 | 1155 | ||
| 1157 | const operand = try self.resolveInst(ty_op.operand); | 1156 | const operand = try self.resolveInst(ty_op.operand); |
| 1158 | const operand_ty = self.air.typeOf(ty_op.operand); | 1157 | const operand_ty = self.typeOf(ty_op.operand); |
| 1159 | const dest_ty = self.air.typeOfIndex(inst); | 1158 | const dest_ty = self.typeOfIndex(inst); |
| 1160 | 1159 | ||
| 1161 | const operand_abi_size = operand_ty.abiSize(self.target.*); | 1160 | const operand_abi_size = operand_ty.abiSize(mod); |
| 1162 | const dest_abi_size = dest_ty.abiSize(self.target.*); | 1161 | const dest_abi_size = dest_ty.abiSize(mod); |
| 1163 | const info_a = operand_ty.intInfo(self.target.*); | 1162 | const info_a = operand_ty.intInfo(mod); |
| 1164 | const info_b = dest_ty.intInfo(self.target.*); | 1163 | const info_b = dest_ty.intInfo(mod); |
| 1165 | 1164 | ||
| 1166 | const dst_mcv: MCValue = blk: { | 1165 | const dst_mcv: MCValue = blk: { |
| 1167 | if (info_a.bits == info_b.bits) { | 1166 | if (info_a.bits == info_b.bits) { |
| ... | @@ -1215,8 +1214,9 @@ fn trunc( | ... | @@ -1215,8 +1214,9 @@ fn trunc( |
| 1215 | operand_ty: Type, | 1214 | operand_ty: Type, |
| 1216 | dest_ty: Type, | 1215 | dest_ty: Type, |
| 1217 | ) !MCValue { | 1216 | ) !MCValue { |
| 1218 | const info_a = operand_ty.intInfo(self.target.*); | 1217 | const mod = self.bin_file.options.module.?; |
| 1219 | const info_b = dest_ty.intInfo(self.target.*); | 1218 | const info_a = operand_ty.intInfo(mod); |
| 1219 | const info_b = dest_ty.intInfo(mod); | ||
| 1220 | 1220 | ||
| 1221 | if (info_b.bits <= 32) { | 1221 | if (info_b.bits <= 32) { |
| 1222 | if (info_a.bits > 32) { | 1222 | if (info_a.bits > 32) { |
| ... | @@ -1259,8 +1259,8 @@ fn trunc( | ... | @@ -1259,8 +1259,8 @@ fn trunc( |
| 1259 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 1259 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1260 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1260 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1261 | const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; | 1261 | const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 1262 | const operand_ty = self.air.typeOf(ty_op.operand); | 1262 | const operand_ty = self.typeOf(ty_op.operand); |
| 1263 | const dest_ty = self.air.typeOfIndex(inst); | 1263 | const dest_ty = self.typeOfIndex(inst); |
| 1264 | 1264 | ||
| 1265 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { | 1265 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 1266 | break :blk try self.trunc(inst, operand_bind, operand_ty, dest_ty); | 1266 | break :blk try self.trunc(inst, operand_bind, operand_ty, dest_ty); |
| ... | @@ -1278,15 +1278,16 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1278,15 +1278,16 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 1278 | 1278 | ||
| 1279 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { | 1279 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1280 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1280 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1281 | const mod = self.bin_file.options.module.?; | ||
| 1281 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1282 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1282 | const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; | 1283 | const operand_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 1283 | const operand_ty = self.air.typeOf(ty_op.operand); | 1284 | const operand_ty = self.typeOf(ty_op.operand); |
| 1284 | switch (try operand_bind.resolveToMcv(self)) { | 1285 | switch (try operand_bind.resolveToMcv(self)) { |
| 1285 | .dead => unreachable, | 1286 | .dead => unreachable, |
| 1286 | .unreach => unreachable, | 1287 | .unreach => unreachable, |
| 1287 | .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() }, | 1288 | .cpsr_flags => |cond| break :result MCValue{ .cpsr_flags = cond.negate() }, |
| 1288 | else => { | 1289 | else => { |
| 1289 | switch (operand_ty.zigTypeTag()) { | 1290 | switch (operand_ty.zigTypeTag(mod)) { |
| 1290 | .Bool => { | 1291 | .Bool => { |
| 1291 | var op_reg: Register = undefined; | 1292 | var op_reg: Register = undefined; |
| 1292 | var dest_reg: Register = undefined; | 1293 | var dest_reg: Register = undefined; |
| ... | @@ -1319,7 +1320,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1319,7 +1320,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1319 | }, | 1320 | }, |
| 1320 | .Vector => return self.fail("TODO bitwise not for vectors", .{}), | 1321 | .Vector => return self.fail("TODO bitwise not for vectors", .{}), |
| 1321 | .Int => { | 1322 | .Int => { |
| 1322 | const int_info = operand_ty.intInfo(self.target.*); | 1323 | const int_info = operand_ty.intInfo(mod); |
| 1323 | if (int_info.bits <= 32) { | 1324 | if (int_info.bits <= 32) { |
| 1324 | var op_reg: Register = undefined; | 1325 | var op_reg: Register = undefined; |
| 1325 | var dest_reg: Register = undefined; | 1326 | var dest_reg: Register = undefined; |
| ... | @@ -1373,13 +1374,13 @@ fn minMax( | ... | @@ -1373,13 +1374,13 @@ fn minMax( |
| 1373 | rhs_ty: Type, | 1374 | rhs_ty: Type, |
| 1374 | maybe_inst: ?Air.Inst.Index, | 1375 | maybe_inst: ?Air.Inst.Index, |
| 1375 | ) !MCValue { | 1376 | ) !MCValue { |
| 1376 | switch (lhs_ty.zigTypeTag()) { | 1377 | const mod = self.bin_file.options.module.?; |
| 1378 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 1377 | .Float => return self.fail("TODO ARM min/max on floats", .{}), | 1379 | .Float => return self.fail("TODO ARM min/max on floats", .{}), |
| 1378 | .Vector => return self.fail("TODO ARM min/max on vectors", .{}), | 1380 | .Vector => return self.fail("TODO ARM min/max on vectors", .{}), |
| 1379 | .Int => { | 1381 | .Int => { |
| 1380 | const mod = self.bin_file.options.module.?; | ||
| 1381 | assert(lhs_ty.eql(rhs_ty, mod)); | 1382 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1382 | const int_info = lhs_ty.intInfo(self.target.*); | 1383 | const int_info = lhs_ty.intInfo(mod); |
| 1383 | if (int_info.bits <= 32) { | 1384 | if (int_info.bits <= 32) { |
| 1384 | var lhs_reg: Register = undefined; | 1385 | var lhs_reg: Register = undefined; |
| 1385 | var rhs_reg: Register = undefined; | 1386 | var rhs_reg: Register = undefined; |
| ... | @@ -1463,8 +1464,8 @@ fn minMax( | ... | @@ -1463,8 +1464,8 @@ fn minMax( |
| 1463 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { | 1464 | fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1464 | const tag = self.air.instructions.items(.tag)[inst]; | 1465 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1465 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1466 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1466 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1467 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1467 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1468 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1468 | 1469 | ||
| 1469 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1470 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1470 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; | 1471 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| ... | @@ -1483,9 +1484,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1483,9 +1484,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1483 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1484 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1484 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1485 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1485 | const ptr = try self.resolveInst(bin_op.lhs); | 1486 | const ptr = try self.resolveInst(bin_op.lhs); |
| 1486 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 1487 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 1487 | const len = try self.resolveInst(bin_op.rhs); | 1488 | const len = try self.resolveInst(bin_op.rhs); |
| 1488 | const len_ty = self.air.typeOf(bin_op.rhs); | 1489 | const len_ty = self.typeOf(bin_op.rhs); |
| 1489 | 1490 | ||
| 1490 | const stack_offset = try self.allocMem(8, 4, inst); | 1491 | const stack_offset = try self.allocMem(8, 4, inst); |
| 1491 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 1492 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| ... | @@ -1497,8 +1498,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1497,8 +1498,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 1497 | 1498 | ||
| 1498 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 1499 | fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1499 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1500 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1500 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1501 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1501 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1502 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1502 | 1503 | ||
| 1503 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1504 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1504 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; | 1505 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| ... | @@ -1548,8 +1549,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | ... | @@ -1548,8 +1549,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1548 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | 1549 | fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1549 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1550 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1550 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1551 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1551 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1552 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1552 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1553 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1553 | 1554 | ||
| 1554 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1555 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1555 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; | 1556 | const lhs_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| ... | @@ -1582,23 +1583,23 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1582,23 +1583,23 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1582 | const tag = self.air.instructions.items(.tag)[inst]; | 1583 | const tag = self.air.instructions.items(.tag)[inst]; |
| 1583 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1584 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1584 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1585 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1586 | const mod = self.bin_file.options.module.?; | ||
| 1585 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1587 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1586 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; | 1588 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 1587 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; | 1589 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 1588 | const lhs_ty = self.air.typeOf(extra.lhs); | 1590 | const lhs_ty = self.typeOf(extra.lhs); |
| 1589 | const rhs_ty = self.air.typeOf(extra.rhs); | 1591 | const rhs_ty = self.typeOf(extra.rhs); |
| 1590 | 1592 | ||
| 1591 | const tuple_ty = self.air.typeOfIndex(inst); | 1593 | const tuple_ty = self.typeOfIndex(inst); |
| 1592 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | 1594 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); |
| 1593 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | 1595 | const tuple_align = tuple_ty.abiAlignment(mod); |
| 1594 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | 1596 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, mod)); |
| 1595 | 1597 | ||
| 1596 | switch (lhs_ty.zigTypeTag()) { | 1598 | switch (lhs_ty.zigTypeTag(mod)) { |
| 1597 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), | 1599 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), |
| 1598 | .Int => { | 1600 | .Int => { |
| 1599 | const mod = self.bin_file.options.module.?; | ||
| 1600 | assert(lhs_ty.eql(rhs_ty, mod)); | 1601 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1601 | const int_info = lhs_ty.intInfo(self.target.*); | 1602 | const int_info = lhs_ty.intInfo(mod); |
| 1602 | if (int_info.bits < 32) { | 1603 | if (int_info.bits < 32) { |
| 1603 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); | 1604 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 1604 | 1605 | ||
| ... | @@ -1631,7 +1632,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1631,7 +1632,7 @@ fn airOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1631 | }); | 1632 | }); |
| 1632 | 1633 | ||
| 1633 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 1634 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1634 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); | 1635 | try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); |
| 1635 | 1636 | ||
| 1636 | break :result MCValue{ .stack_offset = stack_offset }; | 1637 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1637 | } else if (int_info.bits == 32) { | 1638 | } else if (int_info.bits == 32) { |
| ... | @@ -1695,23 +1696,23 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1695,23 +1696,23 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1695 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1696 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1696 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1697 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1697 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); | 1698 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 1699 | const mod = self.bin_file.options.module.?; | ||
| 1698 | const result: MCValue = result: { | 1700 | const result: MCValue = result: { |
| 1699 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; | 1701 | const lhs_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 1700 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; | 1702 | const rhs_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 1701 | const lhs_ty = self.air.typeOf(extra.lhs); | 1703 | const lhs_ty = self.typeOf(extra.lhs); |
| 1702 | const rhs_ty = self.air.typeOf(extra.rhs); | 1704 | const rhs_ty = self.typeOf(extra.rhs); |
| 1703 | 1705 | ||
| 1704 | const tuple_ty = self.air.typeOfIndex(inst); | 1706 | const tuple_ty = self.typeOfIndex(inst); |
| 1705 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | 1707 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); |
| 1706 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | 1708 | const tuple_align = tuple_ty.abiAlignment(mod); |
| 1707 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | 1709 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, mod)); |
| 1708 | 1710 | ||
| 1709 | switch (lhs_ty.zigTypeTag()) { | 1711 | switch (lhs_ty.zigTypeTag(mod)) { |
| 1710 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), | 1712 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| 1711 | .Int => { | 1713 | .Int => { |
| 1712 | const mod = self.bin_file.options.module.?; | ||
| 1713 | assert(lhs_ty.eql(rhs_ty, mod)); | 1714 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1714 | const int_info = lhs_ty.intInfo(self.target.*); | 1715 | const int_info = lhs_ty.intInfo(mod); |
| 1715 | if (int_info.bits <= 16) { | 1716 | if (int_info.bits <= 16) { |
| 1716 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); | 1717 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 1717 | 1718 | ||
| ... | @@ -1744,7 +1745,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1744,7 +1745,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1744 | }); | 1745 | }); |
| 1745 | 1746 | ||
| 1746 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); | 1747 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = truncated_reg }); |
| 1747 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); | 1748 | try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); |
| 1748 | 1749 | ||
| 1749 | break :result MCValue{ .stack_offset = stack_offset }; | 1750 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1750 | } else if (int_info.bits <= 32) { | 1751 | } else if (int_info.bits <= 32) { |
| ... | @@ -1842,7 +1843,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1842,7 +1843,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1842 | }); | 1843 | }); |
| 1843 | 1844 | ||
| 1844 | // strb rdlo, [...] | 1845 | // strb rdlo, [...] |
| 1845 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .register = rdlo }); | 1846 | try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{ .register = rdlo }); |
| 1846 | 1847 | ||
| 1847 | break :result MCValue{ .stack_offset = stack_offset }; | 1848 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1848 | } else { | 1849 | } else { |
| ... | @@ -1859,19 +1860,20 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1859,19 +1860,20 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1859 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1860 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1860 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1861 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1861 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); | 1862 | if (self.liveness.isUnused(inst)) return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none }); |
| 1863 | const mod = self.bin_file.options.module.?; | ||
| 1862 | const result: MCValue = result: { | 1864 | const result: MCValue = result: { |
| 1863 | const lhs_ty = self.air.typeOf(extra.lhs); | 1865 | const lhs_ty = self.typeOf(extra.lhs); |
| 1864 | const rhs_ty = self.air.typeOf(extra.rhs); | 1866 | const rhs_ty = self.typeOf(extra.rhs); |
| 1865 | 1867 | ||
| 1866 | const tuple_ty = self.air.typeOfIndex(inst); | 1868 | const tuple_ty = self.typeOfIndex(inst); |
| 1867 | const tuple_size = @intCast(u32, tuple_ty.abiSize(self.target.*)); | 1869 | const tuple_size = @intCast(u32, tuple_ty.abiSize(mod)); |
| 1868 | const tuple_align = tuple_ty.abiAlignment(self.target.*); | 1870 | const tuple_align = tuple_ty.abiAlignment(mod); |
| 1869 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, self.target.*)); | 1871 | const overflow_bit_offset = @intCast(u32, tuple_ty.structFieldOffset(1, mod)); |
| 1870 | 1872 | ||
| 1871 | switch (lhs_ty.zigTypeTag()) { | 1873 | switch (lhs_ty.zigTypeTag(mod)) { |
| 1872 | .Vector => return self.fail("TODO implement shl_with_overflow for vectors", .{}), | 1874 | .Vector => return self.fail("TODO implement shl_with_overflow for vectors", .{}), |
| 1873 | .Int => { | 1875 | .Int => { |
| 1874 | const int_info = lhs_ty.intInfo(self.target.*); | 1876 | const int_info = lhs_ty.intInfo(mod); |
| 1875 | if (int_info.bits <= 32) { | 1877 | if (int_info.bits <= 32) { |
| 1876 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); | 1878 | const stack_offset = try self.allocMem(tuple_size, tuple_align, inst); |
| 1877 | 1879 | ||
| ... | @@ -1976,7 +1978,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1976,7 +1978,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 1976 | }); | 1978 | }); |
| 1977 | 1979 | ||
| 1978 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg }); | 1980 | try self.genSetStack(lhs_ty, stack_offset, .{ .register = dest_reg }); |
| 1979 | try self.genSetStack(Type.initTag(.u1), stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); | 1981 | try self.genSetStack(Type.u1, stack_offset - overflow_bit_offset, .{ .cpsr_flags = .ne }); |
| 1980 | 1982 | ||
| 1981 | break :result MCValue{ .stack_offset = stack_offset }; | 1983 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1982 | } else { | 1984 | } else { |
| ... | @@ -2014,10 +2016,11 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2014,10 +2016,11 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 2014 | } | 2016 | } |
| 2015 | 2017 | ||
| 2016 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | 2018 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2019 | const mod = self.bin_file.options.module.?; | ||
| 2017 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2020 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2018 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2021 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2019 | const optional_ty = self.air.typeOfIndex(inst); | 2022 | const optional_ty = self.typeOfIndex(inst); |
| 2020 | const abi_size = @intCast(u32, optional_ty.abiSize(self.target.*)); | 2023 | const abi_size = @intCast(u32, optional_ty.abiSize(mod)); |
| 2021 | 2024 | ||
| 2022 | // Optional with a zero-bit payload type is just a boolean true | 2025 | // Optional with a zero-bit payload type is just a boolean true |
| 2023 | if (abi_size == 1) { | 2026 | if (abi_size == 1) { |
| ... | @@ -2036,16 +2039,17 @@ fn errUnionErr( | ... | @@ -2036,16 +2039,17 @@ fn errUnionErr( |
| 2036 | error_union_ty: Type, | 2039 | error_union_ty: Type, |
| 2037 | maybe_inst: ?Air.Inst.Index, | 2040 | maybe_inst: ?Air.Inst.Index, |
| 2038 | ) !MCValue { | 2041 | ) !MCValue { |
| 2039 | const err_ty = error_union_ty.errorUnionSet(); | 2042 | const mod = self.bin_file.options.module.?; |
| 2040 | const payload_ty = error_union_ty.errorUnionPayload(); | 2043 | const err_ty = error_union_ty.errorUnionSet(mod); |
| 2041 | if (err_ty.errorSetIsEmpty()) { | 2044 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 2045 | if (err_ty.errorSetIsEmpty(mod)) { | ||
| 2042 | return MCValue{ .immediate = 0 }; | 2046 | return MCValue{ .immediate = 0 }; |
| 2043 | } | 2047 | } |
| 2044 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 2048 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2045 | return try error_union_bind.resolveToMcv(self); | 2049 | return try error_union_bind.resolveToMcv(self); |
| 2046 | } | 2050 | } |
| 2047 | 2051 | ||
| 2048 | const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*)); | 2052 | const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, mod)); |
| 2049 | switch (try error_union_bind.resolveToMcv(self)) { | 2053 | switch (try error_union_bind.resolveToMcv(self)) { |
| 2050 | .register => { | 2054 | .register => { |
| 2051 | var operand_reg: Register = undefined; | 2055 | var operand_reg: Register = undefined; |
| ... | @@ -2067,7 +2071,7 @@ fn errUnionErr( | ... | @@ -2067,7 +2071,7 @@ fn errUnionErr( |
| 2067 | ); | 2071 | ); |
| 2068 | 2072 | ||
| 2069 | const err_bit_offset = err_offset * 8; | 2073 | const err_bit_offset = err_offset * 8; |
| 2070 | const err_bit_size = @intCast(u32, err_ty.abiSize(self.target.*)) * 8; | 2074 | const err_bit_size = @intCast(u32, err_ty.abiSize(mod)) * 8; |
| 2071 | 2075 | ||
| 2072 | _ = try self.addInst(.{ | 2076 | _ = try self.addInst(.{ |
| 2073 | .tag = .ubfx, // errors are unsigned integers | 2077 | .tag = .ubfx, // errors are unsigned integers |
| ... | @@ -2098,7 +2102,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2098,7 +2102,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2098 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2102 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2099 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2103 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2100 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; | 2104 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 2101 | const error_union_ty = self.air.typeOf(ty_op.operand); | 2105 | const error_union_ty = self.typeOf(ty_op.operand); |
| 2102 | 2106 | ||
| 2103 | break :result try self.errUnionErr(error_union_bind, error_union_ty, inst); | 2107 | break :result try self.errUnionErr(error_union_bind, error_union_ty, inst); |
| 2104 | }; | 2108 | }; |
| ... | @@ -2112,16 +2116,17 @@ fn errUnionPayload( | ... | @@ -2112,16 +2116,17 @@ fn errUnionPayload( |
| 2112 | error_union_ty: Type, | 2116 | error_union_ty: Type, |
| 2113 | maybe_inst: ?Air.Inst.Index, | 2117 | maybe_inst: ?Air.Inst.Index, |
| 2114 | ) !MCValue { | 2118 | ) !MCValue { |
| 2115 | const err_ty = error_union_ty.errorUnionSet(); | 2119 | const mod = self.bin_file.options.module.?; |
| 2116 | const payload_ty = error_union_ty.errorUnionPayload(); | 2120 | const err_ty = error_union_ty.errorUnionSet(mod); |
| 2117 | if (err_ty.errorSetIsEmpty()) { | 2121 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 2122 | if (err_ty.errorSetIsEmpty(mod)) { | ||
| 2118 | return try error_union_bind.resolveToMcv(self); | 2123 | return try error_union_bind.resolveToMcv(self); |
| 2119 | } | 2124 | } |
| 2120 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 2125 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2121 | return MCValue.none; | 2126 | return MCValue.none; |
| 2122 | } | 2127 | } |
| 2123 | 2128 | ||
| 2124 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*)); | 2129 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, mod)); |
| 2125 | switch (try error_union_bind.resolveToMcv(self)) { | 2130 | switch (try error_union_bind.resolveToMcv(self)) { |
| 2126 | .register => { | 2131 | .register => { |
| 2127 | var operand_reg: Register = undefined; | 2132 | var operand_reg: Register = undefined; |
| ... | @@ -2143,10 +2148,10 @@ fn errUnionPayload( | ... | @@ -2143,10 +2148,10 @@ fn errUnionPayload( |
| 2143 | ); | 2148 | ); |
| 2144 | 2149 | ||
| 2145 | const payload_bit_offset = payload_offset * 8; | 2150 | const payload_bit_offset = payload_offset * 8; |
| 2146 | const payload_bit_size = @intCast(u32, payload_ty.abiSize(self.target.*)) * 8; | 2151 | const payload_bit_size = @intCast(u32, payload_ty.abiSize(mod)) * 8; |
| 2147 | 2152 | ||
| 2148 | _ = try self.addInst(.{ | 2153 | _ = try self.addInst(.{ |
| 2149 | .tag = if (payload_ty.isSignedInt()) Mir.Inst.Tag.sbfx else .ubfx, | 2154 | .tag = if (payload_ty.isSignedInt(mod)) Mir.Inst.Tag.sbfx else .ubfx, |
| 2150 | .data = .{ .rr_lsb_width = .{ | 2155 | .data = .{ .rr_lsb_width = .{ |
| 2151 | .rd = dest_reg, | 2156 | .rd = dest_reg, |
| 2152 | .rn = operand_reg, | 2157 | .rn = operand_reg, |
| ... | @@ -2174,7 +2179,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2174,7 +2179,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2174 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2179 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2175 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2180 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2176 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; | 2181 | const error_union_bind: ReadArg.Bind = .{ .inst = ty_op.operand }; |
| 2177 | const error_union_ty = self.air.typeOf(ty_op.operand); | 2182 | const error_union_ty = self.typeOf(ty_op.operand); |
| 2178 | 2183 | ||
| 2179 | break :result try self.errUnionPayload(error_union_bind, error_union_ty, inst); | 2184 | break :result try self.errUnionPayload(error_union_bind, error_union_ty, inst); |
| 2180 | }; | 2185 | }; |
| ... | @@ -2221,19 +2226,20 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2221,19 +2226,20 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { |
| 2221 | 2226 | ||
| 2222 | /// T to E!T | 2227 | /// T to E!T |
| 2223 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | 2228 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2229 | const mod = self.bin_file.options.module.?; | ||
| 2224 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2230 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2225 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2231 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2226 | const error_union_ty = self.air.getRefType(ty_op.ty); | 2232 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2227 | const error_ty = error_union_ty.errorUnionSet(); | 2233 | const error_ty = error_union_ty.errorUnionSet(mod); |
| 2228 | const payload_ty = error_union_ty.errorUnionPayload(); | 2234 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 2229 | const operand = try self.resolveInst(ty_op.operand); | 2235 | const operand = try self.resolveInst(ty_op.operand); |
| 2230 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; | 2236 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result operand; |
| 2231 | 2237 | ||
| 2232 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | 2238 | const abi_size = @intCast(u32, error_union_ty.abiSize(mod)); |
| 2233 | const abi_align = error_union_ty.abiAlignment(self.target.*); | 2239 | const abi_align = error_union_ty.abiAlignment(mod); |
| 2234 | const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst)); | 2240 | const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst)); |
| 2235 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | 2241 | const payload_off = errUnionPayloadOffset(payload_ty, mod); |
| 2236 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | 2242 | const err_off = errUnionErrorOffset(payload_ty, mod); |
| 2237 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand); | 2243 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), operand); |
| 2238 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 }); | 2244 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), .{ .immediate = 0 }); |
| 2239 | 2245 | ||
| ... | @@ -2244,19 +2250,20 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2244,19 +2250,20 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2244 | 2250 | ||
| 2245 | /// E to E!T | 2251 | /// E to E!T |
| 2246 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | 2252 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2253 | const mod = self.bin_file.options.module.?; | ||
| 2247 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2254 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2248 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2255 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2249 | const error_union_ty = self.air.getRefType(ty_op.ty); | 2256 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2250 | const error_ty = error_union_ty.errorUnionSet(); | 2257 | const error_ty = error_union_ty.errorUnionSet(mod); |
| 2251 | const payload_ty = error_union_ty.errorUnionPayload(); | 2258 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 2252 | const operand = try self.resolveInst(ty_op.operand); | 2259 | const operand = try self.resolveInst(ty_op.operand); |
| 2253 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result operand; | 2260 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result operand; |
| 2254 | 2261 | ||
| 2255 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | 2262 | const abi_size = @intCast(u32, error_union_ty.abiSize(mod)); |
| 2256 | const abi_align = error_union_ty.abiAlignment(self.target.*); | 2263 | const abi_align = error_union_ty.abiAlignment(mod); |
| 2257 | const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst)); | 2264 | const stack_offset = @intCast(u32, try self.allocMem(abi_size, abi_align, inst)); |
| 2258 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | 2265 | const payload_off = errUnionPayloadOffset(payload_ty, mod); |
| 2259 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | 2266 | const err_off = errUnionErrorOffset(payload_ty, mod); |
| 2260 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), operand); | 2267 | try self.genSetStack(error_ty, stack_offset - @intCast(u32, err_off), operand); |
| 2261 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef); | 2268 | try self.genSetStack(payload_ty, stack_offset - @intCast(u32, payload_off), .undef); |
| 2262 | 2269 | ||
| ... | @@ -2360,8 +2367,9 @@ fn ptrElemVal( | ... | @@ -2360,8 +2367,9 @@ fn ptrElemVal( |
| 2360 | ptr_ty: Type, | 2367 | ptr_ty: Type, |
| 2361 | maybe_inst: ?Air.Inst.Index, | 2368 | maybe_inst: ?Air.Inst.Index, |
| 2362 | ) !MCValue { | 2369 | ) !MCValue { |
| 2363 | const elem_ty = ptr_ty.childType(); | 2370 | const mod = self.bin_file.options.module.?; |
| 2364 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | 2371 | const elem_ty = ptr_ty.childType(mod); |
| 2372 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); | ||
| 2365 | 2373 | ||
| 2366 | switch (elem_size) { | 2374 | switch (elem_size) { |
| 2367 | 1, 4 => { | 2375 | 1, 4 => { |
| ... | @@ -2418,11 +2426,11 @@ fn ptrElemVal( | ... | @@ -2418,11 +2426,11 @@ fn ptrElemVal( |
| 2418 | } | 2426 | } |
| 2419 | 2427 | ||
| 2420 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 2428 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2429 | const mod = self.bin_file.options.module.?; | ||
| 2421 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2430 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2422 | const slice_ty = self.air.typeOf(bin_op.lhs); | 2431 | const slice_ty = self.typeOf(bin_op.lhs); |
| 2423 | const result: MCValue = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: { | 2432 | const result: MCValue = if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { |
| 2424 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 2433 | const ptr_ty = slice_ty.slicePtrFieldType(mod); |
| 2425 | const ptr_ty = slice_ty.slicePtrFieldType(&buf); | ||
| 2426 | 2434 | ||
| 2427 | const slice_mcv = try self.resolveInst(bin_op.lhs); | 2435 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 2428 | const base_mcv = slicePtr(slice_mcv); | 2436 | const base_mcv = slicePtr(slice_mcv); |
| ... | @@ -2445,8 +2453,8 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2445,8 +2453,8 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2445 | const base_bind: ReadArg.Bind = .{ .mcv = base_mcv }; | 2453 | const base_bind: ReadArg.Bind = .{ .mcv = base_mcv }; |
| 2446 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; | 2454 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2447 | 2455 | ||
| 2448 | const slice_ty = self.air.typeOf(extra.lhs); | 2456 | const slice_ty = self.typeOf(extra.lhs); |
| 2449 | const index_ty = self.air.typeOf(extra.rhs); | 2457 | const index_ty = self.typeOf(extra.rhs); |
| 2450 | 2458 | ||
| 2451 | const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ty, index_ty, null); | 2459 | const addr = try self.ptrArithmetic(.ptr_add, base_bind, index_bind, slice_ty, index_ty, null); |
| 2452 | break :result addr; | 2460 | break :result addr; |
| ... | @@ -2461,7 +2469,8 @@ fn arrayElemVal( | ... | @@ -2461,7 +2469,8 @@ fn arrayElemVal( |
| 2461 | array_ty: Type, | 2469 | array_ty: Type, |
| 2462 | maybe_inst: ?Air.Inst.Index, | 2470 | maybe_inst: ?Air.Inst.Index, |
| 2463 | ) InnerError!MCValue { | 2471 | ) InnerError!MCValue { |
| 2464 | const elem_ty = array_ty.childType(); | 2472 | const mod = self.bin_file.options.module.?; |
| 2473 | const elem_ty = array_ty.childType(mod); | ||
| 2465 | 2474 | ||
| 2466 | const mcv = try array_bind.resolveToMcv(self); | 2475 | const mcv = try array_bind.resolveToMcv(self); |
| 2467 | switch (mcv) { | 2476 | switch (mcv) { |
| ... | @@ -2495,11 +2504,7 @@ fn arrayElemVal( | ... | @@ -2495,11 +2504,7 @@ fn arrayElemVal( |
| 2495 | 2504 | ||
| 2496 | const base_bind: ReadArg.Bind = .{ .mcv = ptr_to_mcv }; | 2505 | const base_bind: ReadArg.Bind = .{ .mcv = ptr_to_mcv }; |
| 2497 | 2506 | ||
| 2498 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 2507 | const ptr_ty = try mod.singleMutPtrType(elem_ty); |
| 2499 | .base = .{ .tag = .single_mut_pointer }, | ||
| 2500 | .data = elem_ty, | ||
| 2501 | }; | ||
| 2502 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 2503 | 2508 | ||
| 2504 | return try self.ptrElemVal(base_bind, index_bind, ptr_ty, maybe_inst); | 2509 | return try self.ptrElemVal(base_bind, index_bind, ptr_ty, maybe_inst); |
| 2505 | }, | 2510 | }, |
| ... | @@ -2512,7 +2517,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2512,7 +2517,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2512 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2517 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2513 | const array_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; | 2518 | const array_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 2514 | const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; | 2519 | const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; |
| 2515 | const array_ty = self.air.typeOf(bin_op.lhs); | 2520 | const array_ty = self.typeOf(bin_op.lhs); |
| 2516 | 2521 | ||
| 2517 | break :result try self.arrayElemVal(array_bind, index_bind, array_ty, inst); | 2522 | break :result try self.arrayElemVal(array_bind, index_bind, array_ty, inst); |
| 2518 | }; | 2523 | }; |
| ... | @@ -2520,9 +2525,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2520,9 +2525,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2520 | } | 2525 | } |
| 2521 | 2526 | ||
| 2522 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { | 2527 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2528 | const mod = self.bin_file.options.module.?; | ||
| 2523 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2529 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2524 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2530 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2525 | const result: MCValue = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: { | 2531 | const result: MCValue = if (!ptr_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) .dead else result: { |
| 2526 | const base_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; | 2532 | const base_bind: ReadArg.Bind = .{ .inst = bin_op.lhs }; |
| 2527 | const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; | 2533 | const index_bind: ReadArg.Bind = .{ .inst = bin_op.rhs }; |
| 2528 | 2534 | ||
| ... | @@ -2538,8 +2544,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2538,8 +2544,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2538 | const ptr_bind: ReadArg.Bind = .{ .inst = extra.lhs }; | 2544 | const ptr_bind: ReadArg.Bind = .{ .inst = extra.lhs }; |
| 2539 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; | 2545 | const index_bind: ReadArg.Bind = .{ .inst = extra.rhs }; |
| 2540 | 2546 | ||
| 2541 | const ptr_ty = self.air.typeOf(extra.lhs); | 2547 | const ptr_ty = self.typeOf(extra.lhs); |
| 2542 | const index_ty = self.air.typeOf(extra.rhs); | 2548 | const index_ty = self.typeOf(extra.rhs); |
| 2543 | 2549 | ||
| 2544 | const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, index_ty, null); | 2550 | const addr = try self.ptrArithmetic(.ptr_add, ptr_bind, index_bind, ptr_ty, index_ty, null); |
| 2545 | break :result addr; | 2551 | break :result addr; |
| ... | @@ -2646,8 +2652,9 @@ fn reuseOperand( | ... | @@ -2646,8 +2652,9 @@ fn reuseOperand( |
| 2646 | } | 2652 | } |
| 2647 | 2653 | ||
| 2648 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { | 2654 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 2649 | const elem_ty = ptr_ty.elemType(); | 2655 | const mod = self.bin_file.options.module.?; |
| 2650 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | 2656 | const elem_ty = ptr_ty.childType(mod); |
| 2657 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); | ||
| 2651 | 2658 | ||
| 2652 | switch (ptr) { | 2659 | switch (ptr) { |
| 2653 | .none => unreachable, | 2660 | .none => unreachable, |
| ... | @@ -2722,19 +2729,20 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -2722,19 +2729,20 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 2722 | } | 2729 | } |
| 2723 | 2730 | ||
| 2724 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | 2731 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2732 | const mod = self.bin_file.options.module.?; | ||
| 2725 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2733 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2726 | const elem_ty = self.air.typeOfIndex(inst); | 2734 | const elem_ty = self.typeOfIndex(inst); |
| 2727 | const result: MCValue = result: { | 2735 | const result: MCValue = result: { |
| 2728 | if (!elem_ty.hasRuntimeBits()) | 2736 | if (!elem_ty.hasRuntimeBits(mod)) |
| 2729 | break :result MCValue.none; | 2737 | break :result MCValue.none; |
| 2730 | 2738 | ||
| 2731 | const ptr = try self.resolveInst(ty_op.operand); | 2739 | const ptr = try self.resolveInst(ty_op.operand); |
| 2732 | const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr(); | 2740 | const is_volatile = self.typeOf(ty_op.operand).isVolatilePtr(mod); |
| 2733 | if (self.liveness.isUnused(inst) and !is_volatile) | 2741 | if (self.liveness.isUnused(inst) and !is_volatile) |
| 2734 | break :result MCValue.dead; | 2742 | break :result MCValue.dead; |
| 2735 | 2743 | ||
| 2736 | const dest_mcv: MCValue = blk: { | 2744 | const dest_mcv: MCValue = blk: { |
| 2737 | const ptr_fits_dest = elem_ty.abiSize(self.target.*) <= 4; | 2745 | const ptr_fits_dest = elem_ty.abiSize(mod) <= 4; |
| 2738 | if (ptr_fits_dest and self.reuseOperand(inst, ty_op.operand, 0, ptr)) { | 2746 | if (ptr_fits_dest and self.reuseOperand(inst, ty_op.operand, 0, ptr)) { |
| 2739 | // The MCValue that holds the pointer can be re-used as the value. | 2747 | // The MCValue that holds the pointer can be re-used as the value. |
| 2740 | break :blk ptr; | 2748 | break :blk ptr; |
| ... | @@ -2742,7 +2750,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2742,7 +2750,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2742 | break :blk try self.allocRegOrMem(elem_ty, true, inst); | 2750 | break :blk try self.allocRegOrMem(elem_ty, true, inst); |
| 2743 | } | 2751 | } |
| 2744 | }; | 2752 | }; |
| 2745 | try self.load(dest_mcv, ptr, self.air.typeOf(ty_op.operand)); | 2753 | try self.load(dest_mcv, ptr, self.typeOf(ty_op.operand)); |
| 2746 | 2754 | ||
| 2747 | break :result dest_mcv; | 2755 | break :result dest_mcv; |
| 2748 | }; | 2756 | }; |
| ... | @@ -2750,7 +2758,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2750,7 +2758,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2750 | } | 2758 | } |
| 2751 | 2759 | ||
| 2752 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { | 2760 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| 2753 | const elem_size = @intCast(u32, value_ty.abiSize(self.target.*)); | 2761 | const mod = self.bin_file.options.module.?; |
| 2762 | const elem_size = @intCast(u32, value_ty.abiSize(mod)); | ||
| 2754 | 2763 | ||
| 2755 | switch (ptr) { | 2764 | switch (ptr) { |
| 2756 | .none => unreachable, | 2765 | .none => unreachable, |
| ... | @@ -2846,8 +2855,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -2846,8 +2855,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 2846 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2855 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2847 | const ptr = try self.resolveInst(bin_op.lhs); | 2856 | const ptr = try self.resolveInst(bin_op.lhs); |
| 2848 | const value = try self.resolveInst(bin_op.rhs); | 2857 | const value = try self.resolveInst(bin_op.rhs); |
| 2849 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2858 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2850 | const value_ty = self.air.typeOf(bin_op.rhs); | 2859 | const value_ty = self.typeOf(bin_op.rhs); |
| 2851 | 2860 | ||
| 2852 | try self.store(ptr, value, ptr_ty, value_ty); | 2861 | try self.store(ptr, value, ptr_ty, value_ty); |
| 2853 | 2862 | ||
| ... | @@ -2869,10 +2878,11 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { | ... | @@ -2869,10 +2878,11 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 2869 | 2878 | ||
| 2870 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { | 2879 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 2871 | return if (self.liveness.isUnused(inst)) .dead else result: { | 2880 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 2881 | const mod = self.bin_file.options.module.?; | ||
| 2872 | const mcv = try self.resolveInst(operand); | 2882 | const mcv = try self.resolveInst(operand); |
| 2873 | const ptr_ty = self.air.typeOf(operand); | 2883 | const ptr_ty = self.typeOf(operand); |
| 2874 | const struct_ty = ptr_ty.childType(); | 2884 | const struct_ty = ptr_ty.childType(mod); |
| 2875 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | 2885 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); |
| 2876 | switch (mcv) { | 2886 | switch (mcv) { |
| 2877 | .ptr_stack_offset => |off| { | 2887 | .ptr_stack_offset => |off| { |
| 2878 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; | 2888 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; |
| ... | @@ -2892,11 +2902,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2892,11 +2902,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2892 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 2902 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 2893 | const operand = extra.struct_operand; | 2903 | const operand = extra.struct_operand; |
| 2894 | const index = extra.field_index; | 2904 | const index = extra.field_index; |
| 2905 | const mod = self.bin_file.options.module.?; | ||
| 2895 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2906 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2896 | const mcv = try self.resolveInst(operand); | 2907 | const mcv = try self.resolveInst(operand); |
| 2897 | const struct_ty = self.air.typeOf(operand); | 2908 | const struct_ty = self.typeOf(operand); |
| 2898 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | 2909 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); |
| 2899 | const struct_field_ty = struct_ty.structFieldType(index); | 2910 | const struct_field_ty = struct_ty.structFieldType(index, mod); |
| 2900 | 2911 | ||
| 2901 | switch (mcv) { | 2912 | switch (mcv) { |
| 2902 | .dead, .unreach => unreachable, | 2913 | .dead, .unreach => unreachable, |
| ... | @@ -2959,10 +2970,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2959,10 +2970,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2959 | ); | 2970 | ); |
| 2960 | 2971 | ||
| 2961 | const field_bit_offset = struct_field_offset * 8; | 2972 | const field_bit_offset = struct_field_offset * 8; |
| 2962 | const field_bit_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)) * 8; | 2973 | const field_bit_size = @intCast(u32, struct_field_ty.abiSize(mod)) * 8; |
| 2963 | 2974 | ||
| 2964 | _ = try self.addInst(.{ | 2975 | _ = try self.addInst(.{ |
| 2965 | .tag = if (struct_field_ty.isSignedInt()) Mir.Inst.Tag.sbfx else .ubfx, | 2976 | .tag = if (struct_field_ty.isSignedInt(mod)) Mir.Inst.Tag.sbfx else .ubfx, |
| 2966 | .data = .{ .rr_lsb_width = .{ | 2977 | .data = .{ .rr_lsb_width = .{ |
| 2967 | .rd = dest_reg, | 2978 | .rd = dest_reg, |
| 2968 | .rn = operand_reg, | 2979 | .rn = operand_reg, |
| ... | @@ -2981,17 +2992,18 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2981,17 +2992,18 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2981 | } | 2992 | } |
| 2982 | 2993 | ||
| 2983 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | 2994 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2995 | const mod = self.bin_file.options.module.?; | ||
| 2984 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2996 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2985 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; | 2997 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 2986 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2998 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2987 | const field_ptr = try self.resolveInst(extra.field_ptr); | 2999 | const field_ptr = try self.resolveInst(extra.field_ptr); |
| 2988 | const struct_ty = self.air.getRefType(ty_pl.ty).childType(); | 3000 | const struct_ty = self.air.getRefType(ty_pl.ty).childType(mod); |
| 2989 | 3001 | ||
| 2990 | if (struct_ty.zigTypeTag() == .Union) { | 3002 | if (struct_ty.zigTypeTag(mod) == .Union) { |
| 2991 | return self.fail("TODO implement @fieldParentPtr codegen for unions", .{}); | 3003 | return self.fail("TODO implement @fieldParentPtr codegen for unions", .{}); |
| 2992 | } | 3004 | } |
| 2993 | 3005 | ||
| 2994 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(extra.field_index, self.target.*)); | 3006 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(extra.field_index, mod)); |
| 2995 | switch (field_ptr) { | 3007 | switch (field_ptr) { |
| 2996 | .ptr_stack_offset => |off| { | 3008 | .ptr_stack_offset => |off| { |
| 2997 | break :result MCValue{ .ptr_stack_offset = off + struct_field_offset }; | 3009 | break :result MCValue{ .ptr_stack_offset = off + struct_field_offset }; |
| ... | @@ -3375,12 +3387,12 @@ fn addSub( | ... | @@ -3375,12 +3387,12 @@ fn addSub( |
| 3375 | maybe_inst: ?Air.Inst.Index, | 3387 | maybe_inst: ?Air.Inst.Index, |
| 3376 | ) InnerError!MCValue { | 3388 | ) InnerError!MCValue { |
| 3377 | const mod = self.bin_file.options.module.?; | 3389 | const mod = self.bin_file.options.module.?; |
| 3378 | switch (lhs_ty.zigTypeTag()) { | 3390 | switch (lhs_ty.zigTypeTag(mod)) { |
| 3379 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), | 3391 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3380 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3392 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3381 | .Int => { | 3393 | .Int => { |
| 3382 | assert(lhs_ty.eql(rhs_ty, mod)); | 3394 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3383 | const int_info = lhs_ty.intInfo(self.target.*); | 3395 | const int_info = lhs_ty.intInfo(mod); |
| 3384 | if (int_info.bits <= 32) { | 3396 | if (int_info.bits <= 32) { |
| 3385 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); | 3397 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 3386 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); | 3398 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| ... | @@ -3431,12 +3443,12 @@ fn mul( | ... | @@ -3431,12 +3443,12 @@ fn mul( |
| 3431 | maybe_inst: ?Air.Inst.Index, | 3443 | maybe_inst: ?Air.Inst.Index, |
| 3432 | ) InnerError!MCValue { | 3444 | ) InnerError!MCValue { |
| 3433 | const mod = self.bin_file.options.module.?; | 3445 | const mod = self.bin_file.options.module.?; |
| 3434 | switch (lhs_ty.zigTypeTag()) { | 3446 | switch (lhs_ty.zigTypeTag(mod)) { |
| 3435 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), | 3447 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3436 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3448 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3437 | .Int => { | 3449 | .Int => { |
| 3438 | assert(lhs_ty.eql(rhs_ty, mod)); | 3450 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3439 | const int_info = lhs_ty.intInfo(self.target.*); | 3451 | const int_info = lhs_ty.intInfo(mod); |
| 3440 | if (int_info.bits <= 32) { | 3452 | if (int_info.bits <= 32) { |
| 3441 | // TODO add optimisations for multiplication | 3453 | // TODO add optimisations for multiplication |
| 3442 | // with immediates, for example a * 2 can be | 3454 | // with immediates, for example a * 2 can be |
| ... | @@ -3463,7 +3475,8 @@ fn divFloat( | ... | @@ -3463,7 +3475,8 @@ fn divFloat( |
| 3463 | _ = rhs_ty; | 3475 | _ = rhs_ty; |
| 3464 | _ = maybe_inst; | 3476 | _ = maybe_inst; |
| 3465 | 3477 | ||
| 3466 | switch (lhs_ty.zigTypeTag()) { | 3478 | const mod = self.bin_file.options.module.?; |
| 3479 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 3467 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), | 3480 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3468 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3481 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3469 | else => unreachable, | 3482 | else => unreachable, |
| ... | @@ -3479,12 +3492,12 @@ fn divTrunc( | ... | @@ -3479,12 +3492,12 @@ fn divTrunc( |
| 3479 | maybe_inst: ?Air.Inst.Index, | 3492 | maybe_inst: ?Air.Inst.Index, |
| 3480 | ) InnerError!MCValue { | 3493 | ) InnerError!MCValue { |
| 3481 | const mod = self.bin_file.options.module.?; | 3494 | const mod = self.bin_file.options.module.?; |
| 3482 | switch (lhs_ty.zigTypeTag()) { | 3495 | switch (lhs_ty.zigTypeTag(mod)) { |
| 3483 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), | 3496 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3484 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3497 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3485 | .Int => { | 3498 | .Int => { |
| 3486 | assert(lhs_ty.eql(rhs_ty, mod)); | 3499 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3487 | const int_info = lhs_ty.intInfo(self.target.*); | 3500 | const int_info = lhs_ty.intInfo(mod); |
| 3488 | if (int_info.bits <= 32) { | 3501 | if (int_info.bits <= 32) { |
| 3489 | switch (int_info.signedness) { | 3502 | switch (int_info.signedness) { |
| 3490 | .signed => { | 3503 | .signed => { |
| ... | @@ -3522,12 +3535,12 @@ fn divFloor( | ... | @@ -3522,12 +3535,12 @@ fn divFloor( |
| 3522 | maybe_inst: ?Air.Inst.Index, | 3535 | maybe_inst: ?Air.Inst.Index, |
| 3523 | ) InnerError!MCValue { | 3536 | ) InnerError!MCValue { |
| 3524 | const mod = self.bin_file.options.module.?; | 3537 | const mod = self.bin_file.options.module.?; |
| 3525 | switch (lhs_ty.zigTypeTag()) { | 3538 | switch (lhs_ty.zigTypeTag(mod)) { |
| 3526 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), | 3539 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3527 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3540 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3528 | .Int => { | 3541 | .Int => { |
| 3529 | assert(lhs_ty.eql(rhs_ty, mod)); | 3542 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3530 | const int_info = lhs_ty.intInfo(self.target.*); | 3543 | const int_info = lhs_ty.intInfo(mod); |
| 3531 | if (int_info.bits <= 32) { | 3544 | if (int_info.bits <= 32) { |
| 3532 | switch (int_info.signedness) { | 3545 | switch (int_info.signedness) { |
| 3533 | .signed => { | 3546 | .signed => { |
| ... | @@ -3569,7 +3582,8 @@ fn divExact( | ... | @@ -3569,7 +3582,8 @@ fn divExact( |
| 3569 | _ = rhs_ty; | 3582 | _ = rhs_ty; |
| 3570 | _ = maybe_inst; | 3583 | _ = maybe_inst; |
| 3571 | 3584 | ||
| 3572 | switch (lhs_ty.zigTypeTag()) { | 3585 | const mod = self.bin_file.options.module.?; |
| 3586 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 3573 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), | 3587 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3574 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3588 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3575 | .Int => return self.fail("TODO ARM div_exact", .{}), | 3589 | .Int => return self.fail("TODO ARM div_exact", .{}), |
| ... | @@ -3586,12 +3600,12 @@ fn rem( | ... | @@ -3586,12 +3600,12 @@ fn rem( |
| 3586 | maybe_inst: ?Air.Inst.Index, | 3600 | maybe_inst: ?Air.Inst.Index, |
| 3587 | ) InnerError!MCValue { | 3601 | ) InnerError!MCValue { |
| 3588 | const mod = self.bin_file.options.module.?; | 3602 | const mod = self.bin_file.options.module.?; |
| 3589 | switch (lhs_ty.zigTypeTag()) { | 3603 | switch (lhs_ty.zigTypeTag(mod)) { |
| 3590 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), | 3604 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3591 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3605 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3592 | .Int => { | 3606 | .Int => { |
| 3593 | assert(lhs_ty.eql(rhs_ty, mod)); | 3607 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3594 | const int_info = lhs_ty.intInfo(self.target.*); | 3608 | const int_info = lhs_ty.intInfo(mod); |
| 3595 | if (int_info.bits <= 32) { | 3609 | if (int_info.bits <= 32) { |
| 3596 | switch (int_info.signedness) { | 3610 | switch (int_info.signedness) { |
| 3597 | .signed => { | 3611 | .signed => { |
| ... | @@ -3654,7 +3668,8 @@ fn modulo( | ... | @@ -3654,7 +3668,8 @@ fn modulo( |
| 3654 | _ = rhs_ty; | 3668 | _ = rhs_ty; |
| 3655 | _ = maybe_inst; | 3669 | _ = maybe_inst; |
| 3656 | 3670 | ||
| 3657 | switch (lhs_ty.zigTypeTag()) { | 3671 | const mod = self.bin_file.options.module.?; |
| 3672 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 3658 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), | 3673 | .Float => return self.fail("TODO ARM binary operations on floats", .{}), |
| 3659 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3674 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3660 | .Int => return self.fail("TODO ARM mod", .{}), | 3675 | .Int => return self.fail("TODO ARM mod", .{}), |
| ... | @@ -3671,10 +3686,11 @@ fn wrappingArithmetic( | ... | @@ -3671,10 +3686,11 @@ fn wrappingArithmetic( |
| 3671 | rhs_ty: Type, | 3686 | rhs_ty: Type, |
| 3672 | maybe_inst: ?Air.Inst.Index, | 3687 | maybe_inst: ?Air.Inst.Index, |
| 3673 | ) InnerError!MCValue { | 3688 | ) InnerError!MCValue { |
| 3674 | switch (lhs_ty.zigTypeTag()) { | 3689 | const mod = self.bin_file.options.module.?; |
| 3690 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 3675 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3691 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3676 | .Int => { | 3692 | .Int => { |
| 3677 | const int_info = lhs_ty.intInfo(self.target.*); | 3693 | const int_info = lhs_ty.intInfo(mod); |
| 3678 | if (int_info.bits <= 32) { | 3694 | if (int_info.bits <= 32) { |
| 3679 | // Generate an add/sub/mul | 3695 | // Generate an add/sub/mul |
| 3680 | const result: MCValue = switch (tag) { | 3696 | const result: MCValue = switch (tag) { |
| ... | @@ -3708,12 +3724,12 @@ fn bitwise( | ... | @@ -3708,12 +3724,12 @@ fn bitwise( |
| 3708 | rhs_ty: Type, | 3724 | rhs_ty: Type, |
| 3709 | maybe_inst: ?Air.Inst.Index, | 3725 | maybe_inst: ?Air.Inst.Index, |
| 3710 | ) InnerError!MCValue { | 3726 | ) InnerError!MCValue { |
| 3711 | switch (lhs_ty.zigTypeTag()) { | 3727 | const mod = self.bin_file.options.module.?; |
| 3728 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 3712 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3729 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3713 | .Int => { | 3730 | .Int => { |
| 3714 | const mod = self.bin_file.options.module.?; | ||
| 3715 | assert(lhs_ty.eql(rhs_ty, mod)); | 3731 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 3716 | const int_info = lhs_ty.intInfo(self.target.*); | 3732 | const int_info = lhs_ty.intInfo(mod); |
| 3717 | if (int_info.bits <= 32) { | 3733 | if (int_info.bits <= 32) { |
| 3718 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); | 3734 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 3719 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); | 3735 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| ... | @@ -3753,16 +3769,17 @@ fn shiftExact( | ... | @@ -3753,16 +3769,17 @@ fn shiftExact( |
| 3753 | rhs_ty: Type, | 3769 | rhs_ty: Type, |
| 3754 | maybe_inst: ?Air.Inst.Index, | 3770 | maybe_inst: ?Air.Inst.Index, |
| 3755 | ) InnerError!MCValue { | 3771 | ) InnerError!MCValue { |
| 3756 | switch (lhs_ty.zigTypeTag()) { | 3772 | const mod = self.bin_file.options.module.?; |
| 3773 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 3757 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3774 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3758 | .Int => { | 3775 | .Int => { |
| 3759 | const int_info = lhs_ty.intInfo(self.target.*); | 3776 | const int_info = lhs_ty.intInfo(mod); |
| 3760 | if (int_info.bits <= 32) { | 3777 | if (int_info.bits <= 32) { |
| 3761 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); | 3778 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| 3762 | 3779 | ||
| 3763 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 3780 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| 3764 | .shl_exact => .lsl, | 3781 | .shl_exact => .lsl, |
| 3765 | .shr_exact => switch (lhs_ty.intInfo(self.target.*).signedness) { | 3782 | .shr_exact => switch (lhs_ty.intInfo(mod).signedness) { |
| 3766 | .signed => Mir.Inst.Tag.asr, | 3783 | .signed => Mir.Inst.Tag.asr, |
| 3767 | .unsigned => Mir.Inst.Tag.lsr, | 3784 | .unsigned => Mir.Inst.Tag.lsr, |
| 3768 | }, | 3785 | }, |
| ... | @@ -3791,10 +3808,11 @@ fn shiftNormal( | ... | @@ -3791,10 +3808,11 @@ fn shiftNormal( |
| 3791 | rhs_ty: Type, | 3808 | rhs_ty: Type, |
| 3792 | maybe_inst: ?Air.Inst.Index, | 3809 | maybe_inst: ?Air.Inst.Index, |
| 3793 | ) InnerError!MCValue { | 3810 | ) InnerError!MCValue { |
| 3794 | switch (lhs_ty.zigTypeTag()) { | 3811 | const mod = self.bin_file.options.module.?; |
| 3812 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 3795 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), | 3813 | .Vector => return self.fail("TODO ARM binary operations on vectors", .{}), |
| 3796 | .Int => { | 3814 | .Int => { |
| 3797 | const int_info = lhs_ty.intInfo(self.target.*); | 3815 | const int_info = lhs_ty.intInfo(mod); |
| 3798 | if (int_info.bits <= 32) { | 3816 | if (int_info.bits <= 32) { |
| 3799 | // Generate a shl_exact/shr_exact | 3817 | // Generate a shl_exact/shr_exact |
| 3800 | const result: MCValue = switch (tag) { | 3818 | const result: MCValue = switch (tag) { |
| ... | @@ -3833,7 +3851,8 @@ fn booleanOp( | ... | @@ -3833,7 +3851,8 @@ fn booleanOp( |
| 3833 | rhs_ty: Type, | 3851 | rhs_ty: Type, |
| 3834 | maybe_inst: ?Air.Inst.Index, | 3852 | maybe_inst: ?Air.Inst.Index, |
| 3835 | ) InnerError!MCValue { | 3853 | ) InnerError!MCValue { |
| 3836 | switch (lhs_ty.zigTypeTag()) { | 3854 | const mod = self.bin_file.options.module.?; |
| 3855 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 3837 | .Bool => { | 3856 | .Bool => { |
| 3838 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); | 3857 | const lhs_immediate = try lhs_bind.resolveToImmediate(self); |
| 3839 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); | 3858 | const rhs_immediate = try rhs_bind.resolveToImmediate(self); |
| ... | @@ -3866,17 +3885,17 @@ fn ptrArithmetic( | ... | @@ -3866,17 +3885,17 @@ fn ptrArithmetic( |
| 3866 | rhs_ty: Type, | 3885 | rhs_ty: Type, |
| 3867 | maybe_inst: ?Air.Inst.Index, | 3886 | maybe_inst: ?Air.Inst.Index, |
| 3868 | ) InnerError!MCValue { | 3887 | ) InnerError!MCValue { |
| 3869 | switch (lhs_ty.zigTypeTag()) { | 3888 | const mod = self.bin_file.options.module.?; |
| 3889 | switch (lhs_ty.zigTypeTag(mod)) { | ||
| 3870 | .Pointer => { | 3890 | .Pointer => { |
| 3871 | const mod = self.bin_file.options.module.?; | ||
| 3872 | assert(rhs_ty.eql(Type.usize, mod)); | 3891 | assert(rhs_ty.eql(Type.usize, mod)); |
| 3873 | 3892 | ||
| 3874 | const ptr_ty = lhs_ty; | 3893 | const ptr_ty = lhs_ty; |
| 3875 | const elem_ty = switch (ptr_ty.ptrSize()) { | 3894 | const elem_ty = switch (ptr_ty.ptrSize(mod)) { |
| 3876 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type | 3895 | .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type |
| 3877 | else => ptr_ty.childType(), | 3896 | else => ptr_ty.childType(mod), |
| 3878 | }; | 3897 | }; |
| 3879 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | 3898 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); |
| 3880 | 3899 | ||
| 3881 | const base_tag: Air.Inst.Tag = switch (tag) { | 3900 | const base_tag: Air.Inst.Tag = switch (tag) { |
| 3882 | .ptr_add => .add, | 3901 | .ptr_add => .add, |
| ... | @@ -3903,11 +3922,12 @@ fn ptrArithmetic( | ... | @@ -3903,11 +3922,12 @@ fn ptrArithmetic( |
| 3903 | } | 3922 | } |
| 3904 | 3923 | ||
| 3905 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void { | 3924 | fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void { |
| 3906 | const abi_size = ty.abiSize(self.target.*); | 3925 | const mod = self.bin_file.options.module.?; |
| 3926 | const abi_size = ty.abiSize(mod); | ||
| 3907 | 3927 | ||
| 3908 | const tag: Mir.Inst.Tag = switch (abi_size) { | 3928 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3909 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb, | 3929 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb else .ldrb, |
| 3910 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh, | 3930 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh else .ldrh, |
| 3911 | 3, 4 => .ldr, | 3931 | 3, 4 => .ldr, |
| 3912 | else => unreachable, | 3932 | else => unreachable, |
| 3913 | }; | 3933 | }; |
| ... | @@ -3924,7 +3944,7 @@ fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) | ... | @@ -3924,7 +3944,7 @@ fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) |
| 3924 | } }; | 3944 | } }; |
| 3925 | 3945 | ||
| 3926 | const data: Mir.Inst.Data = switch (abi_size) { | 3946 | const data: Mir.Inst.Data = switch (abi_size) { |
| 3927 | 1 => if (ty.isSignedInt()) rr_extra_offset else rr_offset, | 3947 | 1 => if (ty.isSignedInt(mod)) rr_extra_offset else rr_offset, |
| 3928 | 2 => rr_extra_offset, | 3948 | 2 => rr_extra_offset, |
| 3929 | 3, 4 => rr_offset, | 3949 | 3, 4 => rr_offset, |
| 3930 | else => unreachable, | 3950 | else => unreachable, |
| ... | @@ -3937,7 +3957,8 @@ fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) | ... | @@ -3937,7 +3957,8 @@ fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) |
| 3937 | } | 3957 | } |
| 3938 | 3958 | ||
| 3939 | fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, ty: Type) !void { | 3959 | fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, ty: Type) !void { |
| 3940 | const abi_size = ty.abiSize(self.target.*); | 3960 | const mod = self.bin_file.options.module.?; |
| 3961 | const abi_size = ty.abiSize(mod); | ||
| 3941 | 3962 | ||
| 3942 | const tag: Mir.Inst.Tag = switch (abi_size) { | 3963 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 3943 | 1 => .strb, | 3964 | 1 => .strb, |
| ... | @@ -4051,14 +4072,14 @@ fn genInlineMemset( | ... | @@ -4051,14 +4072,14 @@ fn genInlineMemset( |
| 4051 | ) !void { | 4072 | ) !void { |
| 4052 | const dst_reg = switch (dst) { | 4073 | const dst_reg = switch (dst) { |
| 4053 | .register => |r| r, | 4074 | .register => |r| r, |
| 4054 | else => try self.copyToTmpRegister(Type.initTag(.manyptr_u8), dst), | 4075 | else => try self.copyToTmpRegister(Type.manyptr_u8, dst), |
| 4055 | }; | 4076 | }; |
| 4056 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); | 4077 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 4057 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); | 4078 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 4058 | 4079 | ||
| 4059 | const val_reg = switch (val) { | 4080 | const val_reg = switch (val) { |
| 4060 | .register => |r| r, | 4081 | .register => |r| r, |
| 4061 | else => try self.copyToTmpRegister(Type.initTag(.u8), val), | 4082 | else => try self.copyToTmpRegister(Type.u8, val), |
| 4062 | }; | 4083 | }; |
| 4063 | const val_reg_lock = self.register_manager.lockReg(val_reg); | 4084 | const val_reg_lock = self.register_manager.lockReg(val_reg); |
| 4064 | defer if (val_reg_lock) |lock| self.register_manager.unlockReg(lock); | 4085 | defer if (val_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | @@ -4143,7 +4164,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4143,7 +4164,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 4143 | while (self.args[arg_index] == .none) arg_index += 1; | 4164 | while (self.args[arg_index] == .none) arg_index += 1; |
| 4144 | self.arg_index = arg_index + 1; | 4165 | self.arg_index = arg_index + 1; |
| 4145 | 4166 | ||
| 4146 | const ty = self.air.typeOfIndex(inst); | 4167 | const ty = self.typeOfIndex(inst); |
| 4147 | const tag = self.air.instructions.items(.tag)[inst]; | 4168 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4148 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; | 4169 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 4149 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index); | 4170 | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index); |
| ... | @@ -4196,11 +4217,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4196,11 +4217,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4196 | const callee = pl_op.operand; | 4217 | const callee = pl_op.operand; |
| 4197 | const extra = self.air.extraData(Air.Call, pl_op.payload); | 4218 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 4198 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); | 4219 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); |
| 4199 | const ty = self.air.typeOf(callee); | 4220 | const ty = self.typeOf(callee); |
| 4221 | const mod = self.bin_file.options.module.?; | ||
| 4200 | 4222 | ||
| 4201 | const fn_ty = switch (ty.zigTypeTag()) { | 4223 | const fn_ty = switch (ty.zigTypeTag(mod)) { |
| 4202 | .Fn => ty, | 4224 | .Fn => ty, |
| 4203 | .Pointer => ty.childType(), | 4225 | .Pointer => ty.childType(mod), |
| 4204 | else => unreachable, | 4226 | else => unreachable, |
| 4205 | }; | 4227 | }; |
| 4206 | 4228 | ||
| ... | @@ -4225,16 +4247,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4225,16 +4247,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4225 | // untouched by the parameter passing code | 4247 | // untouched by the parameter passing code |
| 4226 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { | 4248 | const r0_lock: ?RegisterLock = if (info.return_value == .stack_offset) blk: { |
| 4227 | log.debug("airCall: return by reference", .{}); | 4249 | log.debug("airCall: return by reference", .{}); |
| 4228 | const ret_ty = fn_ty.fnReturnType(); | 4250 | const ret_ty = fn_ty.fnReturnType(mod); |
| 4229 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 4251 | const ret_abi_size = @intCast(u32, ret_ty.abiSize(mod)); |
| 4230 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(self.target.*)); | 4252 | const ret_abi_align = @intCast(u32, ret_ty.abiAlignment(mod)); |
| 4231 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); | 4253 | const stack_offset = try self.allocMem(ret_abi_size, ret_abi_align, inst); |
| 4232 | 4254 | ||
| 4233 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 4255 | const ptr_ty = try mod.singleMutPtrType(ret_ty); |
| 4234 | .base = .{ .tag = .single_mut_pointer }, | ||
| 4235 | .data = ret_ty, | ||
| 4236 | }; | ||
| 4237 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 4238 | try self.register_manager.getReg(.r0, null); | 4256 | try self.register_manager.getReg(.r0, null); |
| 4239 | try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset }); | 4257 | try self.genSetReg(ptr_ty, .r0, .{ .ptr_stack_offset = stack_offset }); |
| 4240 | 4258 | ||
| ... | @@ -4249,7 +4267,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4249,7 +4267,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4249 | 4267 | ||
| 4250 | for (info.args, 0..) |mc_arg, arg_i| { | 4268 | for (info.args, 0..) |mc_arg, arg_i| { |
| 4251 | const arg = args[arg_i]; | 4269 | const arg = args[arg_i]; |
| 4252 | const arg_ty = self.air.typeOf(arg); | 4270 | const arg_ty = self.typeOf(arg); |
| 4253 | const arg_mcv = try self.resolveInst(args[arg_i]); | 4271 | const arg_mcv = try self.resolveInst(args[arg_i]); |
| 4254 | 4272 | ||
| 4255 | switch (mc_arg) { | 4273 | switch (mc_arg) { |
| ... | @@ -4270,16 +4288,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4270,16 +4288,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4270 | 4288 | ||
| 4271 | // Due to incremental compilation, how function calls are generated depends | 4289 | // Due to incremental compilation, how function calls are generated depends |
| 4272 | // on linking. | 4290 | // on linking. |
| 4273 | if (self.air.value(callee)) |func_value| { | 4291 | if (try self.air.value(callee, mod)) |func_value| { |
| 4274 | if (func_value.castTag(.function)) |func_payload| { | 4292 | if (func_value.getFunction(mod)) |func| { |
| 4275 | const func = func_payload.data; | ||
| 4276 | |||
| 4277 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | 4293 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 4278 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); | 4294 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 4279 | const atom = elf_file.getAtom(atom_index); | 4295 | const atom = elf_file.getAtom(atom_index); |
| 4280 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); | 4296 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); |
| 4281 | const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file)); | 4297 | const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file)); |
| 4282 | try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr }); | 4298 | try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr }); |
| 4283 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | 4299 | } else if (self.bin_file.cast(link.File.MachO)) |_| { |
| 4284 | unreachable; // unsupported architecture for MachO | 4300 | unreachable; // unsupported architecture for MachO |
| 4285 | } else { | 4301 | } else { |
| ... | @@ -4288,16 +4304,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4288,16 +4304,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4288 | @tagName(self.target.cpu.arch), | 4304 | @tagName(self.target.cpu.arch), |
| 4289 | }); | 4305 | }); |
| 4290 | } | 4306 | } |
| 4291 | } else if (func_value.castTag(.extern_fn)) |_| { | 4307 | } else if (func_value.getExternFunc(mod)) |_| { |
| 4292 | return self.fail("TODO implement calling extern functions", .{}); | 4308 | return self.fail("TODO implement calling extern functions", .{}); |
| 4293 | } else { | 4309 | } else { |
| 4294 | return self.fail("TODO implement calling bitcasted functions", .{}); | 4310 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 4295 | } | 4311 | } |
| 4296 | } else { | 4312 | } else { |
| 4297 | assert(ty.zigTypeTag() == .Pointer); | 4313 | assert(ty.zigTypeTag(mod) == .Pointer); |
| 4298 | const mcv = try self.resolveInst(callee); | 4314 | const mcv = try self.resolveInst(callee); |
| 4299 | 4315 | ||
| 4300 | try self.genSetReg(Type.initTag(.usize), .lr, mcv); | 4316 | try self.genSetReg(Type.usize, .lr, mcv); |
| 4301 | } | 4317 | } |
| 4302 | 4318 | ||
| 4303 | // TODO: add Instruction.supportedOn | 4319 | // TODO: add Instruction.supportedOn |
| ... | @@ -4329,7 +4345,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4329,7 +4345,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4329 | if (RegisterManager.indexOfRegIntoTracked(reg) == null) { | 4345 | if (RegisterManager.indexOfRegIntoTracked(reg) == null) { |
| 4330 | // Save function return value into a tracked register | 4346 | // Save function return value into a tracked register |
| 4331 | log.debug("airCall: copying {} as it is not tracked", .{reg}); | 4347 | log.debug("airCall: copying {} as it is not tracked", .{reg}); |
| 4332 | const new_reg = try self.copyToTmpRegister(fn_ty.fnReturnType(), info.return_value); | 4348 | const new_reg = try self.copyToTmpRegister(fn_ty.fnReturnType(mod), info.return_value); |
| 4333 | break :result MCValue{ .register = new_reg }; | 4349 | break :result MCValue{ .register = new_reg }; |
| 4334 | } | 4350 | } |
| 4335 | }, | 4351 | }, |
| ... | @@ -4353,14 +4369,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -4353,14 +4369,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4353 | } | 4369 | } |
| 4354 | 4370 | ||
| 4355 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { | 4371 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4372 | const mod = self.bin_file.options.module.?; | ||
| 4356 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4373 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4357 | const operand = try self.resolveInst(un_op); | 4374 | const operand = try self.resolveInst(un_op); |
| 4358 | const ret_ty = self.fn_type.fnReturnType(); | 4375 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 4359 | 4376 | ||
| 4360 | switch (self.ret_mcv) { | 4377 | switch (self.ret_mcv) { |
| 4361 | .none => {}, | 4378 | .none => {}, |
| 4362 | .immediate => { | 4379 | .immediate => { |
| 4363 | assert(ret_ty.isError()); | 4380 | assert(ret_ty.isError(mod)); |
| 4364 | }, | 4381 | }, |
| 4365 | .register => |reg| { | 4382 | .register => |reg| { |
| 4366 | // Return result by value | 4383 | // Return result by value |
| ... | @@ -4371,11 +4388,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4371,11 +4388,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4371 | // | 4388 | // |
| 4372 | // self.ret_mcv is an address to where this function | 4389 | // self.ret_mcv is an address to where this function |
| 4373 | // should store its result into | 4390 | // should store its result into |
| 4374 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 4391 | const ptr_ty = try mod.singleMutPtrType(ret_ty); |
| 4375 | .base = .{ .tag = .single_mut_pointer }, | ||
| 4376 | .data = ret_ty, | ||
| 4377 | }; | ||
| 4378 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 4379 | try self.store(self.ret_mcv, operand, ptr_ty, ret_ty); | 4392 | try self.store(self.ret_mcv, operand, ptr_ty, ret_ty); |
| 4380 | }, | 4393 | }, |
| 4381 | else => unreachable, // invalid return result | 4394 | else => unreachable, // invalid return result |
| ... | @@ -4388,10 +4401,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4388,10 +4401,11 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4388 | } | 4401 | } |
| 4389 | 4402 | ||
| 4390 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | 4403 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4404 | const mod = self.bin_file.options.module.?; | ||
| 4391 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4405 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4392 | const ptr = try self.resolveInst(un_op); | 4406 | const ptr = try self.resolveInst(un_op); |
| 4393 | const ptr_ty = self.air.typeOf(un_op); | 4407 | const ptr_ty = self.typeOf(un_op); |
| 4394 | const ret_ty = self.fn_type.fnReturnType(); | 4408 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 4395 | 4409 | ||
| 4396 | switch (self.ret_mcv) { | 4410 | switch (self.ret_mcv) { |
| 4397 | .none => {}, | 4411 | .none => {}, |
| ... | @@ -4411,8 +4425,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4411,8 +4425,8 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4411 | // location. | 4425 | // location. |
| 4412 | const op_inst = Air.refToIndex(un_op).?; | 4426 | const op_inst = Air.refToIndex(un_op).?; |
| 4413 | if (self.air.instructions.items(.tag)[op_inst] != .ret_ptr) { | 4427 | if (self.air.instructions.items(.tag)[op_inst] != .ret_ptr) { |
| 4414 | const abi_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 4428 | const abi_size = @intCast(u32, ret_ty.abiSize(mod)); |
| 4415 | const abi_align = ret_ty.abiAlignment(self.target.*); | 4429 | const abi_align = ret_ty.abiAlignment(mod); |
| 4416 | 4430 | ||
| 4417 | const offset = try self.allocMem(abi_size, abi_align, null); | 4431 | const offset = try self.allocMem(abi_size, abi_align, null); |
| 4418 | 4432 | ||
| ... | @@ -4432,7 +4446,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4432,7 +4446,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4432 | 4446 | ||
| 4433 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 4447 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 4434 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 4448 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4435 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 4449 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 4436 | 4450 | ||
| 4437 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { | 4451 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 4438 | break :blk try self.cmp(.{ .inst = bin_op.lhs }, .{ .inst = bin_op.rhs }, lhs_ty, op); | 4452 | break :blk try self.cmp(.{ .inst = bin_op.lhs }, .{ .inst = bin_op.rhs }, lhs_ty, op); |
| ... | @@ -4448,29 +4462,28 @@ fn cmp( | ... | @@ -4448,29 +4462,28 @@ fn cmp( |
| 4448 | lhs_ty: Type, | 4462 | lhs_ty: Type, |
| 4449 | op: math.CompareOperator, | 4463 | op: math.CompareOperator, |
| 4450 | ) !MCValue { | 4464 | ) !MCValue { |
| 4451 | var int_buffer: Type.Payload.Bits = undefined; | 4465 | const mod = self.bin_file.options.module.?; |
| 4452 | const int_ty = switch (lhs_ty.zigTypeTag()) { | 4466 | const int_ty = switch (lhs_ty.zigTypeTag(mod)) { |
| 4453 | .Optional => blk: { | 4467 | .Optional => blk: { |
| 4454 | var opt_buffer: Type.Payload.ElemType = undefined; | 4468 | const payload_ty = lhs_ty.optionalChild(mod); |
| 4455 | const payload_ty = lhs_ty.optionalChild(&opt_buffer); | 4469 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4456 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 4470 | break :blk Type.u1; |
| 4457 | break :blk Type.initTag(.u1); | 4471 | } else if (lhs_ty.isPtrLikeOptional(mod)) { |
| 4458 | } else if (lhs_ty.isPtrLikeOptional()) { | ||
| 4459 | break :blk Type.usize; | 4472 | break :blk Type.usize; |
| 4460 | } else { | 4473 | } else { |
| 4461 | return self.fail("TODO ARM cmp non-pointer optionals", .{}); | 4474 | return self.fail("TODO ARM cmp non-pointer optionals", .{}); |
| 4462 | } | 4475 | } |
| 4463 | }, | 4476 | }, |
| 4464 | .Float => return self.fail("TODO ARM cmp floats", .{}), | 4477 | .Float => return self.fail("TODO ARM cmp floats", .{}), |
| 4465 | .Enum => lhs_ty.intTagType(&int_buffer), | 4478 | .Enum => lhs_ty.intTagType(mod), |
| 4466 | .Int => lhs_ty, | 4479 | .Int => lhs_ty, |
| 4467 | .Bool => Type.initTag(.u1), | 4480 | .Bool => Type.u1, |
| 4468 | .Pointer => Type.usize, | 4481 | .Pointer => Type.usize, |
| 4469 | .ErrorSet => Type.initTag(.u16), | 4482 | .ErrorSet => Type.u16, |
| 4470 | else => unreachable, | 4483 | else => unreachable, |
| 4471 | }; | 4484 | }; |
| 4472 | 4485 | ||
| 4473 | const int_info = int_ty.intInfo(self.target.*); | 4486 | const int_info = int_ty.intInfo(mod); |
| 4474 | if (int_info.bits <= 32) { | 4487 | if (int_info.bits <= 32) { |
| 4475 | try self.spillCompareFlagsIfOccupied(); | 4488 | try self.spillCompareFlagsIfOccupied(); |
| 4476 | 4489 | ||
| ... | @@ -4555,8 +4568,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4555,8 +4568,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 4555 | } | 4568 | } |
| 4556 | 4569 | ||
| 4557 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { | 4570 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 4558 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 4571 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; |
| 4559 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | 4572 | const mod = self.bin_file.options.module.?; |
| 4573 | const function = mod.funcPtr(ty_fn.func); | ||
| 4560 | // TODO emit debug info for function change | 4574 | // TODO emit debug info for function change |
| 4561 | _ = function; | 4575 | _ = function; |
| 4562 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); | 4576 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| ... | @@ -4571,7 +4585,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4571,7 +4585,7 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 4571 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 4585 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4572 | const operand = pl_op.operand; | 4586 | const operand = pl_op.operand; |
| 4573 | const tag = self.air.instructions.items(.tag)[inst]; | 4587 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4574 | const ty = self.air.typeOf(operand); | 4588 | const ty = self.typeOf(operand); |
| 4575 | const mcv = try self.resolveInst(operand); | 4589 | const mcv = try self.resolveInst(operand); |
| 4576 | const name = self.air.nullTerminatedString(pl_op.payload); | 4590 | const name = self.air.nullTerminatedString(pl_op.payload); |
| 4577 | 4591 | ||
| ... | @@ -4636,8 +4650,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4636,8 +4650,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4636 | // whether it needs to be spilled in the branches | 4650 | // whether it needs to be spilled in the branches |
| 4637 | if (self.liveness.operandDies(inst, 0)) { | 4651 | if (self.liveness.operandDies(inst, 0)) { |
| 4638 | const op_int = @enumToInt(pl_op.operand); | 4652 | const op_int = @enumToInt(pl_op.operand); |
| 4639 | if (op_int >= Air.Inst.Ref.typed_value_map.len) { | 4653 | if (op_int >= Air.ref_start_index) { |
| 4640 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | 4654 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); |
| 4641 | self.processDeath(op_index); | 4655 | self.processDeath(op_index); |
| 4642 | } | 4656 | } |
| 4643 | } | 4657 | } |
| ... | @@ -4726,7 +4740,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4726,7 +4740,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4726 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); | 4740 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); |
| 4727 | // TODO make sure the destination stack offset / register does not already have something | 4741 | // TODO make sure the destination stack offset / register does not already have something |
| 4728 | // going on there. | 4742 | // going on there. |
| 4729 | try self.setRegOrMem(self.air.typeOfIndex(else_key), canon_mcv, else_value); | 4743 | try self.setRegOrMem(self.typeOfIndex(else_key), canon_mcv, else_value); |
| 4730 | // TODO track the new register / stack allocation | 4744 | // TODO track the new register / stack allocation |
| 4731 | } | 4745 | } |
| 4732 | try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, saved_then_branch.inst_table.count()); | 4746 | try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, saved_then_branch.inst_table.count()); |
| ... | @@ -4753,7 +4767,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4753,7 +4767,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 4753 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); | 4767 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); |
| 4754 | // TODO make sure the destination stack offset / register does not already have something | 4768 | // TODO make sure the destination stack offset / register does not already have something |
| 4755 | // going on there. | 4769 | // going on there. |
| 4756 | try self.setRegOrMem(self.air.typeOfIndex(then_key), parent_mcv, then_value); | 4770 | try self.setRegOrMem(self.typeOfIndex(then_key), parent_mcv, then_value); |
| 4757 | // TODO track the new register / stack allocation | 4771 | // TODO track the new register / stack allocation |
| 4758 | } | 4772 | } |
| 4759 | 4773 | ||
| ... | @@ -4772,8 +4786,9 @@ fn isNull( | ... | @@ -4772,8 +4786,9 @@ fn isNull( |
| 4772 | operand_bind: ReadArg.Bind, | 4786 | operand_bind: ReadArg.Bind, |
| 4773 | operand_ty: Type, | 4787 | operand_ty: Type, |
| 4774 | ) !MCValue { | 4788 | ) !MCValue { |
| 4775 | if (operand_ty.isPtrLikeOptional()) { | 4789 | const mod = self.bin_file.options.module.?; |
| 4776 | assert(operand_ty.abiSize(self.target.*) == 4); | 4790 | if (operand_ty.isPtrLikeOptional(mod)) { |
| 4791 | assert(operand_ty.abiSize(mod) == 4); | ||
| 4777 | 4792 | ||
| 4778 | const imm_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 0 } }; | 4793 | const imm_bind: ReadArg.Bind = .{ .mcv = .{ .immediate = 0 } }; |
| 4779 | return self.cmp(operand_bind, imm_bind, Type.usize, .eq); | 4794 | return self.cmp(operand_bind, imm_bind, Type.usize, .eq); |
| ... | @@ -4797,7 +4812,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4797,7 +4812,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4797 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4812 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4798 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4813 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4799 | const operand_bind: ReadArg.Bind = .{ .inst = un_op }; | 4814 | const operand_bind: ReadArg.Bind = .{ .inst = un_op }; |
| 4800 | const operand_ty = self.air.typeOf(un_op); | 4815 | const operand_ty = self.typeOf(un_op); |
| 4801 | 4816 | ||
| 4802 | break :result try self.isNull(operand_bind, operand_ty); | 4817 | break :result try self.isNull(operand_bind, operand_ty); |
| 4803 | }; | 4818 | }; |
| ... | @@ -4805,11 +4820,12 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4805,11 +4820,12 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4805 | } | 4820 | } |
| 4806 | 4821 | ||
| 4807 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 4822 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4823 | const mod = self.bin_file.options.module.?; | ||
| 4808 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4824 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4809 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4825 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4810 | const operand_ptr = try self.resolveInst(un_op); | 4826 | const operand_ptr = try self.resolveInst(un_op); |
| 4811 | const ptr_ty = self.air.typeOf(un_op); | 4827 | const ptr_ty = self.typeOf(un_op); |
| 4812 | const elem_ty = ptr_ty.elemType(); | 4828 | const elem_ty = ptr_ty.childType(mod); |
| 4813 | 4829 | ||
| 4814 | const operand = try self.allocRegOrMem(elem_ty, true, null); | 4830 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4815 | try self.load(operand, operand_ptr, ptr_ty); | 4831 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | @@ -4823,7 +4839,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4823,7 +4839,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4823 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4839 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4824 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4840 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4825 | const operand_bind: ReadArg.Bind = .{ .inst = un_op }; | 4841 | const operand_bind: ReadArg.Bind = .{ .inst = un_op }; |
| 4826 | const operand_ty = self.air.typeOf(un_op); | 4842 | const operand_ty = self.typeOf(un_op); |
| 4827 | 4843 | ||
| 4828 | break :result try self.isNonNull(operand_bind, operand_ty); | 4844 | break :result try self.isNonNull(operand_bind, operand_ty); |
| 4829 | }; | 4845 | }; |
| ... | @@ -4831,11 +4847,12 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4831,11 +4847,12 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 4831 | } | 4847 | } |
| 4832 | 4848 | ||
| 4833 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 4849 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4850 | const mod = self.bin_file.options.module.?; | ||
| 4834 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4851 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4835 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4852 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4836 | const operand_ptr = try self.resolveInst(un_op); | 4853 | const operand_ptr = try self.resolveInst(un_op); |
| 4837 | const ptr_ty = self.air.typeOf(un_op); | 4854 | const ptr_ty = self.typeOf(un_op); |
| 4838 | const elem_ty = ptr_ty.elemType(); | 4855 | const elem_ty = ptr_ty.childType(mod); |
| 4839 | 4856 | ||
| 4840 | const operand = try self.allocRegOrMem(elem_ty, true, null); | 4857 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4841 | try self.load(operand, operand_ptr, ptr_ty); | 4858 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | @@ -4850,9 +4867,10 @@ fn isErr( | ... | @@ -4850,9 +4867,10 @@ fn isErr( |
| 4850 | error_union_bind: ReadArg.Bind, | 4867 | error_union_bind: ReadArg.Bind, |
| 4851 | error_union_ty: Type, | 4868 | error_union_ty: Type, |
| 4852 | ) !MCValue { | 4869 | ) !MCValue { |
| 4853 | const error_type = error_union_ty.errorUnionSet(); | 4870 | const mod = self.bin_file.options.module.?; |
| 4871 | const error_type = error_union_ty.errorUnionSet(mod); | ||
| 4854 | 4872 | ||
| 4855 | if (error_type.errorSetIsEmpty()) { | 4873 | if (error_type.errorSetIsEmpty(mod)) { |
| 4856 | return MCValue{ .immediate = 0 }; // always false | 4874 | return MCValue{ .immediate = 0 }; // always false |
| 4857 | } | 4875 | } |
| 4858 | 4876 | ||
| ... | @@ -4883,7 +4901,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4883,7 +4901,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4883 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4901 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4884 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4902 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4885 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; | 4903 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; |
| 4886 | const error_union_ty = self.air.typeOf(un_op); | 4904 | const error_union_ty = self.typeOf(un_op); |
| 4887 | 4905 | ||
| 4888 | break :result try self.isErr(error_union_bind, error_union_ty); | 4906 | break :result try self.isErr(error_union_bind, error_union_ty); |
| 4889 | }; | 4907 | }; |
| ... | @@ -4891,11 +4909,12 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4891,11 +4909,12 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4891 | } | 4909 | } |
| 4892 | 4910 | ||
| 4893 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 4911 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4912 | const mod = self.bin_file.options.module.?; | ||
| 4894 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4913 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4895 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4914 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4896 | const operand_ptr = try self.resolveInst(un_op); | 4915 | const operand_ptr = try self.resolveInst(un_op); |
| 4897 | const ptr_ty = self.air.typeOf(un_op); | 4916 | const ptr_ty = self.typeOf(un_op); |
| 4898 | const elem_ty = ptr_ty.elemType(); | 4917 | const elem_ty = ptr_ty.childType(mod); |
| 4899 | 4918 | ||
| 4900 | const operand = try self.allocRegOrMem(elem_ty, true, null); | 4919 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4901 | try self.load(operand, operand_ptr, ptr_ty); | 4920 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | @@ -4909,7 +4928,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4909,7 +4928,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4909 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4928 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4910 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4929 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4911 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; | 4930 | const error_union_bind: ReadArg.Bind = .{ .inst = un_op }; |
| 4912 | const error_union_ty = self.air.typeOf(un_op); | 4931 | const error_union_ty = self.typeOf(un_op); |
| 4913 | 4932 | ||
| 4914 | break :result try self.isNonErr(error_union_bind, error_union_ty); | 4933 | break :result try self.isNonErr(error_union_bind, error_union_ty); |
| 4915 | }; | 4934 | }; |
| ... | @@ -4917,11 +4936,12 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4917,11 +4936,12 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4917 | } | 4936 | } |
| 4918 | 4937 | ||
| 4919 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 4938 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4939 | const mod = self.bin_file.options.module.?; | ||
| 4920 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4940 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4921 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 4941 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 4922 | const operand_ptr = try self.resolveInst(un_op); | 4942 | const operand_ptr = try self.resolveInst(un_op); |
| 4923 | const ptr_ty = self.air.typeOf(un_op); | 4943 | const ptr_ty = self.typeOf(un_op); |
| 4924 | const elem_ty = ptr_ty.elemType(); | 4944 | const elem_ty = ptr_ty.childType(mod); |
| 4925 | 4945 | ||
| 4926 | const operand = try self.allocRegOrMem(elem_ty, true, null); | 4946 | const operand = try self.allocRegOrMem(elem_ty, true, null); |
| 4927 | try self.load(operand, operand_ptr, ptr_ty); | 4947 | try self.load(operand, operand_ptr, ptr_ty); |
| ... | @@ -4988,7 +5008,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4988,7 +5008,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 4988 | 5008 | ||
| 4989 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | 5009 | fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 4990 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 5010 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4991 | const condition_ty = self.air.typeOf(pl_op.operand); | 5011 | const condition_ty = self.typeOf(pl_op.operand); |
| 4992 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); | 5012 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 4993 | const liveness = try self.liveness.getSwitchBr( | 5013 | const liveness = try self.liveness.getSwitchBr( |
| 4994 | self.gpa, | 5014 | self.gpa, |
| ... | @@ -5131,9 +5151,10 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5131,9 +5151,10 @@ fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 5131 | } | 5151 | } |
| 5132 | 5152 | ||
| 5133 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | 5153 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5154 | const mod = self.bin_file.options.module.?; | ||
| 5134 | const block_data = self.blocks.getPtr(block).?; | 5155 | const block_data = self.blocks.getPtr(block).?; |
| 5135 | 5156 | ||
| 5136 | if (self.air.typeOf(operand).hasRuntimeBits()) { | 5157 | if (self.typeOf(operand).hasRuntimeBits(mod)) { |
| 5137 | const operand_mcv = try self.resolveInst(operand); | 5158 | const operand_mcv = try self.resolveInst(operand); |
| 5138 | const block_mcv = block_data.mcv; | 5159 | const block_mcv = block_data.mcv; |
| 5139 | if (block_mcv == .none) { | 5160 | if (block_mcv == .none) { |
| ... | @@ -5141,14 +5162,14 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | ... | @@ -5141,14 +5162,14 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 5141 | .none, .dead, .unreach => unreachable, | 5162 | .none, .dead, .unreach => unreachable, |
| 5142 | .register, .stack_offset, .memory => operand_mcv, | 5163 | .register, .stack_offset, .memory => operand_mcv, |
| 5143 | .immediate, .stack_argument_offset, .cpsr_flags => blk: { | 5164 | .immediate, .stack_argument_offset, .cpsr_flags => blk: { |
| 5144 | const new_mcv = try self.allocRegOrMem(self.air.typeOfIndex(block), true, block); | 5165 | const new_mcv = try self.allocRegOrMem(self.typeOfIndex(block), true, block); |
| 5145 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | 5166 | try self.setRegOrMem(self.typeOfIndex(block), new_mcv, operand_mcv); |
| 5146 | break :blk new_mcv; | 5167 | break :blk new_mcv; |
| 5147 | }, | 5168 | }, |
| 5148 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), | 5169 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), |
| 5149 | }; | 5170 | }; |
| 5150 | } else { | 5171 | } else { |
| 5151 | try self.setRegOrMem(self.air.typeOfIndex(block), block_mcv, operand_mcv); | 5172 | try self.setRegOrMem(self.typeOfIndex(block), block_mcv, operand_mcv); |
| 5152 | } | 5173 | } |
| 5153 | } | 5174 | } |
| 5154 | return self.brVoid(block); | 5175 | return self.brVoid(block); |
| ... | @@ -5212,7 +5233,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5212,7 +5233,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 5212 | 5233 | ||
| 5213 | const arg_mcv = try self.resolveInst(input); | 5234 | const arg_mcv = try self.resolveInst(input); |
| 5214 | try self.register_manager.getReg(reg, null); | 5235 | try self.register_manager.getReg(reg, null); |
| 5215 | try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); | 5236 | try self.genSetReg(self.typeOf(input), reg, arg_mcv); |
| 5216 | } | 5237 | } |
| 5217 | 5238 | ||
| 5218 | { | 5239 | { |
| ... | @@ -5301,7 +5322,8 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { | ... | @@ -5301,7 +5322,8 @@ fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void { |
| 5301 | } | 5322 | } |
| 5302 | 5323 | ||
| 5303 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { | 5324 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 5304 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 5325 | const mod = self.bin_file.options.module.?; |
| 5326 | const abi_size = @intCast(u32, ty.abiSize(mod)); | ||
| 5305 | switch (mcv) { | 5327 | switch (mcv) { |
| 5306 | .dead => unreachable, | 5328 | .dead => unreachable, |
| 5307 | .unreach, .none => return, // Nothing to do. | 5329 | .unreach, .none => return, // Nothing to do. |
| ... | @@ -5332,7 +5354,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5332,7 +5354,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5332 | 1, 4 => { | 5354 | 1, 4 => { |
| 5333 | const offset = if (math.cast(u12, stack_offset)) |imm| blk: { | 5355 | const offset = if (math.cast(u12, stack_offset)) |imm| blk: { |
| 5334 | break :blk Instruction.Offset.imm(imm); | 5356 | break :blk Instruction.Offset.imm(imm); |
| 5335 | } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = stack_offset }), .none); | 5357 | } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.u32, MCValue{ .immediate = stack_offset }), .none); |
| 5336 | 5358 | ||
| 5337 | const tag: Mir.Inst.Tag = switch (abi_size) { | 5359 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5338 | 1 => .strb, | 5360 | 1 => .strb, |
| ... | @@ -5355,7 +5377,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5355,7 +5377,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5355 | 2 => { | 5377 | 2 => { |
| 5356 | const offset = if (stack_offset <= math.maxInt(u8)) blk: { | 5378 | const offset = if (stack_offset <= math.maxInt(u8)) blk: { |
| 5357 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, stack_offset)); | 5379 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, stack_offset)); |
| 5358 | } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = stack_offset })); | 5380 | } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.u32, MCValue{ .immediate = stack_offset })); |
| 5359 | 5381 | ||
| 5360 | _ = try self.addInst(.{ | 5382 | _ = try self.addInst(.{ |
| 5361 | .tag = .strh, | 5383 | .tag = .strh, |
| ... | @@ -5378,11 +5400,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5378,11 +5400,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5378 | const reg_lock = self.register_manager.lockReg(reg); | 5400 | const reg_lock = self.register_manager.lockReg(reg); |
| 5379 | defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg); | 5401 | defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg); |
| 5380 | 5402 | ||
| 5381 | const wrapped_ty = ty.structFieldType(0); | 5403 | const wrapped_ty = ty.structFieldType(0, mod); |
| 5382 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }); | 5404 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = reg }); |
| 5383 | 5405 | ||
| 5384 | const overflow_bit_ty = ty.structFieldType(1); | 5406 | const overflow_bit_ty = ty.structFieldType(1, mod); |
| 5385 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*)); | 5407 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, mod)); |
| 5386 | const cond_reg = try self.register_manager.allocReg(null, gp); | 5408 | const cond_reg = try self.register_manager.allocReg(null, gp); |
| 5387 | 5409 | ||
| 5388 | // C flag: movcs reg, #1 | 5410 | // C flag: movcs reg, #1 |
| ... | @@ -5420,11 +5442,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5420,11 +5442,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5420 | const reg = try self.copyToTmpRegister(ty, mcv); | 5442 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 5421 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 5443 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 5422 | } else { | 5444 | } else { |
| 5423 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 5445 | const ptr_ty = try mod.singleMutPtrType(ty); |
| 5424 | .base = .{ .tag = .single_mut_pointer }, | ||
| 5425 | .data = ty, | ||
| 5426 | }; | ||
| 5427 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 5428 | 5446 | ||
| 5429 | // TODO call extern memcpy | 5447 | // TODO call extern memcpy |
| 5430 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp); | 5448 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp); |
| ... | @@ -5466,6 +5484,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -5466,6 +5484,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 5466 | } | 5484 | } |
| 5467 | 5485 | ||
| 5468 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { | 5486 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 5487 | const mod = self.bin_file.options.module.?; | ||
| 5469 | switch (mcv) { | 5488 | switch (mcv) { |
| 5470 | .dead => unreachable, | 5489 | .dead => unreachable, |
| 5471 | .unreach, .none => return, // Nothing to do. | 5490 | .unreach, .none => return, // Nothing to do. |
| ... | @@ -5640,17 +5659,17 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5640,17 +5659,17 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5640 | }, | 5659 | }, |
| 5641 | .stack_offset => |off| { | 5660 | .stack_offset => |off| { |
| 5642 | // TODO: maybe addressing from sp instead of fp | 5661 | // TODO: maybe addressing from sp instead of fp |
| 5643 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 5662 | const abi_size = @intCast(u32, ty.abiSize(mod)); |
| 5644 | 5663 | ||
| 5645 | const tag: Mir.Inst.Tag = switch (abi_size) { | 5664 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5646 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb, | 5665 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb else .ldrb, |
| 5647 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh, | 5666 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh else .ldrh, |
| 5648 | 3, 4 => .ldr, | 5667 | 3, 4 => .ldr, |
| 5649 | else => unreachable, | 5668 | else => unreachable, |
| 5650 | }; | 5669 | }; |
| 5651 | 5670 | ||
| 5652 | const extra_offset = switch (abi_size) { | 5671 | const extra_offset = switch (abi_size) { |
| 5653 | 1 => ty.isSignedInt(), | 5672 | 1 => ty.isSignedInt(mod), |
| 5654 | 2 => true, | 5673 | 2 => true, |
| 5655 | 3, 4 => false, | 5674 | 3, 4 => false, |
| 5656 | else => unreachable, | 5675 | else => unreachable, |
| ... | @@ -5659,7 +5678,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5659,7 +5678,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5659 | if (extra_offset) { | 5678 | if (extra_offset) { |
| 5660 | const offset = if (off <= math.maxInt(u8)) blk: { | 5679 | const offset = if (off <= math.maxInt(u8)) blk: { |
| 5661 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, off)); | 5680 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, off)); |
| 5662 | } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.usize), MCValue{ .immediate = off })); | 5681 | } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.usize, MCValue{ .immediate = off })); |
| 5663 | 5682 | ||
| 5664 | _ = try self.addInst(.{ | 5683 | _ = try self.addInst(.{ |
| 5665 | .tag = tag, | 5684 | .tag = tag, |
| ... | @@ -5675,7 +5694,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5675,7 +5694,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5675 | } else { | 5694 | } else { |
| 5676 | const offset = if (off <= math.maxInt(u12)) blk: { | 5695 | const offset = if (off <= math.maxInt(u12)) blk: { |
| 5677 | break :blk Instruction.Offset.imm(@intCast(u12, off)); | 5696 | break :blk Instruction.Offset.imm(@intCast(u12, off)); |
| 5678 | } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.usize), MCValue{ .immediate = off }), .none); | 5697 | } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.usize, MCValue{ .immediate = off }), .none); |
| 5679 | 5698 | ||
| 5680 | _ = try self.addInst(.{ | 5699 | _ = try self.addInst(.{ |
| 5681 | .tag = tag, | 5700 | .tag = tag, |
| ... | @@ -5691,11 +5710,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5691,11 +5710,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5691 | } | 5710 | } |
| 5692 | }, | 5711 | }, |
| 5693 | .stack_argument_offset => |off| { | 5712 | .stack_argument_offset => |off| { |
| 5694 | const abi_size = ty.abiSize(self.target.*); | 5713 | const abi_size = ty.abiSize(mod); |
| 5695 | 5714 | ||
| 5696 | const tag: Mir.Inst.Tag = switch (abi_size) { | 5715 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5697 | 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument, | 5716 | 1 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument, |
| 5698 | 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument, | 5717 | 2 => if (ty.isSignedInt(mod)) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument, |
| 5699 | 3, 4 => .ldr_stack_argument, | 5718 | 3, 4 => .ldr_stack_argument, |
| 5700 | else => unreachable, | 5719 | else => unreachable, |
| 5701 | }; | 5720 | }; |
| ... | @@ -5712,7 +5731,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -5712,7 +5731,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 5712 | } | 5731 | } |
| 5713 | 5732 | ||
| 5714 | fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { | 5733 | fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 5715 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 5734 | const mod = self.bin_file.options.module.?; |
| 5735 | const abi_size = @intCast(u32, ty.abiSize(mod)); | ||
| 5716 | switch (mcv) { | 5736 | switch (mcv) { |
| 5717 | .dead => unreachable, | 5737 | .dead => unreachable, |
| 5718 | .none, .unreach => return, | 5738 | .none, .unreach => return, |
| ... | @@ -5732,7 +5752,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -5732,7 +5752,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5732 | 1, 4 => { | 5752 | 1, 4 => { |
| 5733 | const offset = if (math.cast(u12, stack_offset)) |imm| blk: { | 5753 | const offset = if (math.cast(u12, stack_offset)) |imm| blk: { |
| 5734 | break :blk Instruction.Offset.imm(imm); | 5754 | break :blk Instruction.Offset.imm(imm); |
| 5735 | } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = stack_offset }), .none); | 5755 | } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.u32, MCValue{ .immediate = stack_offset }), .none); |
| 5736 | 5756 | ||
| 5737 | const tag: Mir.Inst.Tag = switch (abi_size) { | 5757 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 5738 | 1 => .strb, | 5758 | 1 => .strb, |
| ... | @@ -5752,7 +5772,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -5752,7 +5772,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5752 | 2 => { | 5772 | 2 => { |
| 5753 | const offset = if (stack_offset <= math.maxInt(u8)) blk: { | 5773 | const offset = if (stack_offset <= math.maxInt(u8)) blk: { |
| 5754 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, stack_offset)); | 5774 | break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, stack_offset)); |
| 5755 | } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = stack_offset })); | 5775 | } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.u32, MCValue{ .immediate = stack_offset })); |
| 5756 | 5776 | ||
| 5757 | _ = try self.addInst(.{ | 5777 | _ = try self.addInst(.{ |
| 5758 | .tag = .strh, | 5778 | .tag = .strh, |
| ... | @@ -5779,11 +5799,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I | ... | @@ -5779,11 +5799,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I |
| 5779 | const reg = try self.copyToTmpRegister(ty, mcv); | 5799 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 5780 | return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg }); | 5800 | return self.genSetStackArgument(ty, stack_offset, MCValue{ .register = reg }); |
| 5781 | } else { | 5801 | } else { |
| 5782 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 5802 | const ptr_ty = try mod.singleMutPtrType(ty); |
| 5783 | .base = .{ .tag = .single_mut_pointer }, | ||
| 5784 | .data = ty, | ||
| 5785 | }; | ||
| 5786 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 5787 | 5803 | ||
| 5788 | // TODO call extern memcpy | 5804 | // TODO call extern memcpy |
| 5789 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp); | 5805 | const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, gp); |
| ... | @@ -5862,7 +5878,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5862,7 +5878,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 5862 | }; | 5878 | }; |
| 5863 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | 5879 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 5864 | 5880 | ||
| 5865 | const dest_ty = self.air.typeOfIndex(inst); | 5881 | const dest_ty = self.typeOfIndex(inst); |
| 5866 | const dest = try self.allocRegOrMem(dest_ty, true, inst); | 5882 | const dest = try self.allocRegOrMem(dest_ty, true, inst); |
| 5867 | try self.setRegOrMem(dest_ty, dest, operand); | 5883 | try self.setRegOrMem(dest_ty, dest, operand); |
| 5868 | break :result dest; | 5884 | break :result dest; |
| ... | @@ -5871,16 +5887,17 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5871,16 +5887,17 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 5871 | } | 5887 | } |
| 5872 | 5888 | ||
| 5873 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | 5889 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 5890 | const mod = self.bin_file.options.module.?; | ||
| 5874 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5891 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5875 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 5892 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 5876 | const ptr_ty = self.air.typeOf(ty_op.operand); | 5893 | const ptr_ty = self.typeOf(ty_op.operand); |
| 5877 | const ptr = try self.resolveInst(ty_op.operand); | 5894 | const ptr = try self.resolveInst(ty_op.operand); |
| 5878 | const array_ty = ptr_ty.childType(); | 5895 | const array_ty = ptr_ty.childType(mod); |
| 5879 | const array_len = @intCast(u32, array_ty.arrayLen()); | 5896 | const array_len = @intCast(u32, array_ty.arrayLen(mod)); |
| 5880 | 5897 | ||
| 5881 | const stack_offset = try self.allocMem(8, 8, inst); | 5898 | const stack_offset = try self.allocMem(8, 8, inst); |
| 5882 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 5899 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 5883 | try self.genSetStack(Type.initTag(.usize), stack_offset - 4, .{ .immediate = array_len }); | 5900 | try self.genSetStack(Type.usize, stack_offset - 4, .{ .immediate = array_len }); |
| 5884 | break :result MCValue{ .stack_offset = stack_offset }; | 5901 | break :result MCValue{ .stack_offset = stack_offset }; |
| 5885 | }; | 5902 | }; |
| 5886 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 5903 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -5989,8 +6006,9 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5989,8 +6006,9 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { |
| 5989 | } | 6006 | } |
| 5990 | 6007 | ||
| 5991 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | 6008 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 5992 | const vector_ty = self.air.typeOfIndex(inst); | 6009 | const mod = self.bin_file.options.module.?; |
| 5993 | const len = vector_ty.vectorLen(); | 6010 | const vector_ty = self.typeOfIndex(inst); |
| 6011 | const len = vector_ty.vectorLen(mod); | ||
| 5994 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 6012 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5995 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); | 6013 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 5996 | const result: MCValue = res: { | 6014 | const result: MCValue = res: { |
| ... | @@ -6038,9 +6056,10 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6038,9 +6056,10 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 6038 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 6056 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 6039 | const result: MCValue = result: { | 6057 | const result: MCValue = result: { |
| 6040 | const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand }; | 6058 | const error_union_bind: ReadArg.Bind = .{ .inst = pl_op.operand }; |
| 6041 | const error_union_ty = self.air.typeOf(pl_op.operand); | 6059 | const error_union_ty = self.typeOf(pl_op.operand); |
| 6042 | const error_union_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | 6060 | const mod = self.bin_file.options.module.?; |
| 6043 | const error_union_align = error_union_ty.abiAlignment(self.target.*); | 6061 | const error_union_size = @intCast(u32, error_union_ty.abiSize(mod)); |
| 6062 | const error_union_align = error_union_ty.abiAlignment(mod); | ||
| 6044 | 6063 | ||
| 6045 | // The error union will die in the body. However, we need the | 6064 | // The error union will die in the body. However, we need the |
| 6046 | // error union after the body in order to extract the payload | 6065 | // error union after the body in order to extract the payload |
| ... | @@ -6069,37 +6088,32 @@ fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6069,37 +6088,32 @@ fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 6069 | } | 6088 | } |
| 6070 | 6089 | ||
| 6071 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | 6090 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 6072 | // First section of indexes correspond to a set number of constant values. | 6091 | const mod = self.bin_file.options.module.?; |
| 6073 | const ref_int = @enumToInt(inst); | ||
| 6074 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | ||
| 6075 | const tv = Air.Inst.Ref.typed_value_map[ref_int]; | ||
| 6076 | if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) { | ||
| 6077 | return MCValue{ .none = {} }; | ||
| 6078 | } | ||
| 6079 | return self.genTypedValue(tv); | ||
| 6080 | } | ||
| 6081 | 6092 | ||
| 6082 | // If the type has no codegen bits, no need to store it. | 6093 | // If the type has no codegen bits, no need to store it. |
| 6083 | const inst_ty = self.air.typeOf(inst); | 6094 | const inst_ty = self.typeOf(inst); |
| 6084 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError()) | 6095 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod) and !inst_ty.isError(mod)) |
| 6085 | return MCValue{ .none = {} }; | 6096 | return MCValue{ .none = {} }; |
| 6086 | 6097 | ||
| 6087 | const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); | 6098 | const inst_index = Air.refToIndex(inst) orelse return self.genTypedValue(.{ |
| 6099 | .ty = inst_ty, | ||
| 6100 | .val = (try self.air.value(inst, mod)).?, | ||
| 6101 | }); | ||
| 6102 | |||
| 6088 | switch (self.air.instructions.items(.tag)[inst_index]) { | 6103 | switch (self.air.instructions.items(.tag)[inst_index]) { |
| 6089 | .constant => { | 6104 | .interned => { |
| 6090 | // Constants have static lifetimes, so they are always memoized in the outer most table. | 6105 | // Constants have static lifetimes, so they are always memoized in the outer most table. |
| 6091 | const branch = &self.branch_stack.items[0]; | 6106 | const branch = &self.branch_stack.items[0]; |
| 6092 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); | 6107 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); |
| 6093 | if (!gop.found_existing) { | 6108 | if (!gop.found_existing) { |
| 6094 | const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl; | 6109 | const interned = self.air.instructions.items(.data)[inst_index].interned; |
| 6095 | gop.value_ptr.* = try self.genTypedValue(.{ | 6110 | gop.value_ptr.* = try self.genTypedValue(.{ |
| 6096 | .ty = inst_ty, | 6111 | .ty = inst_ty, |
| 6097 | .val = self.air.values[ty_pl.payload], | 6112 | .val = interned.toValue(), |
| 6098 | }); | 6113 | }); |
| 6099 | } | 6114 | } |
| 6100 | return gop.value_ptr.*; | 6115 | return gop.value_ptr.*; |
| 6101 | }, | 6116 | }, |
| 6102 | .const_ty => unreachable, | ||
| 6103 | else => return self.getResolvedInstValue(inst_index), | 6117 | else => return self.getResolvedInstValue(inst_index), |
| 6104 | } | 6118 | } |
| 6105 | } | 6119 | } |
| ... | @@ -6152,12 +6166,11 @@ const CallMCValues = struct { | ... | @@ -6152,12 +6166,11 @@ const CallMCValues = struct { |
| 6152 | 6166 | ||
| 6153 | /// Caller must call `CallMCValues.deinit`. | 6167 | /// Caller must call `CallMCValues.deinit`. |
| 6154 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | 6168 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6155 | const cc = fn_ty.fnCallingConvention(); | 6169 | const mod = self.bin_file.options.module.?; |
| 6156 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | 6170 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 6157 | defer self.gpa.free(param_types); | 6171 | const cc = fn_info.cc; |
| 6158 | fn_ty.fnParamTypes(param_types); | ||
| 6159 | var result: CallMCValues = .{ | 6172 | var result: CallMCValues = .{ |
| 6160 | .args = try self.gpa.alloc(MCValue, param_types.len), | 6173 | .args = try self.gpa.alloc(MCValue, fn_info.param_types.len), |
| 6161 | // These undefined values must be populated before returning from this function. | 6174 | // These undefined values must be populated before returning from this function. |
| 6162 | .return_value = undefined, | 6175 | .return_value = undefined, |
| 6163 | .stack_byte_count = undefined, | 6176 | .stack_byte_count = undefined, |
| ... | @@ -6165,7 +6178,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6165,7 +6178,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6165 | }; | 6178 | }; |
| 6166 | errdefer self.gpa.free(result.args); | 6179 | errdefer self.gpa.free(result.args); |
| 6167 | 6180 | ||
| 6168 | const ret_ty = fn_ty.fnReturnType(); | 6181 | const ret_ty = fn_ty.fnReturnType(mod); |
| 6169 | 6182 | ||
| 6170 | switch (cc) { | 6183 | switch (cc) { |
| 6171 | .Naked => { | 6184 | .Naked => { |
| ... | @@ -6180,12 +6193,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6180,12 +6193,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6180 | var ncrn: usize = 0; // Next Core Register Number | 6193 | var ncrn: usize = 0; // Next Core Register Number |
| 6181 | var nsaa: u32 = 0; // Next stacked argument address | 6194 | var nsaa: u32 = 0; // Next stacked argument address |
| 6182 | 6195 | ||
| 6183 | if (ret_ty.zigTypeTag() == .NoReturn) { | 6196 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 6184 | result.return_value = .{ .unreach = {} }; | 6197 | result.return_value = .{ .unreach = {} }; |
| 6185 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | 6198 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6186 | result.return_value = .{ .none = {} }; | 6199 | result.return_value = .{ .none = {} }; |
| 6187 | } else { | 6200 | } else { |
| 6188 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 6201 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(mod)); |
| 6189 | // TODO handle cases where multiple registers are used | 6202 | // TODO handle cases where multiple registers are used |
| 6190 | if (ret_ty_size <= 4) { | 6203 | if (ret_ty_size <= 4) { |
| 6191 | result.return_value = .{ .register = c_abi_int_return_regs[0] }; | 6204 | result.return_value = .{ .register = c_abi_int_return_regs[0] }; |
| ... | @@ -6199,11 +6212,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6199,11 +6212,11 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6199 | } | 6212 | } |
| 6200 | } | 6213 | } |
| 6201 | 6214 | ||
| 6202 | for (param_types, 0..) |ty, i| { | 6215 | for (fn_info.param_types, 0..) |ty, i| { |
| 6203 | if (ty.abiAlignment(self.target.*) == 8) | 6216 | if (ty.toType().abiAlignment(mod) == 8) |
| 6204 | ncrn = std.mem.alignForwardGeneric(usize, ncrn, 2); | 6217 | ncrn = std.mem.alignForwardGeneric(usize, ncrn, 2); |
| 6205 | 6218 | ||
| 6206 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 6219 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); |
| 6207 | if (std.math.divCeil(u32, param_size, 4) catch unreachable <= 4 - ncrn) { | 6220 | if (std.math.divCeil(u32, param_size, 4) catch unreachable <= 4 - ncrn) { |
| 6208 | if (param_size <= 4) { | 6221 | if (param_size <= 4) { |
| 6209 | result.args[i] = .{ .register = c_abi_int_param_regs[ncrn] }; | 6222 | result.args[i] = .{ .register = c_abi_int_param_regs[ncrn] }; |
| ... | @@ -6215,7 +6228,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6215,7 +6228,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6215 | return self.fail("TODO MCValues split between registers and stack", .{}); | 6228 | return self.fail("TODO MCValues split between registers and stack", .{}); |
| 6216 | } else { | 6229 | } else { |
| 6217 | ncrn = 4; | 6230 | ncrn = 4; |
| 6218 | if (ty.abiAlignment(self.target.*) == 8) | 6231 | if (ty.toType().abiAlignment(mod) == 8) |
| 6219 | nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8); | 6232 | nsaa = std.mem.alignForwardGeneric(u32, nsaa, 8); |
| 6220 | 6233 | ||
| 6221 | result.args[i] = .{ .stack_argument_offset = nsaa }; | 6234 | result.args[i] = .{ .stack_argument_offset = nsaa }; |
| ... | @@ -6227,14 +6240,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6227,14 +6240,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6227 | result.stack_align = 8; | 6240 | result.stack_align = 8; |
| 6228 | }, | 6241 | }, |
| 6229 | .Unspecified => { | 6242 | .Unspecified => { |
| 6230 | if (ret_ty.zigTypeTag() == .NoReturn) { | 6243 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 6231 | result.return_value = .{ .unreach = {} }; | 6244 | result.return_value = .{ .unreach = {} }; |
| 6232 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { | 6245 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod) and !ret_ty.isError(mod)) { |
| 6233 | result.return_value = .{ .none = {} }; | 6246 | result.return_value = .{ .none = {} }; |
| 6234 | } else { | 6247 | } else { |
| 6235 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 6248 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(mod)); |
| 6236 | if (ret_ty_size == 0) { | 6249 | if (ret_ty_size == 0) { |
| 6237 | assert(ret_ty.isError()); | 6250 | assert(ret_ty.isError(mod)); |
| 6238 | result.return_value = .{ .immediate = 0 }; | 6251 | result.return_value = .{ .immediate = 0 }; |
| 6239 | } else if (ret_ty_size <= 4) { | 6252 | } else if (ret_ty_size <= 4) { |
| 6240 | result.return_value = .{ .register = .r0 }; | 6253 | result.return_value = .{ .register = .r0 }; |
| ... | @@ -6249,10 +6262,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6249,10 +6262,10 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6249 | 6262 | ||
| 6250 | var stack_offset: u32 = 0; | 6263 | var stack_offset: u32 = 0; |
| 6251 | 6264 | ||
| 6252 | for (param_types, 0..) |ty, i| { | 6265 | for (fn_info.param_types, 0..) |ty, i| { |
| 6253 | if (ty.abiSize(self.target.*) > 0) { | 6266 | if (ty.toType().abiSize(mod) > 0) { |
| 6254 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 6267 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); |
| 6255 | const param_alignment = ty.abiAlignment(self.target.*); | 6268 | const param_alignment = ty.toType().abiAlignment(mod); |
| 6256 | 6269 | ||
| 6257 | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment); | 6270 | stack_offset = std.mem.alignForwardGeneric(u32, stack_offset, param_alignment); |
| 6258 | result.args[i] = .{ .stack_argument_offset = stack_offset }; | 6271 | result.args[i] = .{ .stack_argument_offset = stack_offset }; |
| ... | @@ -6301,3 +6314,13 @@ fn parseRegName(name: []const u8) ?Register { | ... | @@ -6301,3 +6314,13 @@ fn parseRegName(name: []const u8) ?Register { |
| 6301 | } | 6314 | } |
| 6302 | return std.meta.stringToEnum(Register, name); | 6315 | return std.meta.stringToEnum(Register, name); |
| 6303 | } | 6316 | } |
| 6317 | |||
| 6318 | fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { | ||
| 6319 | const mod = self.bin_file.options.module.?; | ||
| 6320 | return self.air.typeOf(inst, &mod.intern_pool); | ||
| 6321 | } | ||
| 6322 | |||
| 6323 | fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { | ||
| 6324 | const mod = self.bin_file.options.module.?; | ||
| 6325 | return self.air.typeOfIndex(inst, &mod.intern_pool); | ||
| 6326 | } |
src/arch/arm/abi.zig+30-27| ... | @@ -1,8 +1,10 @@ | ... | @@ -1,8 +1,10 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const assert = std.debug.assert; | ||
| 2 | const bits = @import("bits.zig"); | 3 | const bits = @import("bits.zig"); |
| 3 | const Register = bits.Register; | 4 | const Register = bits.Register; |
| 4 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | 5 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 5 | const Type = @import("../../type.zig").Type; | 6 | const Type = @import("../../type.zig").Type; |
| 7 | const Module = @import("../../Module.zig"); | ||
| 6 | 8 | ||
| 7 | pub const Class = union(enum) { | 9 | pub const Class = union(enum) { |
| 8 | memory, | 10 | memory, |
| ... | @@ -22,28 +24,28 @@ pub const Class = union(enum) { | ... | @@ -22,28 +24,28 @@ pub const Class = union(enum) { |
| 22 | 24 | ||
| 23 | pub const Context = enum { ret, arg }; | 25 | pub const Context = enum { ret, arg }; |
| 24 | 26 | ||
| 25 | pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class { | 27 | pub fn classifyType(ty: Type, mod: *Module, ctx: Context) Class { |
| 26 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime()); | 28 | assert(ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 27 | 29 | ||
| 28 | var maybe_float_bits: ?u16 = null; | 30 | var maybe_float_bits: ?u16 = null; |
| 29 | const max_byval_size = 512; | 31 | const max_byval_size = 512; |
| 30 | switch (ty.zigTypeTag()) { | 32 | switch (ty.zigTypeTag(mod)) { |
| 31 | .Struct => { | 33 | .Struct => { |
| 32 | const bit_size = ty.bitSize(target); | 34 | const bit_size = ty.bitSize(mod); |
| 33 | if (ty.containerLayout() == .Packed) { | 35 | if (ty.containerLayout(mod) == .Packed) { |
| 34 | if (bit_size > 64) return .memory; | 36 | if (bit_size > 64) return .memory; |
| 35 | return .byval; | 37 | return .byval; |
| 36 | } | 38 | } |
| 37 | if (bit_size > max_byval_size) return .memory; | 39 | if (bit_size > max_byval_size) return .memory; |
| 38 | const float_count = countFloats(ty, target, &maybe_float_bits); | 40 | const float_count = countFloats(ty, mod, &maybe_float_bits); |
| 39 | if (float_count <= byval_float_count) return .byval; | 41 | if (float_count <= byval_float_count) return .byval; |
| 40 | 42 | ||
| 41 | const fields = ty.structFieldCount(); | 43 | const fields = ty.structFieldCount(mod); |
| 42 | var i: u32 = 0; | 44 | var i: u32 = 0; |
| 43 | while (i < fields) : (i += 1) { | 45 | while (i < fields) : (i += 1) { |
| 44 | const field_ty = ty.structFieldType(i); | 46 | const field_ty = ty.structFieldType(i, mod); |
| 45 | const field_alignment = ty.structFieldAlign(i, target); | 47 | const field_alignment = ty.structFieldAlign(i, mod); |
| 46 | const field_size = field_ty.bitSize(target); | 48 | const field_size = field_ty.bitSize(mod); |
| 47 | if (field_size > 32 or field_alignment > 32) { | 49 | if (field_size > 32 or field_alignment > 32) { |
| 48 | return Class.arrSize(bit_size, 64); | 50 | return Class.arrSize(bit_size, 64); |
| 49 | } | 51 | } |
| ... | @@ -51,17 +53,17 @@ pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class { | ... | @@ -51,17 +53,17 @@ pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class { |
| 51 | return Class.arrSize(bit_size, 32); | 53 | return Class.arrSize(bit_size, 32); |
| 52 | }, | 54 | }, |
| 53 | .Union => { | 55 | .Union => { |
| 54 | const bit_size = ty.bitSize(target); | 56 | const bit_size = ty.bitSize(mod); |
| 55 | if (ty.containerLayout() == .Packed) { | 57 | if (ty.containerLayout(mod) == .Packed) { |
| 56 | if (bit_size > 64) return .memory; | 58 | if (bit_size > 64) return .memory; |
| 57 | return .byval; | 59 | return .byval; |
| 58 | } | 60 | } |
| 59 | if (bit_size > max_byval_size) return .memory; | 61 | if (bit_size > max_byval_size) return .memory; |
| 60 | const float_count = countFloats(ty, target, &maybe_float_bits); | 62 | const float_count = countFloats(ty, mod, &maybe_float_bits); |
| 61 | if (float_count <= byval_float_count) return .byval; | 63 | if (float_count <= byval_float_count) return .byval; |
| 62 | 64 | ||
| 63 | for (ty.unionFields().values()) |field| { | 65 | for (ty.unionFields(mod).values()) |field| { |
| 64 | if (field.ty.bitSize(target) > 32 or field.normalAlignment(target) > 32) { | 66 | if (field.ty.bitSize(mod) > 32 or field.normalAlignment(mod) > 32) { |
| 65 | return Class.arrSize(bit_size, 64); | 67 | return Class.arrSize(bit_size, 64); |
| 66 | } | 68 | } |
| 67 | } | 69 | } |
| ... | @@ -71,28 +73,28 @@ pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class { | ... | @@ -71,28 +73,28 @@ pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class { |
| 71 | .Int => { | 73 | .Int => { |
| 72 | // TODO this is incorrect for _BitInt(128) but implementing | 74 | // TODO this is incorrect for _BitInt(128) but implementing |
| 73 | // this correctly makes implementing compiler-rt impossible. | 75 | // this correctly makes implementing compiler-rt impossible. |
| 74 | // const bit_size = ty.bitSize(target); | 76 | // const bit_size = ty.bitSize(mod); |
| 75 | // if (bit_size > 64) return .memory; | 77 | // if (bit_size > 64) return .memory; |
| 76 | return .byval; | 78 | return .byval; |
| 77 | }, | 79 | }, |
| 78 | .Enum, .ErrorSet => { | 80 | .Enum, .ErrorSet => { |
| 79 | const bit_size = ty.bitSize(target); | 81 | const bit_size = ty.bitSize(mod); |
| 80 | if (bit_size > 64) return .memory; | 82 | if (bit_size > 64) return .memory; |
| 81 | return .byval; | 83 | return .byval; |
| 82 | }, | 84 | }, |
| 83 | .Vector => { | 85 | .Vector => { |
| 84 | const bit_size = ty.bitSize(target); | 86 | const bit_size = ty.bitSize(mod); |
| 85 | // TODO is this controlled by a cpu feature? | 87 | // TODO is this controlled by a cpu feature? |
| 86 | if (ctx == .ret and bit_size > 128) return .memory; | 88 | if (ctx == .ret and bit_size > 128) return .memory; |
| 87 | if (bit_size > 512) return .memory; | 89 | if (bit_size > 512) return .memory; |
| 88 | return .byval; | 90 | return .byval; |
| 89 | }, | 91 | }, |
| 90 | .Optional => { | 92 | .Optional => { |
| 91 | std.debug.assert(ty.isPtrLikeOptional()); | 93 | assert(ty.isPtrLikeOptional(mod)); |
| 92 | return .byval; | 94 | return .byval; |
| 93 | }, | 95 | }, |
| 94 | .Pointer => { | 96 | .Pointer => { |
| 95 | std.debug.assert(!ty.isSlice()); | 97 | assert(!ty.isSlice(mod)); |
| 96 | return .byval; | 98 | return .byval; |
| 97 | }, | 99 | }, |
| 98 | .ErrorUnion, | 100 | .ErrorUnion, |
| ... | @@ -114,14 +116,15 @@ pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class { | ... | @@ -114,14 +116,15 @@ pub fn classifyType(ty: Type, target: std.Target, ctx: Context) Class { |
| 114 | } | 116 | } |
| 115 | 117 | ||
| 116 | const byval_float_count = 4; | 118 | const byval_float_count = 4; |
| 117 | fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 { | 119 | fn countFloats(ty: Type, mod: *Module, maybe_float_bits: *?u16) u32 { |
| 120 | const target = mod.getTarget(); | ||
| 118 | const invalid = std.math.maxInt(u32); | 121 | const invalid = std.math.maxInt(u32); |
| 119 | switch (ty.zigTypeTag()) { | 122 | switch (ty.zigTypeTag(mod)) { |
| 120 | .Union => { | 123 | .Union => { |
| 121 | const fields = ty.unionFields(); | 124 | const fields = ty.unionFields(mod); |
| 122 | var max_count: u32 = 0; | 125 | var max_count: u32 = 0; |
| 123 | for (fields.values()) |field| { | 126 | for (fields.values()) |field| { |
| 124 | const field_count = countFloats(field.ty, target, maybe_float_bits); | 127 | const field_count = countFloats(field.ty, mod, maybe_float_bits); |
| 125 | if (field_count == invalid) return invalid; | 128 | if (field_count == invalid) return invalid; |
| 126 | if (field_count > max_count) max_count = field_count; | 129 | if (field_count > max_count) max_count = field_count; |
| 127 | if (max_count > byval_float_count) return invalid; | 130 | if (max_count > byval_float_count) return invalid; |
| ... | @@ -129,12 +132,12 @@ fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 { | ... | @@ -129,12 +132,12 @@ fn countFloats(ty: Type, target: std.Target, maybe_float_bits: *?u16) u32 { |
| 129 | return max_count; | 132 | return max_count; |
| 130 | }, | 133 | }, |
| 131 | .Struct => { | 134 | .Struct => { |
| 132 | const fields_len = ty.structFieldCount(); | 135 | const fields_len = ty.structFieldCount(mod); |
| 133 | var count: u32 = 0; | 136 | var count: u32 = 0; |
| 134 | var i: u32 = 0; | 137 | var i: u32 = 0; |
| 135 | while (i < fields_len) : (i += 1) { | 138 | while (i < fields_len) : (i += 1) { |
| 136 | const field_ty = ty.structFieldType(i); | 139 | const field_ty = ty.structFieldType(i, mod); |
| 137 | const field_count = countFloats(field_ty, target, maybe_float_bits); | 140 | const field_count = countFloats(field_ty, mod, maybe_float_bits); |
| 138 | if (field_count == invalid) return invalid; | 141 | if (field_count == invalid) return invalid; |
| 139 | count += field_count; | 142 | count += field_count; |
| 140 | if (count > byval_float_count) return invalid; | 143 | if (count > byval_float_count) return invalid; |
src/arch/riscv64/CodeGen.zig+108-95| ... | @@ -217,7 +217,7 @@ const Self = @This(); | ... | @@ -217,7 +217,7 @@ const Self = @This(); |
| 217 | pub fn generate( | 217 | pub fn generate( |
| 218 | bin_file: *link.File, | 218 | bin_file: *link.File, |
| 219 | src_loc: Module.SrcLoc, | 219 | src_loc: Module.SrcLoc, |
| 220 | module_fn: *Module.Fn, | 220 | module_fn_index: Module.Fn.Index, |
| 221 | air: Air, | 221 | air: Air, |
| 222 | liveness: Liveness, | 222 | liveness: Liveness, |
| 223 | code: *std.ArrayList(u8), | 223 | code: *std.ArrayList(u8), |
| ... | @@ -228,6 +228,7 @@ pub fn generate( | ... | @@ -228,6 +228,7 @@ pub fn generate( |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | const mod = bin_file.options.module.?; | 230 | const mod = bin_file.options.module.?; |
| 231 | const module_fn = mod.funcPtr(module_fn_index); | ||
| 231 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); | 232 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 232 | assert(fn_owner_decl.has_tv); | 233 | assert(fn_owner_decl.has_tv); |
| 233 | const fn_type = fn_owner_decl.ty; | 234 | const fn_type = fn_owner_decl.ty; |
| ... | @@ -347,7 +348,8 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { | ... | @@ -347,7 +348,8 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 347 | } | 348 | } |
| 348 | 349 | ||
| 349 | fn gen(self: *Self) !void { | 350 | fn gen(self: *Self) !void { |
| 350 | const cc = self.fn_type.fnCallingConvention(); | 351 | const mod = self.bin_file.options.module.?; |
| 352 | const cc = self.fn_type.fnCallingConvention(mod); | ||
| 351 | if (cc != .Naked) { | 353 | if (cc != .Naked) { |
| 352 | // TODO Finish function prologue and epilogue for riscv64. | 354 | // TODO Finish function prologue and epilogue for riscv64. |
| 353 | 355 | ||
| ... | @@ -470,13 +472,14 @@ fn gen(self: *Self) !void { | ... | @@ -470,13 +472,14 @@ fn gen(self: *Self) !void { |
| 470 | } | 472 | } |
| 471 | 473 | ||
| 472 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | 474 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 475 | const mod = self.bin_file.options.module.?; | ||
| 476 | const ip = &mod.intern_pool; | ||
| 473 | const air_tags = self.air.instructions.items(.tag); | 477 | const air_tags = self.air.instructions.items(.tag); |
| 474 | 478 | ||
| 475 | for (body) |inst| { | 479 | for (body) |inst| { |
| 476 | // TODO: remove now-redundant isUnused calls from AIR handler functions | 480 | // TODO: remove now-redundant isUnused calls from AIR handler functions |
| 477 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) { | 481 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) |
| 478 | continue; | 482 | continue; |
| 479 | } | ||
| 480 | 483 | ||
| 481 | const old_air_bookkeeping = self.air_bookkeeping; | 484 | const old_air_bookkeeping = self.air_bookkeeping; |
| 482 | try self.ensureProcessDeathCapacity(Liveness.bpi); | 485 | try self.ensureProcessDeathCapacity(Liveness.bpi); |
| ... | @@ -656,8 +659,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -656,8 +659,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 656 | .ptr_elem_val => try self.airPtrElemVal(inst), | 659 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 657 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), | 660 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 658 | 661 | ||
| 659 | .constant => unreachable, // excluded from function bodies | 662 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, |
| 660 | .const_ty => unreachable, // excluded from function bodies | ||
| 661 | .unreach => self.finishAirBookkeeping(), | 663 | .unreach => self.finishAirBookkeeping(), |
| 662 | 664 | ||
| 663 | .optional_payload => try self.airOptionalPayload(inst), | 665 | .optional_payload => try self.airOptionalPayload(inst), |
| ... | @@ -727,8 +729,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -727,8 +729,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 727 | 729 | ||
| 728 | /// Asserts there is already capacity to insert into top branch inst_table. | 730 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 729 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { | 731 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 730 | const air_tags = self.air.instructions.items(.tag); | 732 | assert(self.air.instructions.items(.tag)[inst] != .interned); |
| 731 | if (air_tags[inst] == .constant) return; // Constants are immortal. | ||
| 732 | // When editing this function, note that the logic must synchronize with `reuseOperand`. | 733 | // When editing this function, note that the logic must synchronize with `reuseOperand`. |
| 733 | const prev_value = self.getResolvedInstValue(inst); | 734 | const prev_value = self.getResolvedInstValue(inst); |
| 734 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 735 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | @@ -755,8 +756,8 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -755,8 +756,8 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 755 | tomb_bits >>= 1; | 756 | tomb_bits >>= 1; |
| 756 | if (!dies) continue; | 757 | if (!dies) continue; |
| 757 | const op_int = @enumToInt(op); | 758 | const op_int = @enumToInt(op); |
| 758 | if (op_int < Air.Inst.Ref.typed_value_map.len) continue; | 759 | if (op_int < Air.ref_start_index) continue; |
| 759 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | 760 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); |
| 760 | self.processDeath(op_index); | 761 | self.processDeath(op_index); |
| 761 | } | 762 | } |
| 762 | const is_used = @truncate(u1, tomb_bits) == 0; | 763 | const is_used = @truncate(u1, tomb_bits) == 0; |
| ... | @@ -804,23 +805,23 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u | ... | @@ -804,23 +805,23 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u |
| 804 | 805 | ||
| 805 | /// Use a pointer instruction as the basis for allocating stack memory. | 806 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 806 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | 807 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 807 | const elem_ty = self.air.typeOfIndex(inst).elemType(); | 808 | const mod = self.bin_file.options.module.?; |
| 808 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | 809 | const elem_ty = self.typeOfIndex(inst).childType(mod); |
| 809 | const mod = self.bin_file.options.module.?; | 810 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { |
| 810 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 811 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 811 | }; | 812 | }; |
| 812 | // TODO swap this for inst.ty.ptrAlign | 813 | // TODO swap this for inst.ty.ptrAlign |
| 813 | const abi_align = elem_ty.abiAlignment(self.target.*); | 814 | const abi_align = elem_ty.abiAlignment(mod); |
| 814 | return self.allocMem(inst, abi_size, abi_align); | 815 | return self.allocMem(inst, abi_size, abi_align); |
| 815 | } | 816 | } |
| 816 | 817 | ||
| 817 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | 818 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 818 | const elem_ty = self.air.typeOfIndex(inst); | 819 | const mod = self.bin_file.options.module.?; |
| 819 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | 820 | const elem_ty = self.typeOfIndex(inst); |
| 820 | const mod = self.bin_file.options.module.?; | 821 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { |
| 821 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 822 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 822 | }; | 823 | }; |
| 823 | const abi_align = elem_ty.abiAlignment(self.target.*); | 824 | const abi_align = elem_ty.abiAlignment(mod); |
| 824 | if (abi_align > self.stack_align) | 825 | if (abi_align > self.stack_align) |
| 825 | self.stack_align = abi_align; | 826 | self.stack_align = abi_align; |
| 826 | 827 | ||
| ... | @@ -845,7 +846,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -845,7 +846,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 845 | assert(reg == reg_mcv.register); | 846 | assert(reg == reg_mcv.register); |
| 846 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 847 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 847 | try branch.inst_table.put(self.gpa, inst, stack_mcv); | 848 | try branch.inst_table.put(self.gpa, inst, stack_mcv); |
| 848 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); | 849 | try self.genSetStack(self.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); |
| 849 | } | 850 | } |
| 850 | 851 | ||
| 851 | /// Copies a value to a register without tracking the register. The register is not considered | 852 | /// Copies a value to a register without tracking the register. The register is not considered |
| ... | @@ -862,7 +863,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | ... | @@ -862,7 +863,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 862 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 863 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 863 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 864 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { |
| 864 | const reg = try self.register_manager.allocReg(reg_owner, gp); | 865 | const reg = try self.register_manager.allocReg(reg_owner, gp); |
| 865 | try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv); | 866 | try self.genSetReg(self.typeOfIndex(reg_owner), reg, mcv); |
| 866 | return MCValue{ .register = reg }; | 867 | return MCValue{ .register = reg }; |
| 867 | } | 868 | } |
| 868 | 869 | ||
| ... | @@ -893,10 +894,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -893,10 +894,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 893 | if (self.liveness.isUnused(inst)) | 894 | if (self.liveness.isUnused(inst)) |
| 894 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | 895 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 895 | 896 | ||
| 896 | const operand_ty = self.air.typeOf(ty_op.operand); | 897 | const mod = self.bin_file.options.module.?; |
| 898 | const operand_ty = self.typeOf(ty_op.operand); | ||
| 897 | const operand = try self.resolveInst(ty_op.operand); | 899 | const operand = try self.resolveInst(ty_op.operand); |
| 898 | const info_a = operand_ty.intInfo(self.target.*); | 900 | const info_a = operand_ty.intInfo(mod); |
| 899 | const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*); | 901 | const info_b = self.typeOfIndex(inst).intInfo(mod); |
| 900 | if (info_a.signedness != info_b.signedness) | 902 | if (info_a.signedness != info_b.signedness) |
| 901 | return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); | 903 | return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); |
| 902 | 904 | ||
| ... | @@ -1068,18 +1070,18 @@ fn binOp( | ... | @@ -1068,18 +1070,18 @@ fn binOp( |
| 1068 | lhs_ty: Type, | 1070 | lhs_ty: Type, |
| 1069 | rhs_ty: Type, | 1071 | rhs_ty: Type, |
| 1070 | ) InnerError!MCValue { | 1072 | ) InnerError!MCValue { |
| 1073 | const mod = self.bin_file.options.module.?; | ||
| 1071 | switch (tag) { | 1074 | switch (tag) { |
| 1072 | // Arithmetic operations on integers and floats | 1075 | // Arithmetic operations on integers and floats |
| 1073 | .add, | 1076 | .add, |
| 1074 | .sub, | 1077 | .sub, |
| 1075 | => { | 1078 | => { |
| 1076 | switch (lhs_ty.zigTypeTag()) { | 1079 | switch (lhs_ty.zigTypeTag(mod)) { |
| 1077 | .Float => return self.fail("TODO binary operations on floats", .{}), | 1080 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| 1078 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 1081 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 1079 | .Int => { | 1082 | .Int => { |
| 1080 | const mod = self.bin_file.options.module.?; | ||
| 1081 | assert(lhs_ty.eql(rhs_ty, mod)); | 1083 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 1082 | const int_info = lhs_ty.intInfo(self.target.*); | 1084 | const int_info = lhs_ty.intInfo(mod); |
| 1083 | if (int_info.bits <= 64) { | 1085 | if (int_info.bits <= 64) { |
| 1084 | // TODO immediate operands | 1086 | // TODO immediate operands |
| 1085 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); | 1087 | return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty); |
| ... | @@ -1093,14 +1095,14 @@ fn binOp( | ... | @@ -1093,14 +1095,14 @@ fn binOp( |
| 1093 | .ptr_add, | 1095 | .ptr_add, |
| 1094 | .ptr_sub, | 1096 | .ptr_sub, |
| 1095 | => { | 1097 | => { |
| 1096 | switch (lhs_ty.zigTypeTag()) { | 1098 | switch (lhs_ty.zigTypeTag(mod)) { |
| 1097 | .Pointer => { | 1099 | .Pointer => { |
| 1098 | const ptr_ty = lhs_ty; | 1100 | const ptr_ty = lhs_ty; |
| 1099 | const elem_ty = switch (ptr_ty.ptrSize()) { | 1101 | const elem_ty = switch (ptr_ty.ptrSize(mod)) { |
| 1100 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type | 1102 | .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type |
| 1101 | else => ptr_ty.childType(), | 1103 | else => ptr_ty.childType(mod), |
| 1102 | }; | 1104 | }; |
| 1103 | const elem_size = elem_ty.abiSize(self.target.*); | 1105 | const elem_size = elem_ty.abiSize(mod); |
| 1104 | 1106 | ||
| 1105 | if (elem_size == 1) { | 1107 | if (elem_size == 1) { |
| 1106 | const base_tag: Air.Inst.Tag = switch (tag) { | 1108 | const base_tag: Air.Inst.Tag = switch (tag) { |
| ... | @@ -1125,8 +1127,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | ... | @@ -1125,8 +1127,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1125 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1127 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1126 | const lhs = try self.resolveInst(bin_op.lhs); | 1128 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1127 | const rhs = try self.resolveInst(bin_op.rhs); | 1129 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1128 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1130 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1129 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1131 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1130 | 1132 | ||
| 1131 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); | 1133 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1132 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1134 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | @@ -1137,8 +1139,8 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void | ... | @@ -1137,8 +1139,8 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void |
| 1137 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1139 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1138 | const lhs = try self.resolveInst(bin_op.lhs); | 1140 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1139 | const rhs = try self.resolveInst(bin_op.rhs); | 1141 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1140 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1142 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1141 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1143 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1142 | 1144 | ||
| 1143 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); | 1145 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); |
| 1144 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 1146 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | @@ -1331,10 +1333,11 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1331,10 +1333,11 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { |
| 1331 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | 1333 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1332 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1334 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1333 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1335 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1334 | const optional_ty = self.air.typeOfIndex(inst); | 1336 | const mod = self.bin_file.options.module.?; |
| 1337 | const optional_ty = self.typeOfIndex(inst); | ||
| 1335 | 1338 | ||
| 1336 | // Optional with a zero-bit payload type is just a boolean true | 1339 | // Optional with a zero-bit payload type is just a boolean true |
| 1337 | if (optional_ty.abiSize(self.target.*) == 1) | 1340 | if (optional_ty.abiSize(mod) == 1) |
| 1338 | break :result MCValue{ .immediate = 1 }; | 1341 | break :result MCValue{ .immediate = 1 }; |
| 1339 | 1342 | ||
| 1340 | return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch}); | 1343 | return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch}); |
| ... | @@ -1498,7 +1501,8 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind | ... | @@ -1498,7 +1501,8 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind |
| 1498 | } | 1501 | } |
| 1499 | 1502 | ||
| 1500 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { | 1503 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 1501 | const elem_ty = ptr_ty.elemType(); | 1504 | const mod = self.bin_file.options.module.?; |
| 1505 | const elem_ty = ptr_ty.childType(mod); | ||
| 1502 | switch (ptr) { | 1506 | switch (ptr) { |
| 1503 | .none => unreachable, | 1507 | .none => unreachable, |
| 1504 | .undef => unreachable, | 1508 | .undef => unreachable, |
| ... | @@ -1523,14 +1527,15 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo | ... | @@ -1523,14 +1527,15 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo |
| 1523 | } | 1527 | } |
| 1524 | 1528 | ||
| 1525 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | 1529 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1530 | const mod = self.bin_file.options.module.?; | ||
| 1526 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1531 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1527 | const elem_ty = self.air.typeOfIndex(inst); | 1532 | const elem_ty = self.typeOfIndex(inst); |
| 1528 | const result: MCValue = result: { | 1533 | const result: MCValue = result: { |
| 1529 | if (!elem_ty.hasRuntimeBits()) | 1534 | if (!elem_ty.hasRuntimeBits(mod)) |
| 1530 | break :result MCValue.none; | 1535 | break :result MCValue.none; |
| 1531 | 1536 | ||
| 1532 | const ptr = try self.resolveInst(ty_op.operand); | 1537 | const ptr = try self.resolveInst(ty_op.operand); |
| 1533 | const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr(); | 1538 | const is_volatile = self.typeOf(ty_op.operand).isVolatilePtr(mod); |
| 1534 | if (self.liveness.isUnused(inst) and !is_volatile) | 1539 | if (self.liveness.isUnused(inst) and !is_volatile) |
| 1535 | break :result MCValue.dead; | 1540 | break :result MCValue.dead; |
| 1536 | 1541 | ||
| ... | @@ -1542,7 +1547,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1542,7 +1547,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1542 | break :blk try self.allocRegOrMem(inst, true); | 1547 | break :blk try self.allocRegOrMem(inst, true); |
| 1543 | } | 1548 | } |
| 1544 | }; | 1549 | }; |
| 1545 | try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand)); | 1550 | try self.load(dst_mcv, ptr, self.typeOf(ty_op.operand)); |
| 1546 | break :result dst_mcv; | 1551 | break :result dst_mcv; |
| 1547 | }; | 1552 | }; |
| 1548 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1553 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -1583,8 +1588,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -1583,8 +1588,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 1583 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1588 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1584 | const ptr = try self.resolveInst(bin_op.lhs); | 1589 | const ptr = try self.resolveInst(bin_op.lhs); |
| 1585 | const value = try self.resolveInst(bin_op.rhs); | 1590 | const value = try self.resolveInst(bin_op.rhs); |
| 1586 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 1591 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 1587 | const value_ty = self.air.typeOf(bin_op.rhs); | 1592 | const value_ty = self.typeOf(bin_op.rhs); |
| 1588 | 1593 | ||
| 1589 | try self.store(ptr, value, ptr_ty, value_ty); | 1594 | try self.store(ptr, value, ptr_ty, value_ty); |
| 1590 | 1595 | ||
| ... | @@ -1644,7 +1649,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1644,7 +1649,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 1644 | const arg_index = self.arg_index; | 1649 | const arg_index = self.arg_index; |
| 1645 | self.arg_index += 1; | 1650 | self.arg_index += 1; |
| 1646 | 1651 | ||
| 1647 | const ty = self.air.typeOfIndex(inst); | 1652 | const ty = self.typeOfIndex(inst); |
| 1648 | _ = ty; | 1653 | _ = ty; |
| 1649 | 1654 | ||
| 1650 | const result = self.args[arg_index]; | 1655 | const result = self.args[arg_index]; |
| ... | @@ -1698,9 +1703,10 @@ fn airFence(self: *Self) !void { | ... | @@ -1698,9 +1703,10 @@ fn airFence(self: *Self) !void { |
| 1698 | } | 1703 | } |
| 1699 | 1704 | ||
| 1700 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { | 1705 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 1706 | const mod = self.bin_file.options.module.?; | ||
| 1701 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{}); | 1707 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for riscv64", .{}); |
| 1702 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 1708 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1703 | const fn_ty = self.air.typeOf(pl_op.operand); | 1709 | const fn_ty = self.typeOf(pl_op.operand); |
| 1704 | const callee = pl_op.operand; | 1710 | const callee = pl_op.operand; |
| 1705 | const extra = self.air.extraData(Air.Call, pl_op.payload); | 1711 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 1706 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); | 1712 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); |
| ... | @@ -1713,7 +1719,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1713,7 +1719,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1713 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | 1719 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 1714 | for (info.args, 0..) |mc_arg, arg_i| { | 1720 | for (info.args, 0..) |mc_arg, arg_i| { |
| 1715 | const arg = args[arg_i]; | 1721 | const arg = args[arg_i]; |
| 1716 | const arg_ty = self.air.typeOf(arg); | 1722 | const arg_ty = self.typeOf(arg); |
| 1717 | const arg_mcv = try self.resolveInst(args[arg_i]); | 1723 | const arg_mcv = try self.resolveInst(args[arg_i]); |
| 1718 | 1724 | ||
| 1719 | switch (mc_arg) { | 1725 | switch (mc_arg) { |
| ... | @@ -1736,14 +1742,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1736,14 +1742,13 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1736 | } | 1742 | } |
| 1737 | } | 1743 | } |
| 1738 | 1744 | ||
| 1739 | if (self.air.value(callee)) |func_value| { | 1745 | if (try self.air.value(callee, mod)) |func_value| { |
| 1740 | if (func_value.castTag(.function)) |func_payload| { | 1746 | if (mod.funcPtrUnwrap(mod.intern_pool.indexToFunc(func_value.ip_index))) |func| { |
| 1741 | const func = func_payload.data; | ||
| 1742 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); | 1747 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 1743 | const atom = elf_file.getAtom(atom_index); | 1748 | const atom = elf_file.getAtom(atom_index); |
| 1744 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); | 1749 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); |
| 1745 | const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file)); | 1750 | const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file)); |
| 1746 | try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr }); | 1751 | try self.genSetReg(Type.usize, .ra, .{ .memory = got_addr }); |
| 1747 | _ = try self.addInst(.{ | 1752 | _ = try self.addInst(.{ |
| 1748 | .tag = .jalr, | 1753 | .tag = .jalr, |
| 1749 | .data = .{ .i_type = .{ | 1754 | .data = .{ .i_type = .{ |
| ... | @@ -1752,7 +1757,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1752,7 +1757,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1752 | .imm12 = 0, | 1757 | .imm12 = 0, |
| 1753 | } }, | 1758 | } }, |
| 1754 | }); | 1759 | }); |
| 1755 | } else if (func_value.castTag(.extern_fn)) |_| { | 1760 | } else if (mod.intern_pool.indexToKey(func_value.ip_index) == .extern_func) { |
| 1756 | return self.fail("TODO implement calling extern functions", .{}); | 1761 | return self.fail("TODO implement calling extern functions", .{}); |
| 1757 | } else { | 1762 | } else { |
| 1758 | return self.fail("TODO implement calling bitcasted functions", .{}); | 1763 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| ... | @@ -1796,7 +1801,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1796,7 +1801,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1796 | } | 1801 | } |
| 1797 | 1802 | ||
| 1798 | fn ret(self: *Self, mcv: MCValue) !void { | 1803 | fn ret(self: *Self, mcv: MCValue) !void { |
| 1799 | const ret_ty = self.fn_type.fnReturnType(); | 1804 | const mod = self.bin_file.options.module.?; |
| 1805 | const ret_ty = self.fn_type.fnReturnType(mod); | ||
| 1800 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); | 1806 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| 1801 | // Just add space for an instruction, patch this later | 1807 | // Just add space for an instruction, patch this later |
| 1802 | const index = try self.addInst(.{ | 1808 | const index = try self.addInst(.{ |
| ... | @@ -1825,10 +1831,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -1825,10 +1831,10 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1825 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1831 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1826 | if (self.liveness.isUnused(inst)) | 1832 | if (self.liveness.isUnused(inst)) |
| 1827 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); | 1833 | return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1828 | const ty = self.air.typeOf(bin_op.lhs); | 1834 | const ty = self.typeOf(bin_op.lhs); |
| 1829 | const mod = self.bin_file.options.module.?; | 1835 | const mod = self.bin_file.options.module.?; |
| 1830 | assert(ty.eql(self.air.typeOf(bin_op.rhs), mod)); | 1836 | assert(ty.eql(self.typeOf(bin_op.rhs), mod)); |
| 1831 | if (ty.zigTypeTag() == .ErrorSet) | 1837 | if (ty.zigTypeTag(mod) == .ErrorSet) |
| 1832 | return self.fail("TODO implement cmp for errors", .{}); | 1838 | return self.fail("TODO implement cmp for errors", .{}); |
| 1833 | 1839 | ||
| 1834 | const lhs = try self.resolveInst(bin_op.lhs); | 1840 | const lhs = try self.resolveInst(bin_op.lhs); |
| ... | @@ -1869,8 +1875,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1869,8 +1875,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 1869 | } | 1875 | } |
| 1870 | 1876 | ||
| 1871 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { | 1877 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 1872 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1878 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; |
| 1873 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | 1879 | const mod = self.bin_file.options.module.?; |
| 1880 | const function = mod.funcPtr(ty_fn.func); | ||
| 1874 | // TODO emit debug info for function change | 1881 | // TODO emit debug info for function change |
| 1875 | _ = function; | 1882 | _ = function; |
| 1876 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); | 1883 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| ... | @@ -1946,7 +1953,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1946,7 +1953,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1946 | break :blk try self.allocRegOrMem(inst, true); | 1953 | break :blk try self.allocRegOrMem(inst, true); |
| 1947 | } | 1954 | } |
| 1948 | }; | 1955 | }; |
| 1949 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); | 1956 | try self.load(operand, operand_ptr, self.typeOf(un_op)); |
| 1950 | break :result try self.isNull(operand); | 1957 | break :result try self.isNull(operand); |
| 1951 | }; | 1958 | }; |
| 1952 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 1959 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | @@ -1973,7 +1980,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1973,7 +1980,7 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1973 | break :blk try self.allocRegOrMem(inst, true); | 1980 | break :blk try self.allocRegOrMem(inst, true); |
| 1974 | } | 1981 | } |
| 1975 | }; | 1982 | }; |
| 1976 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); | 1983 | try self.load(operand, operand_ptr, self.typeOf(un_op)); |
| 1977 | break :result try self.isNonNull(operand); | 1984 | break :result try self.isNonNull(operand); |
| 1978 | }; | 1985 | }; |
| 1979 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 1986 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | @@ -2000,7 +2007,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2000,7 +2007,7 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2000 | break :blk try self.allocRegOrMem(inst, true); | 2007 | break :blk try self.allocRegOrMem(inst, true); |
| 2001 | } | 2008 | } |
| 2002 | }; | 2009 | }; |
| 2003 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); | 2010 | try self.load(operand, operand_ptr, self.typeOf(un_op)); |
| 2004 | break :result try self.isErr(operand); | 2011 | break :result try self.isErr(operand); |
| 2005 | }; | 2012 | }; |
| 2006 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2013 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | @@ -2027,7 +2034,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2027,7 +2034,7 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2027 | break :blk try self.allocRegOrMem(inst, true); | 2034 | break :blk try self.allocRegOrMem(inst, true); |
| 2028 | } | 2035 | } |
| 2029 | }; | 2036 | }; |
| 2030 | try self.load(operand, operand_ptr, self.air.typeOf(un_op)); | 2037 | try self.load(operand, operand_ptr, self.typeOf(un_op)); |
| 2031 | break :result try self.isNonErr(operand); | 2038 | break :result try self.isNonErr(operand); |
| 2032 | }; | 2039 | }; |
| 2033 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 2040 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | @@ -2107,13 +2114,14 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2107,13 +2114,14 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2107 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | 2114 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 2108 | const block_data = self.blocks.getPtr(block).?; | 2115 | const block_data = self.blocks.getPtr(block).?; |
| 2109 | 2116 | ||
| 2110 | if (self.air.typeOf(operand).hasRuntimeBits()) { | 2117 | const mod = self.bin_file.options.module.?; |
| 2118 | if (self.typeOf(operand).hasRuntimeBits(mod)) { | ||
| 2111 | const operand_mcv = try self.resolveInst(operand); | 2119 | const operand_mcv = try self.resolveInst(operand); |
| 2112 | const block_mcv = block_data.mcv; | 2120 | const block_mcv = block_data.mcv; |
| 2113 | if (block_mcv == .none) { | 2121 | if (block_mcv == .none) { |
| 2114 | block_data.mcv = operand_mcv; | 2122 | block_data.mcv = operand_mcv; |
| 2115 | } else { | 2123 | } else { |
| 2116 | try self.setRegOrMem(self.air.typeOfIndex(block), block_mcv, operand_mcv); | 2124 | try self.setRegOrMem(self.typeOfIndex(block), block_mcv, operand_mcv); |
| 2117 | } | 2125 | } |
| 2118 | } | 2126 | } |
| 2119 | return self.brVoid(block); | 2127 | return self.brVoid(block); |
| ... | @@ -2176,7 +2184,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2176,7 +2184,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 2176 | 2184 | ||
| 2177 | const arg_mcv = try self.resolveInst(input); | 2185 | const arg_mcv = try self.resolveInst(input); |
| 2178 | try self.register_manager.getReg(reg, null); | 2186 | try self.register_manager.getReg(reg, null); |
| 2179 | try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); | 2187 | try self.genSetReg(self.typeOf(input), reg, arg_mcv); |
| 2180 | } | 2188 | } |
| 2181 | 2189 | ||
| 2182 | { | 2190 | { |
| ... | @@ -2372,7 +2380,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2372,7 +2380,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2372 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | 2380 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 2373 | 2381 | ||
| 2374 | const dest = try self.allocRegOrMem(inst, true); | 2382 | const dest = try self.allocRegOrMem(inst, true); |
| 2375 | try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand); | 2383 | try self.setRegOrMem(self.typeOfIndex(inst), dest, operand); |
| 2376 | break :result dest; | 2384 | break :result dest; |
| 2377 | }; | 2385 | }; |
| 2378 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 2386 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -2489,8 +2497,9 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2489,8 +2497,9 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { |
| 2489 | } | 2497 | } |
| 2490 | 2498 | ||
| 2491 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | 2499 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 2492 | const vector_ty = self.air.typeOfIndex(inst); | 2500 | const mod = self.bin_file.options.module.?; |
| 2493 | const len = vector_ty.vectorLen(); | 2501 | const vector_ty = self.typeOfIndex(inst); |
| 2502 | const len = vector_ty.vectorLen(mod); | ||
| 2494 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2503 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2495 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); | 2504 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 2496 | const result: MCValue = res: { | 2505 | const result: MCValue = res: { |
| ... | @@ -2533,37 +2542,32 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2533,37 +2542,32 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 2533 | } | 2542 | } |
| 2534 | 2543 | ||
| 2535 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | 2544 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 2536 | // First section of indexes correspond to a set number of constant values. | 2545 | const mod = self.bin_file.options.module.?; |
| 2537 | const ref_int = @enumToInt(inst); | ||
| 2538 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | ||
| 2539 | const tv = Air.Inst.Ref.typed_value_map[ref_int]; | ||
| 2540 | if (!tv.ty.hasRuntimeBits()) { | ||
| 2541 | return MCValue{ .none = {} }; | ||
| 2542 | } | ||
| 2543 | return self.genTypedValue(tv); | ||
| 2544 | } | ||
| 2545 | 2546 | ||
| 2546 | // If the type has no codegen bits, no need to store it. | 2547 | // If the type has no codegen bits, no need to store it. |
| 2547 | const inst_ty = self.air.typeOf(inst); | 2548 | const inst_ty = self.typeOf(inst); |
| 2548 | if (!inst_ty.hasRuntimeBits()) | 2549 | if (!inst_ty.hasRuntimeBits(mod)) |
| 2549 | return MCValue{ .none = {} }; | 2550 | return MCValue{ .none = {} }; |
| 2550 | 2551 | ||
| 2551 | const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); | 2552 | const inst_index = Air.refToIndex(inst) orelse return self.genTypedValue(.{ |
| 2553 | .ty = inst_ty, | ||
| 2554 | .val = (try self.air.value(inst, mod)).?, | ||
| 2555 | }); | ||
| 2556 | |||
| 2552 | switch (self.air.instructions.items(.tag)[inst_index]) { | 2557 | switch (self.air.instructions.items(.tag)[inst_index]) { |
| 2553 | .constant => { | 2558 | .interned => { |
| 2554 | // Constants have static lifetimes, so they are always memoized in the outer most table. | 2559 | // Constants have static lifetimes, so they are always memoized in the outer most table. |
| 2555 | const branch = &self.branch_stack.items[0]; | 2560 | const branch = &self.branch_stack.items[0]; |
| 2556 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); | 2561 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); |
| 2557 | if (!gop.found_existing) { | 2562 | if (!gop.found_existing) { |
| 2558 | const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl; | 2563 | const interned = self.air.instructions.items(.data)[inst_index].interned; |
| 2559 | gop.value_ptr.* = try self.genTypedValue(.{ | 2564 | gop.value_ptr.* = try self.genTypedValue(.{ |
| 2560 | .ty = inst_ty, | 2565 | .ty = inst_ty, |
| 2561 | .val = self.air.values[ty_pl.payload], | 2566 | .val = interned.toValue(), |
| 2562 | }); | 2567 | }); |
| 2563 | } | 2568 | } |
| 2564 | return gop.value_ptr.*; | 2569 | return gop.value_ptr.*; |
| 2565 | }, | 2570 | }, |
| 2566 | .const_ty => unreachable, | ||
| 2567 | else => return self.getResolvedInstValue(inst_index), | 2571 | else => return self.getResolvedInstValue(inst_index), |
| 2568 | } | 2572 | } |
| 2569 | } | 2573 | } |
| ... | @@ -2616,12 +2620,11 @@ const CallMCValues = struct { | ... | @@ -2616,12 +2620,11 @@ const CallMCValues = struct { |
| 2616 | 2620 | ||
| 2617 | /// Caller must call `CallMCValues.deinit`. | 2621 | /// Caller must call `CallMCValues.deinit`. |
| 2618 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | 2622 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2619 | const cc = fn_ty.fnCallingConvention(); | 2623 | const mod = self.bin_file.options.module.?; |
| 2620 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | 2624 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 2621 | defer self.gpa.free(param_types); | 2625 | const cc = fn_info.cc; |
| 2622 | fn_ty.fnParamTypes(param_types); | ||
| 2623 | var result: CallMCValues = .{ | 2626 | var result: CallMCValues = .{ |
| 2624 | .args = try self.gpa.alloc(MCValue, param_types.len), | 2627 | .args = try self.gpa.alloc(MCValue, fn_info.param_types.len), |
| 2625 | // These undefined values must be populated before returning from this function. | 2628 | // These undefined values must be populated before returning from this function. |
| 2626 | .return_value = undefined, | 2629 | .return_value = undefined, |
| 2627 | .stack_byte_count = undefined, | 2630 | .stack_byte_count = undefined, |
| ... | @@ -2629,7 +2632,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -2629,7 +2632,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2629 | }; | 2632 | }; |
| 2630 | errdefer self.gpa.free(result.args); | 2633 | errdefer self.gpa.free(result.args); |
| 2631 | 2634 | ||
| 2632 | const ret_ty = fn_ty.fnReturnType(); | 2635 | const ret_ty = fn_ty.fnReturnType(mod); |
| 2633 | 2636 | ||
| 2634 | switch (cc) { | 2637 | switch (cc) { |
| 2635 | .Naked => { | 2638 | .Naked => { |
| ... | @@ -2649,8 +2652,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -2649,8 +2652,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2649 | var next_stack_offset: u32 = 0; | 2652 | var next_stack_offset: u32 = 0; |
| 2650 | const argument_registers = [_]Register{ .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7 }; | 2653 | const argument_registers = [_]Register{ .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7 }; |
| 2651 | 2654 | ||
| 2652 | for (param_types, 0..) |ty, i| { | 2655 | for (fn_info.param_types, 0..) |ty, i| { |
| 2653 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 2656 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); |
| 2654 | if (param_size <= 8) { | 2657 | if (param_size <= 8) { |
| 2655 | if (next_register < argument_registers.len) { | 2658 | if (next_register < argument_registers.len) { |
| 2656 | result.args[i] = .{ .register = argument_registers[next_register] }; | 2659 | result.args[i] = .{ .register = argument_registers[next_register] }; |
| ... | @@ -2680,14 +2683,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -2680,14 +2683,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 2680 | else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}), | 2683 | else => return self.fail("TODO implement function parameters for {} on riscv64", .{cc}), |
| 2681 | } | 2684 | } |
| 2682 | 2685 | ||
| 2683 | if (ret_ty.zigTypeTag() == .NoReturn) { | 2686 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 2684 | result.return_value = .{ .unreach = {} }; | 2687 | result.return_value = .{ .unreach = {} }; |
| 2685 | } else if (!ret_ty.hasRuntimeBits()) { | 2688 | } else if (!ret_ty.hasRuntimeBits(mod)) { |
| 2686 | result.return_value = .{ .none = {} }; | 2689 | result.return_value = .{ .none = {} }; |
| 2687 | } else switch (cc) { | 2690 | } else switch (cc) { |
| 2688 | .Naked => unreachable, | 2691 | .Naked => unreachable, |
| 2689 | .Unspecified, .C => { | 2692 | .Unspecified, .C => { |
| 2690 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 2693 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(mod)); |
| 2691 | if (ret_ty_size <= 8) { | 2694 | if (ret_ty_size <= 8) { |
| 2692 | result.return_value = .{ .register = .a0 }; | 2695 | result.return_value = .{ .register = .a0 }; |
| 2693 | } else if (ret_ty_size <= 16) { | 2696 | } else if (ret_ty_size <= 16) { |
| ... | @@ -2731,3 +2734,13 @@ fn parseRegName(name: []const u8) ?Register { | ... | @@ -2731,3 +2734,13 @@ fn parseRegName(name: []const u8) ?Register { |
| 2731 | } | 2734 | } |
| 2732 | return std.meta.stringToEnum(Register, name); | 2735 | return std.meta.stringToEnum(Register, name); |
| 2733 | } | 2736 | } |
| 2737 | |||
| 2738 | fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { | ||
| 2739 | const mod = self.bin_file.options.module.?; | ||
| 2740 | return self.air.typeOf(inst, &mod.intern_pool); | ||
| 2741 | } | ||
| 2742 | |||
| 2743 | fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { | ||
| 2744 | const mod = self.bin_file.options.module.?; | ||
| 2745 | return self.air.typeOfIndex(inst, &mod.intern_pool); | ||
| 2746 | } |
src/arch/riscv64/abi.zig+13-11| ... | @@ -3,17 +3,19 @@ const bits = @import("bits.zig"); | ... | @@ -3,17 +3,19 @@ const bits = @import("bits.zig"); |
| 3 | const Register = bits.Register; | 3 | const Register = bits.Register; |
| 4 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | 4 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 5 | const Type = @import("../../type.zig").Type; | 5 | const Type = @import("../../type.zig").Type; |
| 6 | const Module = @import("../../Module.zig"); | ||
| 6 | 7 | ||
| 7 | pub const Class = enum { memory, byval, integer, double_integer }; | 8 | pub const Class = enum { memory, byval, integer, double_integer }; |
| 8 | 9 | ||
| 9 | pub fn classifyType(ty: Type, target: std.Target) Class { | 10 | pub fn classifyType(ty: Type, mod: *Module) Class { |
| 10 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime()); | 11 | const target = mod.getTarget(); |
| 12 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(mod)); | ||
| 11 | 13 | ||
| 12 | const max_byval_size = target.ptrBitWidth() * 2; | 14 | const max_byval_size = target.ptrBitWidth() * 2; |
| 13 | switch (ty.zigTypeTag()) { | 15 | switch (ty.zigTypeTag(mod)) { |
| 14 | .Struct => { | 16 | .Struct => { |
| 15 | const bit_size = ty.bitSize(target); | 17 | const bit_size = ty.bitSize(mod); |
| 16 | if (ty.containerLayout() == .Packed) { | 18 | if (ty.containerLayout(mod) == .Packed) { |
| 17 | if (bit_size > max_byval_size) return .memory; | 19 | if (bit_size > max_byval_size) return .memory; |
| 18 | return .byval; | 20 | return .byval; |
| 19 | } | 21 | } |
| ... | @@ -23,8 +25,8 @@ pub fn classifyType(ty: Type, target: std.Target) Class { | ... | @@ -23,8 +25,8 @@ pub fn classifyType(ty: Type, target: std.Target) Class { |
| 23 | return .integer; | 25 | return .integer; |
| 24 | }, | 26 | }, |
| 25 | .Union => { | 27 | .Union => { |
| 26 | const bit_size = ty.bitSize(target); | 28 | const bit_size = ty.bitSize(mod); |
| 27 | if (ty.containerLayout() == .Packed) { | 29 | if (ty.containerLayout(mod) == .Packed) { |
| 28 | if (bit_size > max_byval_size) return .memory; | 30 | if (bit_size > max_byval_size) return .memory; |
| 29 | return .byval; | 31 | return .byval; |
| 30 | } | 32 | } |
| ... | @@ -36,21 +38,21 @@ pub fn classifyType(ty: Type, target: std.Target) Class { | ... | @@ -36,21 +38,21 @@ pub fn classifyType(ty: Type, target: std.Target) Class { |
| 36 | .Bool => return .integer, | 38 | .Bool => return .integer, |
| 37 | .Float => return .byval, | 39 | .Float => return .byval, |
| 38 | .Int, .Enum, .ErrorSet => { | 40 | .Int, .Enum, .ErrorSet => { |
| 39 | const bit_size = ty.bitSize(target); | 41 | const bit_size = ty.bitSize(mod); |
| 40 | if (bit_size > max_byval_size) return .memory; | 42 | if (bit_size > max_byval_size) return .memory; |
| 41 | return .byval; | 43 | return .byval; |
| 42 | }, | 44 | }, |
| 43 | .Vector => { | 45 | .Vector => { |
| 44 | const bit_size = ty.bitSize(target); | 46 | const bit_size = ty.bitSize(mod); |
| 45 | if (bit_size > max_byval_size) return .memory; | 47 | if (bit_size > max_byval_size) return .memory; |
| 46 | return .integer; | 48 | return .integer; |
| 47 | }, | 49 | }, |
| 48 | .Optional => { | 50 | .Optional => { |
| 49 | std.debug.assert(ty.isPtrLikeOptional()); | 51 | std.debug.assert(ty.isPtrLikeOptional(mod)); |
| 50 | return .byval; | 52 | return .byval; |
| 51 | }, | 53 | }, |
| 52 | .Pointer => { | 54 | .Pointer => { |
| 53 | std.debug.assert(!ty.isSlice()); | 55 | std.debug.assert(!ty.isSlice(mod)); |
| 54 | return .byval; | 56 | return .byval; |
| 55 | }, | 57 | }, |
| 56 | .ErrorUnion, | 58 | .ErrorUnion, |
src/arch/sparc64/CodeGen.zig+244-222| ... | @@ -260,7 +260,7 @@ const BigTomb = struct { | ... | @@ -260,7 +260,7 @@ const BigTomb = struct { |
| 260 | pub fn generate( | 260 | pub fn generate( |
| 261 | bin_file: *link.File, | 261 | bin_file: *link.File, |
| 262 | src_loc: Module.SrcLoc, | 262 | src_loc: Module.SrcLoc, |
| 263 | module_fn: *Module.Fn, | 263 | module_fn_index: Module.Fn.Index, |
| 264 | air: Air, | 264 | air: Air, |
| 265 | liveness: Liveness, | 265 | liveness: Liveness, |
| 266 | code: *std.ArrayList(u8), | 266 | code: *std.ArrayList(u8), |
| ... | @@ -271,12 +271,11 @@ pub fn generate( | ... | @@ -271,12 +271,11 @@ pub fn generate( |
| 271 | } | 271 | } |
| 272 | 272 | ||
| 273 | const mod = bin_file.options.module.?; | 273 | const mod = bin_file.options.module.?; |
| 274 | const module_fn = mod.funcPtr(module_fn_index); | ||
| 274 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); | 275 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 275 | assert(fn_owner_decl.has_tv); | 276 | assert(fn_owner_decl.has_tv); |
| 276 | const fn_type = fn_owner_decl.ty; | 277 | const fn_type = fn_owner_decl.ty; |
| 277 | 278 | ||
| 278 | log.debug("fn {s}", .{fn_owner_decl.name}); | ||
| 279 | |||
| 280 | var branch_stack = std.ArrayList(Branch).init(bin_file.allocator); | 279 | var branch_stack = std.ArrayList(Branch).init(bin_file.allocator); |
| 281 | defer { | 280 | defer { |
| 282 | assert(branch_stack.items.len == 1); | 281 | assert(branch_stack.items.len == 1); |
| ... | @@ -363,7 +362,8 @@ pub fn generate( | ... | @@ -363,7 +362,8 @@ pub fn generate( |
| 363 | } | 362 | } |
| 364 | 363 | ||
| 365 | fn gen(self: *Self) !void { | 364 | fn gen(self: *Self) !void { |
| 366 | const cc = self.fn_type.fnCallingConvention(); | 365 | const mod = self.bin_file.options.module.?; |
| 366 | const cc = self.fn_type.fnCallingConvention(mod); | ||
| 367 | if (cc != .Naked) { | 367 | if (cc != .Naked) { |
| 368 | // TODO Finish function prologue and epilogue for sparc64. | 368 | // TODO Finish function prologue and epilogue for sparc64. |
| 369 | 369 | ||
| ... | @@ -490,13 +490,14 @@ fn gen(self: *Self) !void { | ... | @@ -490,13 +490,14 @@ fn gen(self: *Self) !void { |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | 492 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 493 | const mod = self.bin_file.options.module.?; | ||
| 494 | const ip = &mod.intern_pool; | ||
| 493 | const air_tags = self.air.instructions.items(.tag); | 495 | const air_tags = self.air.instructions.items(.tag); |
| 494 | 496 | ||
| 495 | for (body) |inst| { | 497 | for (body) |inst| { |
| 496 | // TODO: remove now-redundant isUnused calls from AIR handler functions | 498 | // TODO: remove now-redundant isUnused calls from AIR handler functions |
| 497 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) { | 499 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) |
| 498 | continue; | 500 | continue; |
| 499 | } | ||
| 500 | 501 | ||
| 501 | const old_air_bookkeeping = self.air_bookkeeping; | 502 | const old_air_bookkeeping = self.air_bookkeeping; |
| 502 | try self.ensureProcessDeathCapacity(Liveness.bpi); | 503 | try self.ensureProcessDeathCapacity(Liveness.bpi); |
| ... | @@ -676,8 +677,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -676,8 +677,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 676 | .ptr_elem_val => try self.airPtrElemVal(inst), | 677 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 677 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), | 678 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 678 | 679 | ||
| 679 | .constant => unreachable, // excluded from function bodies | 680 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, |
| 680 | .const_ty => unreachable, // excluded from function bodies | ||
| 681 | .unreach => self.finishAirBookkeeping(), | 681 | .unreach => self.finishAirBookkeeping(), |
| 682 | 682 | ||
| 683 | .optional_payload => try self.airOptionalPayload(inst), | 683 | .optional_payload => try self.airOptionalPayload(inst), |
| ... | @@ -758,18 +758,18 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -758,18 +758,18 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 758 | const tag = self.air.instructions.items(.tag)[inst]; | 758 | const tag = self.air.instructions.items(.tag)[inst]; |
| 759 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 759 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 760 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 760 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 761 | const mod = self.bin_file.options.module.?; | ||
| 761 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 762 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 762 | const lhs = try self.resolveInst(extra.lhs); | 763 | const lhs = try self.resolveInst(extra.lhs); |
| 763 | const rhs = try self.resolveInst(extra.rhs); | 764 | const rhs = try self.resolveInst(extra.rhs); |
| 764 | const lhs_ty = self.air.typeOf(extra.lhs); | 765 | const lhs_ty = self.typeOf(extra.lhs); |
| 765 | const rhs_ty = self.air.typeOf(extra.rhs); | 766 | const rhs_ty = self.typeOf(extra.rhs); |
| 766 | 767 | ||
| 767 | switch (lhs_ty.zigTypeTag()) { | 768 | switch (lhs_ty.zigTypeTag(mod)) { |
| 768 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), | 769 | .Vector => return self.fail("TODO implement add_with_overflow/sub_with_overflow for vectors", .{}), |
| 769 | .Int => { | 770 | .Int => { |
| 770 | const mod = self.bin_file.options.module.?; | ||
| 771 | assert(lhs_ty.eql(rhs_ty, mod)); | 771 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 772 | const int_info = lhs_ty.intInfo(self.target.*); | 772 | const int_info = lhs_ty.intInfo(mod); |
| 773 | switch (int_info.bits) { | 773 | switch (int_info.bits) { |
| 774 | 32, 64 => { | 774 | 32, 64 => { |
| 775 | // Only say yes if the operation is | 775 | // Only say yes if the operation is |
| ... | @@ -836,8 +836,9 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -836,8 +836,9 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 836 | } | 836 | } |
| 837 | 837 | ||
| 838 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | 838 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 839 | const vector_ty = self.air.typeOfIndex(inst); | 839 | const mod = self.bin_file.options.module.?; |
| 840 | const len = vector_ty.vectorLen(); | 840 | const vector_ty = self.typeOfIndex(inst); |
| 841 | const len = vector_ty.vectorLen(mod); | ||
| 841 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 842 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 842 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); | 843 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 843 | const result: MCValue = res: { | 844 | const result: MCValue = res: { |
| ... | @@ -869,19 +870,20 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -869,19 +870,20 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 869 | } | 870 | } |
| 870 | 871 | ||
| 871 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | 872 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 873 | const mod = self.bin_file.options.module.?; | ||
| 872 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 874 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 873 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 875 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 874 | const ptr_ty = self.air.typeOf(ty_op.operand); | 876 | const ptr_ty = self.typeOf(ty_op.operand); |
| 875 | const ptr = try self.resolveInst(ty_op.operand); | 877 | const ptr = try self.resolveInst(ty_op.operand); |
| 876 | const array_ty = ptr_ty.childType(); | 878 | const array_ty = ptr_ty.childType(mod); |
| 877 | const array_len = @intCast(u32, array_ty.arrayLen()); | 879 | const array_len = @intCast(u32, array_ty.arrayLen(mod)); |
| 878 | 880 | ||
| 879 | const ptr_bits = self.target.ptrBitWidth(); | 881 | const ptr_bits = self.target.ptrBitWidth(); |
| 880 | const ptr_bytes = @divExact(ptr_bits, 8); | 882 | const ptr_bytes = @divExact(ptr_bits, 8); |
| 881 | 883 | ||
| 882 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); | 884 | const stack_offset = try self.allocMem(inst, ptr_bytes * 2, ptr_bytes * 2); |
| 883 | try self.genSetStack(ptr_ty, stack_offset, ptr); | 885 | try self.genSetStack(ptr_ty, stack_offset, ptr); |
| 884 | try self.genSetStack(Type.initTag(.usize), stack_offset - ptr_bytes, .{ .immediate = array_len }); | 886 | try self.genSetStack(Type.usize, stack_offset - ptr_bytes, .{ .immediate = array_len }); |
| 885 | break :result MCValue{ .stack_offset = stack_offset }; | 887 | break :result MCValue{ .stack_offset = stack_offset }; |
| 886 | }; | 888 | }; |
| 887 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 889 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -935,7 +937,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -935,7 +937,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 935 | 937 | ||
| 936 | const arg_mcv = try self.resolveInst(input); | 938 | const arg_mcv = try self.resolveInst(input); |
| 937 | try self.register_manager.getReg(reg, null); | 939 | try self.register_manager.getReg(reg, null); |
| 938 | try self.genSetReg(self.air.typeOf(input), reg, arg_mcv); | 940 | try self.genSetReg(self.typeOf(input), reg, arg_mcv); |
| 939 | } | 941 | } |
| 940 | 942 | ||
| 941 | { | 943 | { |
| ... | @@ -1008,17 +1010,17 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1008,17 +1010,17 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 1008 | } | 1010 | } |
| 1009 | 1011 | ||
| 1010 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { | 1012 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 1013 | const mod = self.bin_file.options.module.?; | ||
| 1011 | const arg_index = self.arg_index; | 1014 | const arg_index = self.arg_index; |
| 1012 | self.arg_index += 1; | 1015 | self.arg_index += 1; |
| 1013 | 1016 | ||
| 1014 | const ty = self.air.typeOfIndex(inst); | 1017 | const ty = self.typeOfIndex(inst); |
| 1015 | 1018 | ||
| 1016 | const arg = self.args[arg_index]; | 1019 | const arg = self.args[arg_index]; |
| 1017 | const mcv = blk: { | 1020 | const mcv = blk: { |
| 1018 | switch (arg) { | 1021 | switch (arg) { |
| 1019 | .stack_offset => |off| { | 1022 | .stack_offset => |off| { |
| 1020 | const mod = self.bin_file.options.module.?; | 1023 | const abi_size = math.cast(u32, ty.abiSize(mod)) orelse { |
| 1021 | const abi_size = math.cast(u32, ty.abiSize(self.target.*)) orelse { | ||
| 1022 | return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)}); | 1024 | return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)}); |
| 1023 | }; | 1025 | }; |
| 1024 | const offset = off + abi_size; | 1026 | const offset = off + abi_size; |
| ... | @@ -1063,8 +1065,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | ... | @@ -1063,8 +1065,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1063 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1065 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1064 | const lhs = try self.resolveInst(bin_op.lhs); | 1066 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1065 | const rhs = try self.resolveInst(bin_op.rhs); | 1067 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1066 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1068 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1067 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1069 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1068 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1070 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1069 | .dead | 1071 | .dead |
| 1070 | else | 1072 | else |
| ... | @@ -1088,8 +1090,8 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void | ... | @@ -1088,8 +1090,8 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void |
| 1088 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 1090 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 1089 | const lhs = try self.resolveInst(bin_op.lhs); | 1091 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1090 | const rhs = try self.resolveInst(bin_op.rhs); | 1092 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1091 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1093 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1092 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1094 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1093 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1095 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1094 | .dead | 1096 | .dead |
| 1095 | else | 1097 | else |
| ... | @@ -1115,7 +1117,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1115,7 +1117,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1115 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | 1117 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 1116 | 1118 | ||
| 1117 | const dest = try self.allocRegOrMem(inst, true); | 1119 | const dest = try self.allocRegOrMem(inst, true); |
| 1118 | try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand); | 1120 | try self.setRegOrMem(self.typeOfIndex(inst), dest, operand); |
| 1119 | break :result dest; | 1121 | break :result dest; |
| 1120 | }; | 1122 | }; |
| 1121 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1123 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -1203,6 +1205,7 @@ fn airBreakpoint(self: *Self) !void { | ... | @@ -1203,6 +1205,7 @@ fn airBreakpoint(self: *Self) !void { |
| 1203 | } | 1205 | } |
| 1204 | 1206 | ||
| 1205 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { | 1207 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 1208 | const mod = self.bin_file.options.module.?; | ||
| 1206 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1209 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1207 | 1210 | ||
| 1208 | // We have hardware byteswapper in SPARCv9, don't let mainstream compilers mislead you. | 1211 | // We have hardware byteswapper in SPARCv9, don't let mainstream compilers mislead you. |
| ... | @@ -1217,15 +1220,15 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1217,15 +1220,15 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 1217 | // TODO: Fold byteswap+store into a single ST*A and load+byteswap into a single LD*A. | 1220 | // TODO: Fold byteswap+store into a single ST*A and load+byteswap into a single LD*A. |
| 1218 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1221 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1219 | const operand = try self.resolveInst(ty_op.operand); | 1222 | const operand = try self.resolveInst(ty_op.operand); |
| 1220 | const operand_ty = self.air.typeOf(ty_op.operand); | 1223 | const operand_ty = self.typeOf(ty_op.operand); |
| 1221 | switch (operand_ty.zigTypeTag()) { | 1224 | switch (operand_ty.zigTypeTag(mod)) { |
| 1222 | .Vector => return self.fail("TODO byteswap for vectors", .{}), | 1225 | .Vector => return self.fail("TODO byteswap for vectors", .{}), |
| 1223 | .Int => { | 1226 | .Int => { |
| 1224 | const int_info = operand_ty.intInfo(self.target.*); | 1227 | const int_info = operand_ty.intInfo(mod); |
| 1225 | if (int_info.bits == 8) break :result operand; | 1228 | if (int_info.bits == 8) break :result operand; |
| 1226 | 1229 | ||
| 1227 | const abi_size = int_info.bits >> 3; | 1230 | const abi_size = int_info.bits >> 3; |
| 1228 | const abi_align = operand_ty.abiAlignment(self.target.*); | 1231 | const abi_align = operand_ty.abiAlignment(mod); |
| 1229 | const opposite_endian_asi = switch (self.target.cpu.arch.endian()) { | 1232 | const opposite_endian_asi = switch (self.target.cpu.arch.endian()) { |
| 1230 | Endian.Big => ASI.asi_primary_little, | 1233 | Endian.Big => ASI.asi_primary_little, |
| 1231 | Endian.Little => ASI.asi_primary, | 1234 | Endian.Little => ASI.asi_primary, |
| ... | @@ -1293,10 +1296,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1293,10 +1296,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1293 | const callee = pl_op.operand; | 1296 | const callee = pl_op.operand; |
| 1294 | const extra = self.air.extraData(Air.Call, pl_op.payload); | 1297 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 1295 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end .. extra.end + extra.data.args_len]); | 1298 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end .. extra.end + extra.data.args_len]); |
| 1296 | const ty = self.air.typeOf(callee); | 1299 | const ty = self.typeOf(callee); |
| 1297 | const fn_ty = switch (ty.zigTypeTag()) { | 1300 | const mod = self.bin_file.options.module.?; |
| 1301 | const fn_ty = switch (ty.zigTypeTag(mod)) { | ||
| 1298 | .Fn => ty, | 1302 | .Fn => ty, |
| 1299 | .Pointer => ty.childType(), | 1303 | .Pointer => ty.childType(mod), |
| 1300 | else => unreachable, | 1304 | else => unreachable, |
| 1301 | }; | 1305 | }; |
| 1302 | 1306 | ||
| ... | @@ -1316,7 +1320,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1316,7 +1320,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1316 | 1320 | ||
| 1317 | for (info.args, 0..) |mc_arg, arg_i| { | 1321 | for (info.args, 0..) |mc_arg, arg_i| { |
| 1318 | const arg = args[arg_i]; | 1322 | const arg = args[arg_i]; |
| 1319 | const arg_ty = self.air.typeOf(arg); | 1323 | const arg_ty = self.typeOf(arg); |
| 1320 | const arg_mcv = try self.resolveInst(arg); | 1324 | const arg_mcv = try self.resolveInst(arg); |
| 1321 | 1325 | ||
| 1322 | switch (mc_arg) { | 1326 | switch (mc_arg) { |
| ... | @@ -1337,10 +1341,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1337,10 +1341,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1337 | 1341 | ||
| 1338 | // Due to incremental compilation, how function calls are generated depends | 1342 | // Due to incremental compilation, how function calls are generated depends |
| 1339 | // on linking. | 1343 | // on linking. |
| 1340 | if (self.air.value(callee)) |func_value| { | 1344 | if (try self.air.value(callee, mod)) |func_value| { |
| 1341 | if (self.bin_file.tag == link.File.Elf.base_tag) { | 1345 | if (self.bin_file.tag == link.File.Elf.base_tag) { |
| 1342 | if (func_value.castTag(.function)) |func_payload| { | 1346 | if (mod.funcPtrUnwrap(mod.intern_pool.indexToFunc(func_value.ip_index))) |func| { |
| 1343 | const func = func_payload.data; | ||
| 1344 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { | 1347 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { |
| 1345 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); | 1348 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 1346 | const atom = elf_file.getAtom(atom_index); | 1349 | const atom = elf_file.getAtom(atom_index); |
| ... | @@ -1348,7 +1351,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1348,7 +1351,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1348 | break :blk @intCast(u32, atom.getOffsetTableAddress(elf_file)); | 1351 | break :blk @intCast(u32, atom.getOffsetTableAddress(elf_file)); |
| 1349 | } else unreachable; | 1352 | } else unreachable; |
| 1350 | 1353 | ||
| 1351 | try self.genSetReg(Type.initTag(.usize), .o7, .{ .memory = got_addr }); | 1354 | try self.genSetReg(Type.usize, .o7, .{ .memory = got_addr }); |
| 1352 | 1355 | ||
| 1353 | _ = try self.addInst(.{ | 1356 | _ = try self.addInst(.{ |
| 1354 | .tag = .jmpl, | 1357 | .tag = .jmpl, |
| ... | @@ -1367,14 +1370,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -1367,14 +1370,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1367 | .tag = .nop, | 1370 | .tag = .nop, |
| 1368 | .data = .{ .nop = {} }, | 1371 | .data = .{ .nop = {} }, |
| 1369 | }); | 1372 | }); |
| 1370 | } else if (func_value.castTag(.extern_fn)) |_| { | 1373 | } else if (mod.intern_pool.indexToKey(func_value.ip_index) == .extern_func) { |
| 1371 | return self.fail("TODO implement calling extern functions", .{}); | 1374 | return self.fail("TODO implement calling extern functions", .{}); |
| 1372 | } else { | 1375 | } else { |
| 1373 | return self.fail("TODO implement calling bitcasted functions", .{}); | 1376 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 1374 | } | 1377 | } |
| 1375 | } else @panic("TODO SPARCv9 currently does not support non-ELF binaries"); | 1378 | } else @panic("TODO SPARCv9 currently does not support non-ELF binaries"); |
| 1376 | } else { | 1379 | } else { |
| 1377 | assert(ty.zigTypeTag() == .Pointer); | 1380 | assert(ty.zigTypeTag(mod) == .Pointer); |
| 1378 | const mcv = try self.resolveInst(callee); | 1381 | const mcv = try self.resolveInst(callee); |
| 1379 | try self.genSetReg(ty, .o7, mcv); | 1382 | try self.genSetReg(ty, .o7, mcv); |
| 1380 | 1383 | ||
| ... | @@ -1422,25 +1425,24 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1422,25 +1425,24 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 1422 | 1425 | ||
| 1423 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 1426 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1424 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1427 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1428 | const mod = self.bin_file.options.module.?; | ||
| 1425 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1429 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1426 | const lhs = try self.resolveInst(bin_op.lhs); | 1430 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1427 | const rhs = try self.resolveInst(bin_op.rhs); | 1431 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1428 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1432 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1429 | 1433 | ||
| 1430 | var int_buffer: Type.Payload.Bits = undefined; | 1434 | const int_ty = switch (lhs_ty.zigTypeTag(mod)) { |
| 1431 | const int_ty = switch (lhs_ty.zigTypeTag()) { | ||
| 1432 | .Vector => unreachable, // Handled by cmp_vector. | 1435 | .Vector => unreachable, // Handled by cmp_vector. |
| 1433 | .Enum => lhs_ty.intTagType(&int_buffer), | 1436 | .Enum => lhs_ty.intTagType(mod), |
| 1434 | .Int => lhs_ty, | 1437 | .Int => lhs_ty, |
| 1435 | .Bool => Type.initTag(.u1), | 1438 | .Bool => Type.u1, |
| 1436 | .Pointer => Type.usize, | 1439 | .Pointer => Type.usize, |
| 1437 | .ErrorSet => Type.initTag(.u16), | 1440 | .ErrorSet => Type.u16, |
| 1438 | .Optional => blk: { | 1441 | .Optional => blk: { |
| 1439 | var opt_buffer: Type.Payload.ElemType = undefined; | 1442 | const payload_ty = lhs_ty.optionalChild(mod); |
| 1440 | const payload_ty = lhs_ty.optionalChild(&opt_buffer); | 1443 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1441 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 1444 | break :blk Type.u1; |
| 1442 | break :blk Type.initTag(.u1); | 1445 | } else if (lhs_ty.isPtrLikeOptional(mod)) { |
| 1443 | } else if (lhs_ty.isPtrLikeOptional()) { | ||
| 1444 | break :blk Type.usize; | 1446 | break :blk Type.usize; |
| 1445 | } else { | 1447 | } else { |
| 1446 | return self.fail("TODO SPARCv9 cmp non-pointer optionals", .{}); | 1448 | return self.fail("TODO SPARCv9 cmp non-pointer optionals", .{}); |
| ... | @@ -1450,7 +1452,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -1450,7 +1452,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 1450 | else => unreachable, | 1452 | else => unreachable, |
| 1451 | }; | 1453 | }; |
| 1452 | 1454 | ||
| 1453 | const int_info = int_ty.intInfo(self.target.*); | 1455 | const int_info = int_ty.intInfo(mod); |
| 1454 | if (int_info.bits <= 64) { | 1456 | if (int_info.bits <= 64) { |
| 1455 | _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{ | 1457 | _ = try self.binOp(.cmp_eq, lhs, rhs, int_ty, int_ty, BinOpMetadata{ |
| 1456 | .lhs = bin_op.lhs, | 1458 | .lhs = bin_op.lhs, |
| ... | @@ -1512,8 +1514,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1512,8 +1514,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1512 | // whether it needs to be spilled in the branches | 1514 | // whether it needs to be spilled in the branches |
| 1513 | if (self.liveness.operandDies(inst, 0)) { | 1515 | if (self.liveness.operandDies(inst, 0)) { |
| 1514 | const op_int = @enumToInt(pl_op.operand); | 1516 | const op_int = @enumToInt(pl_op.operand); |
| 1515 | if (op_int >= Air.Inst.Ref.typed_value_map.len) { | 1517 | if (op_int >= Air.ref_start_index) { |
| 1516 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | 1518 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); |
| 1517 | self.processDeath(op_index); | 1519 | self.processDeath(op_index); |
| 1518 | } | 1520 | } |
| 1519 | } | 1521 | } |
| ... | @@ -1603,7 +1605,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1603,7 +1605,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1603 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); | 1605 | log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv }); |
| 1604 | // TODO make sure the destination stack offset / register does not already have something | 1606 | // TODO make sure the destination stack offset / register does not already have something |
| 1605 | // going on there. | 1607 | // going on there. |
| 1606 | try self.setRegOrMem(self.air.typeOfIndex(else_key), canon_mcv, else_value); | 1608 | try self.setRegOrMem(self.typeOfIndex(else_key), canon_mcv, else_value); |
| 1607 | // TODO track the new register / stack allocation | 1609 | // TODO track the new register / stack allocation |
| 1608 | } | 1610 | } |
| 1609 | try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, saved_then_branch.inst_table.count()); | 1611 | try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, saved_then_branch.inst_table.count()); |
| ... | @@ -1630,7 +1632,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1630,7 +1632,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 1630 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); | 1632 | log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value }); |
| 1631 | // TODO make sure the destination stack offset / register does not already have something | 1633 | // TODO make sure the destination stack offset / register does not already have something |
| 1632 | // going on there. | 1634 | // going on there. |
| 1633 | try self.setRegOrMem(self.air.typeOfIndex(then_key), parent_mcv, then_value); | 1635 | try self.setRegOrMem(self.typeOfIndex(then_key), parent_mcv, then_value); |
| 1634 | // TODO track the new register / stack allocation | 1636 | // TODO track the new register / stack allocation |
| 1635 | } | 1637 | } |
| 1636 | 1638 | ||
| ... | @@ -1656,8 +1658,9 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1656,8 +1658,9 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 1656 | } | 1658 | } |
| 1657 | 1659 | ||
| 1658 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { | 1660 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 1659 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 1661 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; |
| 1660 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | 1662 | const mod = self.bin_file.options.module.?; |
| 1663 | const function = mod.funcPtr(ty_fn.func); | ||
| 1661 | // TODO emit debug info for function change | 1664 | // TODO emit debug info for function change |
| 1662 | _ = function; | 1665 | _ = function; |
| 1663 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); | 1666 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
| ... | @@ -1752,10 +1755,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1752,10 +1755,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1752 | if (self.liveness.isUnused(inst)) | 1755 | if (self.liveness.isUnused(inst)) |
| 1753 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | 1756 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1754 | 1757 | ||
| 1755 | const operand_ty = self.air.typeOf(ty_op.operand); | 1758 | const mod = self.bin_file.options.module.?; |
| 1759 | const operand_ty = self.typeOf(ty_op.operand); | ||
| 1756 | const operand = try self.resolveInst(ty_op.operand); | 1760 | const operand = try self.resolveInst(ty_op.operand); |
| 1757 | const info_a = operand_ty.intInfo(self.target.*); | 1761 | const info_a = operand_ty.intInfo(mod); |
| 1758 | const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*); | 1762 | const info_b = self.typeOfIndex(inst).intInfo(mod); |
| 1759 | if (info_a.signedness != info_b.signedness) | 1763 | if (info_a.signedness != info_b.signedness) |
| 1760 | return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); | 1764 | return self.fail("TODO gen intcast sign safety in semantic analysis", .{}); |
| 1761 | 1765 | ||
| ... | @@ -1777,7 +1781,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1777,7 +1781,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1777 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 1781 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1778 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1782 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1779 | const operand = try self.resolveInst(un_op); | 1783 | const operand = try self.resolveInst(un_op); |
| 1780 | const ty = self.air.typeOf(un_op); | 1784 | const ty = self.typeOf(un_op); |
| 1781 | break :result try self.isErr(ty, operand); | 1785 | break :result try self.isErr(ty, operand); |
| 1782 | }; | 1786 | }; |
| 1783 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 1787 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | @@ -1787,7 +1791,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1787,7 +1791,7 @@ fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1787 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 1791 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1788 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 1792 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1789 | const operand = try self.resolveInst(un_op); | 1793 | const operand = try self.resolveInst(un_op); |
| 1790 | const ty = self.air.typeOf(un_op); | 1794 | const ty = self.typeOf(un_op); |
| 1791 | break :result try self.isNonErr(ty, operand); | 1795 | break :result try self.isNonErr(ty, operand); |
| 1792 | }; | 1796 | }; |
| 1793 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 1797 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| ... | @@ -1812,15 +1816,16 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1812,15 +1816,16 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 1812 | } | 1816 | } |
| 1813 | 1817 | ||
| 1814 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | 1818 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1819 | const mod = self.bin_file.options.module.?; | ||
| 1815 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1820 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1816 | const elem_ty = self.air.typeOfIndex(inst); | 1821 | const elem_ty = self.typeOfIndex(inst); |
| 1817 | const elem_size = elem_ty.abiSize(self.target.*); | 1822 | const elem_size = elem_ty.abiSize(mod); |
| 1818 | const result: MCValue = result: { | 1823 | const result: MCValue = result: { |
| 1819 | if (!elem_ty.hasRuntimeBits()) | 1824 | if (!elem_ty.hasRuntimeBits(mod)) |
| 1820 | break :result MCValue.none; | 1825 | break :result MCValue.none; |
| 1821 | 1826 | ||
| 1822 | const ptr = try self.resolveInst(ty_op.operand); | 1827 | const ptr = try self.resolveInst(ty_op.operand); |
| 1823 | const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr(); | 1828 | const is_volatile = self.typeOf(ty_op.operand).isVolatilePtr(mod); |
| 1824 | if (self.liveness.isUnused(inst) and !is_volatile) | 1829 | if (self.liveness.isUnused(inst) and !is_volatile) |
| 1825 | break :result MCValue.dead; | 1830 | break :result MCValue.dead; |
| 1826 | 1831 | ||
| ... | @@ -1835,7 +1840,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1835,7 +1840,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 1835 | break :blk try self.allocRegOrMem(inst, true); | 1840 | break :blk try self.allocRegOrMem(inst, true); |
| 1836 | } | 1841 | } |
| 1837 | }; | 1842 | }; |
| 1838 | try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand)); | 1843 | try self.load(dst_mcv, ptr, self.typeOf(ty_op.operand)); |
| 1839 | break :result dst_mcv; | 1844 | break :result dst_mcv; |
| 1840 | }; | 1845 | }; |
| 1841 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1846 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -1878,8 +1883,8 @@ fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1878,8 +1883,8 @@ fn airMinMax(self: *Self, inst: Air.Inst.Index) !void { |
| 1878 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1883 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1879 | const lhs = try self.resolveInst(bin_op.lhs); | 1884 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1880 | const rhs = try self.resolveInst(bin_op.rhs); | 1885 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1881 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1886 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1882 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1887 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1883 | 1888 | ||
| 1884 | const result: MCValue = if (self.liveness.isUnused(inst)) | 1889 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 1885 | .dead | 1890 | .dead |
| ... | @@ -1893,8 +1898,8 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1893,8 +1898,8 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void { |
| 1893 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1898 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1894 | const lhs = try self.resolveInst(bin_op.lhs); | 1899 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1895 | const rhs = try self.resolveInst(bin_op.rhs); | 1900 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1896 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 1901 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 1897 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 1902 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 1898 | assert(lhs_ty.eql(rhs_ty, self.bin_file.options.module.?)); | 1903 | assert(lhs_ty.eql(rhs_ty, self.bin_file.options.module.?)); |
| 1899 | 1904 | ||
| 1900 | if (self.liveness.isUnused(inst)) | 1905 | if (self.liveness.isUnused(inst)) |
| ... | @@ -2037,18 +2042,18 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2037,18 +2042,18 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2037 | //const tag = self.air.instructions.items(.tag)[inst]; | 2042 | //const tag = self.air.instructions.items(.tag)[inst]; |
| 2038 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2043 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2039 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2044 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2045 | const mod = self.bin_file.options.module.?; | ||
| 2040 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2046 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2041 | const lhs = try self.resolveInst(extra.lhs); | 2047 | const lhs = try self.resolveInst(extra.lhs); |
| 2042 | const rhs = try self.resolveInst(extra.rhs); | 2048 | const rhs = try self.resolveInst(extra.rhs); |
| 2043 | const lhs_ty = self.air.typeOf(extra.lhs); | 2049 | const lhs_ty = self.typeOf(extra.lhs); |
| 2044 | const rhs_ty = self.air.typeOf(extra.rhs); | 2050 | const rhs_ty = self.typeOf(extra.rhs); |
| 2045 | 2051 | ||
| 2046 | switch (lhs_ty.zigTypeTag()) { | 2052 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2047 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), | 2053 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| 2048 | .Int => { | 2054 | .Int => { |
| 2049 | const mod = self.bin_file.options.module.?; | ||
| 2050 | assert(lhs_ty.eql(rhs_ty, mod)); | 2055 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2051 | const int_info = lhs_ty.intInfo(self.target.*); | 2056 | const int_info = lhs_ty.intInfo(mod); |
| 2052 | switch (int_info.bits) { | 2057 | switch (int_info.bits) { |
| 2053 | 1...32 => { | 2058 | 1...32 => { |
| 2054 | try self.spillConditionFlagsIfOccupied(); | 2059 | try self.spillConditionFlagsIfOccupied(); |
| ... | @@ -2101,9 +2106,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2101,9 +2106,10 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2101 | 2106 | ||
| 2102 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { | 2107 | fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 2103 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2108 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2109 | const mod = self.bin_file.options.module.?; | ||
| 2104 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2110 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2105 | const operand = try self.resolveInst(ty_op.operand); | 2111 | const operand = try self.resolveInst(ty_op.operand); |
| 2106 | const operand_ty = self.air.typeOf(ty_op.operand); | 2112 | const operand_ty = self.typeOf(ty_op.operand); |
| 2107 | switch (operand) { | 2113 | switch (operand) { |
| 2108 | .dead => unreachable, | 2114 | .dead => unreachable, |
| 2109 | .unreach => unreachable, | 2115 | .unreach => unreachable, |
| ... | @@ -2116,7 +2122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2116,7 +2122,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 2116 | }; | 2122 | }; |
| 2117 | }, | 2123 | }, |
| 2118 | else => { | 2124 | else => { |
| 2119 | switch (operand_ty.zigTypeTag()) { | 2125 | switch (operand_ty.zigTypeTag(mod)) { |
| 2120 | .Bool => { | 2126 | .Bool => { |
| 2121 | const op_reg = switch (operand) { | 2127 | const op_reg = switch (operand) { |
| 2122 | .register => |r| r, | 2128 | .register => |r| r, |
| ... | @@ -2150,7 +2156,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2150,7 +2156,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 2150 | }, | 2156 | }, |
| 2151 | .Vector => return self.fail("TODO bitwise not for vectors", .{}), | 2157 | .Vector => return self.fail("TODO bitwise not for vectors", .{}), |
| 2152 | .Int => { | 2158 | .Int => { |
| 2153 | const int_info = operand_ty.intInfo(self.target.*); | 2159 | const int_info = operand_ty.intInfo(mod); |
| 2154 | if (int_info.bits <= 64) { | 2160 | if (int_info.bits <= 64) { |
| 2155 | const op_reg = switch (operand) { | 2161 | const op_reg = switch (operand) { |
| 2156 | .register => |r| r, | 2162 | .register => |r| r, |
| ... | @@ -2280,8 +2286,8 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2280,8 +2286,8 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void { |
| 2280 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2286 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2281 | const lhs = try self.resolveInst(bin_op.lhs); | 2287 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2282 | const rhs = try self.resolveInst(bin_op.rhs); | 2288 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2283 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 2289 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 2284 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 2290 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 2285 | 2291 | ||
| 2286 | // TODO add safety check | 2292 | // TODO add safety check |
| 2287 | 2293 | ||
| ... | @@ -2332,16 +2338,17 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2332,16 +2338,17 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2332 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 2338 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2333 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2339 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2334 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2340 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2341 | const mod = self.bin_file.options.module.?; | ||
| 2335 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2342 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2336 | const lhs = try self.resolveInst(extra.lhs); | 2343 | const lhs = try self.resolveInst(extra.lhs); |
| 2337 | const rhs = try self.resolveInst(extra.rhs); | 2344 | const rhs = try self.resolveInst(extra.rhs); |
| 2338 | const lhs_ty = self.air.typeOf(extra.lhs); | 2345 | const lhs_ty = self.typeOf(extra.lhs); |
| 2339 | const rhs_ty = self.air.typeOf(extra.rhs); | 2346 | const rhs_ty = self.typeOf(extra.rhs); |
| 2340 | 2347 | ||
| 2341 | switch (lhs_ty.zigTypeTag()) { | 2348 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2342 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), | 2349 | .Vector => return self.fail("TODO implement mul_with_overflow for vectors", .{}), |
| 2343 | .Int => { | 2350 | .Int => { |
| 2344 | const int_info = lhs_ty.intInfo(self.target.*); | 2351 | const int_info = lhs_ty.intInfo(mod); |
| 2345 | if (int_info.bits <= 64) { | 2352 | if (int_info.bits <= 64) { |
| 2346 | try self.spillConditionFlagsIfOccupied(); | 2353 | try self.spillConditionFlagsIfOccupied(); |
| 2347 | 2354 | ||
| ... | @@ -2423,9 +2430,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2423,9 +2430,9 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 2423 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2430 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2424 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2431 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2425 | const ptr = try self.resolveInst(bin_op.lhs); | 2432 | const ptr = try self.resolveInst(bin_op.lhs); |
| 2426 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2433 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2427 | const len = try self.resolveInst(bin_op.rhs); | 2434 | const len = try self.resolveInst(bin_op.rhs); |
| 2428 | const len_ty = self.air.typeOf(bin_op.rhs); | 2435 | const len_ty = self.typeOf(bin_op.rhs); |
| 2429 | 2436 | ||
| 2430 | const ptr_bits = self.target.ptrBitWidth(); | 2437 | const ptr_bits = self.target.ptrBitWidth(); |
| 2431 | const ptr_bytes = @divExact(ptr_bits, 8); | 2438 | const ptr_bytes = @divExact(ptr_bits, 8); |
| ... | @@ -2439,6 +2446,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2439,6 +2446,7 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 2439 | } | 2446 | } |
| 2440 | 2447 | ||
| 2441 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 2448 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2449 | const mod = self.bin_file.options.module.?; | ||
| 2442 | const is_volatile = false; // TODO | 2450 | const is_volatile = false; // TODO |
| 2443 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2451 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2444 | 2452 | ||
| ... | @@ -2447,12 +2455,11 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2447,12 +2455,11 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2447 | const slice_mcv = try self.resolveInst(bin_op.lhs); | 2455 | const slice_mcv = try self.resolveInst(bin_op.lhs); |
| 2448 | const index_mcv = try self.resolveInst(bin_op.rhs); | 2456 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 2449 | 2457 | ||
| 2450 | const slice_ty = self.air.typeOf(bin_op.lhs); | 2458 | const slice_ty = self.typeOf(bin_op.lhs); |
| 2451 | const elem_ty = slice_ty.childType(); | 2459 | const elem_ty = slice_ty.childType(mod); |
| 2452 | const elem_size = elem_ty.abiSize(self.target.*); | 2460 | const elem_size = elem_ty.abiSize(mod); |
| 2453 | 2461 | ||
| 2454 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 2462 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(mod); |
| 2455 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | ||
| 2456 | 2463 | ||
| 2457 | const index_lock: ?RegisterLock = if (index_mcv == .register) | 2464 | const index_lock: ?RegisterLock = if (index_mcv == .register) |
| 2458 | self.register_manager.lockRegAssumeUnused(index_mcv.register) | 2465 | self.register_manager.lockRegAssumeUnused(index_mcv.register) |
| ... | @@ -2537,8 +2544,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -2537,8 +2544,8 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 2537 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2544 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2538 | const ptr = try self.resolveInst(bin_op.lhs); | 2545 | const ptr = try self.resolveInst(bin_op.lhs); |
| 2539 | const value = try self.resolveInst(bin_op.rhs); | 2546 | const value = try self.resolveInst(bin_op.rhs); |
| 2540 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2547 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2541 | const value_ty = self.air.typeOf(bin_op.rhs); | 2548 | const value_ty = self.typeOf(bin_op.rhs); |
| 2542 | 2549 | ||
| 2543 | try self.store(ptr, value, ptr_ty, value_ty); | 2550 | try self.store(ptr, value, ptr_ty, value_ty); |
| 2544 | 2551 | ||
| ... | @@ -2564,9 +2571,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2564,9 +2571,10 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 2564 | const operand = extra.struct_operand; | 2571 | const operand = extra.struct_operand; |
| 2565 | const index = extra.field_index; | 2572 | const index = extra.field_index; |
| 2566 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2573 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2574 | const mod = self.bin_file.options.module.?; | ||
| 2567 | const mcv = try self.resolveInst(operand); | 2575 | const mcv = try self.resolveInst(operand); |
| 2568 | const struct_ty = self.air.typeOf(operand); | 2576 | const struct_ty = self.typeOf(operand); |
| 2569 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | 2577 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); |
| 2570 | 2578 | ||
| 2571 | switch (mcv) { | 2579 | switch (mcv) { |
| 2572 | .dead, .unreach => unreachable, | 2580 | .dead, .unreach => unreachable, |
| ... | @@ -2651,8 +2659,8 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2651,8 +2659,8 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 2651 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 2659 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2652 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2660 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2653 | const operand = try self.resolveInst(ty_op.operand); | 2661 | const operand = try self.resolveInst(ty_op.operand); |
| 2654 | const operand_ty = self.air.typeOf(ty_op.operand); | 2662 | const operand_ty = self.typeOf(ty_op.operand); |
| 2655 | const dest_ty = self.air.typeOfIndex(inst); | 2663 | const dest_ty = self.typeOfIndex(inst); |
| 2656 | 2664 | ||
| 2657 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { | 2665 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 2658 | break :blk try self.trunc(inst, operand, operand_ty, dest_ty); | 2666 | break :blk try self.trunc(inst, operand, operand_ty, dest_ty); |
| ... | @@ -2666,7 +2674,7 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2666,7 +2674,7 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 2666 | const extra = self.air.extraData(Air.Try, pl_op.payload); | 2674 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 2667 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 2675 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 2668 | const result: MCValue = result: { | 2676 | const result: MCValue = result: { |
| 2669 | const error_union_ty = self.air.typeOf(pl_op.operand); | 2677 | const error_union_ty = self.typeOf(pl_op.operand); |
| 2670 | const error_union = try self.resolveInst(pl_op.operand); | 2678 | const error_union = try self.resolveInst(pl_op.operand); |
| 2671 | const is_err_result = try self.isErr(error_union_ty, error_union); | 2679 | const is_err_result = try self.isErr(error_union_ty, error_union); |
| 2672 | const reloc = try self.condBr(is_err_result); | 2680 | const reloc = try self.condBr(is_err_result); |
| ... | @@ -2696,12 +2704,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2696,12 +2704,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 2696 | } | 2704 | } |
| 2697 | 2705 | ||
| 2698 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | 2706 | fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2707 | const mod = self.bin_file.options.module.?; | ||
| 2699 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2708 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2700 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2709 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2701 | const error_union_ty = self.air.typeOf(ty_op.operand); | 2710 | const error_union_ty = self.typeOf(ty_op.operand); |
| 2702 | const payload_ty = error_union_ty.errorUnionPayload(); | 2711 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 2703 | const mcv = try self.resolveInst(ty_op.operand); | 2712 | const mcv = try self.resolveInst(ty_op.operand); |
| 2704 | if (!payload_ty.hasRuntimeBits()) break :result mcv; | 2713 | if (!payload_ty.hasRuntimeBits(mod)) break :result mcv; |
| 2705 | 2714 | ||
| 2706 | return self.fail("TODO implement unwrap error union error for non-empty payloads", .{}); | 2715 | return self.fail("TODO implement unwrap error union error for non-empty payloads", .{}); |
| 2707 | }; | 2716 | }; |
| ... | @@ -2709,11 +2718,12 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2709,11 +2718,12 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2709 | } | 2718 | } |
| 2710 | 2719 | ||
| 2711 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { | 2720 | fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2721 | const mod = self.bin_file.options.module.?; | ||
| 2712 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2722 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2713 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2723 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2714 | const error_union_ty = self.air.typeOf(ty_op.operand); | 2724 | const error_union_ty = self.typeOf(ty_op.operand); |
| 2715 | const payload_ty = error_union_ty.errorUnionPayload(); | 2725 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 2716 | if (!payload_ty.hasRuntimeBits()) break :result MCValue.none; | 2726 | if (!payload_ty.hasRuntimeBits(mod)) break :result MCValue.none; |
| 2717 | 2727 | ||
| 2718 | return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{}); | 2728 | return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{}); |
| 2719 | }; | 2729 | }; |
| ... | @@ -2722,12 +2732,13 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2722,12 +2732,13 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2722 | 2732 | ||
| 2723 | /// E to E!T | 2733 | /// E to E!T |
| 2724 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | 2734 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 2735 | const mod = self.bin_file.options.module.?; | ||
| 2725 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2736 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2726 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2737 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2727 | const error_union_ty = self.air.getRefType(ty_op.ty); | 2738 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 2728 | const payload_ty = error_union_ty.errorUnionPayload(); | 2739 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 2729 | const mcv = try self.resolveInst(ty_op.operand); | 2740 | const mcv = try self.resolveInst(ty_op.operand); |
| 2730 | if (!payload_ty.hasRuntimeBits()) break :result mcv; | 2741 | if (!payload_ty.hasRuntimeBits(mod)) break :result mcv; |
| 2731 | 2742 | ||
| 2732 | return self.fail("TODO implement wrap errunion error for non-empty payloads", .{}); | 2743 | return self.fail("TODO implement wrap errunion error for non-empty payloads", .{}); |
| 2733 | }; | 2744 | }; |
| ... | @@ -2742,12 +2753,13 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2742,12 +2753,13 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 2742 | } | 2753 | } |
| 2743 | 2754 | ||
| 2744 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | 2755 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 2756 | const mod = self.bin_file.options.module.?; | ||
| 2745 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2757 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2746 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { | 2758 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { |
| 2747 | const optional_ty = self.air.typeOfIndex(inst); | 2759 | const optional_ty = self.typeOfIndex(inst); |
| 2748 | 2760 | ||
| 2749 | // Optional with a zero-bit payload type is just a boolean true | 2761 | // Optional with a zero-bit payload type is just a boolean true |
| 2750 | if (optional_ty.abiSize(self.target.*) == 1) | 2762 | if (optional_ty.abiSize(mod) == 1) |
| 2751 | break :result MCValue{ .immediate = 1 }; | 2763 | break :result MCValue{ .immediate = 1 }; |
| 2752 | 2764 | ||
| 2753 | return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch}); | 2765 | return self.fail("TODO implement wrap optional for {}", .{self.target.cpu.arch}); |
| ... | @@ -2782,9 +2794,10 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u | ... | @@ -2782,9 +2794,10 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u |
| 2782 | 2794 | ||
| 2783 | /// Use a pointer instruction as the basis for allocating stack memory. | 2795 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 2784 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | 2796 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 2785 | const elem_ty = self.air.typeOfIndex(inst).elemType(); | 2797 | const mod = self.bin_file.options.module.?; |
| 2798 | const elem_ty = self.typeOfIndex(inst).childType(mod); | ||
| 2786 | 2799 | ||
| 2787 | if (!elem_ty.hasRuntimeBits()) { | 2800 | if (!elem_ty.hasRuntimeBits(mod)) { |
| 2788 | // As this stack item will never be dereferenced at runtime, | 2801 | // As this stack item will never be dereferenced at runtime, |
| 2789 | // return the stack offset 0. Stack offset 0 will be where all | 2802 | // return the stack offset 0. Stack offset 0 will be where all |
| 2790 | // zero-sized stack allocations live as non-zero-sized | 2803 | // zero-sized stack allocations live as non-zero-sized |
| ... | @@ -2792,22 +2805,21 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | ... | @@ -2792,22 +2805,21 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 2792 | return @as(u32, 0); | 2805 | return @as(u32, 0); |
| 2793 | } | 2806 | } |
| 2794 | 2807 | ||
| 2795 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | 2808 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { |
| 2796 | const mod = self.bin_file.options.module.?; | ||
| 2797 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 2809 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 2798 | }; | 2810 | }; |
| 2799 | // TODO swap this for inst.ty.ptrAlign | 2811 | // TODO swap this for inst.ty.ptrAlign |
| 2800 | const abi_align = elem_ty.abiAlignment(self.target.*); | 2812 | const abi_align = elem_ty.abiAlignment(mod); |
| 2801 | return self.allocMem(inst, abi_size, abi_align); | 2813 | return self.allocMem(inst, abi_size, abi_align); |
| 2802 | } | 2814 | } |
| 2803 | 2815 | ||
| 2804 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | 2816 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 2805 | const elem_ty = self.air.typeOfIndex(inst); | 2817 | const mod = self.bin_file.options.module.?; |
| 2806 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | 2818 | const elem_ty = self.typeOfIndex(inst); |
| 2807 | const mod = self.bin_file.options.module.?; | 2819 | const abi_size = math.cast(u32, elem_ty.abiSize(mod)) orelse { |
| 2808 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 2820 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); |
| 2809 | }; | 2821 | }; |
| 2810 | const abi_align = elem_ty.abiAlignment(self.target.*); | 2822 | const abi_align = elem_ty.abiAlignment(mod); |
| 2811 | if (abi_align > self.stack_align) | 2823 | if (abi_align > self.stack_align) |
| 2812 | self.stack_align = abi_align; | 2824 | self.stack_align = abi_align; |
| 2813 | 2825 | ||
| ... | @@ -2860,12 +2872,12 @@ fn binOp( | ... | @@ -2860,12 +2872,12 @@ fn binOp( |
| 2860 | .xor, | 2872 | .xor, |
| 2861 | .cmp_eq, | 2873 | .cmp_eq, |
| 2862 | => { | 2874 | => { |
| 2863 | switch (lhs_ty.zigTypeTag()) { | 2875 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2864 | .Float => return self.fail("TODO binary operations on floats", .{}), | 2876 | .Float => return self.fail("TODO binary operations on floats", .{}), |
| 2865 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2877 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2866 | .Int => { | 2878 | .Int => { |
| 2867 | assert(lhs_ty.eql(rhs_ty, mod)); | 2879 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2868 | const int_info = lhs_ty.intInfo(self.target.*); | 2880 | const int_info = lhs_ty.intInfo(mod); |
| 2869 | if (int_info.bits <= 64) { | 2881 | if (int_info.bits <= 64) { |
| 2870 | // Only say yes if the operation is | 2882 | // Only say yes if the operation is |
| 2871 | // commutative, i.e. we can swap both of the | 2883 | // commutative, i.e. we can swap both of the |
| ... | @@ -2934,10 +2946,10 @@ fn binOp( | ... | @@ -2934,10 +2946,10 @@ fn binOp( |
| 2934 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | 2946 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 2935 | 2947 | ||
| 2936 | // Truncate if necessary | 2948 | // Truncate if necessary |
| 2937 | switch (lhs_ty.zigTypeTag()) { | 2949 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2938 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2950 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2939 | .Int => { | 2951 | .Int => { |
| 2940 | const int_info = lhs_ty.intInfo(self.target.*); | 2952 | const int_info = lhs_ty.intInfo(mod); |
| 2941 | if (int_info.bits <= 64) { | 2953 | if (int_info.bits <= 64) { |
| 2942 | const result_reg = result.register; | 2954 | const result_reg = result.register; |
| 2943 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); | 2955 | try self.truncRegister(result_reg, result_reg, int_info.signedness, int_info.bits); |
| ... | @@ -2951,11 +2963,11 @@ fn binOp( | ... | @@ -2951,11 +2963,11 @@ fn binOp( |
| 2951 | }, | 2963 | }, |
| 2952 | 2964 | ||
| 2953 | .div_trunc => { | 2965 | .div_trunc => { |
| 2954 | switch (lhs_ty.zigTypeTag()) { | 2966 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2955 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2967 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 2956 | .Int => { | 2968 | .Int => { |
| 2957 | assert(lhs_ty.eql(rhs_ty, mod)); | 2969 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 2958 | const int_info = lhs_ty.intInfo(self.target.*); | 2970 | const int_info = lhs_ty.intInfo(mod); |
| 2959 | if (int_info.bits <= 64) { | 2971 | if (int_info.bits <= 64) { |
| 2960 | const rhs_immediate_ok = switch (tag) { | 2972 | const rhs_immediate_ok = switch (tag) { |
| 2961 | .div_trunc => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), | 2973 | .div_trunc => rhs == .immediate and rhs.immediate <= std.math.maxInt(u12), |
| ... | @@ -2984,14 +2996,14 @@ fn binOp( | ... | @@ -2984,14 +2996,14 @@ fn binOp( |
| 2984 | }, | 2996 | }, |
| 2985 | 2997 | ||
| 2986 | .ptr_add => { | 2998 | .ptr_add => { |
| 2987 | switch (lhs_ty.zigTypeTag()) { | 2999 | switch (lhs_ty.zigTypeTag(mod)) { |
| 2988 | .Pointer => { | 3000 | .Pointer => { |
| 2989 | const ptr_ty = lhs_ty; | 3001 | const ptr_ty = lhs_ty; |
| 2990 | const elem_ty = switch (ptr_ty.ptrSize()) { | 3002 | const elem_ty = switch (ptr_ty.ptrSize(mod)) { |
| 2991 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type | 3003 | .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type |
| 2992 | else => ptr_ty.childType(), | 3004 | else => ptr_ty.childType(mod), |
| 2993 | }; | 3005 | }; |
| 2994 | const elem_size = elem_ty.abiSize(self.target.*); | 3006 | const elem_size = elem_ty.abiSize(mod); |
| 2995 | 3007 | ||
| 2996 | if (elem_size == 1) { | 3008 | if (elem_size == 1) { |
| 2997 | const base_tag: Mir.Inst.Tag = switch (tag) { | 3009 | const base_tag: Mir.Inst.Tag = switch (tag) { |
| ... | @@ -3005,7 +3017,7 @@ fn binOp( | ... | @@ -3005,7 +3017,7 @@ fn binOp( |
| 3005 | // multiplying it with elem_size | 3017 | // multiplying it with elem_size |
| 3006 | 3018 | ||
| 3007 | const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null); | 3019 | const offset = try self.binOp(.mul, rhs, .{ .immediate = elem_size }, Type.usize, Type.usize, null); |
| 3008 | const addr = try self.binOp(tag, lhs, offset, Type.initTag(.manyptr_u8), Type.usize, null); | 3020 | const addr = try self.binOp(tag, lhs, offset, Type.manyptr_u8, Type.usize, null); |
| 3009 | return addr; | 3021 | return addr; |
| 3010 | } | 3022 | } |
| 3011 | }, | 3023 | }, |
| ... | @@ -3016,7 +3028,7 @@ fn binOp( | ... | @@ -3016,7 +3028,7 @@ fn binOp( |
| 3016 | .bool_and, | 3028 | .bool_and, |
| 3017 | .bool_or, | 3029 | .bool_or, |
| 3018 | => { | 3030 | => { |
| 3019 | switch (lhs_ty.zigTypeTag()) { | 3031 | switch (lhs_ty.zigTypeTag(mod)) { |
| 3020 | .Bool => { | 3032 | .Bool => { |
| 3021 | assert(lhs != .immediate); // should have been handled by Sema | 3033 | assert(lhs != .immediate); // should have been handled by Sema |
| 3022 | assert(rhs != .immediate); // should have been handled by Sema | 3034 | assert(rhs != .immediate); // should have been handled by Sema |
| ... | @@ -3046,10 +3058,10 @@ fn binOp( | ... | @@ -3046,10 +3058,10 @@ fn binOp( |
| 3046 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); | 3058 | const result = try self.binOp(base_tag, lhs, rhs, lhs_ty, rhs_ty, metadata); |
| 3047 | 3059 | ||
| 3048 | // Truncate if necessary | 3060 | // Truncate if necessary |
| 3049 | switch (lhs_ty.zigTypeTag()) { | 3061 | switch (lhs_ty.zigTypeTag(mod)) { |
| 3050 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 3062 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 3051 | .Int => { | 3063 | .Int => { |
| 3052 | const int_info = lhs_ty.intInfo(self.target.*); | 3064 | const int_info = lhs_ty.intInfo(mod); |
| 3053 | if (int_info.bits <= 64) { | 3065 | if (int_info.bits <= 64) { |
| 3054 | // 32 and 64 bit operands doesn't need truncating | 3066 | // 32 and 64 bit operands doesn't need truncating |
| 3055 | if (int_info.bits == 32 or int_info.bits == 64) return result; | 3067 | if (int_info.bits == 32 or int_info.bits == 64) return result; |
| ... | @@ -3068,10 +3080,10 @@ fn binOp( | ... | @@ -3068,10 +3080,10 @@ fn binOp( |
| 3068 | .shl_exact, | 3080 | .shl_exact, |
| 3069 | .shr_exact, | 3081 | .shr_exact, |
| 3070 | => { | 3082 | => { |
| 3071 | switch (lhs_ty.zigTypeTag()) { | 3083 | switch (lhs_ty.zigTypeTag(mod)) { |
| 3072 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 3084 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 3073 | .Int => { | 3085 | .Int => { |
| 3074 | const int_info = lhs_ty.intInfo(self.target.*); | 3086 | const int_info = lhs_ty.intInfo(mod); |
| 3075 | if (int_info.bits <= 64) { | 3087 | if (int_info.bits <= 64) { |
| 3076 | const rhs_immediate_ok = rhs == .immediate; | 3088 | const rhs_immediate_ok = rhs == .immediate; |
| 3077 | 3089 | ||
| ... | @@ -3393,7 +3405,8 @@ fn binOpRegister( | ... | @@ -3393,7 +3405,8 @@ fn binOpRegister( |
| 3393 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | 3405 | fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 3394 | const block_data = self.blocks.getPtr(block).?; | 3406 | const block_data = self.blocks.getPtr(block).?; |
| 3395 | 3407 | ||
| 3396 | if (self.air.typeOf(operand).hasRuntimeBits()) { | 3408 | const mod = self.bin_file.options.module.?; |
| 3409 | if (self.typeOf(operand).hasRuntimeBits(mod)) { | ||
| 3397 | const operand_mcv = try self.resolveInst(operand); | 3410 | const operand_mcv = try self.resolveInst(operand); |
| 3398 | const block_mcv = block_data.mcv; | 3411 | const block_mcv = block_data.mcv; |
| 3399 | if (block_mcv == .none) { | 3412 | if (block_mcv == .none) { |
| ... | @@ -3402,13 +3415,13 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { | ... | @@ -3402,13 +3415,13 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void { |
| 3402 | .register, .stack_offset, .memory => operand_mcv, | 3415 | .register, .stack_offset, .memory => operand_mcv, |
| 3403 | .immediate => blk: { | 3416 | .immediate => blk: { |
| 3404 | const new_mcv = try self.allocRegOrMem(block, true); | 3417 | const new_mcv = try self.allocRegOrMem(block, true); |
| 3405 | try self.setRegOrMem(self.air.typeOfIndex(block), new_mcv, operand_mcv); | 3418 | try self.setRegOrMem(self.typeOfIndex(block), new_mcv, operand_mcv); |
| 3406 | break :blk new_mcv; | 3419 | break :blk new_mcv; |
| 3407 | }, | 3420 | }, |
| 3408 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), | 3421 | else => return self.fail("TODO implement block_data.mcv = operand_mcv for {}", .{operand_mcv}), |
| 3409 | }; | 3422 | }; |
| 3410 | } else { | 3423 | } else { |
| 3411 | try self.setRegOrMem(self.air.typeOfIndex(block), block_mcv, operand_mcv); | 3424 | try self.setRegOrMem(self.typeOfIndex(block), block_mcv, operand_mcv); |
| 3412 | } | 3425 | } |
| 3413 | } | 3426 | } |
| 3414 | return self.brVoid(block); | 3427 | return self.brVoid(block); |
| ... | @@ -3512,16 +3525,17 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { | ... | @@ -3512,16 +3525,17 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void { |
| 3512 | 3525 | ||
| 3513 | /// Given an error union, returns the payload | 3526 | /// Given an error union, returns the payload |
| 3514 | fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { | 3527 | fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { |
| 3515 | const err_ty = error_union_ty.errorUnionSet(); | 3528 | const mod = self.bin_file.options.module.?; |
| 3516 | const payload_ty = error_union_ty.errorUnionPayload(); | 3529 | const err_ty = error_union_ty.errorUnionSet(mod); |
| 3517 | if (err_ty.errorSetIsEmpty()) { | 3530 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 3531 | if (err_ty.errorSetIsEmpty(mod)) { | ||
| 3518 | return error_union_mcv; | 3532 | return error_union_mcv; |
| 3519 | } | 3533 | } |
| 3520 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3534 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3521 | return MCValue.none; | 3535 | return MCValue.none; |
| 3522 | } | 3536 | } |
| 3523 | 3537 | ||
| 3524 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*)); | 3538 | const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, mod)); |
| 3525 | switch (error_union_mcv) { | 3539 | switch (error_union_mcv) { |
| 3526 | .register => return self.fail("TODO errUnionPayload for registers", .{}), | 3540 | .register => return self.fail("TODO errUnionPayload for registers", .{}), |
| 3527 | .stack_offset => |off| { | 3541 | .stack_offset => |off| { |
| ... | @@ -3555,8 +3569,8 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -3555,8 +3569,8 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 3555 | tomb_bits >>= 1; | 3569 | tomb_bits >>= 1; |
| 3556 | if (!dies) continue; | 3570 | if (!dies) continue; |
| 3557 | const op_int = @enumToInt(op); | 3571 | const op_int = @enumToInt(op); |
| 3558 | if (op_int < Air.Inst.Ref.typed_value_map.len) continue; | 3572 | if (op_int < Air.ref_start_index) continue; |
| 3559 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | 3573 | const op_index = @intCast(Air.Inst.Index, op_int - Air.ref_start_index); |
| 3560 | self.processDeath(op_index); | 3574 | self.processDeath(op_index); |
| 3561 | } | 3575 | } |
| 3562 | const is_used = @truncate(u1, tomb_bits) == 0; | 3576 | const is_used = @truncate(u1, tomb_bits) == 0; |
| ... | @@ -3730,6 +3744,7 @@ fn genLoadASI(self: *Self, value_reg: Register, addr_reg: Register, off_reg: Reg | ... | @@ -3730,6 +3744,7 @@ fn genLoadASI(self: *Self, value_reg: Register, addr_reg: Register, off_reg: Reg |
| 3730 | } | 3744 | } |
| 3731 | 3745 | ||
| 3732 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { | 3746 | fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void { |
| 3747 | const mod = self.bin_file.options.module.?; | ||
| 3733 | switch (mcv) { | 3748 | switch (mcv) { |
| 3734 | .dead => unreachable, | 3749 | .dead => unreachable, |
| 3735 | .unreach, .none => return, // Nothing to do. | 3750 | .unreach, .none => return, // Nothing to do. |
| ... | @@ -3928,19 +3943,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -3928,19 +3943,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 3928 | // The value is in memory at a hard-coded address. | 3943 | // The value is in memory at a hard-coded address. |
| 3929 | // If the type is a pointer, it means the pointer address is at this memory location. | 3944 | // If the type is a pointer, it means the pointer address is at this memory location. |
| 3930 | try self.genSetReg(ty, reg, .{ .immediate = addr }); | 3945 | try self.genSetReg(ty, reg, .{ .immediate = addr }); |
| 3931 | try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*)); | 3946 | try self.genLoad(reg, reg, i13, 0, ty.abiSize(mod)); |
| 3932 | }, | 3947 | }, |
| 3933 | .stack_offset => |off| { | 3948 | .stack_offset => |off| { |
| 3934 | const real_offset = realStackOffset(off); | 3949 | const real_offset = realStackOffset(off); |
| 3935 | const simm13 = math.cast(i13, real_offset) orelse | 3950 | const simm13 = math.cast(i13, real_offset) orelse |
| 3936 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); | 3951 | return self.fail("TODO larger stack offsets: {}", .{real_offset}); |
| 3937 | try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*)); | 3952 | try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(mod)); |
| 3938 | }, | 3953 | }, |
| 3939 | } | 3954 | } |
| 3940 | } | 3955 | } |
| 3941 | 3956 | ||
| 3942 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { | 3957 | fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void { |
| 3943 | const abi_size = ty.abiSize(self.target.*); | 3958 | const mod = self.bin_file.options.module.?; |
| 3959 | const abi_size = ty.abiSize(mod); | ||
| 3944 | switch (mcv) { | 3960 | switch (mcv) { |
| 3945 | .dead => unreachable, | 3961 | .dead => unreachable, |
| 3946 | .unreach, .none => return, // Nothing to do. | 3962 | .unreach, .none => return, // Nothing to do. |
| ... | @@ -3948,7 +3964,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3948,7 +3964,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3948 | if (!self.wantSafety()) | 3964 | if (!self.wantSafety()) |
| 3949 | return; // The already existing value will do just fine. | 3965 | return; // The already existing value will do just fine. |
| 3950 | // TODO Upgrade this to a memset call when we have that available. | 3966 | // TODO Upgrade this to a memset call when we have that available. |
| 3951 | switch (ty.abiSize(self.target.*)) { | 3967 | switch (ty.abiSize(mod)) { |
| 3952 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), | 3968 | 1 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaa }), |
| 3953 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), | 3969 | 2 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaa }), |
| 3954 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), | 3970 | 4 => return self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaa }), |
| ... | @@ -3974,11 +3990,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -3974,11 +3990,11 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 3974 | const reg_lock = self.register_manager.lockReg(rwo.reg); | 3990 | const reg_lock = self.register_manager.lockReg(rwo.reg); |
| 3975 | defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg); | 3991 | defer if (reg_lock) |locked_reg| self.register_manager.unlockReg(locked_reg); |
| 3976 | 3992 | ||
| 3977 | const wrapped_ty = ty.structFieldType(0); | 3993 | const wrapped_ty = ty.structFieldType(0, mod); |
| 3978 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = rwo.reg }); | 3994 | try self.genSetStack(wrapped_ty, stack_offset, .{ .register = rwo.reg }); |
| 3979 | 3995 | ||
| 3980 | const overflow_bit_ty = ty.structFieldType(1); | 3996 | const overflow_bit_ty = ty.structFieldType(1, mod); |
| 3981 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, self.target.*)); | 3997 | const overflow_bit_offset = @intCast(u32, ty.structFieldOffset(1, mod)); |
| 3982 | const cond_reg = try self.register_manager.allocReg(null, gp); | 3998 | const cond_reg = try self.register_manager.allocReg(null, gp); |
| 3983 | 3999 | ||
| 3984 | // TODO handle floating point CCRs | 4000 | // TODO handle floating point CCRs |
| ... | @@ -4024,11 +4040,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -4024,11 +4040,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 4024 | const reg = try self.copyToTmpRegister(ty, mcv); | 4040 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 4025 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 4041 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 4026 | } else { | 4042 | } else { |
| 4027 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 4043 | const ptr_ty = try mod.singleMutPtrType(ty); |
| 4028 | .base = .{ .tag = .single_mut_pointer }, | ||
| 4029 | .data = ty, | ||
| 4030 | }; | ||
| 4031 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 4032 | 4044 | ||
| 4033 | const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, gp); | 4045 | const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, gp); |
| 4034 | const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs); | 4046 | const regs_locks = self.register_manager.lockRegsAssumeUnused(4, regs); |
| ... | @@ -4152,13 +4164,14 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { | ... | @@ -4152,13 +4164,14 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue { |
| 4152 | } | 4164 | } |
| 4153 | 4165 | ||
| 4154 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { | 4166 | fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 4155 | const error_type = ty.errorUnionSet(); | 4167 | const mod = self.bin_file.options.module.?; |
| 4156 | const payload_type = ty.errorUnionPayload(); | 4168 | const error_type = ty.errorUnionSet(mod); |
| 4169 | const payload_type = ty.errorUnionPayload(mod); | ||
| 4157 | 4170 | ||
| 4158 | if (!error_type.hasRuntimeBits()) { | 4171 | if (!error_type.hasRuntimeBits(mod)) { |
| 4159 | return MCValue{ .immediate = 0 }; // always false | 4172 | return MCValue{ .immediate = 0 }; // always false |
| 4160 | } else if (!payload_type.hasRuntimeBits()) { | 4173 | } else if (!payload_type.hasRuntimeBits(mod)) { |
| 4161 | if (error_type.abiSize(self.target.*) <= 8) { | 4174 | if (error_type.abiSize(mod) <= 8) { |
| 4162 | const reg_mcv: MCValue = switch (operand) { | 4175 | const reg_mcv: MCValue = switch (operand) { |
| 4163 | .register => operand, | 4176 | .register => operand, |
| 4164 | else => .{ .register = try self.copyToTmpRegister(error_type, operand) }, | 4177 | else => .{ .register = try self.copyToTmpRegister(error_type, operand) }, |
| ... | @@ -4249,8 +4262,9 @@ fn jump(self: *Self, inst: Mir.Inst.Index) !void { | ... | @@ -4249,8 +4262,9 @@ fn jump(self: *Self, inst: Mir.Inst.Index) !void { |
| 4249 | } | 4262 | } |
| 4250 | 4263 | ||
| 4251 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { | 4264 | fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void { |
| 4252 | const elem_ty = ptr_ty.elemType(); | 4265 | const mod = self.bin_file.options.module.?; |
| 4253 | const elem_size = elem_ty.abiSize(self.target.*); | 4266 | const elem_ty = ptr_ty.childType(mod); |
| 4267 | const elem_size = elem_ty.abiSize(mod); | ||
| 4254 | 4268 | ||
| 4255 | switch (ptr) { | 4269 | switch (ptr) { |
| 4256 | .none => unreachable, | 4270 | .none => unreachable, |
| ... | @@ -4321,11 +4335,11 @@ fn minMax( | ... | @@ -4321,11 +4335,11 @@ fn minMax( |
| 4321 | ) InnerError!MCValue { | 4335 | ) InnerError!MCValue { |
| 4322 | const mod = self.bin_file.options.module.?; | 4336 | const mod = self.bin_file.options.module.?; |
| 4323 | assert(lhs_ty.eql(rhs_ty, mod)); | 4337 | assert(lhs_ty.eql(rhs_ty, mod)); |
| 4324 | switch (lhs_ty.zigTypeTag()) { | 4338 | switch (lhs_ty.zigTypeTag(mod)) { |
| 4325 | .Float => return self.fail("TODO min/max on floats", .{}), | 4339 | .Float => return self.fail("TODO min/max on floats", .{}), |
| 4326 | .Vector => return self.fail("TODO min/max on vectors", .{}), | 4340 | .Vector => return self.fail("TODO min/max on vectors", .{}), |
| 4327 | .Int => { | 4341 | .Int => { |
| 4328 | const int_info = lhs_ty.intInfo(self.target.*); | 4342 | const int_info = lhs_ty.intInfo(mod); |
| 4329 | if (int_info.bits <= 64) { | 4343 | if (int_info.bits <= 64) { |
| 4330 | // TODO skip register setting when one of the operands | 4344 | // TODO skip register setting when one of the operands |
| 4331 | // is a small (fits in i13) immediate. | 4345 | // is a small (fits in i13) immediate. |
| ... | @@ -4406,8 +4420,7 @@ fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { | ... | @@ -4406,8 +4420,7 @@ fn performReloc(self: *Self, inst: Mir.Inst.Index) !void { |
| 4406 | 4420 | ||
| 4407 | /// Asserts there is already capacity to insert into top branch inst_table. | 4421 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 4408 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { | 4422 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 4409 | const air_tags = self.air.instructions.items(.tag); | 4423 | assert(self.air.instructions.items(.tag)[inst] != .interned); |
| 4410 | if (air_tags[inst] == .constant) return; // Constants are immortal. | ||
| 4411 | // When editing this function, note that the logic must synchronize with `reuseOperand`. | 4424 | // When editing this function, note that the logic must synchronize with `reuseOperand`. |
| 4412 | const prev_value = self.getResolvedInstValue(inst); | 4425 | const prev_value = self.getResolvedInstValue(inst); |
| 4413 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 4426 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | @@ -4441,12 +4454,11 @@ fn realStackOffset(off: u32) u32 { | ... | @@ -4441,12 +4454,11 @@ fn realStackOffset(off: u32) u32 { |
| 4441 | 4454 | ||
| 4442 | /// Caller must call `CallMCValues.deinit`. | 4455 | /// Caller must call `CallMCValues.deinit`. |
| 4443 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) !CallMCValues { | 4456 | fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) !CallMCValues { |
| 4444 | const cc = fn_ty.fnCallingConvention(); | 4457 | const mod = self.bin_file.options.module.?; |
| 4445 | const param_types = try self.gpa.alloc(Type, fn_ty.fnParamLen()); | 4458 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 4446 | defer self.gpa.free(param_types); | 4459 | const cc = fn_info.cc; |
| 4447 | fn_ty.fnParamTypes(param_types); | ||
| 4448 | var result: CallMCValues = .{ | 4460 | var result: CallMCValues = .{ |
| 4449 | .args = try self.gpa.alloc(MCValue, param_types.len), | 4461 | .args = try self.gpa.alloc(MCValue, fn_info.param_types.len), |
| 4450 | // These undefined values must be populated before returning from this function. | 4462 | // These undefined values must be populated before returning from this function. |
| 4451 | .return_value = undefined, | 4463 | .return_value = undefined, |
| 4452 | .stack_byte_count = undefined, | 4464 | .stack_byte_count = undefined, |
| ... | @@ -4454,7 +4466,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) | ... | @@ -4454,7 +4466,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4454 | }; | 4466 | }; |
| 4455 | errdefer self.gpa.free(result.args); | 4467 | errdefer self.gpa.free(result.args); |
| 4456 | 4468 | ||
| 4457 | const ret_ty = fn_ty.fnReturnType(); | 4469 | const ret_ty = fn_ty.fnReturnType(mod); |
| 4458 | 4470 | ||
| 4459 | switch (cc) { | 4471 | switch (cc) { |
| 4460 | .Naked => { | 4472 | .Naked => { |
| ... | @@ -4477,8 +4489,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) | ... | @@ -4477,8 +4489,8 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4477 | .callee => abi.c_abi_int_param_regs_callee_view, | 4489 | .callee => abi.c_abi_int_param_regs_callee_view, |
| 4478 | }; | 4490 | }; |
| 4479 | 4491 | ||
| 4480 | for (param_types, 0..) |ty, i| { | 4492 | for (fn_info.param_types, 0..) |ty, i| { |
| 4481 | const param_size = @intCast(u32, ty.abiSize(self.target.*)); | 4493 | const param_size = @intCast(u32, ty.toType().abiSize(mod)); |
| 4482 | if (param_size <= 8) { | 4494 | if (param_size <= 8) { |
| 4483 | if (next_register < argument_registers.len) { | 4495 | if (next_register < argument_registers.len) { |
| 4484 | result.args[i] = .{ .register = argument_registers[next_register] }; | 4496 | result.args[i] = .{ .register = argument_registers[next_register] }; |
| ... | @@ -4505,12 +4517,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) | ... | @@ -4505,12 +4517,12 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4505 | result.stack_byte_count = next_stack_offset; | 4517 | result.stack_byte_count = next_stack_offset; |
| 4506 | result.stack_align = 16; | 4518 | result.stack_align = 16; |
| 4507 | 4519 | ||
| 4508 | if (ret_ty.zigTypeTag() == .NoReturn) { | 4520 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 4509 | result.return_value = .{ .unreach = {} }; | 4521 | result.return_value = .{ .unreach = {} }; |
| 4510 | } else if (!ret_ty.hasRuntimeBits()) { | 4522 | } else if (!ret_ty.hasRuntimeBits(mod)) { |
| 4511 | result.return_value = .{ .none = {} }; | 4523 | result.return_value = .{ .none = {} }; |
| 4512 | } else { | 4524 | } else { |
| 4513 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 4525 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(mod)); |
| 4514 | // The callee puts the return values in %i0-%i3, which becomes %o0-%o3 inside the caller. | 4526 | // The callee puts the return values in %i0-%i3, which becomes %o0-%o3 inside the caller. |
| 4515 | if (ret_ty_size <= 8) { | 4527 | if (ret_ty_size <= 8) { |
| 4516 | result.return_value = switch (role) { | 4528 | result.return_value = switch (role) { |
| ... | @@ -4528,44 +4540,41 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) | ... | @@ -4528,44 +4540,41 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type, role: RegisterView) |
| 4528 | return result; | 4540 | return result; |
| 4529 | } | 4541 | } |
| 4530 | 4542 | ||
| 4531 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | 4543 | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { |
| 4532 | // First section of indexes correspond to a set number of constant values. | 4544 | const mod = self.bin_file.options.module.?; |
| 4533 | const ref_int = @enumToInt(inst); | 4545 | const ty = self.typeOf(ref); |
| 4534 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | ||
| 4535 | const tv = Air.Inst.Ref.typed_value_map[ref_int]; | ||
| 4536 | if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) { | ||
| 4537 | return MCValue{ .none = {} }; | ||
| 4538 | } | ||
| 4539 | return self.genTypedValue(tv); | ||
| 4540 | } | ||
| 4541 | 4546 | ||
| 4542 | // If the type has no codegen bits, no need to store it. | 4547 | // If the type has no codegen bits, no need to store it. |
| 4543 | const inst_ty = self.air.typeOf(inst); | 4548 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return .none; |
| 4544 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError()) | 4549 | |
| 4545 | return MCValue{ .none = {} }; | 4550 | if (Air.refToIndex(ref)) |inst| { |
| 4546 | 4551 | switch (self.air.instructions.items(.tag)[inst]) { | |
| 4547 | const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); | 4552 | .interned => { |
| 4548 | switch (self.air.instructions.items(.tag)[inst_index]) { | 4553 | // Constants have static lifetimes, so they are always memoized in the outer most table. |
| 4549 | .constant => { | 4554 | const branch = &self.branch_stack.items[0]; |
| 4550 | // Constants have static lifetimes, so they are always memoized in the outer most table. | 4555 | const gop = try branch.inst_table.getOrPut(self.gpa, inst); |
| 4551 | const branch = &self.branch_stack.items[0]; | 4556 | if (!gop.found_existing) { |
| 4552 | const gop = try branch.inst_table.getOrPut(self.gpa, inst_index); | 4557 | const interned = self.air.instructions.items(.data)[inst].interned; |
| 4553 | if (!gop.found_existing) { | 4558 | gop.value_ptr.* = try self.genTypedValue(.{ |
| 4554 | const ty_pl = self.air.instructions.items(.data)[inst_index].ty_pl; | 4559 | .ty = ty, |
| 4555 | gop.value_ptr.* = try self.genTypedValue(.{ | 4560 | .val = interned.toValue(), |
| 4556 | .ty = inst_ty, | 4561 | }); |
| 4557 | .val = self.air.values[ty_pl.payload], | 4562 | } |
| 4558 | }); | 4563 | return gop.value_ptr.*; |
| 4559 | } | 4564 | }, |
| 4560 | return gop.value_ptr.*; | 4565 | else => return self.getResolvedInstValue(inst), |
| 4561 | }, | 4566 | } |
| 4562 | .const_ty => unreachable, | ||
| 4563 | else => return self.getResolvedInstValue(inst_index), | ||
| 4564 | } | 4567 | } |
| 4568 | |||
| 4569 | return self.genTypedValue(.{ | ||
| 4570 | .ty = ty, | ||
| 4571 | .val = (try self.air.value(ref, mod)).?, | ||
| 4572 | }); | ||
| 4565 | } | 4573 | } |
| 4566 | 4574 | ||
| 4567 | fn ret(self: *Self, mcv: MCValue) !void { | 4575 | fn ret(self: *Self, mcv: MCValue) !void { |
| 4568 | const ret_ty = self.fn_type.fnReturnType(); | 4576 | const mod = self.bin_file.options.module.?; |
| 4577 | const ret_ty = self.fn_type.fnReturnType(mod); | ||
| 4569 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); | 4578 | try self.setRegOrMem(ret_ty, self.ret_mcv, mcv); |
| 4570 | 4579 | ||
| 4571 | // Just add space for a branch instruction, patch this later | 4580 | // Just add space for a branch instruction, patch this later |
| ... | @@ -4638,7 +4647,7 @@ fn spillConditionFlagsIfOccupied(self: *Self) !void { | ... | @@ -4638,7 +4647,7 @@ fn spillConditionFlagsIfOccupied(self: *Self) !void { |
| 4638 | else => unreachable, // mcv doesn't occupy the compare flags | 4647 | else => unreachable, // mcv doesn't occupy the compare flags |
| 4639 | }; | 4648 | }; |
| 4640 | 4649 | ||
| 4641 | try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); | 4650 | try self.setRegOrMem(self.typeOfIndex(inst_to_save), new_mcv, mcv); |
| 4642 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); | 4651 | log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); |
| 4643 | 4652 | ||
| 4644 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 4653 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| ... | @@ -4662,11 +4671,12 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -4662,11 +4671,12 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 4662 | assert(reg == reg_mcv.register); | 4671 | assert(reg == reg_mcv.register); |
| 4663 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; | 4672 | const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; |
| 4664 | try branch.inst_table.put(self.gpa, inst, stack_mcv); | 4673 | try branch.inst_table.put(self.gpa, inst, stack_mcv); |
| 4665 | try self.genSetStack(self.air.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); | 4674 | try self.genSetStack(self.typeOfIndex(inst), stack_mcv.stack_offset, reg_mcv); |
| 4666 | } | 4675 | } |
| 4667 | 4676 | ||
| 4668 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { | 4677 | fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void { |
| 4669 | const abi_size = value_ty.abiSize(self.target.*); | 4678 | const mod = self.bin_file.options.module.?; |
| 4679 | const abi_size = value_ty.abiSize(mod); | ||
| 4670 | 4680 | ||
| 4671 | switch (ptr) { | 4681 | switch (ptr) { |
| 4672 | .none => unreachable, | 4682 | .none => unreachable, |
| ... | @@ -4707,10 +4717,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -4707,10 +4717,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 4707 | 4717 | ||
| 4708 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { | 4718 | fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 4709 | return if (self.liveness.isUnused(inst)) .dead else result: { | 4719 | return if (self.liveness.isUnused(inst)) .dead else result: { |
| 4720 | const mod = self.bin_file.options.module.?; | ||
| 4710 | const mcv = try self.resolveInst(operand); | 4721 | const mcv = try self.resolveInst(operand); |
| 4711 | const ptr_ty = self.air.typeOf(operand); | 4722 | const ptr_ty = self.typeOf(operand); |
| 4712 | const struct_ty = ptr_ty.childType(); | 4723 | const struct_ty = ptr_ty.childType(mod); |
| 4713 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); | 4724 | const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, mod)); |
| 4714 | switch (mcv) { | 4725 | switch (mcv) { |
| 4715 | .ptr_stack_offset => |off| { | 4726 | .ptr_stack_offset => |off| { |
| 4716 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; | 4727 | break :result MCValue{ .ptr_stack_offset = off - struct_field_offset }; |
| ... | @@ -4748,8 +4759,9 @@ fn trunc( | ... | @@ -4748,8 +4759,9 @@ fn trunc( |
| 4748 | operand_ty: Type, | 4759 | operand_ty: Type, |
| 4749 | dest_ty: Type, | 4760 | dest_ty: Type, |
| 4750 | ) !MCValue { | 4761 | ) !MCValue { |
| 4751 | const info_a = operand_ty.intInfo(self.target.*); | 4762 | const mod = self.bin_file.options.module.?; |
| 4752 | const info_b = dest_ty.intInfo(self.target.*); | 4763 | const info_a = operand_ty.intInfo(mod); |
| 4764 | const info_b = dest_ty.intInfo(mod); | ||
| 4753 | 4765 | ||
| 4754 | if (info_b.bits <= 64) { | 4766 | if (info_b.bits <= 64) { |
| 4755 | const operand_reg = switch (operand) { | 4767 | const operand_reg = switch (operand) { |
| ... | @@ -4866,3 +4878,13 @@ fn wantSafety(self: *Self) bool { | ... | @@ -4866,3 +4878,13 @@ fn wantSafety(self: *Self) bool { |
| 4866 | .ReleaseSmall => false, | 4878 | .ReleaseSmall => false, |
| 4867 | }; | 4879 | }; |
| 4868 | } | 4880 | } |
| 4881 | |||
| 4882 | fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { | ||
| 4883 | const mod = self.bin_file.options.module.?; | ||
| 4884 | return self.air.typeOf(inst, &mod.intern_pool); | ||
| 4885 | } | ||
| 4886 | |||
| 4887 | fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { | ||
| 4888 | const mod = self.bin_file.options.module.?; | ||
| 4889 | return self.air.typeOfIndex(inst, &mod.intern_pool); | ||
| 4890 | } |
src/arch/wasm/CodeGen.zig+1035-920| ... | @@ -11,6 +11,7 @@ const log = std.log.scoped(.codegen); | ... | @@ -11,6 +11,7 @@ const log = std.log.scoped(.codegen); |
| 11 | 11 | ||
| 12 | const codegen = @import("../../codegen.zig"); | 12 | const codegen = @import("../../codegen.zig"); |
| 13 | const Module = @import("../../Module.zig"); | 13 | const Module = @import("../../Module.zig"); |
| 14 | const InternPool = @import("../../InternPool.zig"); | ||
| 14 | const Decl = Module.Decl; | 15 | const Decl = Module.Decl; |
| 15 | const Type = @import("../../type.zig").Type; | 16 | const Type = @import("../../type.zig").Type; |
| 16 | const Value = @import("../../value.zig").Value; | 17 | const Value = @import("../../value.zig").Value; |
| ... | @@ -764,8 +765,9 @@ pub fn deinit(func: *CodeGen) void { | ... | @@ -764,8 +765,9 @@ pub fn deinit(func: *CodeGen) void { |
| 764 | 765 | ||
| 765 | /// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig | 766 | /// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig |
| 766 | fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) InnerError { | 767 | fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) InnerError { |
| 768 | const mod = func.bin_file.base.options.module.?; | ||
| 767 | const src = LazySrcLoc.nodeOffset(0); | 769 | const src = LazySrcLoc.nodeOffset(0); |
| 768 | const src_loc = src.toSrcLoc(func.decl); | 770 | const src_loc = src.toSrcLoc(func.decl, mod); |
| 769 | func.err_msg = try Module.ErrorMsg.create(func.gpa, src_loc, fmt, args); | 771 | func.err_msg = try Module.ErrorMsg.create(func.gpa, src_loc, fmt, args); |
| 770 | return error.CodegenFail; | 772 | return error.CodegenFail; |
| 771 | } | 773 | } |
| ... | @@ -788,9 +790,10 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { | ... | @@ -788,9 +790,10 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { |
| 788 | const gop = try func.branches.items[0].values.getOrPut(func.gpa, ref); | 790 | const gop = try func.branches.items[0].values.getOrPut(func.gpa, ref); |
| 789 | assert(!gop.found_existing); | 791 | assert(!gop.found_existing); |
| 790 | 792 | ||
| 791 | const val = func.air.value(ref).?; | 793 | const mod = func.bin_file.base.options.module.?; |
| 792 | const ty = func.air.typeOf(ref); | 794 | const val = (try func.air.value(ref, mod)).?; |
| 793 | if (!ty.hasRuntimeBitsIgnoreComptime() and !ty.isInt() and !ty.isError()) { | 795 | const ty = func.typeOf(ref); |
| 796 | if (!ty.hasRuntimeBitsIgnoreComptime(mod) and !ty.isInt(mod) and !ty.isError(mod)) { | ||
| 794 | gop.value_ptr.* = WValue{ .none = {} }; | 797 | gop.value_ptr.* = WValue{ .none = {} }; |
| 795 | return gop.value_ptr.*; | 798 | return gop.value_ptr.*; |
| 796 | } | 799 | } |
| ... | @@ -801,7 +804,7 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { | ... | @@ -801,7 +804,7 @@ fn resolveInst(func: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { |
| 801 | // | 804 | // |
| 802 | // In the other cases, we will simply lower the constant to a value that fits | 805 | // In the other cases, we will simply lower the constant to a value that fits |
| 803 | // into a single local (such as a pointer, integer, bool, etc). | 806 | // into a single local (such as a pointer, integer, bool, etc). |
| 804 | const result = if (isByRef(ty, func.target)) blk: { | 807 | const result = if (isByRef(ty, mod)) blk: { |
| 805 | const sym_index = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, func.decl_index); | 808 | const sym_index = try func.bin_file.lowerUnnamedConst(.{ .ty = ty, .val = val }, func.decl_index); |
| 806 | break :blk WValue{ .memory = sym_index }; | 809 | break :blk WValue{ .memory = sym_index }; |
| 807 | } else try func.lowerConstant(val, ty); | 810 | } else try func.lowerConstant(val, ty); |
| ... | @@ -880,7 +883,7 @@ fn iterateBigTomb(func: *CodeGen, inst: Air.Inst.Index, operand_count: usize) !B | ... | @@ -880,7 +883,7 @@ fn iterateBigTomb(func: *CodeGen, inst: Air.Inst.Index, operand_count: usize) !B |
| 880 | 883 | ||
| 881 | fn processDeath(func: *CodeGen, ref: Air.Inst.Ref) void { | 884 | fn processDeath(func: *CodeGen, ref: Air.Inst.Ref) void { |
| 882 | const inst = Air.refToIndex(ref) orelse return; | 885 | const inst = Air.refToIndex(ref) orelse return; |
| 883 | if (func.air.instructions.items(.tag)[inst] == .constant) return; | 886 | assert(func.air.instructions.items(.tag)[inst] != .interned); |
| 884 | // Branches are currently only allowed to free locals allocated | 887 | // Branches are currently only allowed to free locals allocated |
| 885 | // within their own branch. | 888 | // within their own branch. |
| 886 | // TODO: Upon branch consolidation free any locals if needed. | 889 | // TODO: Upon branch consolidation free any locals if needed. |
| ... | @@ -987,8 +990,9 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 | ... | @@ -987,8 +990,9 @@ fn addExtraAssumeCapacity(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 |
| 987 | } | 990 | } |
| 988 | 991 | ||
| 989 | /// Using a given `Type`, returns the corresponding type | 992 | /// Using a given `Type`, returns the corresponding type |
| 990 | fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { | 993 | fn typeToValtype(ty: Type, mod: *Module) wasm.Valtype { |
| 991 | return switch (ty.zigTypeTag()) { | 994 | const target = mod.getTarget(); |
| 995 | return switch (ty.zigTypeTag(mod)) { | ||
| 992 | .Float => blk: { | 996 | .Float => blk: { |
| 993 | const bits = ty.floatBits(target); | 997 | const bits = ty.floatBits(target); |
| 994 | if (bits == 16) return wasm.Valtype.i32; // stored/loaded as u16 | 998 | if (bits == 16) return wasm.Valtype.i32; // stored/loaded as u16 |
| ... | @@ -998,30 +1002,26 @@ fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { | ... | @@ -998,30 +1002,26 @@ fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { |
| 998 | return wasm.Valtype.i32; // represented as pointer to stack | 1002 | return wasm.Valtype.i32; // represented as pointer to stack |
| 999 | }, | 1003 | }, |
| 1000 | .Int, .Enum => blk: { | 1004 | .Int, .Enum => blk: { |
| 1001 | const info = ty.intInfo(target); | 1005 | const info = ty.intInfo(mod); |
| 1002 | if (info.bits <= 32) break :blk wasm.Valtype.i32; | 1006 | if (info.bits <= 32) break :blk wasm.Valtype.i32; |
| 1003 | if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64; | 1007 | if (info.bits > 32 and info.bits <= 128) break :blk wasm.Valtype.i64; |
| 1004 | break :blk wasm.Valtype.i32; // represented as pointer to stack | 1008 | break :blk wasm.Valtype.i32; // represented as pointer to stack |
| 1005 | }, | 1009 | }, |
| 1006 | .Struct => switch (ty.containerLayout()) { | 1010 | .Struct => switch (ty.containerLayout(mod)) { |
| 1007 | .Packed => { | 1011 | .Packed => { |
| 1008 | const struct_obj = ty.castTag(.@"struct").?.data; | 1012 | const struct_obj = mod.typeToStruct(ty).?; |
| 1009 | return typeToValtype(struct_obj.backing_int_ty, target); | 1013 | return typeToValtype(struct_obj.backing_int_ty, mod); |
| 1010 | }, | 1014 | }, |
| 1011 | else => wasm.Valtype.i32, | 1015 | else => wasm.Valtype.i32, |
| 1012 | }, | 1016 | }, |
| 1013 | .Vector => switch (determineSimdStoreStrategy(ty, target)) { | 1017 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { |
| 1014 | .direct => wasm.Valtype.v128, | 1018 | .direct => wasm.Valtype.v128, |
| 1015 | .unrolled => wasm.Valtype.i32, | 1019 | .unrolled => wasm.Valtype.i32, |
| 1016 | }, | 1020 | }, |
| 1017 | .Union => switch (ty.containerLayout()) { | 1021 | .Union => switch (ty.containerLayout(mod)) { |
| 1018 | .Packed => { | 1022 | .Packed => { |
| 1019 | var int_ty_payload: Type.Payload.Bits = .{ | 1023 | const int_ty = mod.intType(.unsigned, @intCast(u16, ty.bitSize(mod))) catch @panic("out of memory"); |
| 1020 | .base = .{ .tag = .int_unsigned }, | 1024 | return typeToValtype(int_ty, mod); |
| 1021 | .data = @intCast(u16, ty.bitSize(target)), | ||
| 1022 | }; | ||
| 1023 | const int_ty = Type.initPayload(&int_ty_payload.base); | ||
| 1024 | return typeToValtype(int_ty, target); | ||
| 1025 | }, | 1025 | }, |
| 1026 | else => wasm.Valtype.i32, | 1026 | else => wasm.Valtype.i32, |
| 1027 | }, | 1027 | }, |
| ... | @@ -1030,17 +1030,17 @@ fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { | ... | @@ -1030,17 +1030,17 @@ fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { |
| 1030 | } | 1030 | } |
| 1031 | 1031 | ||
| 1032 | /// Using a given `Type`, returns the byte representation of its wasm value type | 1032 | /// Using a given `Type`, returns the byte representation of its wasm value type |
| 1033 | fn genValtype(ty: Type, target: std.Target) u8 { | 1033 | fn genValtype(ty: Type, mod: *Module) u8 { |
| 1034 | return wasm.valtype(typeToValtype(ty, target)); | 1034 | return wasm.valtype(typeToValtype(ty, mod)); |
| 1035 | } | 1035 | } |
| 1036 | 1036 | ||
| 1037 | /// Using a given `Type`, returns the corresponding wasm value type | 1037 | /// Using a given `Type`, returns the corresponding wasm value type |
| 1038 | /// Differently from `genValtype` this also allows `void` to create a block | 1038 | /// Differently from `genValtype` this also allows `void` to create a block |
| 1039 | /// with no return type | 1039 | /// with no return type |
| 1040 | fn genBlockType(ty: Type, target: std.Target) u8 { | 1040 | fn genBlockType(ty: Type, mod: *Module) u8 { |
| 1041 | return switch (ty.tag()) { | 1041 | return switch (ty.ip_index) { |
| 1042 | .void, .noreturn => wasm.block_empty, | 1042 | .void_type, .noreturn_type => wasm.block_empty, |
| 1043 | else => genValtype(ty, target), | 1043 | else => genValtype(ty, mod), |
| 1044 | }; | 1044 | }; |
| 1045 | } | 1045 | } |
| 1046 | 1046 | ||
| ... | @@ -1101,7 +1101,8 @@ fn getResolvedInst(func: *CodeGen, ref: Air.Inst.Ref) *WValue { | ... | @@ -1101,7 +1101,8 @@ fn getResolvedInst(func: *CodeGen, ref: Air.Inst.Ref) *WValue { |
| 1101 | /// Creates one locals for a given `Type`. | 1101 | /// Creates one locals for a given `Type`. |
| 1102 | /// Returns a corresponding `Wvalue` with `local` as active tag | 1102 | /// Returns a corresponding `Wvalue` with `local` as active tag |
| 1103 | fn allocLocal(func: *CodeGen, ty: Type) InnerError!WValue { | 1103 | fn allocLocal(func: *CodeGen, ty: Type) InnerError!WValue { |
| 1104 | const valtype = typeToValtype(ty, func.target); | 1104 | const mod = func.bin_file.base.options.module.?; |
| 1105 | const valtype = typeToValtype(ty, mod); | ||
| 1105 | switch (valtype) { | 1106 | switch (valtype) { |
| 1106 | .i32 => if (func.free_locals_i32.popOrNull()) |index| { | 1107 | .i32 => if (func.free_locals_i32.popOrNull()) |index| { |
| 1107 | log.debug("reusing local ({d}) of type {}", .{ index, valtype }); | 1108 | log.debug("reusing local ({d}) of type {}", .{ index, valtype }); |
| ... | @@ -1132,7 +1133,8 @@ fn allocLocal(func: *CodeGen, ty: Type) InnerError!WValue { | ... | @@ -1132,7 +1133,8 @@ fn allocLocal(func: *CodeGen, ty: Type) InnerError!WValue { |
| 1132 | /// Ensures a new local will be created. This is useful when it's useful | 1133 | /// Ensures a new local will be created. This is useful when it's useful |
| 1133 | /// to use a zero-initialized local. | 1134 | /// to use a zero-initialized local. |
| 1134 | fn ensureAllocLocal(func: *CodeGen, ty: Type) InnerError!WValue { | 1135 | fn ensureAllocLocal(func: *CodeGen, ty: Type) InnerError!WValue { |
| 1135 | try func.locals.append(func.gpa, genValtype(ty, func.target)); | 1136 | const mod = func.bin_file.base.options.module.?; |
| 1137 | try func.locals.append(func.gpa, genValtype(ty, mod)); | ||
| 1136 | const initial_index = func.local_index; | 1138 | const initial_index = func.local_index; |
| 1137 | func.local_index += 1; | 1139 | func.local_index += 1; |
| 1138 | return WValue{ .local = .{ .value = initial_index, .references = 1 } }; | 1140 | return WValue{ .local = .{ .value = initial_index, .references = 1 } }; |
| ... | @@ -1140,48 +1142,55 @@ fn ensureAllocLocal(func: *CodeGen, ty: Type) InnerError!WValue { | ... | @@ -1140,48 +1142,55 @@ fn ensureAllocLocal(func: *CodeGen, ty: Type) InnerError!WValue { |
| 1140 | 1142 | ||
| 1141 | /// Generates a `wasm.Type` from a given function type. | 1143 | /// Generates a `wasm.Type` from a given function type. |
| 1142 | /// Memory is owned by the caller. | 1144 | /// Memory is owned by the caller. |
| 1143 | fn genFunctype(gpa: Allocator, cc: std.builtin.CallingConvention, params: []const Type, return_type: Type, target: std.Target) !wasm.Type { | 1145 | fn genFunctype( |
| 1146 | gpa: Allocator, | ||
| 1147 | cc: std.builtin.CallingConvention, | ||
| 1148 | params: []const InternPool.Index, | ||
| 1149 | return_type: Type, | ||
| 1150 | mod: *Module, | ||
| 1151 | ) !wasm.Type { | ||
| 1144 | var temp_params = std.ArrayList(wasm.Valtype).init(gpa); | 1152 | var temp_params = std.ArrayList(wasm.Valtype).init(gpa); |
| 1145 | defer temp_params.deinit(); | 1153 | defer temp_params.deinit(); |
| 1146 | var returns = std.ArrayList(wasm.Valtype).init(gpa); | 1154 | var returns = std.ArrayList(wasm.Valtype).init(gpa); |
| 1147 | defer returns.deinit(); | 1155 | defer returns.deinit(); |
| 1148 | 1156 | ||
| 1149 | if (firstParamSRet(cc, return_type, target)) { | 1157 | if (firstParamSRet(cc, return_type, mod)) { |
| 1150 | try temp_params.append(.i32); // memory address is always a 32-bit handle | 1158 | try temp_params.append(.i32); // memory address is always a 32-bit handle |
| 1151 | } else if (return_type.hasRuntimeBitsIgnoreComptime()) { | 1159 | } else if (return_type.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1152 | if (cc == .C) { | 1160 | if (cc == .C) { |
| 1153 | const res_classes = abi.classifyType(return_type, target); | 1161 | const res_classes = abi.classifyType(return_type, mod); |
| 1154 | assert(res_classes[0] == .direct and res_classes[1] == .none); | 1162 | assert(res_classes[0] == .direct and res_classes[1] == .none); |
| 1155 | const scalar_type = abi.scalarType(return_type, target); | 1163 | const scalar_type = abi.scalarType(return_type, mod); |
| 1156 | try returns.append(typeToValtype(scalar_type, target)); | 1164 | try returns.append(typeToValtype(scalar_type, mod)); |
| 1157 | } else { | 1165 | } else { |
| 1158 | try returns.append(typeToValtype(return_type, target)); | 1166 | try returns.append(typeToValtype(return_type, mod)); |
| 1159 | } | 1167 | } |
| 1160 | } else if (return_type.isError()) { | 1168 | } else if (return_type.isError(mod)) { |
| 1161 | try returns.append(.i32); | 1169 | try returns.append(.i32); |
| 1162 | } | 1170 | } |
| 1163 | 1171 | ||
| 1164 | // param types | 1172 | // param types |
| 1165 | for (params) |param_type| { | 1173 | for (params) |param_type_ip| { |
| 1166 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | 1174 | const param_type = param_type_ip.toType(); |
| 1175 | if (!param_type.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1167 | 1176 | ||
| 1168 | switch (cc) { | 1177 | switch (cc) { |
| 1169 | .C => { | 1178 | .C => { |
| 1170 | const param_classes = abi.classifyType(param_type, target); | 1179 | const param_classes = abi.classifyType(param_type, mod); |
| 1171 | for (param_classes) |class| { | 1180 | for (param_classes) |class| { |
| 1172 | if (class == .none) continue; | 1181 | if (class == .none) continue; |
| 1173 | if (class == .direct) { | 1182 | if (class == .direct) { |
| 1174 | const scalar_type = abi.scalarType(param_type, target); | 1183 | const scalar_type = abi.scalarType(param_type, mod); |
| 1175 | try temp_params.append(typeToValtype(scalar_type, target)); | 1184 | try temp_params.append(typeToValtype(scalar_type, mod)); |
| 1176 | } else { | 1185 | } else { |
| 1177 | try temp_params.append(typeToValtype(param_type, target)); | 1186 | try temp_params.append(typeToValtype(param_type, mod)); |
| 1178 | } | 1187 | } |
| 1179 | } | 1188 | } |
| 1180 | }, | 1189 | }, |
| 1181 | else => if (isByRef(param_type, target)) | 1190 | else => if (isByRef(param_type, mod)) |
| 1182 | try temp_params.append(.i32) | 1191 | try temp_params.append(.i32) |
| 1183 | else | 1192 | else |
| 1184 | try temp_params.append(typeToValtype(param_type, target)), | 1193 | try temp_params.append(typeToValtype(param_type, mod)), |
| 1185 | } | 1194 | } |
| 1186 | } | 1195 | } |
| 1187 | 1196 | ||
| ... | @@ -1194,20 +1203,22 @@ fn genFunctype(gpa: Allocator, cc: std.builtin.CallingConvention, params: []cons | ... | @@ -1194,20 +1203,22 @@ fn genFunctype(gpa: Allocator, cc: std.builtin.CallingConvention, params: []cons |
| 1194 | pub fn generate( | 1203 | pub fn generate( |
| 1195 | bin_file: *link.File, | 1204 | bin_file: *link.File, |
| 1196 | src_loc: Module.SrcLoc, | 1205 | src_loc: Module.SrcLoc, |
| 1197 | func: *Module.Fn, | 1206 | func_index: Module.Fn.Index, |
| 1198 | air: Air, | 1207 | air: Air, |
| 1199 | liveness: Liveness, | 1208 | liveness: Liveness, |
| 1200 | code: *std.ArrayList(u8), | 1209 | code: *std.ArrayList(u8), |
| 1201 | debug_output: codegen.DebugInfoOutput, | 1210 | debug_output: codegen.DebugInfoOutput, |
| 1202 | ) codegen.CodeGenError!codegen.Result { | 1211 | ) codegen.CodeGenError!codegen.Result { |
| 1203 | _ = src_loc; | 1212 | _ = src_loc; |
| 1213 | const mod = bin_file.options.module.?; | ||
| 1214 | const func = mod.funcPtr(func_index); | ||
| 1204 | var code_gen: CodeGen = .{ | 1215 | var code_gen: CodeGen = .{ |
| 1205 | .gpa = bin_file.allocator, | 1216 | .gpa = bin_file.allocator, |
| 1206 | .air = air, | 1217 | .air = air, |
| 1207 | .liveness = liveness, | 1218 | .liveness = liveness, |
| 1208 | .code = code, | 1219 | .code = code, |
| 1209 | .decl_index = func.owner_decl, | 1220 | .decl_index = func.owner_decl, |
| 1210 | .decl = bin_file.options.module.?.declPtr(func.owner_decl), | 1221 | .decl = mod.declPtr(func.owner_decl), |
| 1211 | .err_msg = undefined, | 1222 | .err_msg = undefined, |
| 1212 | .locals = .{}, | 1223 | .locals = .{}, |
| 1213 | .target = bin_file.options.target, | 1224 | .target = bin_file.options.target, |
| ... | @@ -1226,8 +1237,9 @@ pub fn generate( | ... | @@ -1226,8 +1237,9 @@ pub fn generate( |
| 1226 | } | 1237 | } |
| 1227 | 1238 | ||
| 1228 | fn genFunc(func: *CodeGen) InnerError!void { | 1239 | fn genFunc(func: *CodeGen) InnerError!void { |
| 1229 | const fn_info = func.decl.ty.fnInfo(); | 1240 | const mod = func.bin_file.base.options.module.?; |
| 1230 | var func_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types, fn_info.return_type, func.target); | 1241 | const fn_info = mod.typeToFunc(func.decl.ty).?; |
| 1242 | var func_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types, fn_info.return_type.toType(), mod); | ||
| 1231 | defer func_type.deinit(func.gpa); | 1243 | defer func_type.deinit(func.gpa); |
| 1232 | _ = try func.bin_file.storeDeclType(func.decl_index, func_type); | 1244 | _ = try func.bin_file.storeDeclType(func.decl_index, func_type); |
| 1233 | 1245 | ||
| ... | @@ -1253,8 +1265,8 @@ fn genFunc(func: *CodeGen) InnerError!void { | ... | @@ -1253,8 +1265,8 @@ fn genFunc(func: *CodeGen) InnerError!void { |
| 1253 | // we emit an unreachable instruction to tell the stack validator that part will never be reached. | 1265 | // we emit an unreachable instruction to tell the stack validator that part will never be reached. |
| 1254 | if (func_type.returns.len != 0 and func.air.instructions.len > 0) { | 1266 | if (func_type.returns.len != 0 and func.air.instructions.len > 0) { |
| 1255 | const inst = @intCast(u32, func.air.instructions.len - 1); | 1267 | const inst = @intCast(u32, func.air.instructions.len - 1); |
| 1256 | const last_inst_ty = func.air.typeOfIndex(inst); | 1268 | const last_inst_ty = func.typeOfIndex(inst); |
| 1257 | if (!last_inst_ty.hasRuntimeBitsIgnoreComptime() or last_inst_ty.isNoReturn()) { | 1269 | if (!last_inst_ty.hasRuntimeBitsIgnoreComptime(mod) or last_inst_ty.isNoReturn(mod)) { |
| 1258 | try func.addTag(.@"unreachable"); | 1270 | try func.addTag(.@"unreachable"); |
| 1259 | } | 1271 | } |
| 1260 | } | 1272 | } |
| ... | @@ -1335,10 +1347,9 @@ const CallWValues = struct { | ... | @@ -1335,10 +1347,9 @@ const CallWValues = struct { |
| 1335 | }; | 1347 | }; |
| 1336 | 1348 | ||
| 1337 | fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWValues { | 1349 | fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWValues { |
| 1338 | const cc = fn_ty.fnCallingConvention(); | 1350 | const mod = func.bin_file.base.options.module.?; |
| 1339 | const param_types = try func.gpa.alloc(Type, fn_ty.fnParamLen()); | 1351 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 1340 | defer func.gpa.free(param_types); | 1352 | const cc = fn_info.cc; |
| 1341 | fn_ty.fnParamTypes(param_types); | ||
| 1342 | var result: CallWValues = .{ | 1353 | var result: CallWValues = .{ |
| 1343 | .args = &.{}, | 1354 | .args = &.{}, |
| 1344 | .return_value = .none, | 1355 | .return_value = .none, |
| ... | @@ -1350,8 +1361,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV | ... | @@ -1350,8 +1361,7 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV |
| 1350 | 1361 | ||
| 1351 | // Check if we store the result as a pointer to the stack rather than | 1362 | // Check if we store the result as a pointer to the stack rather than |
| 1352 | // by value | 1363 | // by value |
| 1353 | const fn_info = fn_ty.fnInfo(); | 1364 | if (firstParamSRet(fn_info.cc, fn_info.return_type.toType(), mod)) { |
| 1354 | if (firstParamSRet(fn_info.cc, fn_info.return_type, func.target)) { | ||
| 1355 | // the sret arg will be passed as first argument, therefore we | 1365 | // the sret arg will be passed as first argument, therefore we |
| 1356 | // set the `return_value` before allocating locals for regular args. | 1366 | // set the `return_value` before allocating locals for regular args. |
| 1357 | result.return_value = .{ .local = .{ .value = func.local_index, .references = 1 } }; | 1367 | result.return_value = .{ .local = .{ .value = func.local_index, .references = 1 } }; |
| ... | @@ -1360,8 +1370,8 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV | ... | @@ -1360,8 +1370,8 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV |
| 1360 | 1370 | ||
| 1361 | switch (cc) { | 1371 | switch (cc) { |
| 1362 | .Unspecified => { | 1372 | .Unspecified => { |
| 1363 | for (param_types) |ty| { | 1373 | for (fn_info.param_types) |ty| { |
| 1364 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | 1374 | if (!ty.toType().hasRuntimeBitsIgnoreComptime(mod)) { |
| 1365 | continue; | 1375 | continue; |
| 1366 | } | 1376 | } |
| 1367 | 1377 | ||
| ... | @@ -1370,8 +1380,8 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV | ... | @@ -1370,8 +1380,8 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV |
| 1370 | } | 1380 | } |
| 1371 | }, | 1381 | }, |
| 1372 | .C => { | 1382 | .C => { |
| 1373 | for (param_types) |ty| { | 1383 | for (fn_info.param_types) |ty| { |
| 1374 | const ty_classes = abi.classifyType(ty, func.target); | 1384 | const ty_classes = abi.classifyType(ty.toType(), mod); |
| 1375 | for (ty_classes) |class| { | 1385 | for (ty_classes) |class| { |
| 1376 | if (class == .none) continue; | 1386 | if (class == .none) continue; |
| 1377 | try args.append(.{ .local = .{ .value = func.local_index, .references = 1 } }); | 1387 | try args.append(.{ .local = .{ .value = func.local_index, .references = 1 } }); |
| ... | @@ -1385,11 +1395,11 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV | ... | @@ -1385,11 +1395,11 @@ fn resolveCallingConventionValues(func: *CodeGen, fn_ty: Type) InnerError!CallWV |
| 1385 | return result; | 1395 | return result; |
| 1386 | } | 1396 | } |
| 1387 | 1397 | ||
| 1388 | fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, target: std.Target) bool { | 1398 | fn firstParamSRet(cc: std.builtin.CallingConvention, return_type: Type, mod: *Module) bool { |
| 1389 | switch (cc) { | 1399 | switch (cc) { |
| 1390 | .Unspecified, .Inline => return isByRef(return_type, target), | 1400 | .Unspecified, .Inline => return isByRef(return_type, mod), |
| 1391 | .C => { | 1401 | .C => { |
| 1392 | const ty_classes = abi.classifyType(return_type, target); | 1402 | const ty_classes = abi.classifyType(return_type, mod); |
| 1393 | if (ty_classes[0] == .indirect) return true; | 1403 | if (ty_classes[0] == .indirect) return true; |
| 1394 | if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true; | 1404 | if (ty_classes[0] == .direct and ty_classes[1] == .direct) return true; |
| 1395 | return false; | 1405 | return false; |
| ... | @@ -1405,16 +1415,17 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: | ... | @@ -1405,16 +1415,17 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: |
| 1405 | return func.lowerToStack(value); | 1415 | return func.lowerToStack(value); |
| 1406 | } | 1416 | } |
| 1407 | 1417 | ||
| 1408 | const ty_classes = abi.classifyType(ty, func.target); | 1418 | const mod = func.bin_file.base.options.module.?; |
| 1419 | const ty_classes = abi.classifyType(ty, mod); | ||
| 1409 | assert(ty_classes[0] != .none); | 1420 | assert(ty_classes[0] != .none); |
| 1410 | switch (ty.zigTypeTag()) { | 1421 | switch (ty.zigTypeTag(mod)) { |
| 1411 | .Struct, .Union => { | 1422 | .Struct, .Union => { |
| 1412 | if (ty_classes[0] == .indirect) { | 1423 | if (ty_classes[0] == .indirect) { |
| 1413 | return func.lowerToStack(value); | 1424 | return func.lowerToStack(value); |
| 1414 | } | 1425 | } |
| 1415 | assert(ty_classes[0] == .direct); | 1426 | assert(ty_classes[0] == .direct); |
| 1416 | const scalar_type = abi.scalarType(ty, func.target); | 1427 | const scalar_type = abi.scalarType(ty, mod); |
| 1417 | const abi_size = scalar_type.abiSize(func.target); | 1428 | const abi_size = scalar_type.abiSize(mod); |
| 1418 | try func.emitWValue(value); | 1429 | try func.emitWValue(value); |
| 1419 | 1430 | ||
| 1420 | // When the value lives in the virtual stack, we must load it onto the actual stack | 1431 | // When the value lives in the virtual stack, we must load it onto the actual stack |
| ... | @@ -1422,12 +1433,12 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: | ... | @@ -1422,12 +1433,12 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: |
| 1422 | const opcode = buildOpcode(.{ | 1433 | const opcode = buildOpcode(.{ |
| 1423 | .op = .load, | 1434 | .op = .load, |
| 1424 | .width = @intCast(u8, abi_size), | 1435 | .width = @intCast(u8, abi_size), |
| 1425 | .signedness = if (scalar_type.isSignedInt()) .signed else .unsigned, | 1436 | .signedness = if (scalar_type.isSignedInt(mod)) .signed else .unsigned, |
| 1426 | .valtype1 = typeToValtype(scalar_type, func.target), | 1437 | .valtype1 = typeToValtype(scalar_type, mod), |
| 1427 | }); | 1438 | }); |
| 1428 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ | 1439 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 1429 | .offset = value.offset(), | 1440 | .offset = value.offset(), |
| 1430 | .alignment = scalar_type.abiAlignment(func.target), | 1441 | .alignment = scalar_type.abiAlignment(mod), |
| 1431 | }); | 1442 | }); |
| 1432 | } | 1443 | } |
| 1433 | }, | 1444 | }, |
| ... | @@ -1436,7 +1447,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: | ... | @@ -1436,7 +1447,7 @@ fn lowerArg(func: *CodeGen, cc: std.builtin.CallingConvention, ty: Type, value: |
| 1436 | return func.lowerToStack(value); | 1447 | return func.lowerToStack(value); |
| 1437 | } | 1448 | } |
| 1438 | assert(ty_classes[0] == .direct and ty_classes[1] == .direct); | 1449 | assert(ty_classes[0] == .direct and ty_classes[1] == .direct); |
| 1439 | assert(ty.abiSize(func.target) == 16); | 1450 | assert(ty.abiSize(mod) == 16); |
| 1440 | // in this case we have an integer or float that must be lowered as 2 i64's. | 1451 | // in this case we have an integer or float that must be lowered as 2 i64's. |
| 1441 | try func.emitWValue(value); | 1452 | try func.emitWValue(value); |
| 1442 | try func.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = 8 }); | 1453 | try func.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = 8 }); |
| ... | @@ -1503,18 +1514,18 @@ fn restoreStackPointer(func: *CodeGen) !void { | ... | @@ -1503,18 +1514,18 @@ fn restoreStackPointer(func: *CodeGen) !void { |
| 1503 | /// | 1514 | /// |
| 1504 | /// Asserts Type has codegenbits | 1515 | /// Asserts Type has codegenbits |
| 1505 | fn allocStack(func: *CodeGen, ty: Type) !WValue { | 1516 | fn allocStack(func: *CodeGen, ty: Type) !WValue { |
| 1506 | assert(ty.hasRuntimeBitsIgnoreComptime()); | 1517 | const mod = func.bin_file.base.options.module.?; |
| 1518 | assert(ty.hasRuntimeBitsIgnoreComptime(mod)); | ||
| 1507 | if (func.initial_stack_value == .none) { | 1519 | if (func.initial_stack_value == .none) { |
| 1508 | try func.initializeStack(); | 1520 | try func.initializeStack(); |
| 1509 | } | 1521 | } |
| 1510 | 1522 | ||
| 1511 | const abi_size = std.math.cast(u32, ty.abiSize(func.target)) orelse { | 1523 | const abi_size = std.math.cast(u32, ty.abiSize(mod)) orelse { |
| 1512 | const module = func.bin_file.base.options.module.?; | ||
| 1513 | return func.fail("Type {} with ABI size of {d} exceeds stack frame size", .{ | 1524 | return func.fail("Type {} with ABI size of {d} exceeds stack frame size", .{ |
| 1514 | ty.fmt(module), ty.abiSize(func.target), | 1525 | ty.fmt(mod), ty.abiSize(mod), |
| 1515 | }); | 1526 | }); |
| 1516 | }; | 1527 | }; |
| 1517 | const abi_align = ty.abiAlignment(func.target); | 1528 | const abi_align = ty.abiAlignment(mod); |
| 1518 | 1529 | ||
| 1519 | if (abi_align > func.stack_alignment) { | 1530 | if (abi_align > func.stack_alignment) { |
| 1520 | func.stack_alignment = abi_align; | 1531 | func.stack_alignment = abi_align; |
| ... | @@ -1531,22 +1542,22 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue { | ... | @@ -1531,22 +1542,22 @@ fn allocStack(func: *CodeGen, ty: Type) !WValue { |
| 1531 | /// This is different from allocStack where this will use the pointer's alignment | 1542 | /// This is different from allocStack where this will use the pointer's alignment |
| 1532 | /// if it is set, to ensure the stack alignment will be set correctly. | 1543 | /// if it is set, to ensure the stack alignment will be set correctly. |
| 1533 | fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue { | 1544 | fn allocStackPtr(func: *CodeGen, inst: Air.Inst.Index) !WValue { |
| 1534 | const ptr_ty = func.air.typeOfIndex(inst); | 1545 | const mod = func.bin_file.base.options.module.?; |
| 1535 | const pointee_ty = ptr_ty.childType(); | 1546 | const ptr_ty = func.typeOfIndex(inst); |
| 1547 | const pointee_ty = ptr_ty.childType(mod); | ||
| 1536 | 1548 | ||
| 1537 | if (func.initial_stack_value == .none) { | 1549 | if (func.initial_stack_value == .none) { |
| 1538 | try func.initializeStack(); | 1550 | try func.initializeStack(); |
| 1539 | } | 1551 | } |
| 1540 | 1552 | ||
| 1541 | if (!pointee_ty.hasRuntimeBitsIgnoreComptime()) { | 1553 | if (!pointee_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1542 | return func.allocStack(Type.usize); // create a value containing just the stack pointer. | 1554 | return func.allocStack(Type.usize); // create a value containing just the stack pointer. |
| 1543 | } | 1555 | } |
| 1544 | 1556 | ||
| 1545 | const abi_alignment = ptr_ty.ptrAlignment(func.target); | 1557 | const abi_alignment = ptr_ty.ptrAlignment(mod); |
| 1546 | const abi_size = std.math.cast(u32, pointee_ty.abiSize(func.target)) orelse { | 1558 | const abi_size = std.math.cast(u32, pointee_ty.abiSize(mod)) orelse { |
| 1547 | const module = func.bin_file.base.options.module.?; | ||
| 1548 | return func.fail("Type {} with ABI size of {d} exceeds stack frame size", .{ | 1559 | return func.fail("Type {} with ABI size of {d} exceeds stack frame size", .{ |
| 1549 | pointee_ty.fmt(module), pointee_ty.abiSize(func.target), | 1560 | pointee_ty.fmt(mod), pointee_ty.abiSize(mod), |
| 1550 | }); | 1561 | }); |
| 1551 | }; | 1562 | }; |
| 1552 | if (abi_alignment > func.stack_alignment) { | 1563 | if (abi_alignment > func.stack_alignment) { |
| ... | @@ -1704,8 +1715,9 @@ fn arch(func: *const CodeGen) std.Target.Cpu.Arch { | ... | @@ -1704,8 +1715,9 @@ fn arch(func: *const CodeGen) std.Target.Cpu.Arch { |
| 1704 | 1715 | ||
| 1705 | /// For a given `Type`, will return true when the type will be passed | 1716 | /// For a given `Type`, will return true when the type will be passed |
| 1706 | /// by reference, rather than by value | 1717 | /// by reference, rather than by value |
| 1707 | fn isByRef(ty: Type, target: std.Target) bool { | 1718 | fn isByRef(ty: Type, mod: *Module) bool { |
| 1708 | switch (ty.zigTypeTag()) { | 1719 | const target = mod.getTarget(); |
| 1720 | switch (ty.zigTypeTag(mod)) { | ||
| 1709 | .Type, | 1721 | .Type, |
| 1710 | .ComptimeInt, | 1722 | .ComptimeInt, |
| 1711 | .ComptimeFloat, | 1723 | .ComptimeFloat, |
| ... | @@ -1726,44 +1738,42 @@ fn isByRef(ty: Type, target: std.Target) bool { | ... | @@ -1726,44 +1738,42 @@ fn isByRef(ty: Type, target: std.Target) bool { |
| 1726 | 1738 | ||
| 1727 | .Array, | 1739 | .Array, |
| 1728 | .Frame, | 1740 | .Frame, |
| 1729 | => return ty.hasRuntimeBitsIgnoreComptime(), | 1741 | => return ty.hasRuntimeBitsIgnoreComptime(mod), |
| 1730 | .Union => { | 1742 | .Union => { |
| 1731 | if (ty.castTag(.@"union")) |union_ty| { | 1743 | if (mod.typeToUnion(ty)) |union_obj| { |
| 1732 | if (union_ty.data.layout == .Packed) { | 1744 | if (union_obj.layout == .Packed) { |
| 1733 | return ty.abiSize(target) > 8; | 1745 | return ty.abiSize(mod) > 8; |
| 1734 | } | 1746 | } |
| 1735 | } | 1747 | } |
| 1736 | return ty.hasRuntimeBitsIgnoreComptime(); | 1748 | return ty.hasRuntimeBitsIgnoreComptime(mod); |
| 1737 | }, | 1749 | }, |
| 1738 | .Struct => { | 1750 | .Struct => { |
| 1739 | if (ty.castTag(.@"struct")) |struct_ty| { | 1751 | if (mod.typeToStruct(ty)) |struct_obj| { |
| 1740 | const struct_obj = struct_ty.data; | ||
| 1741 | if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { | 1752 | if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { |
| 1742 | return isByRef(struct_obj.backing_int_ty, target); | 1753 | return isByRef(struct_obj.backing_int_ty, mod); |
| 1743 | } | 1754 | } |
| 1744 | } | 1755 | } |
| 1745 | return ty.hasRuntimeBitsIgnoreComptime(); | 1756 | return ty.hasRuntimeBitsIgnoreComptime(mod); |
| 1746 | }, | 1757 | }, |
| 1747 | .Vector => return determineSimdStoreStrategy(ty, target) == .unrolled, | 1758 | .Vector => return determineSimdStoreStrategy(ty, mod) == .unrolled, |
| 1748 | .Int => return ty.intInfo(target).bits > 64, | 1759 | .Int => return ty.intInfo(mod).bits > 64, |
| 1749 | .Float => return ty.floatBits(target) > 64, | 1760 | .Float => return ty.floatBits(target) > 64, |
| 1750 | .ErrorUnion => { | 1761 | .ErrorUnion => { |
| 1751 | const pl_ty = ty.errorUnionPayload(); | 1762 | const pl_ty = ty.errorUnionPayload(mod); |
| 1752 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { | 1763 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1753 | return false; | 1764 | return false; |
| 1754 | } | 1765 | } |
| 1755 | return true; | 1766 | return true; |
| 1756 | }, | 1767 | }, |
| 1757 | .Optional => { | 1768 | .Optional => { |
| 1758 | if (ty.isPtrLikeOptional()) return false; | 1769 | if (ty.isPtrLikeOptional(mod)) return false; |
| 1759 | var buf: Type.Payload.ElemType = undefined; | 1770 | const pl_type = ty.optionalChild(mod); |
| 1760 | const pl_type = ty.optionalChild(&buf); | 1771 | if (pl_type.zigTypeTag(mod) == .ErrorSet) return false; |
| 1761 | if (pl_type.zigTypeTag() == .ErrorSet) return false; | 1772 | return pl_type.hasRuntimeBitsIgnoreComptime(mod); |
| 1762 | return pl_type.hasRuntimeBitsIgnoreComptime(); | ||
| 1763 | }, | 1773 | }, |
| 1764 | .Pointer => { | 1774 | .Pointer => { |
| 1765 | // Slices act like struct and will be passed by reference | 1775 | // Slices act like struct and will be passed by reference |
| 1766 | if (ty.isSlice()) return true; | 1776 | if (ty.isSlice(mod)) return true; |
| 1767 | return false; | 1777 | return false; |
| 1768 | }, | 1778 | }, |
| 1769 | } | 1779 | } |
| ... | @@ -1778,10 +1788,11 @@ const SimdStoreStrategy = enum { | ... | @@ -1778,10 +1788,11 @@ const SimdStoreStrategy = enum { |
| 1778 | /// This means when a given type is 128 bits and either the simd128 or relaxed-simd | 1788 | /// This means when a given type is 128 bits and either the simd128 or relaxed-simd |
| 1779 | /// features are enabled, the function will return `.direct`. This would allow to store | 1789 | /// features are enabled, the function will return `.direct`. This would allow to store |
| 1780 | /// it using a instruction, rather than an unrolled version. | 1790 | /// it using a instruction, rather than an unrolled version. |
| 1781 | fn determineSimdStoreStrategy(ty: Type, target: std.Target) SimdStoreStrategy { | 1791 | fn determineSimdStoreStrategy(ty: Type, mod: *Module) SimdStoreStrategy { |
| 1782 | std.debug.assert(ty.zigTypeTag() == .Vector); | 1792 | std.debug.assert(ty.zigTypeTag(mod) == .Vector); |
| 1783 | if (ty.bitSize(target) != 128) return .unrolled; | 1793 | if (ty.bitSize(mod) != 128) return .unrolled; |
| 1784 | const hasFeature = std.Target.wasm.featureSetHas; | 1794 | const hasFeature = std.Target.wasm.featureSetHas; |
| 1795 | const target = mod.getTarget(); | ||
| 1785 | const features = target.cpu.features; | 1796 | const features = target.cpu.features; |
| 1786 | if (hasFeature(features, .relaxed_simd) or hasFeature(features, .simd128)) { | 1797 | if (hasFeature(features, .relaxed_simd) or hasFeature(features, .simd128)) { |
| 1787 | return .direct; | 1798 | return .direct; |
| ... | @@ -1821,8 +1832,7 @@ fn buildPointerOffset(func: *CodeGen, ptr_value: WValue, offset: u64, action: en | ... | @@ -1821,8 +1832,7 @@ fn buildPointerOffset(func: *CodeGen, ptr_value: WValue, offset: u64, action: en |
| 1821 | fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 1832 | fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1822 | const air_tags = func.air.instructions.items(.tag); | 1833 | const air_tags = func.air.instructions.items(.tag); |
| 1823 | return switch (air_tags[inst]) { | 1834 | return switch (air_tags[inst]) { |
| 1824 | .constant => unreachable, | 1835 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, |
| 1825 | .const_ty => unreachable, | ||
| 1826 | 1836 | ||
| 1827 | .add => func.airBinOp(inst, .add), | 1837 | .add => func.airBinOp(inst, .add), |
| 1828 | .add_sat => func.airSatBinOp(inst, .add), | 1838 | .add_sat => func.airSatBinOp(inst, .add), |
| ... | @@ -2062,8 +2072,11 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2062,8 +2072,11 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2062 | } | 2072 | } |
| 2063 | 2073 | ||
| 2064 | fn genBody(func: *CodeGen, body: []const Air.Inst.Index) InnerError!void { | 2074 | fn genBody(func: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 2075 | const mod = func.bin_file.base.options.module.?; | ||
| 2076 | const ip = &mod.intern_pool; | ||
| 2077 | |||
| 2065 | for (body) |inst| { | 2078 | for (body) |inst| { |
| 2066 | if (func.liveness.isUnused(inst) and !func.air.mustLower(inst)) { | 2079 | if (func.liveness.isUnused(inst) and !func.air.mustLower(inst, ip)) { |
| 2067 | continue; | 2080 | continue; |
| 2068 | } | 2081 | } |
| 2069 | const old_bookkeeping_value = func.air_bookkeeping; | 2082 | const old_bookkeeping_value = func.air_bookkeeping; |
| ... | @@ -2080,36 +2093,37 @@ fn genBody(func: *CodeGen, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -2080,36 +2093,37 @@ fn genBody(func: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 2080 | } | 2093 | } |
| 2081 | 2094 | ||
| 2082 | fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 2095 | fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2096 | const mod = func.bin_file.base.options.module.?; | ||
| 2083 | const un_op = func.air.instructions.items(.data)[inst].un_op; | 2097 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 2084 | const operand = try func.resolveInst(un_op); | 2098 | const operand = try func.resolveInst(un_op); |
| 2085 | const fn_info = func.decl.ty.fnInfo(); | 2099 | const fn_info = mod.typeToFunc(func.decl.ty).?; |
| 2086 | const ret_ty = fn_info.return_type; | 2100 | const ret_ty = fn_info.return_type.toType(); |
| 2087 | 2101 | ||
| 2088 | // result must be stored in the stack and we return a pointer | 2102 | // result must be stored in the stack and we return a pointer |
| 2089 | // to the stack instead | 2103 | // to the stack instead |
| 2090 | if (func.return_value != .none) { | 2104 | if (func.return_value != .none) { |
| 2091 | try func.store(func.return_value, operand, ret_ty, 0); | 2105 | try func.store(func.return_value, operand, ret_ty, 0); |
| 2092 | } else if (fn_info.cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime()) { | 2106 | } else if (fn_info.cc == .C and ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2093 | switch (ret_ty.zigTypeTag()) { | 2107 | switch (ret_ty.zigTypeTag(mod)) { |
| 2094 | // Aggregate types can be lowered as a singular value | 2108 | // Aggregate types can be lowered as a singular value |
| 2095 | .Struct, .Union => { | 2109 | .Struct, .Union => { |
| 2096 | const scalar_type = abi.scalarType(ret_ty, func.target); | 2110 | const scalar_type = abi.scalarType(ret_ty, mod); |
| 2097 | try func.emitWValue(operand); | 2111 | try func.emitWValue(operand); |
| 2098 | const opcode = buildOpcode(.{ | 2112 | const opcode = buildOpcode(.{ |
| 2099 | .op = .load, | 2113 | .op = .load, |
| 2100 | .width = @intCast(u8, scalar_type.abiSize(func.target) * 8), | 2114 | .width = @intCast(u8, scalar_type.abiSize(mod) * 8), |
| 2101 | .signedness = if (scalar_type.isSignedInt()) .signed else .unsigned, | 2115 | .signedness = if (scalar_type.isSignedInt(mod)) .signed else .unsigned, |
| 2102 | .valtype1 = typeToValtype(scalar_type, func.target), | 2116 | .valtype1 = typeToValtype(scalar_type, mod), |
| 2103 | }); | 2117 | }); |
| 2104 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ | 2118 | try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{ |
| 2105 | .offset = operand.offset(), | 2119 | .offset = operand.offset(), |
| 2106 | .alignment = scalar_type.abiAlignment(func.target), | 2120 | .alignment = scalar_type.abiAlignment(mod), |
| 2107 | }); | 2121 | }); |
| 2108 | }, | 2122 | }, |
| 2109 | else => try func.emitWValue(operand), | 2123 | else => try func.emitWValue(operand), |
| 2110 | } | 2124 | } |
| 2111 | } else { | 2125 | } else { |
| 2112 | if (!ret_ty.hasRuntimeBitsIgnoreComptime() and ret_ty.isError()) { | 2126 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod) and ret_ty.isError(mod)) { |
| 2113 | try func.addImm32(0); | 2127 | try func.addImm32(0); |
| 2114 | } else { | 2128 | } else { |
| 2115 | try func.emitWValue(operand); | 2129 | try func.emitWValue(operand); |
| ... | @@ -2122,15 +2136,16 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2122,15 +2136,16 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2122 | } | 2136 | } |
| 2123 | 2137 | ||
| 2124 | fn airRetPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 2138 | fn airRetPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2125 | const child_type = func.air.typeOfIndex(inst).childType(); | 2139 | const mod = func.bin_file.base.options.module.?; |
| 2140 | const child_type = func.typeOfIndex(inst).childType(mod); | ||
| 2126 | 2141 | ||
| 2127 | var result = result: { | 2142 | var result = result: { |
| 2128 | if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime()) { | 2143 | if (!child_type.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { |
| 2129 | break :result try func.allocStack(Type.usize); // create pointer to void | 2144 | break :result try func.allocStack(Type.usize); // create pointer to void |
| 2130 | } | 2145 | } |
| 2131 | 2146 | ||
| 2132 | const fn_info = func.decl.ty.fnInfo(); | 2147 | const fn_info = mod.typeToFunc(func.decl.ty).?; |
| 2133 | if (firstParamSRet(fn_info.cc, fn_info.return_type, func.target)) { | 2148 | if (firstParamSRet(fn_info.cc, fn_info.return_type.toType(), mod)) { |
| 2134 | break :result func.return_value; | 2149 | break :result func.return_value; |
| 2135 | } | 2150 | } |
| 2136 | 2151 | ||
| ... | @@ -2141,16 +2156,17 @@ fn airRetPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2141,16 +2156,17 @@ fn airRetPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2141 | } | 2156 | } |
| 2142 | 2157 | ||
| 2143 | fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 2158 | fn airRetLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2159 | const mod = func.bin_file.base.options.module.?; | ||
| 2144 | const un_op = func.air.instructions.items(.data)[inst].un_op; | 2160 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 2145 | const operand = try func.resolveInst(un_op); | 2161 | const operand = try func.resolveInst(un_op); |
| 2146 | const ret_ty = func.air.typeOf(un_op).childType(); | 2162 | const ret_ty = func.typeOf(un_op).childType(mod); |
| 2147 | 2163 | ||
| 2148 | const fn_info = func.decl.ty.fnInfo(); | 2164 | const fn_info = mod.typeToFunc(func.decl.ty).?; |
| 2149 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | 2165 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2150 | if (ret_ty.isError()) { | 2166 | if (ret_ty.isError(mod)) { |
| 2151 | try func.addImm32(0); | 2167 | try func.addImm32(0); |
| 2152 | } | 2168 | } |
| 2153 | } else if (!firstParamSRet(fn_info.cc, fn_info.return_type, func.target)) { | 2169 | } else if (!firstParamSRet(fn_info.cc, fn_info.return_type.toType(), mod)) { |
| 2154 | // leave on the stack | 2170 | // leave on the stack |
| 2155 | _ = try func.load(operand, ret_ty, 0); | 2171 | _ = try func.load(operand, ret_ty, 0); |
| 2156 | } | 2172 | } |
| ... | @@ -2165,42 +2181,48 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif | ... | @@ -2165,42 +2181,48 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif |
| 2165 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; | 2181 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 2166 | const extra = func.air.extraData(Air.Call, pl_op.payload); | 2182 | const extra = func.air.extraData(Air.Call, pl_op.payload); |
| 2167 | const args = @ptrCast([]const Air.Inst.Ref, func.air.extra[extra.end..][0..extra.data.args_len]); | 2183 | const args = @ptrCast([]const Air.Inst.Ref, func.air.extra[extra.end..][0..extra.data.args_len]); |
| 2168 | const ty = func.air.typeOf(pl_op.operand); | 2184 | const ty = func.typeOf(pl_op.operand); |
| 2169 | 2185 | ||
| 2170 | const fn_ty = switch (ty.zigTypeTag()) { | 2186 | const mod = func.bin_file.base.options.module.?; |
| 2187 | const fn_ty = switch (ty.zigTypeTag(mod)) { | ||
| 2171 | .Fn => ty, | 2188 | .Fn => ty, |
| 2172 | .Pointer => ty.childType(), | 2189 | .Pointer => ty.childType(mod), |
| 2173 | else => unreachable, | 2190 | else => unreachable, |
| 2174 | }; | 2191 | }; |
| 2175 | const ret_ty = fn_ty.fnReturnType(); | 2192 | const ret_ty = fn_ty.fnReturnType(mod); |
| 2176 | const fn_info = fn_ty.fnInfo(); | 2193 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 2177 | const first_param_sret = firstParamSRet(fn_info.cc, fn_info.return_type, func.target); | 2194 | const first_param_sret = firstParamSRet(fn_info.cc, fn_info.return_type.toType(), mod); |
| 2178 | 2195 | ||
| 2179 | const callee: ?Decl.Index = blk: { | 2196 | const callee: ?Decl.Index = blk: { |
| 2180 | const func_val = func.air.value(pl_op.operand) orelse break :blk null; | 2197 | const func_val = (try func.air.value(pl_op.operand, mod)) orelse break :blk null; |
| 2181 | const module = func.bin_file.base.options.module.?; | 2198 | |
| 2182 | 2199 | if (func_val.getFunction(mod)) |function| { | |
| 2183 | if (func_val.castTag(.function)) |function| { | 2200 | _ = try func.bin_file.getOrCreateAtomForDecl(function.owner_decl); |
| 2184 | _ = try func.bin_file.getOrCreateAtomForDecl(function.data.owner_decl); | 2201 | break :blk function.owner_decl; |
| 2185 | break :blk function.data.owner_decl; | 2202 | } else if (func_val.getExternFunc(mod)) |extern_func| { |
| 2186 | } else if (func_val.castTag(.extern_fn)) |extern_fn| { | 2203 | const ext_decl = mod.declPtr(extern_func.decl); |
| 2187 | const ext_decl = module.declPtr(extern_fn.data.owner_decl); | 2204 | const ext_info = mod.typeToFunc(ext_decl.ty).?; |
| 2188 | const ext_info = ext_decl.ty.fnInfo(); | 2205 | var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type.toType(), mod); |
| 2189 | var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type, func.target); | ||
| 2190 | defer func_type.deinit(func.gpa); | 2206 | defer func_type.deinit(func.gpa); |
| 2191 | const atom_index = try func.bin_file.getOrCreateAtomForDecl(extern_fn.data.owner_decl); | 2207 | const atom_index = try func.bin_file.getOrCreateAtomForDecl(extern_func.decl); |
| 2192 | const atom = func.bin_file.getAtomPtr(atom_index); | 2208 | const atom = func.bin_file.getAtomPtr(atom_index); |
| 2193 | const type_index = try func.bin_file.storeDeclType(extern_fn.data.owner_decl, func_type); | 2209 | const type_index = try func.bin_file.storeDeclType(extern_func.decl, func_type); |
| 2194 | try func.bin_file.addOrUpdateImport( | 2210 | try func.bin_file.addOrUpdateImport( |
| 2195 | mem.sliceTo(ext_decl.name, 0), | 2211 | mod.intern_pool.stringToSlice(ext_decl.name), |
| 2196 | atom.getSymbolIndex().?, | 2212 | atom.getSymbolIndex().?, |
| 2197 | ext_decl.getExternFn().?.lib_name, | 2213 | mod.intern_pool.stringToSliceUnwrap(ext_decl.getOwnedExternFunc(mod).?.lib_name), |
| 2198 | type_index, | 2214 | type_index, |
| 2199 | ); | 2215 | ); |
| 2200 | break :blk extern_fn.data.owner_decl; | 2216 | break :blk extern_func.decl; |
| 2201 | } else if (func_val.castTag(.decl_ref)) |decl_ref| { | 2217 | } else switch (mod.intern_pool.indexToKey(func_val.ip_index)) { |
| 2202 | _ = try func.bin_file.getOrCreateAtomForDecl(decl_ref.data); | 2218 | .ptr => |ptr| switch (ptr.addr) { |
| 2203 | break :blk decl_ref.data; | 2219 | .decl => |decl| { |
| 2220 | _ = try func.bin_file.getOrCreateAtomForDecl(decl); | ||
| 2221 | break :blk decl; | ||
| 2222 | }, | ||
| 2223 | else => {}, | ||
| 2224 | }, | ||
| 2225 | else => {}, | ||
| 2204 | } | 2226 | } |
| 2205 | return func.fail("Expected a function, but instead found type '{}'", .{func_val.tag()}); | 2227 | return func.fail("Expected a function, but instead found type '{}'", .{func_val.tag()}); |
| 2206 | }; | 2228 | }; |
| ... | @@ -2214,10 +2236,10 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif | ... | @@ -2214,10 +2236,10 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif |
| 2214 | for (args) |arg| { | 2236 | for (args) |arg| { |
| 2215 | const arg_val = try func.resolveInst(arg); | 2237 | const arg_val = try func.resolveInst(arg); |
| 2216 | 2238 | ||
| 2217 | const arg_ty = func.air.typeOf(arg); | 2239 | const arg_ty = func.typeOf(arg); |
| 2218 | if (!arg_ty.hasRuntimeBitsIgnoreComptime()) continue; | 2240 | if (!arg_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 2219 | 2241 | ||
| 2220 | try func.lowerArg(fn_ty.fnInfo().cc, arg_ty, arg_val); | 2242 | try func.lowerArg(mod.typeToFunc(fn_ty).?.cc, arg_ty, arg_val); |
| 2221 | } | 2243 | } |
| 2222 | 2244 | ||
| 2223 | if (callee) |direct| { | 2245 | if (callee) |direct| { |
| ... | @@ -2226,11 +2248,11 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif | ... | @@ -2226,11 +2248,11 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif |
| 2226 | } else { | 2248 | } else { |
| 2227 | // in this case we call a function pointer | 2249 | // in this case we call a function pointer |
| 2228 | // so load its value onto the stack | 2250 | // so load its value onto the stack |
| 2229 | std.debug.assert(ty.zigTypeTag() == .Pointer); | 2251 | std.debug.assert(ty.zigTypeTag(mod) == .Pointer); |
| 2230 | const operand = try func.resolveInst(pl_op.operand); | 2252 | const operand = try func.resolveInst(pl_op.operand); |
| 2231 | try func.emitWValue(operand); | 2253 | try func.emitWValue(operand); |
| 2232 | 2254 | ||
| 2233 | var fn_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types, fn_info.return_type, func.target); | 2255 | var fn_type = try genFunctype(func.gpa, fn_info.cc, fn_info.param_types, fn_info.return_type.toType(), mod); |
| 2234 | defer fn_type.deinit(func.gpa); | 2256 | defer fn_type.deinit(func.gpa); |
| 2235 | 2257 | ||
| 2236 | const fn_type_index = try func.bin_file.putOrGetFuncType(fn_type); | 2258 | const fn_type_index = try func.bin_file.putOrGetFuncType(fn_type); |
| ... | @@ -2238,18 +2260,18 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif | ... | @@ -2238,18 +2260,18 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif |
| 2238 | } | 2260 | } |
| 2239 | 2261 | ||
| 2240 | const result_value = result_value: { | 2262 | const result_value = result_value: { |
| 2241 | if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { | 2263 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod) and !ret_ty.isError(mod)) { |
| 2242 | break :result_value WValue{ .none = {} }; | 2264 | break :result_value WValue{ .none = {} }; |
| 2243 | } else if (ret_ty.isNoReturn()) { | 2265 | } else if (ret_ty.isNoReturn(mod)) { |
| 2244 | try func.addTag(.@"unreachable"); | 2266 | try func.addTag(.@"unreachable"); |
| 2245 | break :result_value WValue{ .none = {} }; | 2267 | break :result_value WValue{ .none = {} }; |
| 2246 | } else if (first_param_sret) { | 2268 | } else if (first_param_sret) { |
| 2247 | break :result_value sret; | 2269 | break :result_value sret; |
| 2248 | // TODO: Make this less fragile and optimize | 2270 | // TODO: Make this less fragile and optimize |
| 2249 | } else if (fn_ty.fnInfo().cc == .C and ret_ty.zigTypeTag() == .Struct or ret_ty.zigTypeTag() == .Union) { | 2271 | } else if (mod.typeToFunc(fn_ty).?.cc == .C and ret_ty.zigTypeTag(mod) == .Struct or ret_ty.zigTypeTag(mod) == .Union) { |
| 2250 | const result_local = try func.allocLocal(ret_ty); | 2272 | const result_local = try func.allocLocal(ret_ty); |
| 2251 | try func.addLabel(.local_set, result_local.local.value); | 2273 | try func.addLabel(.local_set, result_local.local.value); |
| 2252 | const scalar_type = abi.scalarType(ret_ty, func.target); | 2274 | const scalar_type = abi.scalarType(ret_ty, mod); |
| 2253 | const result = try func.allocStack(scalar_type); | 2275 | const result = try func.allocStack(scalar_type); |
| 2254 | try func.store(result, result_local, scalar_type, 0); | 2276 | try func.store(result, result_local, scalar_type, 0); |
| 2255 | break :result_value result; | 2277 | break :result_value result; |
| ... | @@ -2272,6 +2294,7 @@ fn airAlloc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2272,6 +2294,7 @@ fn airAlloc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2272 | } | 2294 | } |
| 2273 | 2295 | ||
| 2274 | fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { | 2296 | fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { |
| 2297 | const mod = func.bin_file.base.options.module.?; | ||
| 2275 | if (safety) { | 2298 | if (safety) { |
| 2276 | // TODO if the value is undef, write 0xaa bytes to dest | 2299 | // TODO if the value is undef, write 0xaa bytes to dest |
| 2277 | } else { | 2300 | } else { |
| ... | @@ -2281,26 +2304,22 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void | ... | @@ -2281,26 +2304,22 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void |
| 2281 | 2304 | ||
| 2282 | const lhs = try func.resolveInst(bin_op.lhs); | 2305 | const lhs = try func.resolveInst(bin_op.lhs); |
| 2283 | const rhs = try func.resolveInst(bin_op.rhs); | 2306 | const rhs = try func.resolveInst(bin_op.rhs); |
| 2284 | const ptr_ty = func.air.typeOf(bin_op.lhs); | 2307 | const ptr_ty = func.typeOf(bin_op.lhs); |
| 2285 | const ptr_info = ptr_ty.ptrInfo().data; | 2308 | const ptr_info = ptr_ty.ptrInfo(mod); |
| 2286 | const ty = ptr_ty.childType(); | 2309 | const ty = ptr_ty.childType(mod); |
| 2287 | 2310 | ||
| 2288 | if (ptr_info.host_size == 0) { | 2311 | if (ptr_info.host_size == 0) { |
| 2289 | try func.store(lhs, rhs, ty, 0); | 2312 | try func.store(lhs, rhs, ty, 0); |
| 2290 | } else { | 2313 | } else { |
| 2291 | // at this point we have a non-natural alignment, we must | 2314 | // at this point we have a non-natural alignment, we must |
| 2292 | // load the value, and then shift+or the rhs into the result location. | 2315 | // load the value, and then shift+or the rhs into the result location. |
| 2293 | var int_ty_payload: Type.Payload.Bits = .{ | 2316 | const int_elem_ty = try mod.intType(.unsigned, ptr_info.host_size * 8); |
| 2294 | .base = .{ .tag = .int_unsigned }, | ||
| 2295 | .data = ptr_info.host_size * 8, | ||
| 2296 | }; | ||
| 2297 | const int_elem_ty = Type.initPayload(&int_ty_payload.base); | ||
| 2298 | 2317 | ||
| 2299 | if (isByRef(int_elem_ty, func.target)) { | 2318 | if (isByRef(int_elem_ty, mod)) { |
| 2300 | return func.fail("TODO: airStore for pointers to bitfields with backing type larger than 64bits", .{}); | 2319 | return func.fail("TODO: airStore for pointers to bitfields with backing type larger than 64bits", .{}); |
| 2301 | } | 2320 | } |
| 2302 | 2321 | ||
| 2303 | var mask = @intCast(u64, (@as(u65, 1) << @intCast(u7, ty.bitSize(func.target))) - 1); | 2322 | var mask = @intCast(u64, (@as(u65, 1) << @intCast(u7, ty.bitSize(mod))) - 1); |
| 2304 | mask <<= @intCast(u6, ptr_info.bit_offset); | 2323 | mask <<= @intCast(u6, ptr_info.bit_offset); |
| 2305 | mask ^= ~@as(u64, 0); | 2324 | mask ^= ~@as(u64, 0); |
| 2306 | const shift_val = if (ptr_info.host_size <= 4) | 2325 | const shift_val = if (ptr_info.host_size <= 4) |
| ... | @@ -2329,11 +2348,12 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void | ... | @@ -2329,11 +2348,12 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void |
| 2329 | 2348 | ||
| 2330 | fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void { | 2349 | fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void { |
| 2331 | assert(!(lhs != .stack and rhs == .stack)); | 2350 | assert(!(lhs != .stack and rhs == .stack)); |
| 2332 | const abi_size = ty.abiSize(func.target); | 2351 | const mod = func.bin_file.base.options.module.?; |
| 2333 | switch (ty.zigTypeTag()) { | 2352 | const abi_size = ty.abiSize(mod); |
| 2353 | switch (ty.zigTypeTag(mod)) { | ||
| 2334 | .ErrorUnion => { | 2354 | .ErrorUnion => { |
| 2335 | const pl_ty = ty.errorUnionPayload(); | 2355 | const pl_ty = ty.errorUnionPayload(mod); |
| 2336 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { | 2356 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2337 | return func.store(lhs, rhs, Type.anyerror, 0); | 2357 | return func.store(lhs, rhs, Type.anyerror, 0); |
| 2338 | } | 2358 | } |
| 2339 | 2359 | ||
| ... | @@ -2341,26 +2361,25 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE | ... | @@ -2341,26 +2361,25 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2341 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); | 2361 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); |
| 2342 | }, | 2362 | }, |
| 2343 | .Optional => { | 2363 | .Optional => { |
| 2344 | if (ty.isPtrLikeOptional()) { | 2364 | if (ty.isPtrLikeOptional(mod)) { |
| 2345 | return func.store(lhs, rhs, Type.usize, 0); | 2365 | return func.store(lhs, rhs, Type.usize, 0); |
| 2346 | } | 2366 | } |
| 2347 | var buf: Type.Payload.ElemType = undefined; | 2367 | const pl_ty = ty.optionalChild(mod); |
| 2348 | const pl_ty = ty.optionalChild(&buf); | 2368 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2349 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 2350 | return func.store(lhs, rhs, Type.u8, 0); | 2369 | return func.store(lhs, rhs, Type.u8, 0); |
| 2351 | } | 2370 | } |
| 2352 | if (pl_ty.zigTypeTag() == .ErrorSet) { | 2371 | if (pl_ty.zigTypeTag(mod) == .ErrorSet) { |
| 2353 | return func.store(lhs, rhs, Type.anyerror, 0); | 2372 | return func.store(lhs, rhs, Type.anyerror, 0); |
| 2354 | } | 2373 | } |
| 2355 | 2374 | ||
| 2356 | const len = @intCast(u32, abi_size); | 2375 | const len = @intCast(u32, abi_size); |
| 2357 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); | 2376 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); |
| 2358 | }, | 2377 | }, |
| 2359 | .Struct, .Array, .Union => if (isByRef(ty, func.target)) { | 2378 | .Struct, .Array, .Union => if (isByRef(ty, mod)) { |
| 2360 | const len = @intCast(u32, abi_size); | 2379 | const len = @intCast(u32, abi_size); |
| 2361 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); | 2380 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); |
| 2362 | }, | 2381 | }, |
| 2363 | .Vector => switch (determineSimdStoreStrategy(ty, func.target)) { | 2382 | .Vector => switch (determineSimdStoreStrategy(ty, mod)) { |
| 2364 | .unrolled => { | 2383 | .unrolled => { |
| 2365 | const len = @intCast(u32, abi_size); | 2384 | const len = @intCast(u32, abi_size); |
| 2366 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); | 2385 | return func.memcpy(lhs, rhs, .{ .imm32 = len }); |
| ... | @@ -2374,13 +2393,13 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE | ... | @@ -2374,13 +2393,13 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2374 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ | 2393 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 2375 | std.wasm.simdOpcode(.v128_store), | 2394 | std.wasm.simdOpcode(.v128_store), |
| 2376 | offset + lhs.offset(), | 2395 | offset + lhs.offset(), |
| 2377 | ty.abiAlignment(func.target), | 2396 | ty.abiAlignment(mod), |
| 2378 | }); | 2397 | }); |
| 2379 | return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 2398 | return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 2380 | }, | 2399 | }, |
| 2381 | }, | 2400 | }, |
| 2382 | .Pointer => { | 2401 | .Pointer => { |
| 2383 | if (ty.isSlice()) { | 2402 | if (ty.isSlice(mod)) { |
| 2384 | // store pointer first | 2403 | // store pointer first |
| 2385 | // lower it to the stack so we do not have to store rhs into a local first | 2404 | // lower it to the stack so we do not have to store rhs into a local first |
| 2386 | try func.emitWValue(lhs); | 2405 | try func.emitWValue(lhs); |
| ... | @@ -2404,7 +2423,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE | ... | @@ -2404,7 +2423,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2404 | try func.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset()); | 2423 | try func.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset()); |
| 2405 | return; | 2424 | return; |
| 2406 | } else if (abi_size > 16) { | 2425 | } else if (abi_size > 16) { |
| 2407 | try func.memcpy(lhs, rhs, .{ .imm32 = @intCast(u32, ty.abiSize(func.target)) }); | 2426 | try func.memcpy(lhs, rhs, .{ .imm32 = @intCast(u32, ty.abiSize(mod)) }); |
| 2408 | }, | 2427 | }, |
| 2409 | else => if (abi_size > 8) { | 2428 | else => if (abi_size > 8) { |
| 2410 | return func.fail("TODO: `store` for type `{}` with abisize `{d}`", .{ | 2429 | return func.fail("TODO: `store` for type `{}` with abisize `{d}`", .{ |
| ... | @@ -2418,7 +2437,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE | ... | @@ -2418,7 +2437,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2418 | // into lhs, so we calculate that and emit that instead | 2437 | // into lhs, so we calculate that and emit that instead |
| 2419 | try func.lowerToStack(rhs); | 2438 | try func.lowerToStack(rhs); |
| 2420 | 2439 | ||
| 2421 | const valtype = typeToValtype(ty, func.target); | 2440 | const valtype = typeToValtype(ty, mod); |
| 2422 | const opcode = buildOpcode(.{ | 2441 | const opcode = buildOpcode(.{ |
| 2423 | .valtype1 = valtype, | 2442 | .valtype1 = valtype, |
| 2424 | .width = @intCast(u8, abi_size * 8), | 2443 | .width = @intCast(u8, abi_size * 8), |
| ... | @@ -2428,21 +2447,22 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE | ... | @@ -2428,21 +2447,22 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE |
| 2428 | // store rhs value at stack pointer's location in memory | 2447 | // store rhs value at stack pointer's location in memory |
| 2429 | try func.addMemArg( | 2448 | try func.addMemArg( |
| 2430 | Mir.Inst.Tag.fromOpcode(opcode), | 2449 | Mir.Inst.Tag.fromOpcode(opcode), |
| 2431 | .{ .offset = offset + lhs.offset(), .alignment = ty.abiAlignment(func.target) }, | 2450 | .{ .offset = offset + lhs.offset(), .alignment = ty.abiAlignment(mod) }, |
| 2432 | ); | 2451 | ); |
| 2433 | } | 2452 | } |
| 2434 | 2453 | ||
| 2435 | fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 2454 | fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2455 | const mod = func.bin_file.base.options.module.?; | ||
| 2436 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 2456 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 2437 | const operand = try func.resolveInst(ty_op.operand); | 2457 | const operand = try func.resolveInst(ty_op.operand); |
| 2438 | const ty = func.air.getRefType(ty_op.ty); | 2458 | const ty = func.air.getRefType(ty_op.ty); |
| 2439 | const ptr_ty = func.air.typeOf(ty_op.operand); | 2459 | const ptr_ty = func.typeOf(ty_op.operand); |
| 2440 | const ptr_info = ptr_ty.ptrInfo().data; | 2460 | const ptr_info = ptr_ty.ptrInfo(mod); |
| 2441 | 2461 | ||
| 2442 | if (!ty.hasRuntimeBitsIgnoreComptime()) return func.finishAir(inst, .none, &.{ty_op.operand}); | 2462 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return func.finishAir(inst, .none, &.{ty_op.operand}); |
| 2443 | 2463 | ||
| 2444 | const result = result: { | 2464 | const result = result: { |
| 2445 | if (isByRef(ty, func.target)) { | 2465 | if (isByRef(ty, mod)) { |
| 2446 | const new_local = try func.allocStack(ty); | 2466 | const new_local = try func.allocStack(ty); |
| 2447 | try func.store(new_local, operand, ty, 0); | 2467 | try func.store(new_local, operand, ty, 0); |
| 2448 | break :result new_local; | 2468 | break :result new_local; |
| ... | @@ -2455,11 +2475,7 @@ fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2455,11 +2475,7 @@ fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2455 | 2475 | ||
| 2456 | // at this point we have a non-natural alignment, we must | 2476 | // at this point we have a non-natural alignment, we must |
| 2457 | // shift the value to obtain the correct bit. | 2477 | // shift the value to obtain the correct bit. |
| 2458 | var int_ty_payload: Type.Payload.Bits = .{ | 2478 | const int_elem_ty = try mod.intType(.unsigned, ptr_info.host_size * 8); |
| 2459 | .base = .{ .tag = .int_unsigned }, | ||
| 2460 | .data = ptr_info.host_size * 8, | ||
| 2461 | }; | ||
| 2462 | const int_elem_ty = Type.initPayload(&int_ty_payload.base); | ||
| 2463 | const shift_val = if (ptr_info.host_size <= 4) | 2479 | const shift_val = if (ptr_info.host_size <= 4) |
| 2464 | WValue{ .imm32 = ptr_info.bit_offset } | 2480 | WValue{ .imm32 = ptr_info.bit_offset } |
| 2465 | else if (ptr_info.host_size <= 8) | 2481 | else if (ptr_info.host_size <= 8) |
| ... | @@ -2479,25 +2495,26 @@ fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2479,25 +2495,26 @@ fn airLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2479 | /// Loads an operand from the linear memory section. | 2495 | /// Loads an operand from the linear memory section. |
| 2480 | /// NOTE: Leaves the value on the stack. | 2496 | /// NOTE: Leaves the value on the stack. |
| 2481 | fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue { | 2497 | fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValue { |
| 2498 | const mod = func.bin_file.base.options.module.?; | ||
| 2482 | // load local's value from memory by its stack position | 2499 | // load local's value from memory by its stack position |
| 2483 | try func.emitWValue(operand); | 2500 | try func.emitWValue(operand); |
| 2484 | 2501 | ||
| 2485 | if (ty.zigTypeTag() == .Vector) { | 2502 | if (ty.zigTypeTag(mod) == .Vector) { |
| 2486 | // TODO: Add helper functions for simd opcodes | 2503 | // TODO: Add helper functions for simd opcodes |
| 2487 | const extra_index = @intCast(u32, func.mir_extra.items.len); | 2504 | const extra_index = @intCast(u32, func.mir_extra.items.len); |
| 2488 | // stores as := opcode, offset, alignment (opcode::memarg) | 2505 | // stores as := opcode, offset, alignment (opcode::memarg) |
| 2489 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ | 2506 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 2490 | std.wasm.simdOpcode(.v128_load), | 2507 | std.wasm.simdOpcode(.v128_load), |
| 2491 | offset + operand.offset(), | 2508 | offset + operand.offset(), |
| 2492 | ty.abiAlignment(func.target), | 2509 | ty.abiAlignment(mod), |
| 2493 | }); | 2510 | }); |
| 2494 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 2511 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 2495 | return WValue{ .stack = {} }; | 2512 | return WValue{ .stack = {} }; |
| 2496 | } | 2513 | } |
| 2497 | 2514 | ||
| 2498 | const abi_size = @intCast(u8, ty.abiSize(func.target)); | 2515 | const abi_size = @intCast(u8, ty.abiSize(mod)); |
| 2499 | const opcode = buildOpcode(.{ | 2516 | const opcode = buildOpcode(.{ |
| 2500 | .valtype1 = typeToValtype(ty, func.target), | 2517 | .valtype1 = typeToValtype(ty, mod), |
| 2501 | .width = abi_size * 8, | 2518 | .width = abi_size * 8, |
| 2502 | .op = .load, | 2519 | .op = .load, |
| 2503 | .signedness = .unsigned, | 2520 | .signedness = .unsigned, |
| ... | @@ -2505,19 +2522,20 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu | ... | @@ -2505,19 +2522,20 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu |
| 2505 | 2522 | ||
| 2506 | try func.addMemArg( | 2523 | try func.addMemArg( |
| 2507 | Mir.Inst.Tag.fromOpcode(opcode), | 2524 | Mir.Inst.Tag.fromOpcode(opcode), |
| 2508 | .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(func.target) }, | 2525 | .{ .offset = offset + operand.offset(), .alignment = ty.abiAlignment(mod) }, |
| 2509 | ); | 2526 | ); |
| 2510 | 2527 | ||
| 2511 | return WValue{ .stack = {} }; | 2528 | return WValue{ .stack = {} }; |
| 2512 | } | 2529 | } |
| 2513 | 2530 | ||
| 2514 | fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 2531 | fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2532 | const mod = func.bin_file.base.options.module.?; | ||
| 2515 | const arg_index = func.arg_index; | 2533 | const arg_index = func.arg_index; |
| 2516 | const arg = func.args[arg_index]; | 2534 | const arg = func.args[arg_index]; |
| 2517 | const cc = func.decl.ty.fnInfo().cc; | 2535 | const cc = mod.typeToFunc(func.decl.ty).?.cc; |
| 2518 | const arg_ty = func.air.typeOfIndex(inst); | 2536 | const arg_ty = func.typeOfIndex(inst); |
| 2519 | if (cc == .C) { | 2537 | if (cc == .C) { |
| 2520 | const arg_classes = abi.classifyType(arg_ty, func.target); | 2538 | const arg_classes = abi.classifyType(arg_ty, mod); |
| 2521 | for (arg_classes) |class| { | 2539 | for (arg_classes) |class| { |
| 2522 | if (class != .none) { | 2540 | if (class != .none) { |
| 2523 | func.arg_index += 1; | 2541 | func.arg_index += 1; |
| ... | @@ -2527,7 +2545,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2527,7 +2545,7 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2527 | // When we have an argument that's passed using more than a single parameter, | 2545 | // When we have an argument that's passed using more than a single parameter, |
| 2528 | // we combine them into a single stack value | 2546 | // we combine them into a single stack value |
| 2529 | if (arg_classes[0] == .direct and arg_classes[1] == .direct) { | 2547 | if (arg_classes[0] == .direct and arg_classes[1] == .direct) { |
| 2530 | if (arg_ty.zigTypeTag() != .Int and arg_ty.zigTypeTag() != .Float) { | 2548 | if (arg_ty.zigTypeTag(mod) != .Int and arg_ty.zigTypeTag(mod) != .Float) { |
| 2531 | return func.fail( | 2549 | return func.fail( |
| 2532 | "TODO: Implement C-ABI argument for type '{}'", | 2550 | "TODO: Implement C-ABI argument for type '{}'", |
| 2533 | .{arg_ty.fmt(func.bin_file.base.options.module.?)}, | 2551 | .{arg_ty.fmt(func.bin_file.base.options.module.?)}, |
| ... | @@ -2557,11 +2575,12 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2557,11 +2575,12 @@ fn airArg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2557 | } | 2575 | } |
| 2558 | 2576 | ||
| 2559 | fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | 2577 | fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 2578 | const mod = func.bin_file.base.options.module.?; | ||
| 2560 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 2579 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 2561 | const lhs = try func.resolveInst(bin_op.lhs); | 2580 | const lhs = try func.resolveInst(bin_op.lhs); |
| 2562 | const rhs = try func.resolveInst(bin_op.rhs); | 2581 | const rhs = try func.resolveInst(bin_op.rhs); |
| 2563 | const lhs_ty = func.air.typeOf(bin_op.lhs); | 2582 | const lhs_ty = func.typeOf(bin_op.lhs); |
| 2564 | const rhs_ty = func.air.typeOf(bin_op.rhs); | 2583 | const rhs_ty = func.typeOf(bin_op.rhs); |
| 2565 | 2584 | ||
| 2566 | // For certain operations, such as shifting, the types are different. | 2585 | // For certain operations, such as shifting, the types are different. |
| 2567 | // When converting this to a WebAssembly type, they *must* match to perform | 2586 | // When converting this to a WebAssembly type, they *must* match to perform |
| ... | @@ -2570,10 +2589,10 @@ fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | ... | @@ -2570,10 +2589,10 @@ fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 2570 | // For big integers we can ignore this as we will call into compiler-rt which handles this. | 2589 | // For big integers we can ignore this as we will call into compiler-rt which handles this. |
| 2571 | const result = switch (op) { | 2590 | const result = switch (op) { |
| 2572 | .shr, .shl => res: { | 2591 | .shr, .shl => res: { |
| 2573 | const lhs_wasm_bits = toWasmBits(@intCast(u16, lhs_ty.bitSize(func.target))) orelse { | 2592 | const lhs_wasm_bits = toWasmBits(@intCast(u16, lhs_ty.bitSize(mod))) orelse { |
| 2574 | return func.fail("TODO: implement '{s}' for types larger than 128 bits", .{@tagName(op)}); | 2593 | return func.fail("TODO: implement '{s}' for types larger than 128 bits", .{@tagName(op)}); |
| 2575 | }; | 2594 | }; |
| 2576 | const rhs_wasm_bits = toWasmBits(@intCast(u16, rhs_ty.bitSize(func.target))).?; | 2595 | const rhs_wasm_bits = toWasmBits(@intCast(u16, rhs_ty.bitSize(mod))).?; |
| 2577 | const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128) blk: { | 2596 | const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128) blk: { |
| 2578 | const tmp = try func.intcast(rhs, rhs_ty, lhs_ty); | 2597 | const tmp = try func.intcast(rhs, rhs_ty, lhs_ty); |
| 2579 | break :blk try tmp.toLocal(func, lhs_ty); | 2598 | break :blk try tmp.toLocal(func, lhs_ty); |
| ... | @@ -2593,6 +2612,7 @@ fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | ... | @@ -2593,6 +2612,7 @@ fn airBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 2593 | /// Performs a binary operation on the given `WValue`'s | 2612 | /// Performs a binary operation on the given `WValue`'s |
| 2594 | /// NOTE: THis leaves the value on top of the stack. | 2613 | /// NOTE: THis leaves the value on top of the stack. |
| 2595 | fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { | 2614 | fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { |
| 2615 | const mod = func.bin_file.base.options.module.?; | ||
| 2596 | assert(!(lhs != .stack and rhs == .stack)); | 2616 | assert(!(lhs != .stack and rhs == .stack)); |
| 2597 | 2617 | ||
| 2598 | if (ty.isAnyFloat()) { | 2618 | if (ty.isAnyFloat()) { |
| ... | @@ -2600,8 +2620,8 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError! | ... | @@ -2600,8 +2620,8 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError! |
| 2600 | return func.floatOp(float_op, ty, &.{ lhs, rhs }); | 2620 | return func.floatOp(float_op, ty, &.{ lhs, rhs }); |
| 2601 | } | 2621 | } |
| 2602 | 2622 | ||
| 2603 | if (isByRef(ty, func.target)) { | 2623 | if (isByRef(ty, mod)) { |
| 2604 | if (ty.zigTypeTag() == .Int) { | 2624 | if (ty.zigTypeTag(mod) == .Int) { |
| 2605 | return func.binOpBigInt(lhs, rhs, ty, op); | 2625 | return func.binOpBigInt(lhs, rhs, ty, op); |
| 2606 | } else { | 2626 | } else { |
| 2607 | return func.fail( | 2627 | return func.fail( |
| ... | @@ -2613,8 +2633,8 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError! | ... | @@ -2613,8 +2633,8 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError! |
| 2613 | 2633 | ||
| 2614 | const opcode: wasm.Opcode = buildOpcode(.{ | 2634 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 2615 | .op = op, | 2635 | .op = op, |
| 2616 | .valtype1 = typeToValtype(ty, func.target), | 2636 | .valtype1 = typeToValtype(ty, mod), |
| 2617 | .signedness = if (ty.isSignedInt()) .signed else .unsigned, | 2637 | .signedness = if (ty.isSignedInt(mod)) .signed else .unsigned, |
| 2618 | }); | 2638 | }); |
| 2619 | try func.emitWValue(lhs); | 2639 | try func.emitWValue(lhs); |
| 2620 | try func.emitWValue(rhs); | 2640 | try func.emitWValue(rhs); |
| ... | @@ -2625,14 +2645,15 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError! | ... | @@ -2625,14 +2645,15 @@ fn binOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError! |
| 2625 | } | 2645 | } |
| 2626 | 2646 | ||
| 2627 | fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { | 2647 | fn binOpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerError!WValue { |
| 2628 | if (ty.intInfo(func.target).bits > 128) { | 2648 | const mod = func.bin_file.base.options.module.?; |
| 2649 | if (ty.intInfo(mod).bits > 128) { | ||
| 2629 | return func.fail("TODO: Implement binary operation for big integers larger than 128 bits", .{}); | 2650 | return func.fail("TODO: Implement binary operation for big integers larger than 128 bits", .{}); |
| 2630 | } | 2651 | } |
| 2631 | 2652 | ||
| 2632 | switch (op) { | 2653 | switch (op) { |
| 2633 | .mul => return func.callIntrinsic("__multi3", &.{ ty, ty }, ty, &.{ lhs, rhs }), | 2654 | .mul => return func.callIntrinsic("__multi3", &.{ ty.toIntern(), ty.toIntern() }, ty, &.{ lhs, rhs }), |
| 2634 | .shr => return func.callIntrinsic("__lshrti3", &.{ ty, Type.i32 }, ty, &.{ lhs, rhs }), | 2655 | .shr => return func.callIntrinsic("__lshrti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), |
| 2635 | .shl => return func.callIntrinsic("__ashlti3", &.{ ty, Type.i32 }, ty, &.{ lhs, rhs }), | 2656 | .shl => return func.callIntrinsic("__ashlti3", &.{ ty.toIntern(), .i32_type }, ty, &.{ lhs, rhs }), |
| 2636 | .xor => { | 2657 | .xor => { |
| 2637 | const result = try func.allocStack(ty); | 2658 | const result = try func.allocStack(ty); |
| 2638 | try func.emitWValue(result); | 2659 | try func.emitWValue(result); |
| ... | @@ -2756,14 +2777,15 @@ const FloatOp = enum { | ... | @@ -2756,14 +2777,15 @@ const FloatOp = enum { |
| 2756 | fn airUnaryFloatOp(func: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void { | 2777 | fn airUnaryFloatOp(func: *CodeGen, inst: Air.Inst.Index, op: FloatOp) InnerError!void { |
| 2757 | const un_op = func.air.instructions.items(.data)[inst].un_op; | 2778 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 2758 | const operand = try func.resolveInst(un_op); | 2779 | const operand = try func.resolveInst(un_op); |
| 2759 | const ty = func.air.typeOf(un_op); | 2780 | const ty = func.typeOf(un_op); |
| 2760 | 2781 | ||
| 2761 | const result = try (try func.floatOp(op, ty, &.{operand})).toLocal(func, ty); | 2782 | const result = try (try func.floatOp(op, ty, &.{operand})).toLocal(func, ty); |
| 2762 | func.finishAir(inst, result, &.{un_op}); | 2783 | func.finishAir(inst, result, &.{un_op}); |
| 2763 | } | 2784 | } |
| 2764 | 2785 | ||
| 2765 | fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) InnerError!WValue { | 2786 | fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) InnerError!WValue { |
| 2766 | if (ty.zigTypeTag() == .Vector) { | 2787 | const mod = func.bin_file.base.options.module.?; |
| 2788 | if (ty.zigTypeTag(mod) == .Vector) { | ||
| 2767 | return func.fail("TODO: Implement floatOps for vectors", .{}); | 2789 | return func.fail("TODO: Implement floatOps for vectors", .{}); |
| 2768 | } | 2790 | } |
| 2769 | 2791 | ||
| ... | @@ -2773,7 +2795,7 @@ fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) In | ... | @@ -2773,7 +2795,7 @@ fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) In |
| 2773 | for (args) |operand| { | 2795 | for (args) |operand| { |
| 2774 | try func.emitWValue(operand); | 2796 | try func.emitWValue(operand); |
| 2775 | } | 2797 | } |
| 2776 | const opcode = buildOpcode(.{ .op = op, .valtype1 = typeToValtype(ty, func.target) }); | 2798 | const opcode = buildOpcode(.{ .op = op, .valtype1 = typeToValtype(ty, mod) }); |
| 2777 | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 2799 | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 2778 | return .stack; | 2800 | return .stack; |
| 2779 | } | 2801 | } |
| ... | @@ -2821,20 +2843,21 @@ fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) In | ... | @@ -2821,20 +2843,21 @@ fn floatOp(func: *CodeGen, float_op: FloatOp, ty: Type, args: []const WValue) In |
| 2821 | }; | 2843 | }; |
| 2822 | 2844 | ||
| 2823 | // fma requires three operands | 2845 | // fma requires three operands |
| 2824 | var param_types_buffer: [3]Type = .{ ty, ty, ty }; | 2846 | var param_types_buffer: [3]InternPool.Index = .{ ty.ip_index, ty.ip_index, ty.ip_index }; |
| 2825 | const param_types = param_types_buffer[0..args.len]; | 2847 | const param_types = param_types_buffer[0..args.len]; |
| 2826 | return func.callIntrinsic(fn_name, param_types, ty, args); | 2848 | return func.callIntrinsic(fn_name, param_types, ty, args); |
| 2827 | } | 2849 | } |
| 2828 | 2850 | ||
| 2829 | fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | 2851 | fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 2852 | const mod = func.bin_file.base.options.module.?; | ||
| 2830 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 2853 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 2831 | 2854 | ||
| 2832 | const lhs = try func.resolveInst(bin_op.lhs); | 2855 | const lhs = try func.resolveInst(bin_op.lhs); |
| 2833 | const rhs = try func.resolveInst(bin_op.rhs); | 2856 | const rhs = try func.resolveInst(bin_op.rhs); |
| 2834 | const lhs_ty = func.air.typeOf(bin_op.lhs); | 2857 | const lhs_ty = func.typeOf(bin_op.lhs); |
| 2835 | const rhs_ty = func.air.typeOf(bin_op.rhs); | 2858 | const rhs_ty = func.typeOf(bin_op.rhs); |
| 2836 | 2859 | ||
| 2837 | if (lhs_ty.zigTypeTag() == .Vector or rhs_ty.zigTypeTag() == .Vector) { | 2860 | if (lhs_ty.zigTypeTag(mod) == .Vector or rhs_ty.zigTypeTag(mod) == .Vector) { |
| 2838 | return func.fail("TODO: Implement wrapping arithmetic for vectors", .{}); | 2861 | return func.fail("TODO: Implement wrapping arithmetic for vectors", .{}); |
| 2839 | } | 2862 | } |
| 2840 | 2863 | ||
| ... | @@ -2845,10 +2868,10 @@ fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | ... | @@ -2845,10 +2868,10 @@ fn airWrapBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 2845 | // For big integers we can ignore this as we will call into compiler-rt which handles this. | 2868 | // For big integers we can ignore this as we will call into compiler-rt which handles this. |
| 2846 | const result = switch (op) { | 2869 | const result = switch (op) { |
| 2847 | .shr, .shl => res: { | 2870 | .shr, .shl => res: { |
| 2848 | const lhs_wasm_bits = toWasmBits(@intCast(u16, lhs_ty.bitSize(func.target))) orelse { | 2871 | const lhs_wasm_bits = toWasmBits(@intCast(u16, lhs_ty.bitSize(mod))) orelse { |
| 2849 | return func.fail("TODO: implement '{s}' for types larger than 128 bits", .{@tagName(op)}); | 2872 | return func.fail("TODO: implement '{s}' for types larger than 128 bits", .{@tagName(op)}); |
| 2850 | }; | 2873 | }; |
| 2851 | const rhs_wasm_bits = toWasmBits(@intCast(u16, rhs_ty.bitSize(func.target))).?; | 2874 | const rhs_wasm_bits = toWasmBits(@intCast(u16, rhs_ty.bitSize(mod))).?; |
| 2852 | const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128) blk: { | 2875 | const new_rhs = if (lhs_wasm_bits != rhs_wasm_bits and lhs_wasm_bits != 128) blk: { |
| 2853 | const tmp = try func.intcast(rhs, rhs_ty, lhs_ty); | 2876 | const tmp = try func.intcast(rhs, rhs_ty, lhs_ty); |
| 2854 | break :blk try tmp.toLocal(func, lhs_ty); | 2877 | break :blk try tmp.toLocal(func, lhs_ty); |
| ... | @@ -2877,8 +2900,9 @@ fn wrapBinOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerEr | ... | @@ -2877,8 +2900,9 @@ fn wrapBinOp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: Op) InnerEr |
| 2877 | /// Asserts `Type` is <= 128 bits. | 2900 | /// Asserts `Type` is <= 128 bits. |
| 2878 | /// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack. | 2901 | /// NOTE: When the Type is <= 64 bits, leaves the value on top of the stack. |
| 2879 | fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { | 2902 | fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { |
| 2880 | assert(ty.abiSize(func.target) <= 16); | 2903 | const mod = func.bin_file.base.options.module.?; |
| 2881 | const bitsize = @intCast(u16, ty.bitSize(func.target)); | 2904 | assert(ty.abiSize(mod) <= 16); |
| 2905 | const bitsize = @intCast(u16, ty.bitSize(mod)); | ||
| 2882 | const wasm_bits = toWasmBits(bitsize) orelse { | 2906 | const wasm_bits = toWasmBits(bitsize) orelse { |
| 2883 | return func.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize}); | 2907 | return func.fail("TODO: Implement wrapOperand for bitsize '{d}'", .{bitsize}); |
| 2884 | }; | 2908 | }; |
| ... | @@ -2914,43 +2938,67 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { | ... | @@ -2914,43 +2938,67 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { |
| 2914 | return WValue{ .stack = {} }; | 2938 | return WValue{ .stack = {} }; |
| 2915 | } | 2939 | } |
| 2916 | 2940 | ||
| 2917 | fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue { | 2941 | fn lowerParentPtr(func: *CodeGen, ptr_val: Value) InnerError!WValue { |
| 2918 | switch (ptr_val.tag()) { | 2942 | const mod = func.bin_file.base.options.module.?; |
| 2919 | .decl_ref_mut => { | 2943 | const ptr = mod.intern_pool.indexToKey(ptr_val.ip_index).ptr; |
| 2920 | const decl_index = ptr_val.castTag(.decl_ref_mut).?.data.decl_index; | 2944 | switch (ptr.addr) { |
| 2921 | return func.lowerParentPtrDecl(ptr_val, decl_index, offset); | 2945 | .decl => |decl_index| { |
| 2946 | return func.lowerParentPtrDecl(ptr_val, decl_index, 0); | ||
| 2947 | }, | ||
| 2948 | .mut_decl => |mut_decl| { | ||
| 2949 | const decl_index = mut_decl.decl; | ||
| 2950 | return func.lowerParentPtrDecl(ptr_val, decl_index, 0); | ||
| 2922 | }, | 2951 | }, |
| 2923 | .decl_ref => { | 2952 | .int, .eu_payload => |tag| return func.fail("TODO: Implement lowerParentPtr for {}", .{tag}), |
| 2924 | const decl_index = ptr_val.castTag(.decl_ref).?.data; | 2953 | .opt_payload => |base_ptr| { |
| 2925 | return func.lowerParentPtrDecl(ptr_val, decl_index, offset); | 2954 | return func.lowerParentPtr(base_ptr.toValue()); |
| 2926 | }, | 2955 | }, |
| 2927 | .variable => { | 2956 | .comptime_field => unreachable, |
| 2928 | const decl_index = ptr_val.castTag(.variable).?.data.owner_decl; | 2957 | .elem => |elem| { |
| 2929 | return func.lowerParentPtrDecl(ptr_val, decl_index, offset); | 2958 | const index = elem.index; |
| 2959 | const elem_type = mod.intern_pool.typeOf(elem.base).toType().elemType2(mod); | ||
| 2960 | const offset = index * elem_type.abiSize(mod); | ||
| 2961 | const array_ptr = try func.lowerParentPtr(elem.base.toValue()); | ||
| 2962 | |||
| 2963 | return switch (array_ptr) { | ||
| 2964 | .memory => |ptr_| WValue{ | ||
| 2965 | .memory_offset = .{ | ||
| 2966 | .pointer = ptr_, | ||
| 2967 | .offset = @intCast(u32, offset), | ||
| 2968 | }, | ||
| 2969 | }, | ||
| 2970 | .memory_offset => |mem_off| WValue{ | ||
| 2971 | .memory_offset = .{ | ||
| 2972 | .pointer = mem_off.pointer, | ||
| 2973 | .offset = @intCast(u32, offset) + mem_off.offset, | ||
| 2974 | }, | ||
| 2975 | }, | ||
| 2976 | else => unreachable, | ||
| 2977 | }; | ||
| 2930 | }, | 2978 | }, |
| 2931 | .field_ptr => { | 2979 | .field => |field| { |
| 2932 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | 2980 | const parent_ty = mod.intern_pool.typeOf(field.base).toType().childType(mod); |
| 2933 | const parent_ty = field_ptr.container_ty; | 2981 | const parent_ptr = try func.lowerParentPtr(field.base.toValue()); |
| 2934 | 2982 | ||
| 2935 | const field_offset = switch (parent_ty.zigTypeTag()) { | 2983 | const offset = switch (parent_ty.zigTypeTag(mod)) { |
| 2936 | .Struct => switch (parent_ty.containerLayout()) { | 2984 | .Struct => switch (parent_ty.containerLayout(mod)) { |
| 2937 | .Packed => parent_ty.packedStructFieldByteOffset(field_ptr.field_index, func.target), | 2985 | .Packed => parent_ty.packedStructFieldByteOffset(@intCast(usize, field.index), mod), |
| 2938 | else => parent_ty.structFieldOffset(field_ptr.field_index, func.target), | 2986 | else => parent_ty.structFieldOffset(@intCast(usize, field.index), mod), |
| 2939 | }, | 2987 | }, |
| 2940 | .Union => switch (parent_ty.containerLayout()) { | 2988 | .Union => switch (parent_ty.containerLayout(mod)) { |
| 2941 | .Packed => 0, | 2989 | .Packed => 0, |
| 2942 | else => blk: { | 2990 | else => blk: { |
| 2943 | const layout: Module.Union.Layout = parent_ty.unionGetLayout(func.target); | 2991 | const layout: Module.Union.Layout = parent_ty.unionGetLayout(mod); |
| 2944 | if (layout.payload_size == 0) break :blk 0; | 2992 | if (layout.payload_size == 0) break :blk 0; |
| 2945 | if (layout.payload_align > layout.tag_align) break :blk 0; | 2993 | if (layout.payload_align > layout.tag_align) break :blk 0; |
| 2946 | 2994 | ||
| 2947 | // tag is stored first so calculate offset from where payload starts | 2995 | // tag is stored first so calculate offset from where payload starts |
| 2948 | const field_offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align)); | 2996 | const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align)); |
| 2949 | break :blk field_offset; | 2997 | break :blk offset; |
| 2950 | }, | 2998 | }, |
| 2951 | }, | 2999 | }, |
| 2952 | .Pointer => switch (parent_ty.ptrSize()) { | 3000 | .Pointer => switch (parent_ty.ptrSize(mod)) { |
| 2953 | .Slice => switch (field_ptr.field_index) { | 3001 | .Slice => switch (field.index) { |
| 2954 | 0 => 0, | 3002 | 0 => 0, |
| 2955 | 1 => func.ptrSize(), | 3003 | 1 => func.ptrSize(), |
| 2956 | else => unreachable, | 3004 | else => unreachable, |
| ... | @@ -2959,51 +3007,51 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue | ... | @@ -2959,51 +3007,51 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue |
| 2959 | }, | 3007 | }, |
| 2960 | else => unreachable, | 3008 | else => unreachable, |
| 2961 | }; | 3009 | }; |
| 2962 | return func.lowerParentPtr(field_ptr.container_ptr, offset + @intCast(u32, field_offset)); | 3010 | |
| 2963 | }, | 3011 | return switch (parent_ptr) { |
| 2964 | .elem_ptr => { | 3012 | .memory => |ptr_| WValue{ |
| 2965 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | 3013 | .memory_offset = .{ |
| 2966 | const index = elem_ptr.index; | 3014 | .pointer = ptr_, |
| 2967 | const elem_offset = index * elem_ptr.elem_ty.abiSize(func.target); | 3015 | .offset = @intCast(u32, offset), |
| 2968 | return func.lowerParentPtr(elem_ptr.array_ptr, offset + @intCast(u32, elem_offset)); | 3016 | }, |
| 2969 | }, | 3017 | }, |
| 2970 | .opt_payload_ptr => { | 3018 | .memory_offset => |mem_off| WValue{ |
| 2971 | const payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; | 3019 | .memory_offset = .{ |
| 2972 | return func.lowerParentPtr(payload_ptr.container_ptr, offset); | 3020 | .pointer = mem_off.pointer, |
| 3021 | .offset = @intCast(u32, offset) + mem_off.offset, | ||
| 3022 | }, | ||
| 3023 | }, | ||
| 3024 | else => unreachable, | ||
| 3025 | }; | ||
| 2973 | }, | 3026 | }, |
| 2974 | else => |tag| return func.fail("TODO: Implement lowerParentPtr for tag: {}", .{tag}), | ||
| 2975 | } | 3027 | } |
| 2976 | } | 3028 | } |
| 2977 | 3029 | ||
| 2978 | fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue { | 3030 | fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue { |
| 2979 | const module = func.bin_file.base.options.module.?; | 3031 | const mod = func.bin_file.base.options.module.?; |
| 2980 | const decl = module.declPtr(decl_index); | 3032 | const decl = mod.declPtr(decl_index); |
| 2981 | module.markDeclAlive(decl); | 3033 | try mod.markDeclAlive(decl); |
| 2982 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 3034 | const ptr_ty = try mod.singleMutPtrType(decl.ty); |
| 2983 | .base = .{ .tag = .single_mut_pointer }, | ||
| 2984 | .data = decl.ty, | ||
| 2985 | }; | ||
| 2986 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 2987 | return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset); | 3035 | return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset); |
| 2988 | } | 3036 | } |
| 2989 | 3037 | ||
| 2990 | fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue { | 3038 | fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue { |
| 2991 | if (tv.ty.isSlice()) { | 3039 | const mod = func.bin_file.base.options.module.?; |
| 3040 | if (tv.ty.isSlice(mod)) { | ||
| 2992 | return WValue{ .memory = try func.bin_file.lowerUnnamedConst(tv, decl_index) }; | 3041 | return WValue{ .memory = try func.bin_file.lowerUnnamedConst(tv, decl_index) }; |
| 2993 | } | 3042 | } |
| 2994 | 3043 | ||
| 2995 | const module = func.bin_file.base.options.module.?; | 3044 | const decl = mod.declPtr(decl_index); |
| 2996 | const decl = module.declPtr(decl_index); | 3045 | if (decl.ty.zigTypeTag(mod) != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2997 | if (decl.ty.zigTypeTag() != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 2998 | return WValue{ .imm32 = 0xaaaaaaaa }; | 3046 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 2999 | } | 3047 | } |
| 3000 | 3048 | ||
| 3001 | module.markDeclAlive(decl); | 3049 | try mod.markDeclAlive(decl); |
| 3002 | const atom_index = try func.bin_file.getOrCreateAtomForDecl(decl_index); | 3050 | const atom_index = try func.bin_file.getOrCreateAtomForDecl(decl_index); |
| 3003 | const atom = func.bin_file.getAtom(atom_index); | 3051 | const atom = func.bin_file.getAtom(atom_index); |
| 3004 | 3052 | ||
| 3005 | const target_sym_index = atom.sym_index; | 3053 | const target_sym_index = atom.sym_index; |
| 3006 | if (decl.ty.zigTypeTag() == .Fn) { | 3054 | if (decl.ty.zigTypeTag(mod) == .Fn) { |
| 3007 | try func.bin_file.addTableFunction(target_sym_index); | 3055 | try func.bin_file.addTableFunction(target_sym_index); |
| 3008 | return WValue{ .function_index = target_sym_index }; | 3056 | return WValue{ .function_index = target_sym_index }; |
| 3009 | } else if (offset == 0) { | 3057 | } else if (offset == 0) { |
| ... | @@ -3028,142 +3076,201 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo( | ... | @@ -3028,142 +3076,201 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo( |
| 3028 | } | 3076 | } |
| 3029 | 3077 | ||
| 3030 | fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { | 3078 | fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3079 | const mod = func.bin_file.base.options.module.?; | ||
| 3031 | var val = arg_val; | 3080 | var val = arg_val; |
| 3032 | if (val.castTag(.runtime_value)) |rt| { | 3081 | switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 3033 | val = rt.data; | 3082 | .runtime_value => |rt| val = rt.val.toValue(), |
| 3034 | } | 3083 | else => {}, |
| 3035 | if (val.isUndefDeep()) return func.emitUndefined(ty); | 3084 | } |
| 3036 | if (val.castTag(.decl_ref)) |decl_ref| { | 3085 | if (val.isUndefDeep(mod)) return func.emitUndefined(ty); |
| 3037 | const decl_index = decl_ref.data; | 3086 | |
| 3038 | return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0); | 3087 | if (val.ip_index == .none) switch (ty.zigTypeTag(mod)) { |
| 3039 | } | 3088 | .Array => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}), |
| 3040 | if (val.castTag(.decl_ref_mut)) |decl_ref_mut| { | 3089 | .Struct => { |
| 3041 | const decl_index = decl_ref_mut.data.decl_index; | 3090 | const struct_obj = mod.typeToStruct(ty).?; |
| 3042 | return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0); | 3091 | assert(struct_obj.layout == .Packed); |
| 3043 | } | 3092 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer |
| 3044 | const target = func.target; | 3093 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; |
| 3045 | switch (ty.zigTypeTag()) { | 3094 | const int_val = try mod.intValue( |
| 3046 | .Void => return WValue{ .none = {} }, | 3095 | struct_obj.backing_int_ty, |
| 3047 | .Int => { | 3096 | std.mem.readIntLittle(u64, &buf), |
| 3048 | const int_info = ty.intInfo(func.target); | 3097 | ); |
| 3098 | return func.lowerConstant(int_val, struct_obj.backing_int_ty); | ||
| 3099 | }, | ||
| 3100 | .Vector => { | ||
| 3101 | assert(determineSimdStoreStrategy(ty, mod) == .direct); | ||
| 3102 | var buf: [16]u8 = undefined; | ||
| 3103 | val.writeToMemory(ty, mod, &buf) catch unreachable; | ||
| 3104 | return func.storeSimdImmd(buf); | ||
| 3105 | }, | ||
| 3106 | .Frame, | ||
| 3107 | .AnyFrame, | ||
| 3108 | => return func.fail("Wasm TODO: LowerConstant for type {}", .{ty.fmt(mod)}), | ||
| 3109 | .Float, | ||
| 3110 | .Union, | ||
| 3111 | .Optional, | ||
| 3112 | .ErrorUnion, | ||
| 3113 | .ErrorSet, | ||
| 3114 | .Int, | ||
| 3115 | .Enum, | ||
| 3116 | .Bool, | ||
| 3117 | .Pointer, | ||
| 3118 | => unreachable, // handled below | ||
| 3119 | .Type, | ||
| 3120 | .Void, | ||
| 3121 | .NoReturn, | ||
| 3122 | .ComptimeFloat, | ||
| 3123 | .ComptimeInt, | ||
| 3124 | .Undefined, | ||
| 3125 | .Null, | ||
| 3126 | .Opaque, | ||
| 3127 | .EnumLiteral, | ||
| 3128 | .Fn, | ||
| 3129 | => unreachable, // comptime-only types | ||
| 3130 | }; | ||
| 3131 | |||
| 3132 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | ||
| 3133 | .int_type, | ||
| 3134 | .ptr_type, | ||
| 3135 | .array_type, | ||
| 3136 | .vector_type, | ||
| 3137 | .opt_type, | ||
| 3138 | .anyframe_type, | ||
| 3139 | .error_union_type, | ||
| 3140 | .simple_type, | ||
| 3141 | .struct_type, | ||
| 3142 | .anon_struct_type, | ||
| 3143 | .union_type, | ||
| 3144 | .opaque_type, | ||
| 3145 | .enum_type, | ||
| 3146 | .func_type, | ||
| 3147 | .error_set_type, | ||
| 3148 | .inferred_error_set_type, | ||
| 3149 | => unreachable, // types, not values | ||
| 3150 | |||
| 3151 | .undef, .runtime_value => unreachable, // handled above | ||
| 3152 | .simple_value => |simple_value| switch (simple_value) { | ||
| 3153 | .undefined, | ||
| 3154 | .void, | ||
| 3155 | .null, | ||
| 3156 | .empty_struct, | ||
| 3157 | .@"unreachable", | ||
| 3158 | .generic_poison, | ||
| 3159 | => unreachable, // non-runtime values | ||
| 3160 | .false, .true => return WValue{ .imm32 = switch (simple_value) { | ||
| 3161 | .false => 0, | ||
| 3162 | .true => 1, | ||
| 3163 | else => unreachable, | ||
| 3164 | } }, | ||
| 3165 | }, | ||
| 3166 | .variable, | ||
| 3167 | .extern_func, | ||
| 3168 | .func, | ||
| 3169 | .enum_literal, | ||
| 3170 | .empty_enum_value, | ||
| 3171 | => unreachable, // non-runtime values | ||
| 3172 | .int => { | ||
| 3173 | const int_info = ty.intInfo(mod); | ||
| 3049 | switch (int_info.signedness) { | 3174 | switch (int_info.signedness) { |
| 3050 | .signed => switch (int_info.bits) { | 3175 | .signed => switch (int_info.bits) { |
| 3051 | 0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement( | 3176 | 0...32 => return WValue{ .imm32 = @intCast(u32, toTwosComplement( |
| 3052 | val.toSignedInt(target), | 3177 | val.toSignedInt(mod), |
| 3053 | @intCast(u6, int_info.bits), | 3178 | @intCast(u6, int_info.bits), |
| 3054 | )) }, | 3179 | )) }, |
| 3055 | 33...64 => return WValue{ .imm64 = toTwosComplement( | 3180 | 33...64 => return WValue{ .imm64 = toTwosComplement( |
| 3056 | val.toSignedInt(target), | 3181 | val.toSignedInt(mod), |
| 3057 | @intCast(u7, int_info.bits), | 3182 | @intCast(u7, int_info.bits), |
| 3058 | ) }, | 3183 | ) }, |
| 3059 | else => unreachable, | 3184 | else => unreachable, |
| 3060 | }, | 3185 | }, |
| 3061 | .unsigned => switch (int_info.bits) { | 3186 | .unsigned => switch (int_info.bits) { |
| 3062 | 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) }, | 3187 | 0...32 => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(mod)) }, |
| 3063 | 33...64 => return WValue{ .imm64 = val.toUnsignedInt(target) }, | 3188 | 33...64 => return WValue{ .imm64 = val.toUnsignedInt(mod) }, |
| 3064 | else => unreachable, | 3189 | else => unreachable, |
| 3065 | }, | 3190 | }, |
| 3066 | } | 3191 | } |
| 3067 | }, | 3192 | }, |
| 3068 | .Bool => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) }, | 3193 | .err => |err| { |
| 3069 | .Float => switch (ty.floatBits(func.target)) { | 3194 | const int = try mod.getErrorValue(err.name); |
| 3070 | 16 => return WValue{ .imm32 = @bitCast(u16, val.toFloat(f16)) }, | 3195 | return WValue{ .imm32 = int }; |
| 3071 | 32 => return WValue{ .float32 = val.toFloat(f32) }, | ||
| 3072 | 64 => return WValue{ .float64 = val.toFloat(f64) }, | ||
| 3073 | else => unreachable, | ||
| 3074 | }, | ||
| 3075 | .Pointer => switch (val.tag()) { | ||
| 3076 | .field_ptr, .elem_ptr, .opt_payload_ptr => return func.lowerParentPtr(val, 0), | ||
| 3077 | .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(target)) }, | ||
| 3078 | .zero, .null_value => return WValue{ .imm32 = 0 }, | ||
| 3079 | else => return func.fail("Wasm TODO: lowerConstant for other const pointer tag {}", .{val.tag()}), | ||
| 3080 | }, | 3196 | }, |
| 3081 | .Enum => { | 3197 | .error_union => |error_union| { |
| 3082 | if (val.castTag(.enum_field_index)) |field_index| { | 3198 | const err_tv: TypedValue = switch (error_union.val) { |
| 3083 | switch (ty.tag()) { | 3199 | .err_name => |err_name| .{ |
| 3084 | .enum_simple => return WValue{ .imm32 = field_index.data }, | 3200 | .ty = ty.errorUnionSet(mod), |
| 3085 | .enum_full, .enum_nonexhaustive => { | 3201 | .val = (try mod.intern(.{ .err = .{ |
| 3086 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | 3202 | .ty = ty.errorUnionSet(mod).toIntern(), |
| 3087 | if (enum_full.values.count() != 0) { | 3203 | .name = err_name, |
| 3088 | const tag_val = enum_full.values.keys()[field_index.data]; | 3204 | } })).toValue(), |
| 3089 | return func.lowerConstant(tag_val, enum_full.tag_ty); | 3205 | }, |
| 3090 | } else { | 3206 | .payload => .{ |
| 3091 | return WValue{ .imm32 = field_index.data }; | 3207 | .ty = Type.err_int, |
| 3092 | } | 3208 | .val = try mod.intValue(Type.err_int, 0), |
| 3093 | }, | 3209 | }, |
| 3094 | .enum_numbered => { | 3210 | }; |
| 3095 | const index = field_index.data; | 3211 | const payload_type = ty.errorUnionPayload(mod); |
| 3096 | const enum_data = ty.castTag(.enum_numbered).?.data; | 3212 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3097 | const enum_val = enum_data.values.keys()[index]; | ||
| 3098 | return func.lowerConstant(enum_val, enum_data.tag_ty); | ||
| 3099 | }, | ||
| 3100 | else => return func.fail("TODO: lowerConstant for enum tag: {}", .{ty.tag()}), | ||
| 3101 | } | ||
| 3102 | } else { | ||
| 3103 | var int_tag_buffer: Type.Payload.Bits = undefined; | ||
| 3104 | const int_tag_ty = ty.intTagType(&int_tag_buffer); | ||
| 3105 | return func.lowerConstant(val, int_tag_ty); | ||
| 3106 | } | ||
| 3107 | }, | ||
| 3108 | .ErrorSet => switch (val.tag()) { | ||
| 3109 | .@"error" => { | ||
| 3110 | const kv = try func.bin_file.base.options.module.?.getErrorValue(val.getError().?); | ||
| 3111 | return WValue{ .imm32 = kv.value }; | ||
| 3112 | }, | ||
| 3113 | else => return WValue{ .imm32 = 0 }, | ||
| 3114 | }, | ||
| 3115 | .ErrorUnion => { | ||
| 3116 | const error_type = ty.errorUnionSet(); | ||
| 3117 | const payload_type = ty.errorUnionPayload(); | ||
| 3118 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | ||
| 3119 | // We use the error type directly as the type. | 3213 | // We use the error type directly as the type. |
| 3120 | const is_pl = val.errorUnionIsPayload(); | 3214 | return func.lowerConstant(err_tv.val, err_tv.ty); |
| 3121 | const err_val = if (!is_pl) val else Value.initTag(.zero); | ||
| 3122 | return func.lowerConstant(err_val, error_type); | ||
| 3123 | } | 3215 | } |
| 3216 | |||
| 3124 | return func.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{}); | 3217 | return func.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{}); |
| 3125 | }, | 3218 | }, |
| 3126 | .Optional => if (ty.optionalReprIsPayload()) { | 3219 | .enum_tag => |enum_tag| { |
| 3127 | var buf: Type.Payload.ElemType = undefined; | 3220 | const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int); |
| 3128 | const pl_ty = ty.optionalChild(&buf); | 3221 | return func.lowerConstant(enum_tag.int.toValue(), int_tag_ty.toType()); |
| 3129 | if (val.castTag(.opt_payload)) |payload| { | 3222 | }, |
| 3130 | return func.lowerConstant(payload.data, pl_ty); | 3223 | .float => |float| switch (float.storage) { |
| 3131 | } else if (val.isNull()) { | 3224 | .f16 => |f16_val| return WValue{ .imm32 = @bitCast(u16, f16_val) }, |
| 3132 | return WValue{ .imm32 = 0 }; | 3225 | .f32 => |f32_val| return WValue{ .float32 = f32_val }, |
| 3226 | .f64 => |f64_val| return WValue{ .float64 = f64_val }, | ||
| 3227 | else => unreachable, | ||
| 3228 | }, | ||
| 3229 | .ptr => |ptr| switch (ptr.addr) { | ||
| 3230 | .decl => |decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl, 0), | ||
| 3231 | .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0), | ||
| 3232 | .int => |int| return func.lowerConstant(int.toValue(), mod.intern_pool.typeOf(int).toType()), | ||
| 3233 | .opt_payload, .elem, .field => return func.lowerParentPtr(val), | ||
| 3234 | else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}), | ||
| 3235 | }, | ||
| 3236 | .opt => if (ty.optionalReprIsPayload(mod)) { | ||
| 3237 | const pl_ty = ty.optionalChild(mod); | ||
| 3238 | if (val.optionalValue(mod)) |payload| { | ||
| 3239 | return func.lowerConstant(payload, pl_ty); | ||
| 3133 | } else { | 3240 | } else { |
| 3134 | return func.lowerConstant(val, pl_ty); | 3241 | return WValue{ .imm32 = 0 }; |
| 3135 | } | 3242 | } |
| 3136 | } else { | 3243 | } else { |
| 3137 | const is_pl = val.tag() == .opt_payload; | 3244 | return WValue{ .imm32 = @boolToInt(!val.isNull(mod)) }; |
| 3138 | return WValue{ .imm32 = @boolToInt(is_pl) }; | ||
| 3139 | }, | 3245 | }, |
| 3140 | .Struct => { | 3246 | .aggregate => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 3141 | const struct_obj = ty.castTag(.@"struct").?.data; | 3247 | .array_type => return func.fail("Wasm TODO: LowerConstant for {}", .{ty.fmt(mod)}), |
| 3142 | assert(struct_obj.layout == .Packed); | 3248 | .vector_type => { |
| 3143 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer | 3249 | assert(determineSimdStoreStrategy(ty, mod) == .direct); |
| 3144 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; | 3250 | var buf: [16]u8 = undefined; |
| 3145 | var payload: Value.Payload.U64 = .{ | 3251 | val.writeToMemory(ty, mod, &buf) catch unreachable; |
| 3146 | .base = .{ .tag = .int_u64 }, | 3252 | return func.storeSimdImmd(buf); |
| 3147 | .data = std.mem.readIntLittle(u64, &buf), | 3253 | }, |
| 3148 | }; | 3254 | .struct_type, .anon_struct_type => { |
| 3149 | const int_val = Value.initPayload(&payload.base); | 3255 | const struct_obj = mod.typeToStruct(ty).?; |
| 3150 | return func.lowerConstant(int_val, struct_obj.backing_int_ty); | 3256 | assert(struct_obj.layout == .Packed); |
| 3151 | }, | 3257 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer |
| 3152 | .Vector => { | 3258 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; |
| 3153 | assert(determineSimdStoreStrategy(ty, target) == .direct); | 3259 | const int_val = try mod.intValue( |
| 3154 | var buf: [16]u8 = undefined; | 3260 | struct_obj.backing_int_ty, |
| 3155 | val.writeToMemory(ty, func.bin_file.base.options.module.?, &buf) catch unreachable; | 3261 | std.mem.readIntLittle(u64, &buf), |
| 3156 | return func.storeSimdImmd(buf); | 3262 | ); |
| 3263 | return func.lowerConstant(int_val, struct_obj.backing_int_ty); | ||
| 3264 | }, | ||
| 3265 | else => unreachable, | ||
| 3157 | }, | 3266 | }, |
| 3158 | .Union => { | 3267 | .un => |union_obj| { |
| 3159 | // in this case we have a packed union which will not be passed by reference. | 3268 | // in this case we have a packed union which will not be passed by reference. |
| 3160 | const union_ty = ty.cast(Type.Payload.Union).?.data; | 3269 | const field_index = ty.unionTagFieldIndex(union_obj.tag.toValue(), func.bin_file.base.options.module.?).?; |
| 3161 | const union_obj = val.castTag(.@"union").?.data; | 3270 | const field_ty = ty.unionFields(mod).values()[field_index].ty; |
| 3162 | const field_index = ty.unionTagFieldIndex(union_obj.tag, func.bin_file.base.options.module.?).?; | 3271 | return func.lowerConstant(union_obj.val.toValue(), field_ty); |
| 3163 | const field_ty = union_ty.fields.values()[field_index].ty; | ||
| 3164 | return func.lowerConstant(union_obj.val, field_ty); | ||
| 3165 | }, | 3272 | }, |
| 3166 | else => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}), | 3273 | .memoized_call => unreachable, |
| 3167 | } | 3274 | } |
| 3168 | } | 3275 | } |
| 3169 | 3276 | ||
| ... | @@ -3176,9 +3283,10 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue { | ... | @@ -3176,9 +3283,10 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue { |
| 3176 | } | 3283 | } |
| 3177 | 3284 | ||
| 3178 | fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { | 3285 | fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3179 | switch (ty.zigTypeTag()) { | 3286 | const mod = func.bin_file.base.options.module.?; |
| 3287 | switch (ty.zigTypeTag(mod)) { | ||
| 3180 | .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa }, | 3288 | .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa }, |
| 3181 | .Int, .Enum => switch (ty.intInfo(func.target).bits) { | 3289 | .Int, .Enum => switch (ty.intInfo(mod).bits) { |
| 3182 | 0...32 => return WValue{ .imm32 = 0xaaaaaaaa }, | 3290 | 0...32 => return WValue{ .imm32 = 0xaaaaaaaa }, |
| 3183 | 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa }, | 3291 | 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa }, |
| 3184 | else => unreachable, | 3292 | else => unreachable, |
| ... | @@ -3195,9 +3303,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { | ... | @@ -3195,9 +3303,8 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3195 | else => unreachable, | 3303 | else => unreachable, |
| 3196 | }, | 3304 | }, |
| 3197 | .Optional => { | 3305 | .Optional => { |
| 3198 | var buf: Type.Payload.ElemType = undefined; | 3306 | const pl_ty = ty.optionalChild(mod); |
| 3199 | const pl_ty = ty.optionalChild(&buf); | 3307 | if (ty.optionalReprIsPayload(mod)) { |
| 3200 | if (ty.optionalReprIsPayload()) { | ||
| 3201 | return func.emitUndefined(pl_ty); | 3308 | return func.emitUndefined(pl_ty); |
| 3202 | } | 3309 | } |
| 3203 | return WValue{ .imm32 = 0xaaaaaaaa }; | 3310 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| ... | @@ -3206,11 +3313,11 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { | ... | @@ -3206,11 +3313,11 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3206 | return WValue{ .imm32 = 0xaaaaaaaa }; | 3313 | return WValue{ .imm32 = 0xaaaaaaaa }; |
| 3207 | }, | 3314 | }, |
| 3208 | .Struct => { | 3315 | .Struct => { |
| 3209 | const struct_obj = ty.castTag(.@"struct").?.data; | 3316 | const struct_obj = mod.typeToStruct(ty).?; |
| 3210 | assert(struct_obj.layout == .Packed); | 3317 | assert(struct_obj.layout == .Packed); |
| 3211 | return func.emitUndefined(struct_obj.backing_int_ty); | 3318 | return func.emitUndefined(struct_obj.backing_int_ty); |
| 3212 | }, | 3319 | }, |
| 3213 | else => return func.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag()}), | 3320 | else => return func.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag(mod)}), |
| 3214 | } | 3321 | } |
| 3215 | } | 3322 | } |
| 3216 | 3323 | ||
| ... | @@ -3218,56 +3325,52 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { | ... | @@ -3218,56 +3325,52 @@ fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { |
| 3218 | /// It's illegal to provide a value with a type that cannot be represented | 3325 | /// It's illegal to provide a value with a type that cannot be represented |
| 3219 | /// as an integer value. | 3326 | /// as an integer value. |
| 3220 | fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { | 3327 | fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { |
| 3221 | const target = func.target; | 3328 | const mod = func.bin_file.base.options.module.?; |
| 3222 | switch (ty.zigTypeTag()) { | 3329 | |
| 3223 | .Enum => { | 3330 | switch (val.ip_index) { |
| 3224 | if (val.castTag(.enum_field_index)) |field_index| { | 3331 | .none => {}, |
| 3225 | switch (ty.tag()) { | 3332 | .bool_true => return 1, |
| 3226 | .enum_simple => return @bitCast(i32, field_index.data), | 3333 | .bool_false => return 0, |
| 3227 | .enum_full, .enum_nonexhaustive => { | 3334 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 3228 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | 3335 | .enum_tag => |enum_tag| intIndexAsI32(&mod.intern_pool, enum_tag.int, mod), |
| 3229 | if (enum_full.values.count() != 0) { | 3336 | .int => |int| intStorageAsI32(int.storage, mod), |
| 3230 | const tag_val = enum_full.values.keys()[field_index.data]; | 3337 | .ptr => |ptr| intIndexAsI32(&mod.intern_pool, ptr.addr.int, mod), |
| 3231 | return func.valueAsI32(tag_val, enum_full.tag_ty); | 3338 | .err => |err| @bitCast(i32, @intCast(Module.ErrorInt, mod.global_error_set.getIndex(err.name).?)), |
| 3232 | } else return @bitCast(i32, field_index.data); | 3339 | else => unreachable, |
| 3233 | }, | ||
| 3234 | .enum_numbered => { | ||
| 3235 | const index = field_index.data; | ||
| 3236 | const enum_data = ty.castTag(.enum_numbered).?.data; | ||
| 3237 | return func.valueAsI32(enum_data.values.keys()[index], enum_data.tag_ty); | ||
| 3238 | }, | ||
| 3239 | else => unreachable, | ||
| 3240 | } | ||
| 3241 | } else { | ||
| 3242 | var int_tag_buffer: Type.Payload.Bits = undefined; | ||
| 3243 | const int_tag_ty = ty.intTagType(&int_tag_buffer); | ||
| 3244 | return func.valueAsI32(val, int_tag_ty); | ||
| 3245 | } | ||
| 3246 | }, | ||
| 3247 | .Int => switch (ty.intInfo(func.target).signedness) { | ||
| 3248 | .signed => return @truncate(i32, val.toSignedInt(target)), | ||
| 3249 | .unsigned => return @bitCast(i32, @truncate(u32, val.toUnsignedInt(target))), | ||
| 3250 | }, | ||
| 3251 | .ErrorSet => { | ||
| 3252 | const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function | ||
| 3253 | return @bitCast(i32, kv.value); | ||
| 3254 | }, | 3340 | }, |
| 3255 | .Bool => return @intCast(i32, val.toSignedInt(target)), | ||
| 3256 | .Pointer => return @intCast(i32, val.toSignedInt(target)), | ||
| 3257 | else => unreachable, // Programmer called this function for an illegal type | ||
| 3258 | } | 3341 | } |
| 3342 | |||
| 3343 | return switch (ty.zigTypeTag(mod)) { | ||
| 3344 | .ErrorSet => @bitCast(i32, val.getErrorInt(mod)), | ||
| 3345 | else => unreachable, // Programmer called this function for an illegal type | ||
| 3346 | }; | ||
| 3347 | } | ||
| 3348 | |||
| 3349 | fn intIndexAsI32(ip: *const InternPool, int: InternPool.Index, mod: *Module) i32 { | ||
| 3350 | return intStorageAsI32(ip.indexToKey(int).int.storage, mod); | ||
| 3351 | } | ||
| 3352 | |||
| 3353 | fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 { | ||
| 3354 | return switch (storage) { | ||
| 3355 | .i64 => |x| @intCast(i32, x), | ||
| 3356 | .u64 => |x| @bitCast(i32, @intCast(u32, x)), | ||
| 3357 | .big_int => unreachable, | ||
| 3358 | .lazy_align => |ty| @bitCast(i32, ty.toType().abiAlignment(mod)), | ||
| 3359 | .lazy_size => |ty| @bitCast(i32, @intCast(u32, ty.toType().abiSize(mod))), | ||
| 3360 | }; | ||
| 3259 | } | 3361 | } |
| 3260 | 3362 | ||
| 3261 | fn airBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 3363 | fn airBlock(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3364 | const mod = func.bin_file.base.options.module.?; | ||
| 3262 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 3365 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 3263 | const block_ty = func.air.getRefType(ty_pl.ty); | 3366 | const block_ty = func.air.getRefType(ty_pl.ty); |
| 3264 | const wasm_block_ty = genBlockType(block_ty, func.target); | 3367 | const wasm_block_ty = genBlockType(block_ty, mod); |
| 3265 | const extra = func.air.extraData(Air.Block, ty_pl.payload); | 3368 | const extra = func.air.extraData(Air.Block, ty_pl.payload); |
| 3266 | const body = func.air.extra[extra.end..][0..extra.data.body_len]; | 3369 | const body = func.air.extra[extra.end..][0..extra.data.body_len]; |
| 3267 | 3370 | ||
| 3268 | // if wasm_block_ty is non-empty, we create a register to store the temporary value | 3371 | // if wasm_block_ty is non-empty, we create a register to store the temporary value |
| 3269 | const block_result: WValue = if (wasm_block_ty != wasm.block_empty) blk: { | 3372 | const block_result: WValue = if (wasm_block_ty != wasm.block_empty) blk: { |
| 3270 | const ty: Type = if (isByRef(block_ty, func.target)) Type.u32 else block_ty; | 3373 | const ty: Type = if (isByRef(block_ty, mod)) Type.u32 else block_ty; |
| 3271 | break :blk try func.ensureAllocLocal(ty); // make sure it's a clean local as it may never get overwritten | 3374 | break :blk try func.ensureAllocLocal(ty); // make sure it's a clean local as it may never get overwritten |
| 3272 | } else WValue.none; | 3375 | } else WValue.none; |
| 3273 | 3376 | ||
| ... | @@ -3369,7 +3472,7 @@ fn airCmp(func: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) In | ... | @@ -3369,7 +3472,7 @@ fn airCmp(func: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) In |
| 3369 | 3472 | ||
| 3370 | const lhs = try func.resolveInst(bin_op.lhs); | 3473 | const lhs = try func.resolveInst(bin_op.lhs); |
| 3371 | const rhs = try func.resolveInst(bin_op.rhs); | 3474 | const rhs = try func.resolveInst(bin_op.rhs); |
| 3372 | const operand_ty = func.air.typeOf(bin_op.lhs); | 3475 | const operand_ty = func.typeOf(bin_op.lhs); |
| 3373 | const result = try (try func.cmp(lhs, rhs, operand_ty, op)).toLocal(func, Type.u32); // comparison result is always 32 bits | 3476 | const result = try (try func.cmp(lhs, rhs, operand_ty, op)).toLocal(func, Type.u32); // comparison result is always 32 bits |
| 3374 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); | 3477 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 3375 | } | 3478 | } |
| ... | @@ -3379,16 +3482,16 @@ fn airCmp(func: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) In | ... | @@ -3379,16 +3482,16 @@ fn airCmp(func: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) In |
| 3379 | /// NOTE: This leaves the result on top of the stack, rather than a new local. | 3482 | /// NOTE: This leaves the result on top of the stack, rather than a new local. |
| 3380 | fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue { | 3483 | fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 3381 | assert(!(lhs != .stack and rhs == .stack)); | 3484 | assert(!(lhs != .stack and rhs == .stack)); |
| 3382 | if (ty.zigTypeTag() == .Optional and !ty.optionalReprIsPayload()) { | 3485 | const mod = func.bin_file.base.options.module.?; |
| 3383 | var buf: Type.Payload.ElemType = undefined; | 3486 | if (ty.zigTypeTag(mod) == .Optional and !ty.optionalReprIsPayload(mod)) { |
| 3384 | const payload_ty = ty.optionalChild(&buf); | 3487 | const payload_ty = ty.optionalChild(mod); |
| 3385 | if (payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3488 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3386 | // When we hit this case, we must check the value of optionals | 3489 | // When we hit this case, we must check the value of optionals |
| 3387 | // that are not pointers. This means first checking against non-null for | 3490 | // that are not pointers. This means first checking against non-null for |
| 3388 | // both lhs and rhs, as well as checking the payload are matching of lhs and rhs | 3491 | // both lhs and rhs, as well as checking the payload are matching of lhs and rhs |
| 3389 | return func.cmpOptionals(lhs, rhs, ty, op); | 3492 | return func.cmpOptionals(lhs, rhs, ty, op); |
| 3390 | } | 3493 | } |
| 3391 | } else if (isByRef(ty, func.target)) { | 3494 | } else if (isByRef(ty, mod)) { |
| 3392 | return func.cmpBigInt(lhs, rhs, ty, op); | 3495 | return func.cmpBigInt(lhs, rhs, ty, op); |
| 3393 | } else if (ty.isAnyFloat() and ty.floatBits(func.target) == 16) { | 3496 | } else if (ty.isAnyFloat() and ty.floatBits(func.target) == 16) { |
| 3394 | return func.cmpFloat16(lhs, rhs, op); | 3497 | return func.cmpFloat16(lhs, rhs, op); |
| ... | @@ -3401,13 +3504,13 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO | ... | @@ -3401,13 +3504,13 @@ fn cmp(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, op: std.math.CompareO |
| 3401 | 3504 | ||
| 3402 | const signedness: std.builtin.Signedness = blk: { | 3505 | const signedness: std.builtin.Signedness = blk: { |
| 3403 | // by default we tell the operand type is unsigned (i.e. bools and enum values) | 3506 | // by default we tell the operand type is unsigned (i.e. bools and enum values) |
| 3404 | if (ty.zigTypeTag() != .Int) break :blk .unsigned; | 3507 | if (ty.zigTypeTag(mod) != .Int) break :blk .unsigned; |
| 3405 | 3508 | ||
| 3406 | // incase of an actual integer, we emit the correct signedness | 3509 | // incase of an actual integer, we emit the correct signedness |
| 3407 | break :blk ty.intInfo(func.target).signedness; | 3510 | break :blk ty.intInfo(mod).signedness; |
| 3408 | }; | 3511 | }; |
| 3409 | const opcode: wasm.Opcode = buildOpcode(.{ | 3512 | const opcode: wasm.Opcode = buildOpcode(.{ |
| 3410 | .valtype1 = typeToValtype(ty, func.target), | 3513 | .valtype1 = typeToValtype(ty, mod), |
| 3411 | .op = switch (op) { | 3514 | .op = switch (op) { |
| 3412 | .lt => .lt, | 3515 | .lt => .lt, |
| 3413 | .lte => .le, | 3516 | .lte => .le, |
| ... | @@ -3464,11 +3567,12 @@ fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3464,11 +3567,12 @@ fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3464 | } | 3567 | } |
| 3465 | 3568 | ||
| 3466 | fn airBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 3569 | fn airBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3570 | const mod = func.bin_file.base.options.module.?; | ||
| 3467 | const br = func.air.instructions.items(.data)[inst].br; | 3571 | const br = func.air.instructions.items(.data)[inst].br; |
| 3468 | const block = func.blocks.get(br.block_inst).?; | 3572 | const block = func.blocks.get(br.block_inst).?; |
| 3469 | 3573 | ||
| 3470 | // if operand has codegen bits we should break with a value | 3574 | // if operand has codegen bits we should break with a value |
| 3471 | if (func.air.typeOf(br.operand).hasRuntimeBitsIgnoreComptime()) { | 3575 | if (func.typeOf(br.operand).hasRuntimeBitsIgnoreComptime(mod)) { |
| 3472 | const operand = try func.resolveInst(br.operand); | 3576 | const operand = try func.resolveInst(br.operand); |
| 3473 | try func.lowerToStack(operand); | 3577 | try func.lowerToStack(operand); |
| 3474 | 3578 | ||
| ... | @@ -3489,17 +3593,18 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3489,17 +3593,18 @@ fn airNot(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3489 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 3593 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 3490 | 3594 | ||
| 3491 | const operand = try func.resolveInst(ty_op.operand); | 3595 | const operand = try func.resolveInst(ty_op.operand); |
| 3492 | const operand_ty = func.air.typeOf(ty_op.operand); | 3596 | const operand_ty = func.typeOf(ty_op.operand); |
| 3597 | const mod = func.bin_file.base.options.module.?; | ||
| 3493 | 3598 | ||
| 3494 | const result = result: { | 3599 | const result = result: { |
| 3495 | if (operand_ty.zigTypeTag() == .Bool) { | 3600 | if (operand_ty.zigTypeTag(mod) == .Bool) { |
| 3496 | try func.emitWValue(operand); | 3601 | try func.emitWValue(operand); |
| 3497 | try func.addTag(.i32_eqz); | 3602 | try func.addTag(.i32_eqz); |
| 3498 | const not_tmp = try func.allocLocal(operand_ty); | 3603 | const not_tmp = try func.allocLocal(operand_ty); |
| 3499 | try func.addLabel(.local_set, not_tmp.local.value); | 3604 | try func.addLabel(.local_set, not_tmp.local.value); |
| 3500 | break :result not_tmp; | 3605 | break :result not_tmp; |
| 3501 | } else { | 3606 | } else { |
| 3502 | const operand_bits = operand_ty.intInfo(func.target).bits; | 3607 | const operand_bits = operand_ty.intInfo(mod).bits; |
| 3503 | const wasm_bits = toWasmBits(operand_bits) orelse { | 3608 | const wasm_bits = toWasmBits(operand_bits) orelse { |
| 3504 | return func.fail("TODO: Implement binary NOT for integer with bitsize '{d}'", .{operand_bits}); | 3609 | return func.fail("TODO: Implement binary NOT for integer with bitsize '{d}'", .{operand_bits}); |
| 3505 | }; | 3610 | }; |
| ... | @@ -3554,8 +3659,8 @@ fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3554,8 +3659,8 @@ fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3554 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 3659 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 3555 | const result = result: { | 3660 | const result = result: { |
| 3556 | const operand = try func.resolveInst(ty_op.operand); | 3661 | const operand = try func.resolveInst(ty_op.operand); |
| 3557 | const wanted_ty = func.air.typeOfIndex(inst); | 3662 | const wanted_ty = func.typeOfIndex(inst); |
| 3558 | const given_ty = func.air.typeOf(ty_op.operand); | 3663 | const given_ty = func.typeOf(ty_op.operand); |
| 3559 | if (given_ty.isAnyFloat() or wanted_ty.isAnyFloat()) { | 3664 | if (given_ty.isAnyFloat() or wanted_ty.isAnyFloat()) { |
| 3560 | const bitcast_result = try func.bitcast(wanted_ty, given_ty, operand); | 3665 | const bitcast_result = try func.bitcast(wanted_ty, given_ty, operand); |
| 3561 | break :result try bitcast_result.toLocal(func, wanted_ty); | 3666 | break :result try bitcast_result.toLocal(func, wanted_ty); |
| ... | @@ -3566,16 +3671,17 @@ fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3566,16 +3671,17 @@ fn airBitcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3566 | } | 3671 | } |
| 3567 | 3672 | ||
| 3568 | fn bitcast(func: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) InnerError!WValue { | 3673 | fn bitcast(func: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) InnerError!WValue { |
| 3674 | const mod = func.bin_file.base.options.module.?; | ||
| 3569 | // if we bitcast a float to or from an integer we must use the 'reinterpret' instruction | 3675 | // if we bitcast a float to or from an integer we must use the 'reinterpret' instruction |
| 3570 | if (!(wanted_ty.isAnyFloat() or given_ty.isAnyFloat())) return operand; | 3676 | if (!(wanted_ty.isAnyFloat() or given_ty.isAnyFloat())) return operand; |
| 3571 | if (wanted_ty.tag() == .f16 or given_ty.tag() == .f16) return operand; | 3677 | if (wanted_ty.ip_index == .f16_type or given_ty.ip_index == .f16_type) return operand; |
| 3572 | if (wanted_ty.bitSize(func.target) > 64) return operand; | 3678 | if (wanted_ty.bitSize(mod) > 64) return operand; |
| 3573 | assert((wanted_ty.isInt() and given_ty.isAnyFloat()) or (wanted_ty.isAnyFloat() and given_ty.isInt())); | 3679 | assert((wanted_ty.isInt(mod) and given_ty.isAnyFloat()) or (wanted_ty.isAnyFloat() and given_ty.isInt(mod))); |
| 3574 | 3680 | ||
| 3575 | const opcode = buildOpcode(.{ | 3681 | const opcode = buildOpcode(.{ |
| 3576 | .op = .reinterpret, | 3682 | .op = .reinterpret, |
| 3577 | .valtype1 = typeToValtype(wanted_ty, func.target), | 3683 | .valtype1 = typeToValtype(wanted_ty, mod), |
| 3578 | .valtype2 = typeToValtype(given_ty, func.target), | 3684 | .valtype2 = typeToValtype(given_ty, mod), |
| 3579 | }); | 3685 | }); |
| 3580 | try func.emitWValue(operand); | 3686 | try func.emitWValue(operand); |
| 3581 | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 3687 | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| ... | @@ -3583,19 +3689,21 @@ fn bitcast(func: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) Inn | ... | @@ -3583,19 +3689,21 @@ fn bitcast(func: *CodeGen, wanted_ty: Type, given_ty: Type, operand: WValue) Inn |
| 3583 | } | 3689 | } |
| 3584 | 3690 | ||
| 3585 | fn airStructFieldPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 3691 | fn airStructFieldPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3692 | const mod = func.bin_file.base.options.module.?; | ||
| 3586 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 3693 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 3587 | const extra = func.air.extraData(Air.StructField, ty_pl.payload); | 3694 | const extra = func.air.extraData(Air.StructField, ty_pl.payload); |
| 3588 | 3695 | ||
| 3589 | const struct_ptr = try func.resolveInst(extra.data.struct_operand); | 3696 | const struct_ptr = try func.resolveInst(extra.data.struct_operand); |
| 3590 | const struct_ty = func.air.typeOf(extra.data.struct_operand).childType(); | 3697 | const struct_ty = func.typeOf(extra.data.struct_operand).childType(mod); |
| 3591 | const result = try func.structFieldPtr(inst, extra.data.struct_operand, struct_ptr, struct_ty, extra.data.field_index); | 3698 | const result = try func.structFieldPtr(inst, extra.data.struct_operand, struct_ptr, struct_ty, extra.data.field_index); |
| 3592 | func.finishAir(inst, result, &.{extra.data.struct_operand}); | 3699 | func.finishAir(inst, result, &.{extra.data.struct_operand}); |
| 3593 | } | 3700 | } |
| 3594 | 3701 | ||
| 3595 | fn airStructFieldPtrIndex(func: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void { | 3702 | fn airStructFieldPtrIndex(func: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void { |
| 3703 | const mod = func.bin_file.base.options.module.?; | ||
| 3596 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 3704 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 3597 | const struct_ptr = try func.resolveInst(ty_op.operand); | 3705 | const struct_ptr = try func.resolveInst(ty_op.operand); |
| 3598 | const struct_ty = func.air.typeOf(ty_op.operand).childType(); | 3706 | const struct_ty = func.typeOf(ty_op.operand).childType(mod); |
| 3599 | 3707 | ||
| 3600 | const result = try func.structFieldPtr(inst, ty_op.operand, struct_ptr, struct_ty, index); | 3708 | const result = try func.structFieldPtr(inst, ty_op.operand, struct_ptr, struct_ty, index); |
| 3601 | func.finishAir(inst, result, &.{ty_op.operand}); | 3709 | func.finishAir(inst, result, &.{ty_op.operand}); |
| ... | @@ -3609,19 +3717,20 @@ fn structFieldPtr( | ... | @@ -3609,19 +3717,20 @@ fn structFieldPtr( |
| 3609 | struct_ty: Type, | 3717 | struct_ty: Type, |
| 3610 | index: u32, | 3718 | index: u32, |
| 3611 | ) InnerError!WValue { | 3719 | ) InnerError!WValue { |
| 3612 | const result_ty = func.air.typeOfIndex(inst); | 3720 | const mod = func.bin_file.base.options.module.?; |
| 3613 | const offset = switch (struct_ty.containerLayout()) { | 3721 | const result_ty = func.typeOfIndex(inst); |
| 3614 | .Packed => switch (struct_ty.zigTypeTag()) { | 3722 | const offset = switch (struct_ty.containerLayout(mod)) { |
| 3723 | .Packed => switch (struct_ty.zigTypeTag(mod)) { | ||
| 3615 | .Struct => offset: { | 3724 | .Struct => offset: { |
| 3616 | if (result_ty.ptrInfo().data.host_size != 0) { | 3725 | if (result_ty.ptrInfo(mod).host_size != 0) { |
| 3617 | break :offset @as(u32, 0); | 3726 | break :offset @as(u32, 0); |
| 3618 | } | 3727 | } |
| 3619 | break :offset struct_ty.packedStructFieldByteOffset(index, func.target); | 3728 | break :offset struct_ty.packedStructFieldByteOffset(index, mod); |
| 3620 | }, | 3729 | }, |
| 3621 | .Union => 0, | 3730 | .Union => 0, |
| 3622 | else => unreachable, | 3731 | else => unreachable, |
| 3623 | }, | 3732 | }, |
| 3624 | else => struct_ty.structFieldOffset(index, func.target), | 3733 | else => struct_ty.structFieldOffset(index, mod), |
| 3625 | }; | 3734 | }; |
| 3626 | // save a load and store when we can simply reuse the operand | 3735 | // save a load and store when we can simply reuse the operand |
| 3627 | if (offset == 0) { | 3736 | if (offset == 0) { |
| ... | @@ -3636,22 +3745,23 @@ fn structFieldPtr( | ... | @@ -3636,22 +3745,23 @@ fn structFieldPtr( |
| 3636 | } | 3745 | } |
| 3637 | 3746 | ||
| 3638 | fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 3747 | fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3748 | const mod = func.bin_file.base.options.module.?; | ||
| 3639 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 3749 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 3640 | const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data; | 3750 | const struct_field = func.air.extraData(Air.StructField, ty_pl.payload).data; |
| 3641 | 3751 | ||
| 3642 | const struct_ty = func.air.typeOf(struct_field.struct_operand); | 3752 | const struct_ty = func.typeOf(struct_field.struct_operand); |
| 3643 | const operand = try func.resolveInst(struct_field.struct_operand); | 3753 | const operand = try func.resolveInst(struct_field.struct_operand); |
| 3644 | const field_index = struct_field.field_index; | 3754 | const field_index = struct_field.field_index; |
| 3645 | const field_ty = struct_ty.structFieldType(field_index); | 3755 | const field_ty = struct_ty.structFieldType(field_index, mod); |
| 3646 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) return func.finishAir(inst, .none, &.{struct_field.struct_operand}); | 3756 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return func.finishAir(inst, .none, &.{struct_field.struct_operand}); |
| 3647 | 3757 | ||
| 3648 | const result = switch (struct_ty.containerLayout()) { | 3758 | const result = switch (struct_ty.containerLayout(mod)) { |
| 3649 | .Packed => switch (struct_ty.zigTypeTag()) { | 3759 | .Packed => switch (struct_ty.zigTypeTag(mod)) { |
| 3650 | .Struct => result: { | 3760 | .Struct => result: { |
| 3651 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 3761 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| 3652 | const offset = struct_obj.packedFieldBitOffset(func.target, field_index); | 3762 | const offset = struct_obj.packedFieldBitOffset(mod, field_index); |
| 3653 | const backing_ty = struct_obj.backing_int_ty; | 3763 | const backing_ty = struct_obj.backing_int_ty; |
| 3654 | const wasm_bits = toWasmBits(backing_ty.intInfo(func.target).bits) orelse { | 3764 | const wasm_bits = toWasmBits(backing_ty.intInfo(mod).bits) orelse { |
| 3655 | return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{}); | 3765 | return func.fail("TODO: airStructFieldVal for packed structs larger than 128 bits", .{}); |
| 3656 | }; | 3766 | }; |
| 3657 | const const_wvalue = if (wasm_bits == 32) | 3767 | const const_wvalue = if (wasm_bits == 32) |
| ... | @@ -3667,25 +3777,17 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3667,25 +3777,17 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3667 | else | 3777 | else |
| 3668 | try func.binOp(operand, const_wvalue, backing_ty, .shr); | 3778 | try func.binOp(operand, const_wvalue, backing_ty, .shr); |
| 3669 | 3779 | ||
| 3670 | if (field_ty.zigTypeTag() == .Float) { | 3780 | if (field_ty.zigTypeTag(mod) == .Float) { |
| 3671 | var payload: Type.Payload.Bits = .{ | 3781 | const int_type = try mod.intType(.unsigned, @intCast(u16, field_ty.bitSize(mod))); |
| 3672 | .base = .{ .tag = .int_unsigned }, | ||
| 3673 | .data = @intCast(u16, field_ty.bitSize(func.target)), | ||
| 3674 | }; | ||
| 3675 | const int_type = Type.initPayload(&payload.base); | ||
| 3676 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); | 3782 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); |
| 3677 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); | 3783 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); |
| 3678 | break :result try bitcasted.toLocal(func, field_ty); | 3784 | break :result try bitcasted.toLocal(func, field_ty); |
| 3679 | } else if (field_ty.isPtrAtRuntime() and struct_obj.fields.count() == 1) { | 3785 | } else if (field_ty.isPtrAtRuntime(mod) and struct_obj.fields.count() == 1) { |
| 3680 | // In this case we do not have to perform any transformations, | 3786 | // In this case we do not have to perform any transformations, |
| 3681 | // we can simply reuse the operand. | 3787 | // we can simply reuse the operand. |
| 3682 | break :result func.reuseOperand(struct_field.struct_operand, operand); | 3788 | break :result func.reuseOperand(struct_field.struct_operand, operand); |
| 3683 | } else if (field_ty.isPtrAtRuntime()) { | 3789 | } else if (field_ty.isPtrAtRuntime(mod)) { |
| 3684 | var payload: Type.Payload.Bits = .{ | 3790 | const int_type = try mod.intType(.unsigned, @intCast(u16, field_ty.bitSize(mod))); |
| 3685 | .base = .{ .tag = .int_unsigned }, | ||
| 3686 | .data = @intCast(u16, field_ty.bitSize(func.target)), | ||
| 3687 | }; | ||
| 3688 | const int_type = Type.initPayload(&payload.base); | ||
| 3689 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); | 3791 | const truncated = try func.trunc(shifted_value, int_type, backing_ty); |
| 3690 | break :result try truncated.toLocal(func, field_ty); | 3792 | break :result try truncated.toLocal(func, field_ty); |
| 3691 | } | 3793 | } |
| ... | @@ -3693,8 +3795,8 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3693,8 +3795,8 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3693 | break :result try truncated.toLocal(func, field_ty); | 3795 | break :result try truncated.toLocal(func, field_ty); |
| 3694 | }, | 3796 | }, |
| 3695 | .Union => result: { | 3797 | .Union => result: { |
| 3696 | if (isByRef(struct_ty, func.target)) { | 3798 | if (isByRef(struct_ty, mod)) { |
| 3697 | if (!isByRef(field_ty, func.target)) { | 3799 | if (!isByRef(field_ty, mod)) { |
| 3698 | const val = try func.load(operand, field_ty, 0); | 3800 | const val = try func.load(operand, field_ty, 0); |
| 3699 | break :result try val.toLocal(func, field_ty); | 3801 | break :result try val.toLocal(func, field_ty); |
| 3700 | } else { | 3802 | } else { |
| ... | @@ -3704,26 +3806,14 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3704,26 +3806,14 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3704 | } | 3806 | } |
| 3705 | } | 3807 | } |
| 3706 | 3808 | ||
| 3707 | var payload: Type.Payload.Bits = .{ | 3809 | const union_int_type = try mod.intType(.unsigned, @intCast(u16, struct_ty.bitSize(mod))); |
| 3708 | .base = .{ .tag = .int_unsigned }, | 3810 | if (field_ty.zigTypeTag(mod) == .Float) { |
| 3709 | .data = @intCast(u16, struct_ty.bitSize(func.target)), | 3811 | const int_type = try mod.intType(.unsigned, @intCast(u16, field_ty.bitSize(mod))); |
| 3710 | }; | ||
| 3711 | const union_int_type = Type.initPayload(&payload.base); | ||
| 3712 | if (field_ty.zigTypeTag() == .Float) { | ||
| 3713 | var int_payload: Type.Payload.Bits = .{ | ||
| 3714 | .base = .{ .tag = .int_unsigned }, | ||
| 3715 | .data = @intCast(u16, field_ty.bitSize(func.target)), | ||
| 3716 | }; | ||
| 3717 | const int_type = Type.initPayload(&int_payload.base); | ||
| 3718 | const truncated = try func.trunc(operand, int_type, union_int_type); | 3812 | const truncated = try func.trunc(operand, int_type, union_int_type); |
| 3719 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); | 3813 | const bitcasted = try func.bitcast(field_ty, int_type, truncated); |
| 3720 | break :result try bitcasted.toLocal(func, field_ty); | 3814 | break :result try bitcasted.toLocal(func, field_ty); |
| 3721 | } else if (field_ty.isPtrAtRuntime()) { | 3815 | } else if (field_ty.isPtrAtRuntime(mod)) { |
| 3722 | var int_payload: Type.Payload.Bits = .{ | 3816 | const int_type = try mod.intType(.unsigned, @intCast(u16, field_ty.bitSize(mod))); |
| 3723 | .base = .{ .tag = .int_unsigned }, | ||
| 3724 | .data = @intCast(u16, field_ty.bitSize(func.target)), | ||
| 3725 | }; | ||
| 3726 | const int_type = Type.initPayload(&int_payload.base); | ||
| 3727 | const truncated = try func.trunc(operand, int_type, union_int_type); | 3817 | const truncated = try func.trunc(operand, int_type, union_int_type); |
| 3728 | break :result try truncated.toLocal(func, field_ty); | 3818 | break :result try truncated.toLocal(func, field_ty); |
| 3729 | } | 3819 | } |
| ... | @@ -3733,11 +3823,10 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3733,11 +3823,10 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3733 | else => unreachable, | 3823 | else => unreachable, |
| 3734 | }, | 3824 | }, |
| 3735 | else => result: { | 3825 | else => result: { |
| 3736 | const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, func.target)) orelse { | 3826 | const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, mod)) orelse { |
| 3737 | const module = func.bin_file.base.options.module.?; | 3827 | return func.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(mod)}); |
| 3738 | return func.fail("Field type '{}' too big to fit into stack frame", .{field_ty.fmt(module)}); | ||
| 3739 | }; | 3828 | }; |
| 3740 | if (isByRef(field_ty, func.target)) { | 3829 | if (isByRef(field_ty, mod)) { |
| 3741 | switch (operand) { | 3830 | switch (operand) { |
| 3742 | .stack_offset => |stack_offset| { | 3831 | .stack_offset => |stack_offset| { |
| 3743 | break :result WValue{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } }; | 3832 | break :result WValue{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } }; |
| ... | @@ -3754,11 +3843,12 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3754,11 +3843,12 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3754 | } | 3843 | } |
| 3755 | 3844 | ||
| 3756 | fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 3845 | fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3846 | const mod = func.bin_file.base.options.module.?; | ||
| 3757 | // result type is always 'noreturn' | 3847 | // result type is always 'noreturn' |
| 3758 | const blocktype = wasm.block_empty; | 3848 | const blocktype = wasm.block_empty; |
| 3759 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; | 3849 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 3760 | const target = try func.resolveInst(pl_op.operand); | 3850 | const target = try func.resolveInst(pl_op.operand); |
| 3761 | const target_ty = func.air.typeOf(pl_op.operand); | 3851 | const target_ty = func.typeOf(pl_op.operand); |
| 3762 | const switch_br = func.air.extraData(Air.SwitchBr, pl_op.payload); | 3852 | const switch_br = func.air.extraData(Air.SwitchBr, pl_op.payload); |
| 3763 | const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.data.cases_len + 1); | 3853 | const liveness = try func.liveness.getSwitchBr(func.gpa, inst, switch_br.data.cases_len + 1); |
| 3764 | defer func.gpa.free(liveness.deaths); | 3854 | defer func.gpa.free(liveness.deaths); |
| ... | @@ -3787,7 +3877,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3787,7 +3877,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3787 | errdefer func.gpa.free(values); | 3877 | errdefer func.gpa.free(values); |
| 3788 | 3878 | ||
| 3789 | for (items, 0..) |ref, i| { | 3879 | for (items, 0..) |ref, i| { |
| 3790 | const item_val = func.air.value(ref).?; | 3880 | const item_val = (try func.air.value(ref, mod)).?; |
| 3791 | const int_val = func.valueAsI32(item_val, target_ty); | 3881 | const int_val = func.valueAsI32(item_val, target_ty); |
| 3792 | if (lowest_maybe == null or int_val < lowest_maybe.?) { | 3882 | if (lowest_maybe == null or int_val < lowest_maybe.?) { |
| 3793 | lowest_maybe = int_val; | 3883 | lowest_maybe = int_val; |
| ... | @@ -3810,7 +3900,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3810,7 +3900,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3810 | // When the target is an integer size larger than u32, we have no way to use the value | 3900 | // When the target is an integer size larger than u32, we have no way to use the value |
| 3811 | // as an index, therefore we also use an if/else-chain for those cases. | 3901 | // as an index, therefore we also use an if/else-chain for those cases. |
| 3812 | // TODO: Benchmark this to find a proper value, LLVM seems to draw the line at '40~45'. | 3902 | // TODO: Benchmark this to find a proper value, LLVM seems to draw the line at '40~45'. |
| 3813 | const is_sparse = highest - lowest > 50 or target_ty.bitSize(func.target) > 32; | 3903 | const is_sparse = highest - lowest > 50 or target_ty.bitSize(mod) > 32; |
| 3814 | 3904 | ||
| 3815 | const else_body = func.air.extra[extra_index..][0..switch_br.data.else_body_len]; | 3905 | const else_body = func.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| 3816 | const has_else_body = else_body.len != 0; | 3906 | const has_else_body = else_body.len != 0; |
| ... | @@ -3855,7 +3945,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3855,7 +3945,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3855 | // for errors that are not present in any branch. This is fine as this default | 3945 | // for errors that are not present in any branch. This is fine as this default |
| 3856 | // case will never be hit for those cases but we do save runtime cost and size | 3946 | // case will never be hit for those cases but we do save runtime cost and size |
| 3857 | // by using a jump table for this instead of if-else chains. | 3947 | // by using a jump table for this instead of if-else chains. |
| 3858 | break :blk if (has_else_body or target_ty.zigTypeTag() == .ErrorSet) case_i else unreachable; | 3948 | break :blk if (has_else_body or target_ty.zigTypeTag(mod) == .ErrorSet) case_i else unreachable; |
| 3859 | }; | 3949 | }; |
| 3860 | func.mir_extra.appendAssumeCapacity(idx); | 3950 | func.mir_extra.appendAssumeCapacity(idx); |
| 3861 | } else if (has_else_body) { | 3951 | } else if (has_else_body) { |
| ... | @@ -3866,10 +3956,10 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3866,10 +3956,10 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3866 | 3956 | ||
| 3867 | const signedness: std.builtin.Signedness = blk: { | 3957 | const signedness: std.builtin.Signedness = blk: { |
| 3868 | // by default we tell the operand type is unsigned (i.e. bools and enum values) | 3958 | // by default we tell the operand type is unsigned (i.e. bools and enum values) |
| 3869 | if (target_ty.zigTypeTag() != .Int) break :blk .unsigned; | 3959 | if (target_ty.zigTypeTag(mod) != .Int) break :blk .unsigned; |
| 3870 | 3960 | ||
| 3871 | // incase of an actual integer, we emit the correct signedness | 3961 | // incase of an actual integer, we emit the correct signedness |
| 3872 | break :blk target_ty.intInfo(func.target).signedness; | 3962 | break :blk target_ty.intInfo(mod).signedness; |
| 3873 | }; | 3963 | }; |
| 3874 | 3964 | ||
| 3875 | try func.branches.ensureUnusedCapacity(func.gpa, case_list.items.len + @boolToInt(has_else_body)); | 3965 | try func.branches.ensureUnusedCapacity(func.gpa, case_list.items.len + @boolToInt(has_else_body)); |
| ... | @@ -3882,7 +3972,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3882,7 +3972,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3882 | const val = try func.lowerConstant(case.values[0].value, target_ty); | 3972 | const val = try func.lowerConstant(case.values[0].value, target_ty); |
| 3883 | try func.emitWValue(val); | 3973 | try func.emitWValue(val); |
| 3884 | const opcode = buildOpcode(.{ | 3974 | const opcode = buildOpcode(.{ |
| 3885 | .valtype1 = typeToValtype(target_ty, func.target), | 3975 | .valtype1 = typeToValtype(target_ty, mod), |
| 3886 | .op = .ne, // not equal, because we want to jump out of this block if it does not match the condition. | 3976 | .op = .ne, // not equal, because we want to jump out of this block if it does not match the condition. |
| 3887 | .signedness = signedness, | 3977 | .signedness = signedness, |
| 3888 | }); | 3978 | }); |
| ... | @@ -3896,7 +3986,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3896,7 +3986,7 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3896 | const val = try func.lowerConstant(value.value, target_ty); | 3986 | const val = try func.lowerConstant(value.value, target_ty); |
| 3897 | try func.emitWValue(val); | 3987 | try func.emitWValue(val); |
| 3898 | const opcode = buildOpcode(.{ | 3988 | const opcode = buildOpcode(.{ |
| 3899 | .valtype1 = typeToValtype(target_ty, func.target), | 3989 | .valtype1 = typeToValtype(target_ty, mod), |
| 3900 | .op = .eq, | 3990 | .op = .eq, |
| 3901 | .signedness = signedness, | 3991 | .signedness = signedness, |
| 3902 | }); | 3992 | }); |
| ... | @@ -3933,13 +4023,14 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3933,13 +4023,14 @@ fn airSwitchBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3933 | } | 4023 | } |
| 3934 | 4024 | ||
| 3935 | fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!void { | 4025 | fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!void { |
| 4026 | const mod = func.bin_file.base.options.module.?; | ||
| 3936 | const un_op = func.air.instructions.items(.data)[inst].un_op; | 4027 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 3937 | const operand = try func.resolveInst(un_op); | 4028 | const operand = try func.resolveInst(un_op); |
| 3938 | const err_union_ty = func.air.typeOf(un_op); | 4029 | const err_union_ty = func.typeOf(un_op); |
| 3939 | const pl_ty = err_union_ty.errorUnionPayload(); | 4030 | const pl_ty = err_union_ty.errorUnionPayload(mod); |
| 3940 | 4031 | ||
| 3941 | const result = result: { | 4032 | const result = result: { |
| 3942 | if (err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 4033 | if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 3943 | switch (opcode) { | 4034 | switch (opcode) { |
| 3944 | .i32_ne => break :result WValue{ .imm32 = 0 }, | 4035 | .i32_ne => break :result WValue{ .imm32 = 0 }, |
| 3945 | .i32_eq => break :result WValue{ .imm32 = 1 }, | 4036 | .i32_eq => break :result WValue{ .imm32 = 1 }, |
| ... | @@ -3948,10 +4039,10 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro | ... | @@ -3948,10 +4039,10 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro |
| 3948 | } | 4039 | } |
| 3949 | 4040 | ||
| 3950 | try func.emitWValue(operand); | 4041 | try func.emitWValue(operand); |
| 3951 | if (pl_ty.hasRuntimeBitsIgnoreComptime()) { | 4042 | if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3952 | try func.addMemArg(.i32_load16_u, .{ | 4043 | try func.addMemArg(.i32_load16_u, .{ |
| 3953 | .offset = operand.offset() + @intCast(u32, errUnionErrorOffset(pl_ty, func.target)), | 4044 | .offset = operand.offset() + @intCast(u32, errUnionErrorOffset(pl_ty, mod)), |
| 3954 | .alignment = Type.anyerror.abiAlignment(func.target), | 4045 | .alignment = Type.anyerror.abiAlignment(mod), |
| 3955 | }); | 4046 | }); |
| 3956 | } | 4047 | } |
| 3957 | 4048 | ||
| ... | @@ -3967,23 +4058,24 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro | ... | @@ -3967,23 +4058,24 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro |
| 3967 | } | 4058 | } |
| 3968 | 4059 | ||
| 3969 | fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void { | 4060 | fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void { |
| 4061 | const mod = func.bin_file.base.options.module.?; | ||
| 3970 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4062 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 3971 | 4063 | ||
| 3972 | const operand = try func.resolveInst(ty_op.operand); | 4064 | const operand = try func.resolveInst(ty_op.operand); |
| 3973 | const op_ty = func.air.typeOf(ty_op.operand); | 4065 | const op_ty = func.typeOf(ty_op.operand); |
| 3974 | const err_ty = if (op_is_ptr) op_ty.childType() else op_ty; | 4066 | const err_ty = if (op_is_ptr) op_ty.childType(mod) else op_ty; |
| 3975 | const payload_ty = err_ty.errorUnionPayload(); | 4067 | const payload_ty = err_ty.errorUnionPayload(mod); |
| 3976 | 4068 | ||
| 3977 | const result = result: { | 4069 | const result = result: { |
| 3978 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 4070 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3979 | if (op_is_ptr) { | 4071 | if (op_is_ptr) { |
| 3980 | break :result func.reuseOperand(ty_op.operand, operand); | 4072 | break :result func.reuseOperand(ty_op.operand, operand); |
| 3981 | } | 4073 | } |
| 3982 | break :result WValue{ .none = {} }; | 4074 | break :result WValue{ .none = {} }; |
| 3983 | } | 4075 | } |
| 3984 | 4076 | ||
| 3985 | const pl_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, func.target)); | 4077 | const pl_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, mod)); |
| 3986 | if (op_is_ptr or isByRef(payload_ty, func.target)) { | 4078 | if (op_is_ptr or isByRef(payload_ty, mod)) { |
| 3987 | break :result try func.buildPointerOffset(operand, pl_offset, .new); | 4079 | break :result try func.buildPointerOffset(operand, pl_offset, .new); |
| 3988 | } | 4080 | } |
| 3989 | 4081 | ||
| ... | @@ -3994,48 +4086,50 @@ fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: boo | ... | @@ -3994,48 +4086,50 @@ fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: boo |
| 3994 | } | 4086 | } |
| 3995 | 4087 | ||
| 3996 | fn airUnwrapErrUnionError(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void { | 4088 | fn airUnwrapErrUnionError(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void { |
| 4089 | const mod = func.bin_file.base.options.module.?; | ||
| 3997 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4090 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 3998 | 4091 | ||
| 3999 | const operand = try func.resolveInst(ty_op.operand); | 4092 | const operand = try func.resolveInst(ty_op.operand); |
| 4000 | const op_ty = func.air.typeOf(ty_op.operand); | 4093 | const op_ty = func.typeOf(ty_op.operand); |
| 4001 | const err_ty = if (op_is_ptr) op_ty.childType() else op_ty; | 4094 | const err_ty = if (op_is_ptr) op_ty.childType(mod) else op_ty; |
| 4002 | const payload_ty = err_ty.errorUnionPayload(); | 4095 | const payload_ty = err_ty.errorUnionPayload(mod); |
| 4003 | 4096 | ||
| 4004 | const result = result: { | 4097 | const result = result: { |
| 4005 | if (err_ty.errorUnionSet().errorSetIsEmpty()) { | 4098 | if (err_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 4006 | break :result WValue{ .imm32 = 0 }; | 4099 | break :result WValue{ .imm32 = 0 }; |
| 4007 | } | 4100 | } |
| 4008 | 4101 | ||
| 4009 | if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime()) { | 4102 | if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4010 | break :result func.reuseOperand(ty_op.operand, operand); | 4103 | break :result func.reuseOperand(ty_op.operand, operand); |
| 4011 | } | 4104 | } |
| 4012 | 4105 | ||
| 4013 | const error_val = try func.load(operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(payload_ty, func.target))); | 4106 | const error_val = try func.load(operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(payload_ty, mod))); |
| 4014 | break :result try error_val.toLocal(func, Type.anyerror); | 4107 | break :result try error_val.toLocal(func, Type.anyerror); |
| 4015 | }; | 4108 | }; |
| 4016 | func.finishAir(inst, result, &.{ty_op.operand}); | 4109 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 4017 | } | 4110 | } |
| 4018 | 4111 | ||
| 4019 | fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4112 | fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4113 | const mod = func.bin_file.base.options.module.?; | ||
| 4020 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4114 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4021 | 4115 | ||
| 4022 | const operand = try func.resolveInst(ty_op.operand); | 4116 | const operand = try func.resolveInst(ty_op.operand); |
| 4023 | const err_ty = func.air.typeOfIndex(inst); | 4117 | const err_ty = func.typeOfIndex(inst); |
| 4024 | 4118 | ||
| 4025 | const pl_ty = func.air.typeOf(ty_op.operand); | 4119 | const pl_ty = func.typeOf(ty_op.operand); |
| 4026 | const result = result: { | 4120 | const result = result: { |
| 4027 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { | 4121 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4028 | break :result func.reuseOperand(ty_op.operand, operand); | 4122 | break :result func.reuseOperand(ty_op.operand, operand); |
| 4029 | } | 4123 | } |
| 4030 | 4124 | ||
| 4031 | const err_union = try func.allocStack(err_ty); | 4125 | const err_union = try func.allocStack(err_ty); |
| 4032 | const payload_ptr = try func.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, func.target)), .new); | 4126 | const payload_ptr = try func.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, mod)), .new); |
| 4033 | try func.store(payload_ptr, operand, pl_ty, 0); | 4127 | try func.store(payload_ptr, operand, pl_ty, 0); |
| 4034 | 4128 | ||
| 4035 | // ensure we also write '0' to the error part, so any present stack value gets overwritten by it. | 4129 | // ensure we also write '0' to the error part, so any present stack value gets overwritten by it. |
| 4036 | try func.emitWValue(err_union); | 4130 | try func.emitWValue(err_union); |
| 4037 | try func.addImm32(0); | 4131 | try func.addImm32(0); |
| 4038 | const err_val_offset = @intCast(u32, errUnionErrorOffset(pl_ty, func.target)); | 4132 | const err_val_offset = @intCast(u32, errUnionErrorOffset(pl_ty, mod)); |
| 4039 | try func.addMemArg(.i32_store16, .{ .offset = err_union.offset() + err_val_offset, .alignment = 2 }); | 4133 | try func.addMemArg(.i32_store16, .{ .offset = err_union.offset() + err_val_offset, .alignment = 2 }); |
| 4040 | break :result err_union; | 4134 | break :result err_union; |
| 4041 | }; | 4135 | }; |
| ... | @@ -4043,24 +4137,25 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void | ... | @@ -4043,24 +4137,25 @@ fn airWrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void |
| 4043 | } | 4137 | } |
| 4044 | 4138 | ||
| 4045 | fn airWrapErrUnionErr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4139 | fn airWrapErrUnionErr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4140 | const mod = func.bin_file.base.options.module.?; | ||
| 4046 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4141 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4047 | 4142 | ||
| 4048 | const operand = try func.resolveInst(ty_op.operand); | 4143 | const operand = try func.resolveInst(ty_op.operand); |
| 4049 | const err_ty = func.air.getRefType(ty_op.ty); | 4144 | const err_ty = func.air.getRefType(ty_op.ty); |
| 4050 | const pl_ty = err_ty.errorUnionPayload(); | 4145 | const pl_ty = err_ty.errorUnionPayload(mod); |
| 4051 | 4146 | ||
| 4052 | const result = result: { | 4147 | const result = result: { |
| 4053 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) { | 4148 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4054 | break :result func.reuseOperand(ty_op.operand, operand); | 4149 | break :result func.reuseOperand(ty_op.operand, operand); |
| 4055 | } | 4150 | } |
| 4056 | 4151 | ||
| 4057 | const err_union = try func.allocStack(err_ty); | 4152 | const err_union = try func.allocStack(err_ty); |
| 4058 | // store error value | 4153 | // store error value |
| 4059 | try func.store(err_union, operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(pl_ty, func.target))); | 4154 | try func.store(err_union, operand, Type.anyerror, @intCast(u32, errUnionErrorOffset(pl_ty, mod))); |
| 4060 | 4155 | ||
| 4061 | // write 'undefined' to the payload | 4156 | // write 'undefined' to the payload |
| 4062 | const payload_ptr = try func.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, func.target)), .new); | 4157 | const payload_ptr = try func.buildPointerOffset(err_union, @intCast(u32, errUnionPayloadOffset(pl_ty, mod)), .new); |
| 4063 | const len = @intCast(u32, err_ty.errorUnionPayload().abiSize(func.target)); | 4158 | const len = @intCast(u32, err_ty.errorUnionPayload(mod).abiSize(mod)); |
| 4064 | try func.memset(Type.u8, payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaa }); | 4159 | try func.memset(Type.u8, payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaa }); |
| 4065 | 4160 | ||
| 4066 | break :result err_union; | 4161 | break :result err_union; |
| ... | @@ -4073,16 +4168,17 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4073,16 +4168,17 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4073 | 4168 | ||
| 4074 | const ty = func.air.getRefType(ty_op.ty); | 4169 | const ty = func.air.getRefType(ty_op.ty); |
| 4075 | const operand = try func.resolveInst(ty_op.operand); | 4170 | const operand = try func.resolveInst(ty_op.operand); |
| 4076 | const operand_ty = func.air.typeOf(ty_op.operand); | 4171 | const operand_ty = func.typeOf(ty_op.operand); |
| 4077 | if (ty.zigTypeTag() == .Vector or operand_ty.zigTypeTag() == .Vector) { | 4172 | const mod = func.bin_file.base.options.module.?; |
| 4173 | if (ty.zigTypeTag(mod) == .Vector or operand_ty.zigTypeTag(mod) == .Vector) { | ||
| 4078 | return func.fail("todo Wasm intcast for vectors", .{}); | 4174 | return func.fail("todo Wasm intcast for vectors", .{}); |
| 4079 | } | 4175 | } |
| 4080 | if (ty.abiSize(func.target) > 16 or operand_ty.abiSize(func.target) > 16) { | 4176 | if (ty.abiSize(mod) > 16 or operand_ty.abiSize(mod) > 16) { |
| 4081 | return func.fail("todo Wasm intcast for bitsize > 128", .{}); | 4177 | return func.fail("todo Wasm intcast for bitsize > 128", .{}); |
| 4082 | } | 4178 | } |
| 4083 | 4179 | ||
| 4084 | const op_bits = toWasmBits(@intCast(u16, operand_ty.bitSize(func.target))).?; | 4180 | const op_bits = toWasmBits(@intCast(u16, operand_ty.bitSize(mod))).?; |
| 4085 | const wanted_bits = toWasmBits(@intCast(u16, ty.bitSize(func.target))).?; | 4181 | const wanted_bits = toWasmBits(@intCast(u16, ty.bitSize(mod))).?; |
| 4086 | const result = if (op_bits == wanted_bits) | 4182 | const result = if (op_bits == wanted_bits) |
| 4087 | func.reuseOperand(ty_op.operand, operand) | 4183 | func.reuseOperand(ty_op.operand, operand) |
| 4088 | else | 4184 | else |
| ... | @@ -4096,8 +4192,9 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4096,8 +4192,9 @@ fn airIntcast(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4096 | /// Asserts type's bitsize <= 128 | 4192 | /// Asserts type's bitsize <= 128 |
| 4097 | /// NOTE: May leave the result on the top of the stack. | 4193 | /// NOTE: May leave the result on the top of the stack. |
| 4098 | fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue { | 4194 | fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError!WValue { |
| 4099 | const given_bitsize = @intCast(u16, given.bitSize(func.target)); | 4195 | const mod = func.bin_file.base.options.module.?; |
| 4100 | const wanted_bitsize = @intCast(u16, wanted.bitSize(func.target)); | 4196 | const given_bitsize = @intCast(u16, given.bitSize(mod)); |
| 4197 | const wanted_bitsize = @intCast(u16, wanted.bitSize(mod)); | ||
| 4101 | assert(given_bitsize <= 128); | 4198 | assert(given_bitsize <= 128); |
| 4102 | assert(wanted_bitsize <= 128); | 4199 | assert(wanted_bitsize <= 128); |
| 4103 | 4200 | ||
| ... | @@ -4110,7 +4207,7 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro | ... | @@ -4110,7 +4207,7 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4110 | try func.addTag(.i32_wrap_i64); | 4207 | try func.addTag(.i32_wrap_i64); |
| 4111 | } else if (op_bits == 32 and wanted_bits > 32 and wanted_bits <= 64) { | 4208 | } else if (op_bits == 32 and wanted_bits > 32 and wanted_bits <= 64) { |
| 4112 | try func.emitWValue(operand); | 4209 | try func.emitWValue(operand); |
| 4113 | try func.addTag(if (wanted.isSignedInt()) .i64_extend_i32_s else .i64_extend_i32_u); | 4210 | try func.addTag(if (wanted.isSignedInt(mod)) .i64_extend_i32_s else .i64_extend_i32_u); |
| 4114 | } else if (wanted_bits == 128) { | 4211 | } else if (wanted_bits == 128) { |
| 4115 | // for 128bit integers we store the integer in the virtual stack, rather than a local | 4212 | // for 128bit integers we store the integer in the virtual stack, rather than a local |
| 4116 | const stack_ptr = try func.allocStack(wanted); | 4213 | const stack_ptr = try func.allocStack(wanted); |
| ... | @@ -4119,14 +4216,14 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro | ... | @@ -4119,14 +4216,14 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4119 | // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it | 4216 | // for 32 bit integers, we first coerce the value into a 64 bit integer before storing it |
| 4120 | // meaning less store operations are required. | 4217 | // meaning less store operations are required. |
| 4121 | const lhs = if (op_bits == 32) blk: { | 4218 | const lhs = if (op_bits == 32) blk: { |
| 4122 | break :blk try func.intcast(operand, given, if (wanted.isSignedInt()) Type.i64 else Type.u64); | 4219 | break :blk try func.intcast(operand, given, if (wanted.isSignedInt(mod)) Type.i64 else Type.u64); |
| 4123 | } else operand; | 4220 | } else operand; |
| 4124 | 4221 | ||
| 4125 | // store msb first | 4222 | // store msb first |
| 4126 | try func.store(.{ .stack = {} }, lhs, Type.u64, 0 + stack_ptr.offset()); | 4223 | try func.store(.{ .stack = {} }, lhs, Type.u64, 0 + stack_ptr.offset()); |
| 4127 | 4224 | ||
| 4128 | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value | 4225 | // For signed integers we shift msb by 63 (64bit integer - 1 sign bit) and store remaining value |
| 4129 | if (wanted.isSignedInt()) { | 4226 | if (wanted.isSignedInt(mod)) { |
| 4130 | try func.emitWValue(stack_ptr); | 4227 | try func.emitWValue(stack_ptr); |
| 4131 | const shr = try func.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); | 4228 | const shr = try func.binOp(lhs, .{ .imm64 = 63 }, Type.i64, .shr); |
| 4132 | try func.store(.{ .stack = {} }, shr, Type.u64, 8 + stack_ptr.offset()); | 4229 | try func.store(.{ .stack = {} }, shr, Type.u64, 8 + stack_ptr.offset()); |
| ... | @@ -4141,11 +4238,12 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro | ... | @@ -4141,11 +4238,12 @@ fn intcast(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 4141 | } | 4238 | } |
| 4142 | 4239 | ||
| 4143 | fn airIsNull(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void { | 4240 | fn airIsNull(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void { |
| 4241 | const mod = func.bin_file.base.options.module.?; | ||
| 4144 | const un_op = func.air.instructions.items(.data)[inst].un_op; | 4242 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 4145 | const operand = try func.resolveInst(un_op); | 4243 | const operand = try func.resolveInst(un_op); |
| 4146 | 4244 | ||
| 4147 | const op_ty = func.air.typeOf(un_op); | 4245 | const op_ty = func.typeOf(un_op); |
| 4148 | const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty; | 4246 | const optional_ty = if (op_kind == .ptr) op_ty.childType(mod) else op_ty; |
| 4149 | const is_null = try func.isNull(operand, optional_ty, opcode); | 4247 | const is_null = try func.isNull(operand, optional_ty, opcode); |
| 4150 | const result = try is_null.toLocal(func, optional_ty); | 4248 | const result = try is_null.toLocal(func, optional_ty); |
| 4151 | func.finishAir(inst, result, &.{un_op}); | 4249 | func.finishAir(inst, result, &.{un_op}); |
| ... | @@ -4154,20 +4252,19 @@ fn airIsNull(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: | ... | @@ -4154,20 +4252,19 @@ fn airIsNull(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: |
| 4154 | /// For a given type and operand, checks if it's considered `null`. | 4252 | /// For a given type and operand, checks if it's considered `null`. |
| 4155 | /// NOTE: Leaves the result on the stack | 4253 | /// NOTE: Leaves the result on the stack |
| 4156 | fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue { | 4254 | fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcode) InnerError!WValue { |
| 4255 | const mod = func.bin_file.base.options.module.?; | ||
| 4157 | try func.emitWValue(operand); | 4256 | try func.emitWValue(operand); |
| 4158 | var buf: Type.Payload.ElemType = undefined; | 4257 | const payload_ty = optional_ty.optionalChild(mod); |
| 4159 | const payload_ty = optional_ty.optionalChild(&buf); | 4258 | if (!optional_ty.optionalReprIsPayload(mod)) { |
| 4160 | if (!optional_ty.optionalReprIsPayload()) { | ||
| 4161 | // When payload is zero-bits, we can treat operand as a value, rather than | 4259 | // When payload is zero-bits, we can treat operand as a value, rather than |
| 4162 | // a pointer to the stack value | 4260 | // a pointer to the stack value |
| 4163 | if (payload_ty.hasRuntimeBitsIgnoreComptime()) { | 4261 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4164 | const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse { | 4262 | const offset = std.math.cast(u32, payload_ty.abiSize(mod)) orelse { |
| 4165 | const module = func.bin_file.base.options.module.?; | 4263 | return func.fail("Optional type {} too big to fit into stack frame", .{optional_ty.fmt(mod)}); |
| 4166 | return func.fail("Optional type {} too big to fit into stack frame", .{optional_ty.fmt(module)}); | ||
| 4167 | }; | 4264 | }; |
| 4168 | try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset() + offset, .alignment = 1 }); | 4265 | try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset() + offset, .alignment = 1 }); |
| 4169 | } | 4266 | } |
| 4170 | } else if (payload_ty.isSlice()) { | 4267 | } else if (payload_ty.isSlice(mod)) { |
| 4171 | switch (func.arch()) { | 4268 | switch (func.arch()) { |
| 4172 | .wasm32 => try func.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }), | 4269 | .wasm32 => try func.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }), |
| 4173 | .wasm64 => try func.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }), | 4270 | .wasm64 => try func.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }), |
| ... | @@ -4183,18 +4280,19 @@ fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcod | ... | @@ -4183,18 +4280,19 @@ fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcod |
| 4183 | } | 4280 | } |
| 4184 | 4281 | ||
| 4185 | fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4282 | fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4283 | const mod = func.bin_file.base.options.module.?; | ||
| 4186 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4284 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4187 | const opt_ty = func.air.typeOf(ty_op.operand); | 4285 | const opt_ty = func.typeOf(ty_op.operand); |
| 4188 | const payload_ty = func.air.typeOfIndex(inst); | 4286 | const payload_ty = func.typeOfIndex(inst); |
| 4189 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 4287 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4190 | return func.finishAir(inst, .none, &.{ty_op.operand}); | 4288 | return func.finishAir(inst, .none, &.{ty_op.operand}); |
| 4191 | } | 4289 | } |
| 4192 | 4290 | ||
| 4193 | const result = result: { | 4291 | const result = result: { |
| 4194 | const operand = try func.resolveInst(ty_op.operand); | 4292 | const operand = try func.resolveInst(ty_op.operand); |
| 4195 | if (opt_ty.optionalReprIsPayload()) break :result func.reuseOperand(ty_op.operand, operand); | 4293 | if (opt_ty.optionalReprIsPayload(mod)) break :result func.reuseOperand(ty_op.operand, operand); |
| 4196 | 4294 | ||
| 4197 | if (isByRef(payload_ty, func.target)) { | 4295 | if (isByRef(payload_ty, mod)) { |
| 4198 | break :result try func.buildPointerOffset(operand, 0, .new); | 4296 | break :result try func.buildPointerOffset(operand, 0, .new); |
| 4199 | } | 4297 | } |
| 4200 | 4298 | ||
| ... | @@ -4205,14 +4303,14 @@ fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4205,14 +4303,14 @@ fn airOptionalPayload(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4205 | } | 4303 | } |
| 4206 | 4304 | ||
| 4207 | fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4305 | fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4306 | const mod = func.bin_file.base.options.module.?; | ||
| 4208 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4307 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4209 | const operand = try func.resolveInst(ty_op.operand); | 4308 | const operand = try func.resolveInst(ty_op.operand); |
| 4210 | const opt_ty = func.air.typeOf(ty_op.operand).childType(); | 4309 | const opt_ty = func.typeOf(ty_op.operand).childType(mod); |
| 4211 | 4310 | ||
| 4212 | const result = result: { | 4311 | const result = result: { |
| 4213 | var buf: Type.Payload.ElemType = undefined; | 4312 | const payload_ty = opt_ty.optionalChild(mod); |
| 4214 | const payload_ty = opt_ty.optionalChild(&buf); | 4313 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or opt_ty.optionalReprIsPayload(mod)) { |
| 4215 | if (!payload_ty.hasRuntimeBitsIgnoreComptime() or opt_ty.optionalReprIsPayload()) { | ||
| 4216 | break :result func.reuseOperand(ty_op.operand, operand); | 4314 | break :result func.reuseOperand(ty_op.operand, operand); |
| 4217 | } | 4315 | } |
| 4218 | 4316 | ||
| ... | @@ -4222,22 +4320,21 @@ fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4222,22 +4320,21 @@ fn airOptionalPayloadPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4222 | } | 4320 | } |
| 4223 | 4321 | ||
| 4224 | fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4322 | fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4323 | const mod = func.bin_file.base.options.module.?; | ||
| 4225 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4324 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4226 | const operand = try func.resolveInst(ty_op.operand); | 4325 | const operand = try func.resolveInst(ty_op.operand); |
| 4227 | const opt_ty = func.air.typeOf(ty_op.operand).childType(); | 4326 | const opt_ty = func.typeOf(ty_op.operand).childType(mod); |
| 4228 | var buf: Type.Payload.ElemType = undefined; | 4327 | const payload_ty = opt_ty.optionalChild(mod); |
| 4229 | const payload_ty = opt_ty.optionalChild(&buf); | 4328 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4230 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 4231 | return func.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty.fmtDebug()}); | 4329 | return func.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty.fmtDebug()}); |
| 4232 | } | 4330 | } |
| 4233 | 4331 | ||
| 4234 | if (opt_ty.optionalReprIsPayload()) { | 4332 | if (opt_ty.optionalReprIsPayload(mod)) { |
| 4235 | return func.finishAir(inst, operand, &.{ty_op.operand}); | 4333 | return func.finishAir(inst, operand, &.{ty_op.operand}); |
| 4236 | } | 4334 | } |
| 4237 | 4335 | ||
| 4238 | const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse { | 4336 | const offset = std.math.cast(u32, payload_ty.abiSize(mod)) orelse { |
| 4239 | const module = func.bin_file.base.options.module.?; | 4337 | return func.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(mod)}); |
| 4240 | return func.fail("Optional type {} too big to fit into stack frame", .{opt_ty.fmt(module)}); | ||
| 4241 | }; | 4338 | }; |
| 4242 | 4339 | ||
| 4243 | try func.emitWValue(operand); | 4340 | try func.emitWValue(operand); |
| ... | @@ -4250,11 +4347,12 @@ fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi | ... | @@ -4250,11 +4347,12 @@ fn airOptionalPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi |
| 4250 | 4347 | ||
| 4251 | fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4348 | fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4252 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4349 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4253 | const payload_ty = func.air.typeOf(ty_op.operand); | 4350 | const payload_ty = func.typeOf(ty_op.operand); |
| 4351 | const mod = func.bin_file.base.options.module.?; | ||
| 4254 | 4352 | ||
| 4255 | const result = result: { | 4353 | const result = result: { |
| 4256 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 4354 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4257 | const non_null_bit = try func.allocStack(Type.initTag(.u1)); | 4355 | const non_null_bit = try func.allocStack(Type.u1); |
| 4258 | try func.emitWValue(non_null_bit); | 4356 | try func.emitWValue(non_null_bit); |
| 4259 | try func.addImm32(1); | 4357 | try func.addImm32(1); |
| 4260 | try func.addMemArg(.i32_store8, .{ .offset = non_null_bit.offset(), .alignment = 1 }); | 4358 | try func.addMemArg(.i32_store8, .{ .offset = non_null_bit.offset(), .alignment = 1 }); |
| ... | @@ -4262,13 +4360,12 @@ fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4262,13 +4360,12 @@ fn airWrapOptional(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4262 | } | 4360 | } |
| 4263 | 4361 | ||
| 4264 | const operand = try func.resolveInst(ty_op.operand); | 4362 | const operand = try func.resolveInst(ty_op.operand); |
| 4265 | const op_ty = func.air.typeOfIndex(inst); | 4363 | const op_ty = func.typeOfIndex(inst); |
| 4266 | if (op_ty.optionalReprIsPayload()) { | 4364 | if (op_ty.optionalReprIsPayload(mod)) { |
| 4267 | break :result func.reuseOperand(ty_op.operand, operand); | 4365 | break :result func.reuseOperand(ty_op.operand, operand); |
| 4268 | } | 4366 | } |
| 4269 | const offset = std.math.cast(u32, payload_ty.abiSize(func.target)) orelse { | 4367 | const offset = std.math.cast(u32, payload_ty.abiSize(mod)) orelse { |
| 4270 | const module = func.bin_file.base.options.module.?; | 4368 | return func.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(mod)}); |
| 4271 | return func.fail("Optional type {} too big to fit into stack frame", .{op_ty.fmt(module)}); | ||
| 4272 | }; | 4369 | }; |
| 4273 | 4370 | ||
| 4274 | // Create optional type, set the non-null bit, and store the operand inside the optional type | 4371 | // Create optional type, set the non-null bit, and store the operand inside the optional type |
| ... | @@ -4291,7 +4388,7 @@ fn airSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4291,7 +4388,7 @@ fn airSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4291 | 4388 | ||
| 4292 | const lhs = try func.resolveInst(bin_op.lhs); | 4389 | const lhs = try func.resolveInst(bin_op.lhs); |
| 4293 | const rhs = try func.resolveInst(bin_op.rhs); | 4390 | const rhs = try func.resolveInst(bin_op.rhs); |
| 4294 | const slice_ty = func.air.typeOfIndex(inst); | 4391 | const slice_ty = func.typeOfIndex(inst); |
| 4295 | 4392 | ||
| 4296 | const slice = try func.allocStack(slice_ty); | 4393 | const slice = try func.allocStack(slice_ty); |
| 4297 | try func.store(slice, lhs, Type.usize, 0); | 4394 | try func.store(slice, lhs, Type.usize, 0); |
| ... | @@ -4308,13 +4405,14 @@ fn airSliceLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4308,13 +4405,14 @@ fn airSliceLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4308 | } | 4405 | } |
| 4309 | 4406 | ||
| 4310 | fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4407 | fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4408 | const mod = func.bin_file.base.options.module.?; | ||
| 4311 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 4409 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 4312 | 4410 | ||
| 4313 | const slice_ty = func.air.typeOf(bin_op.lhs); | 4411 | const slice_ty = func.typeOf(bin_op.lhs); |
| 4314 | const slice = try func.resolveInst(bin_op.lhs); | 4412 | const slice = try func.resolveInst(bin_op.lhs); |
| 4315 | const index = try func.resolveInst(bin_op.rhs); | 4413 | const index = try func.resolveInst(bin_op.rhs); |
| 4316 | const elem_ty = slice_ty.childType(); | 4414 | const elem_ty = slice_ty.childType(mod); |
| 4317 | const elem_size = elem_ty.abiSize(func.target); | 4415 | const elem_size = elem_ty.abiSize(mod); |
| 4318 | 4416 | ||
| 4319 | // load pointer onto stack | 4417 | // load pointer onto stack |
| 4320 | _ = try func.load(slice, Type.usize, 0); | 4418 | _ = try func.load(slice, Type.usize, 0); |
| ... | @@ -4328,7 +4426,7 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4328,7 +4426,7 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4328 | const result_ptr = try func.allocLocal(Type.usize); | 4426 | const result_ptr = try func.allocLocal(Type.usize); |
| 4329 | try func.addLabel(.local_set, result_ptr.local.value); | 4427 | try func.addLabel(.local_set, result_ptr.local.value); |
| 4330 | 4428 | ||
| 4331 | const result = if (!isByRef(elem_ty, func.target)) result: { | 4429 | const result = if (!isByRef(elem_ty, mod)) result: { |
| 4332 | const elem_val = try func.load(result_ptr, elem_ty, 0); | 4430 | const elem_val = try func.load(result_ptr, elem_ty, 0); |
| 4333 | break :result try elem_val.toLocal(func, elem_ty); | 4431 | break :result try elem_val.toLocal(func, elem_ty); |
| 4334 | } else result_ptr; | 4432 | } else result_ptr; |
| ... | @@ -4337,11 +4435,12 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4337,11 +4435,12 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4337 | } | 4435 | } |
| 4338 | 4436 | ||
| 4339 | fn airSliceElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4437 | fn airSliceElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4438 | const mod = func.bin_file.base.options.module.?; | ||
| 4340 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 4439 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 4341 | const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data; | 4440 | const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 4342 | 4441 | ||
| 4343 | const elem_ty = func.air.getRefType(ty_pl.ty).childType(); | 4442 | const elem_ty = func.air.getRefType(ty_pl.ty).childType(mod); |
| 4344 | const elem_size = elem_ty.abiSize(func.target); | 4443 | const elem_size = elem_ty.abiSize(mod); |
| 4345 | 4444 | ||
| 4346 | const slice = try func.resolveInst(bin_op.lhs); | 4445 | const slice = try func.resolveInst(bin_op.lhs); |
| 4347 | const index = try func.resolveInst(bin_op.rhs); | 4446 | const index = try func.resolveInst(bin_op.rhs); |
| ... | @@ -4380,7 +4479,7 @@ fn airTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4380,7 +4479,7 @@ fn airTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4380 | 4479 | ||
| 4381 | const operand = try func.resolveInst(ty_op.operand); | 4480 | const operand = try func.resolveInst(ty_op.operand); |
| 4382 | const wanted_ty = func.air.getRefType(ty_op.ty); | 4481 | const wanted_ty = func.air.getRefType(ty_op.ty); |
| 4383 | const op_ty = func.air.typeOf(ty_op.operand); | 4482 | const op_ty = func.typeOf(ty_op.operand); |
| 4384 | 4483 | ||
| 4385 | const result = try func.trunc(operand, wanted_ty, op_ty); | 4484 | const result = try func.trunc(operand, wanted_ty, op_ty); |
| 4386 | func.finishAir(inst, try result.toLocal(func, wanted_ty), &.{ty_op.operand}); | 4485 | func.finishAir(inst, try result.toLocal(func, wanted_ty), &.{ty_op.operand}); |
| ... | @@ -4389,13 +4488,14 @@ fn airTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4389,13 +4488,14 @@ fn airTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4389 | /// Truncates a given operand to a given type, discarding any overflown bits. | 4488 | /// Truncates a given operand to a given type, discarding any overflown bits. |
| 4390 | /// NOTE: Resulting value is left on the stack. | 4489 | /// NOTE: Resulting value is left on the stack. |
| 4391 | fn trunc(func: *CodeGen, operand: WValue, wanted_ty: Type, given_ty: Type) InnerError!WValue { | 4490 | fn trunc(func: *CodeGen, operand: WValue, wanted_ty: Type, given_ty: Type) InnerError!WValue { |
| 4392 | const given_bits = @intCast(u16, given_ty.bitSize(func.target)); | 4491 | const mod = func.bin_file.base.options.module.?; |
| 4492 | const given_bits = @intCast(u16, given_ty.bitSize(mod)); | ||
| 4393 | if (toWasmBits(given_bits) == null) { | 4493 | if (toWasmBits(given_bits) == null) { |
| 4394 | return func.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{given_bits}); | 4494 | return func.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{given_bits}); |
| 4395 | } | 4495 | } |
| 4396 | 4496 | ||
| 4397 | var result = try func.intcast(operand, given_ty, wanted_ty); | 4497 | var result = try func.intcast(operand, given_ty, wanted_ty); |
| 4398 | const wanted_bits = @intCast(u16, wanted_ty.bitSize(func.target)); | 4498 | const wanted_bits = @intCast(u16, wanted_ty.bitSize(mod)); |
| 4399 | const wasm_bits = toWasmBits(wanted_bits).?; | 4499 | const wasm_bits = toWasmBits(wanted_bits).?; |
| 4400 | if (wasm_bits != wanted_bits) { | 4500 | if (wasm_bits != wanted_bits) { |
| 4401 | result = try func.wrapOperand(result, wanted_ty); | 4501 | result = try func.wrapOperand(result, wanted_ty); |
| ... | @@ -4412,32 +4512,34 @@ fn airBoolToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4412,32 +4512,34 @@ fn airBoolToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4412 | } | 4512 | } |
| 4413 | 4513 | ||
| 4414 | fn airArrayToSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4514 | fn airArrayToSlice(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4515 | const mod = func.bin_file.base.options.module.?; | ||
| 4415 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4516 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4416 | 4517 | ||
| 4417 | const operand = try func.resolveInst(ty_op.operand); | 4518 | const operand = try func.resolveInst(ty_op.operand); |
| 4418 | const array_ty = func.air.typeOf(ty_op.operand).childType(); | 4519 | const array_ty = func.typeOf(ty_op.operand).childType(mod); |
| 4419 | const slice_ty = func.air.getRefType(ty_op.ty); | 4520 | const slice_ty = func.air.getRefType(ty_op.ty); |
| 4420 | 4521 | ||
| 4421 | // create a slice on the stack | 4522 | // create a slice on the stack |
| 4422 | const slice_local = try func.allocStack(slice_ty); | 4523 | const slice_local = try func.allocStack(slice_ty); |
| 4423 | 4524 | ||
| 4424 | // store the array ptr in the slice | 4525 | // store the array ptr in the slice |
| 4425 | if (array_ty.hasRuntimeBitsIgnoreComptime()) { | 4526 | if (array_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4426 | try func.store(slice_local, operand, Type.usize, 0); | 4527 | try func.store(slice_local, operand, Type.usize, 0); |
| 4427 | } | 4528 | } |
| 4428 | 4529 | ||
| 4429 | // store the length of the array in the slice | 4530 | // store the length of the array in the slice |
| 4430 | const len = WValue{ .imm32 = @intCast(u32, array_ty.arrayLen()) }; | 4531 | const len = WValue{ .imm32 = @intCast(u32, array_ty.arrayLen(mod)) }; |
| 4431 | try func.store(slice_local, len, Type.usize, func.ptrSize()); | 4532 | try func.store(slice_local, len, Type.usize, func.ptrSize()); |
| 4432 | 4533 | ||
| 4433 | func.finishAir(inst, slice_local, &.{ty_op.operand}); | 4534 | func.finishAir(inst, slice_local, &.{ty_op.operand}); |
| 4434 | } | 4535 | } |
| 4435 | 4536 | ||
| 4436 | fn airPtrToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4537 | fn airPtrToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4538 | const mod = func.bin_file.base.options.module.?; | ||
| 4437 | const un_op = func.air.instructions.items(.data)[inst].un_op; | 4539 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 4438 | const operand = try func.resolveInst(un_op); | 4540 | const operand = try func.resolveInst(un_op); |
| 4439 | const ptr_ty = func.air.typeOf(un_op); | 4541 | const ptr_ty = func.typeOf(un_op); |
| 4440 | const result = if (ptr_ty.isSlice()) | 4542 | const result = if (ptr_ty.isSlice(mod)) |
| 4441 | try func.slicePtr(operand) | 4543 | try func.slicePtr(operand) |
| 4442 | else switch (operand) { | 4544 | else switch (operand) { |
| 4443 | // for stack offset, return a pointer to this offset. | 4545 | // for stack offset, return a pointer to this offset. |
| ... | @@ -4448,16 +4550,17 @@ fn airPtrToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4448,16 +4550,17 @@ fn airPtrToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4448 | } | 4550 | } |
| 4449 | 4551 | ||
| 4450 | fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4552 | fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4553 | const mod = func.bin_file.base.options.module.?; | ||
| 4451 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 4554 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 4452 | 4555 | ||
| 4453 | const ptr_ty = func.air.typeOf(bin_op.lhs); | 4556 | const ptr_ty = func.typeOf(bin_op.lhs); |
| 4454 | const ptr = try func.resolveInst(bin_op.lhs); | 4557 | const ptr = try func.resolveInst(bin_op.lhs); |
| 4455 | const index = try func.resolveInst(bin_op.rhs); | 4558 | const index = try func.resolveInst(bin_op.rhs); |
| 4456 | const elem_ty = ptr_ty.childType(); | 4559 | const elem_ty = ptr_ty.childType(mod); |
| 4457 | const elem_size = elem_ty.abiSize(func.target); | 4560 | const elem_size = elem_ty.abiSize(mod); |
| 4458 | 4561 | ||
| 4459 | // load pointer onto the stack | 4562 | // load pointer onto the stack |
| 4460 | if (ptr_ty.isSlice()) { | 4563 | if (ptr_ty.isSlice(mod)) { |
| 4461 | _ = try func.load(ptr, Type.usize, 0); | 4564 | _ = try func.load(ptr, Type.usize, 0); |
| 4462 | } else { | 4565 | } else { |
| 4463 | try func.lowerToStack(ptr); | 4566 | try func.lowerToStack(ptr); |
| ... | @@ -4472,7 +4575,7 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4472,7 +4575,7 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4472 | const elem_result = val: { | 4575 | const elem_result = val: { |
| 4473 | var result = try func.allocLocal(Type.usize); | 4576 | var result = try func.allocLocal(Type.usize); |
| 4474 | try func.addLabel(.local_set, result.local.value); | 4577 | try func.addLabel(.local_set, result.local.value); |
| 4475 | if (isByRef(elem_ty, func.target)) { | 4578 | if (isByRef(elem_ty, mod)) { |
| 4476 | break :val result; | 4579 | break :val result; |
| 4477 | } | 4580 | } |
| 4478 | defer result.free(func); // only free if it's not returned like above | 4581 | defer result.free(func); // only free if it's not returned like above |
| ... | @@ -4484,18 +4587,19 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4484,18 +4587,19 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4484 | } | 4587 | } |
| 4485 | 4588 | ||
| 4486 | fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4589 | fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4590 | const mod = func.bin_file.base.options.module.?; | ||
| 4487 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 4591 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 4488 | const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data; | 4592 | const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 4489 | 4593 | ||
| 4490 | const ptr_ty = func.air.typeOf(bin_op.lhs); | 4594 | const ptr_ty = func.typeOf(bin_op.lhs); |
| 4491 | const elem_ty = func.air.getRefType(ty_pl.ty).childType(); | 4595 | const elem_ty = func.air.getRefType(ty_pl.ty).childType(mod); |
| 4492 | const elem_size = elem_ty.abiSize(func.target); | 4596 | const elem_size = elem_ty.abiSize(mod); |
| 4493 | 4597 | ||
| 4494 | const ptr = try func.resolveInst(bin_op.lhs); | 4598 | const ptr = try func.resolveInst(bin_op.lhs); |
| 4495 | const index = try func.resolveInst(bin_op.rhs); | 4599 | const index = try func.resolveInst(bin_op.rhs); |
| 4496 | 4600 | ||
| 4497 | // load pointer onto the stack | 4601 | // load pointer onto the stack |
| 4498 | if (ptr_ty.isSlice()) { | 4602 | if (ptr_ty.isSlice(mod)) { |
| 4499 | _ = try func.load(ptr, Type.usize, 0); | 4603 | _ = try func.load(ptr, Type.usize, 0); |
| 4500 | } else { | 4604 | } else { |
| 4501 | try func.lowerToStack(ptr); | 4605 | try func.lowerToStack(ptr); |
| ... | @@ -4513,24 +4617,25 @@ fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4513,24 +4617,25 @@ fn airPtrElemPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4513 | } | 4617 | } |
| 4514 | 4618 | ||
| 4515 | fn airPtrBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | 4619 | fn airPtrBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 4620 | const mod = func.bin_file.base.options.module.?; | ||
| 4516 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 4621 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 4517 | const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data; | 4622 | const bin_op = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 4518 | 4623 | ||
| 4519 | const ptr = try func.resolveInst(bin_op.lhs); | 4624 | const ptr = try func.resolveInst(bin_op.lhs); |
| 4520 | const offset = try func.resolveInst(bin_op.rhs); | 4625 | const offset = try func.resolveInst(bin_op.rhs); |
| 4521 | const ptr_ty = func.air.typeOf(bin_op.lhs); | 4626 | const ptr_ty = func.typeOf(bin_op.lhs); |
| 4522 | const pointee_ty = switch (ptr_ty.ptrSize()) { | 4627 | const pointee_ty = switch (ptr_ty.ptrSize(mod)) { |
| 4523 | .One => ptr_ty.childType().childType(), // ptr to array, so get array element type | 4628 | .One => ptr_ty.childType(mod).childType(mod), // ptr to array, so get array element type |
| 4524 | else => ptr_ty.childType(), | 4629 | else => ptr_ty.childType(mod), |
| 4525 | }; | 4630 | }; |
| 4526 | 4631 | ||
| 4527 | const valtype = typeToValtype(Type.usize, func.target); | 4632 | const valtype = typeToValtype(Type.usize, mod); |
| 4528 | const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul }); | 4633 | const mul_opcode = buildOpcode(.{ .valtype1 = valtype, .op = .mul }); |
| 4529 | const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op }); | 4634 | const bin_opcode = buildOpcode(.{ .valtype1 = valtype, .op = op }); |
| 4530 | 4635 | ||
| 4531 | try func.lowerToStack(ptr); | 4636 | try func.lowerToStack(ptr); |
| 4532 | try func.emitWValue(offset); | 4637 | try func.emitWValue(offset); |
| 4533 | try func.addImm32(@bitCast(i32, @intCast(u32, pointee_ty.abiSize(func.target)))); | 4638 | try func.addImm32(@bitCast(i32, @intCast(u32, pointee_ty.abiSize(mod)))); |
| 4534 | try func.addTag(Mir.Inst.Tag.fromOpcode(mul_opcode)); | 4639 | try func.addTag(Mir.Inst.Tag.fromOpcode(mul_opcode)); |
| 4535 | try func.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode)); | 4640 | try func.addTag(Mir.Inst.Tag.fromOpcode(bin_opcode)); |
| 4536 | 4641 | ||
| ... | @@ -4540,6 +4645,7 @@ fn airPtrBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | ... | @@ -4540,6 +4645,7 @@ fn airPtrBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 4540 | } | 4645 | } |
| 4541 | 4646 | ||
| 4542 | fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { | 4647 | fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { |
| 4648 | const mod = func.bin_file.base.options.module.?; | ||
| 4543 | if (safety) { | 4649 | if (safety) { |
| 4544 | // TODO if the value is undef, write 0xaa bytes to dest | 4650 | // TODO if the value is undef, write 0xaa bytes to dest |
| 4545 | } else { | 4651 | } else { |
| ... | @@ -4548,18 +4654,18 @@ fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void | ... | @@ -4548,18 +4654,18 @@ fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void |
| 4548 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 4654 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 4549 | 4655 | ||
| 4550 | const ptr = try func.resolveInst(bin_op.lhs); | 4656 | const ptr = try func.resolveInst(bin_op.lhs); |
| 4551 | const ptr_ty = func.air.typeOf(bin_op.lhs); | 4657 | const ptr_ty = func.typeOf(bin_op.lhs); |
| 4552 | const value = try func.resolveInst(bin_op.rhs); | 4658 | const value = try func.resolveInst(bin_op.rhs); |
| 4553 | const len = switch (ptr_ty.ptrSize()) { | 4659 | const len = switch (ptr_ty.ptrSize(mod)) { |
| 4554 | .Slice => try func.sliceLen(ptr), | 4660 | .Slice => try func.sliceLen(ptr), |
| 4555 | .One => @as(WValue, .{ .imm32 = @intCast(u32, ptr_ty.childType().arrayLen()) }), | 4661 | .One => @as(WValue, .{ .imm32 = @intCast(u32, ptr_ty.childType(mod).arrayLen(mod)) }), |
| 4556 | .C, .Many => unreachable, | 4662 | .C, .Many => unreachable, |
| 4557 | }; | 4663 | }; |
| 4558 | 4664 | ||
| 4559 | const elem_ty = if (ptr_ty.ptrSize() == .One) | 4665 | const elem_ty = if (ptr_ty.ptrSize(mod) == .One) |
| 4560 | ptr_ty.childType().childType() | 4666 | ptr_ty.childType(mod).childType(mod) |
| 4561 | else | 4667 | else |
| 4562 | ptr_ty.childType(); | 4668 | ptr_ty.childType(mod); |
| 4563 | 4669 | ||
| 4564 | const dst_ptr = try func.sliceOrArrayPtr(ptr, ptr_ty); | 4670 | const dst_ptr = try func.sliceOrArrayPtr(ptr, ptr_ty); |
| 4565 | try func.memset(elem_ty, dst_ptr, len, value); | 4671 | try func.memset(elem_ty, dst_ptr, len, value); |
| ... | @@ -4572,7 +4678,8 @@ fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void | ... | @@ -4572,7 +4678,8 @@ fn airMemset(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void |
| 4572 | /// this to wasm's memset instruction. When the feature is not present, | 4678 | /// this to wasm's memset instruction. When the feature is not present, |
| 4573 | /// we implement it manually. | 4679 | /// we implement it manually. |
| 4574 | fn memset(func: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) InnerError!void { | 4680 | fn memset(func: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) InnerError!void { |
| 4575 | const abi_size = @intCast(u32, elem_ty.abiSize(func.target)); | 4681 | const mod = func.bin_file.base.options.module.?; |
| 4682 | const abi_size = @intCast(u32, elem_ty.abiSize(mod)); | ||
| 4576 | 4683 | ||
| 4577 | // When bulk_memory is enabled, we lower it to wasm's memset instruction. | 4684 | // When bulk_memory is enabled, we lower it to wasm's memset instruction. |
| 4578 | // If not, we lower it ourselves. | 4685 | // If not, we lower it ourselves. |
| ... | @@ -4660,30 +4767,31 @@ fn memset(func: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue | ... | @@ -4660,30 +4767,31 @@ fn memset(func: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue |
| 4660 | } | 4767 | } |
| 4661 | 4768 | ||
| 4662 | fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4769 | fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4770 | const mod = func.bin_file.base.options.module.?; | ||
| 4663 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 4771 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 4664 | 4772 | ||
| 4665 | const array_ty = func.air.typeOf(bin_op.lhs); | 4773 | const array_ty = func.typeOf(bin_op.lhs); |
| 4666 | const array = try func.resolveInst(bin_op.lhs); | 4774 | const array = try func.resolveInst(bin_op.lhs); |
| 4667 | const index = try func.resolveInst(bin_op.rhs); | 4775 | const index = try func.resolveInst(bin_op.rhs); |
| 4668 | const elem_ty = array_ty.childType(); | 4776 | const elem_ty = array_ty.childType(mod); |
| 4669 | const elem_size = elem_ty.abiSize(func.target); | 4777 | const elem_size = elem_ty.abiSize(mod); |
| 4670 | 4778 | ||
| 4671 | if (isByRef(array_ty, func.target)) { | 4779 | if (isByRef(array_ty, mod)) { |
| 4672 | try func.lowerToStack(array); | 4780 | try func.lowerToStack(array); |
| 4673 | try func.emitWValue(index); | 4781 | try func.emitWValue(index); |
| 4674 | try func.addImm32(@bitCast(i32, @intCast(u32, elem_size))); | 4782 | try func.addImm32(@bitCast(i32, @intCast(u32, elem_size))); |
| 4675 | try func.addTag(.i32_mul); | 4783 | try func.addTag(.i32_mul); |
| 4676 | try func.addTag(.i32_add); | 4784 | try func.addTag(.i32_add); |
| 4677 | } else { | 4785 | } else { |
| 4678 | std.debug.assert(array_ty.zigTypeTag() == .Vector); | 4786 | std.debug.assert(array_ty.zigTypeTag(mod) == .Vector); |
| 4679 | 4787 | ||
| 4680 | switch (index) { | 4788 | switch (index) { |
| 4681 | inline .imm32, .imm64 => |lane| { | 4789 | inline .imm32, .imm64 => |lane| { |
| 4682 | const opcode: wasm.SimdOpcode = switch (elem_ty.bitSize(func.target)) { | 4790 | const opcode: wasm.SimdOpcode = switch (elem_ty.bitSize(mod)) { |
| 4683 | 8 => if (elem_ty.isSignedInt()) .i8x16_extract_lane_s else .i8x16_extract_lane_u, | 4791 | 8 => if (elem_ty.isSignedInt(mod)) .i8x16_extract_lane_s else .i8x16_extract_lane_u, |
| 4684 | 16 => if (elem_ty.isSignedInt()) .i16x8_extract_lane_s else .i16x8_extract_lane_u, | 4792 | 16 => if (elem_ty.isSignedInt(mod)) .i16x8_extract_lane_s else .i16x8_extract_lane_u, |
| 4685 | 32 => if (elem_ty.isInt()) .i32x4_extract_lane else .f32x4_extract_lane, | 4793 | 32 => if (elem_ty.isInt(mod)) .i32x4_extract_lane else .f32x4_extract_lane, |
| 4686 | 64 => if (elem_ty.isInt()) .i64x2_extract_lane else .f64x2_extract_lane, | 4794 | 64 => if (elem_ty.isInt(mod)) .i64x2_extract_lane else .f64x2_extract_lane, |
| 4687 | else => unreachable, | 4795 | else => unreachable, |
| 4688 | }; | 4796 | }; |
| 4689 | 4797 | ||
| ... | @@ -4715,7 +4823,7 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4715,7 +4823,7 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4715 | var result = try func.allocLocal(Type.usize); | 4823 | var result = try func.allocLocal(Type.usize); |
| 4716 | try func.addLabel(.local_set, result.local.value); | 4824 | try func.addLabel(.local_set, result.local.value); |
| 4717 | 4825 | ||
| 4718 | if (isByRef(elem_ty, func.target)) { | 4826 | if (isByRef(elem_ty, mod)) { |
| 4719 | break :val result; | 4827 | break :val result; |
| 4720 | } | 4828 | } |
| 4721 | defer result.free(func); // only free if no longer needed and not returned like above | 4829 | defer result.free(func); // only free if no longer needed and not returned like above |
| ... | @@ -4728,22 +4836,23 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4728,22 +4836,23 @@ fn airArrayElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4728 | } | 4836 | } |
| 4729 | 4837 | ||
| 4730 | fn airFloatToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4838 | fn airFloatToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4839 | const mod = func.bin_file.base.options.module.?; | ||
| 4731 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4840 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4732 | 4841 | ||
| 4733 | const operand = try func.resolveInst(ty_op.operand); | 4842 | const operand = try func.resolveInst(ty_op.operand); |
| 4734 | const dest_ty = func.air.typeOfIndex(inst); | 4843 | const dest_ty = func.typeOfIndex(inst); |
| 4735 | const op_ty = func.air.typeOf(ty_op.operand); | 4844 | const op_ty = func.typeOf(ty_op.operand); |
| 4736 | 4845 | ||
| 4737 | if (op_ty.abiSize(func.target) > 8) { | 4846 | if (op_ty.abiSize(mod) > 8) { |
| 4738 | return func.fail("TODO: floatToInt for integers/floats with bitsize larger than 64 bits", .{}); | 4847 | return func.fail("TODO: floatToInt for integers/floats with bitsize larger than 64 bits", .{}); |
| 4739 | } | 4848 | } |
| 4740 | 4849 | ||
| 4741 | try func.emitWValue(operand); | 4850 | try func.emitWValue(operand); |
| 4742 | const op = buildOpcode(.{ | 4851 | const op = buildOpcode(.{ |
| 4743 | .op = .trunc, | 4852 | .op = .trunc, |
| 4744 | .valtype1 = typeToValtype(dest_ty, func.target), | 4853 | .valtype1 = typeToValtype(dest_ty, mod), |
| 4745 | .valtype2 = typeToValtype(op_ty, func.target), | 4854 | .valtype2 = typeToValtype(op_ty, mod), |
| 4746 | .signedness = if (dest_ty.isSignedInt()) .signed else .unsigned, | 4855 | .signedness = if (dest_ty.isSignedInt(mod)) .signed else .unsigned, |
| 4747 | }); | 4856 | }); |
| 4748 | try func.addTag(Mir.Inst.Tag.fromOpcode(op)); | 4857 | try func.addTag(Mir.Inst.Tag.fromOpcode(op)); |
| 4749 | const wrapped = try func.wrapOperand(.{ .stack = {} }, dest_ty); | 4858 | const wrapped = try func.wrapOperand(.{ .stack = {} }, dest_ty); |
| ... | @@ -4752,22 +4861,23 @@ fn airFloatToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4752,22 +4861,23 @@ fn airFloatToInt(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4752 | } | 4861 | } |
| 4753 | 4862 | ||
| 4754 | fn airIntToFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4863 | fn airIntToFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4864 | const mod = func.bin_file.base.options.module.?; | ||
| 4755 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4865 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4756 | 4866 | ||
| 4757 | const operand = try func.resolveInst(ty_op.operand); | 4867 | const operand = try func.resolveInst(ty_op.operand); |
| 4758 | const dest_ty = func.air.typeOfIndex(inst); | 4868 | const dest_ty = func.typeOfIndex(inst); |
| 4759 | const op_ty = func.air.typeOf(ty_op.operand); | 4869 | const op_ty = func.typeOf(ty_op.operand); |
| 4760 | 4870 | ||
| 4761 | if (op_ty.abiSize(func.target) > 8) { | 4871 | if (op_ty.abiSize(mod) > 8) { |
| 4762 | return func.fail("TODO: intToFloat for integers/floats with bitsize larger than 64 bits", .{}); | 4872 | return func.fail("TODO: intToFloat for integers/floats with bitsize larger than 64 bits", .{}); |
| 4763 | } | 4873 | } |
| 4764 | 4874 | ||
| 4765 | try func.emitWValue(operand); | 4875 | try func.emitWValue(operand); |
| 4766 | const op = buildOpcode(.{ | 4876 | const op = buildOpcode(.{ |
| 4767 | .op = .convert, | 4877 | .op = .convert, |
| 4768 | .valtype1 = typeToValtype(dest_ty, func.target), | 4878 | .valtype1 = typeToValtype(dest_ty, mod), |
| 4769 | .valtype2 = typeToValtype(op_ty, func.target), | 4879 | .valtype2 = typeToValtype(op_ty, mod), |
| 4770 | .signedness = if (op_ty.isSignedInt()) .signed else .unsigned, | 4880 | .signedness = if (op_ty.isSignedInt(mod)) .signed else .unsigned, |
| 4771 | }); | 4881 | }); |
| 4772 | try func.addTag(Mir.Inst.Tag.fromOpcode(op)); | 4882 | try func.addTag(Mir.Inst.Tag.fromOpcode(op)); |
| 4773 | 4883 | ||
| ... | @@ -4777,18 +4887,19 @@ fn airIntToFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4777,18 +4887,19 @@ fn airIntToFloat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4777 | } | 4887 | } |
| 4778 | 4888 | ||
| 4779 | fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4889 | fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4890 | const mod = func.bin_file.base.options.module.?; | ||
| 4780 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 4891 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 4781 | const operand = try func.resolveInst(ty_op.operand); | 4892 | const operand = try func.resolveInst(ty_op.operand); |
| 4782 | const ty = func.air.typeOfIndex(inst); | 4893 | const ty = func.typeOfIndex(inst); |
| 4783 | const elem_ty = ty.childType(); | 4894 | const elem_ty = ty.childType(mod); |
| 4784 | 4895 | ||
| 4785 | if (determineSimdStoreStrategy(ty, func.target) == .direct) blk: { | 4896 | if (determineSimdStoreStrategy(ty, mod) == .direct) blk: { |
| 4786 | switch (operand) { | 4897 | switch (operand) { |
| 4787 | // when the operand lives in the linear memory section, we can directly | 4898 | // when the operand lives in the linear memory section, we can directly |
| 4788 | // load and splat the value at once. Meaning we do not first have to load | 4899 | // load and splat the value at once. Meaning we do not first have to load |
| 4789 | // the scalar value onto the stack. | 4900 | // the scalar value onto the stack. |
| 4790 | .stack_offset, .memory, .memory_offset => { | 4901 | .stack_offset, .memory, .memory_offset => { |
| 4791 | const opcode = switch (elem_ty.bitSize(func.target)) { | 4902 | const opcode = switch (elem_ty.bitSize(mod)) { |
| 4792 | 8 => std.wasm.simdOpcode(.v128_load8_splat), | 4903 | 8 => std.wasm.simdOpcode(.v128_load8_splat), |
| 4793 | 16 => std.wasm.simdOpcode(.v128_load16_splat), | 4904 | 16 => std.wasm.simdOpcode(.v128_load16_splat), |
| 4794 | 32 => std.wasm.simdOpcode(.v128_load32_splat), | 4905 | 32 => std.wasm.simdOpcode(.v128_load32_splat), |
| ... | @@ -4803,18 +4914,18 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4803,18 +4914,18 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4803 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ | 4914 | try func.mir_extra.appendSlice(func.gpa, &[_]u32{ |
| 4804 | opcode, | 4915 | opcode, |
| 4805 | operand.offset(), | 4916 | operand.offset(), |
| 4806 | elem_ty.abiAlignment(func.target), | 4917 | elem_ty.abiAlignment(mod), |
| 4807 | }); | 4918 | }); |
| 4808 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 4919 | try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| 4809 | try func.addLabel(.local_set, result.local.value); | 4920 | try func.addLabel(.local_set, result.local.value); |
| 4810 | return func.finishAir(inst, result, &.{ty_op.operand}); | 4921 | return func.finishAir(inst, result, &.{ty_op.operand}); |
| 4811 | }, | 4922 | }, |
| 4812 | .local => { | 4923 | .local => { |
| 4813 | const opcode = switch (elem_ty.bitSize(func.target)) { | 4924 | const opcode = switch (elem_ty.bitSize(mod)) { |
| 4814 | 8 => std.wasm.simdOpcode(.i8x16_splat), | 4925 | 8 => std.wasm.simdOpcode(.i8x16_splat), |
| 4815 | 16 => std.wasm.simdOpcode(.i16x8_splat), | 4926 | 16 => std.wasm.simdOpcode(.i16x8_splat), |
| 4816 | 32 => if (elem_ty.isInt()) std.wasm.simdOpcode(.i32x4_splat) else std.wasm.simdOpcode(.f32x4_splat), | 4927 | 32 => if (elem_ty.isInt(mod)) std.wasm.simdOpcode(.i32x4_splat) else std.wasm.simdOpcode(.f32x4_splat), |
| 4817 | 64 => if (elem_ty.isInt()) std.wasm.simdOpcode(.i64x2_splat) else std.wasm.simdOpcode(.f64x2_splat), | 4928 | 64 => if (elem_ty.isInt(mod)) std.wasm.simdOpcode(.i64x2_splat) else std.wasm.simdOpcode(.f64x2_splat), |
| 4818 | else => break :blk, // Cannot make use of simd-instructions | 4929 | else => break :blk, // Cannot make use of simd-instructions |
| 4819 | }; | 4930 | }; |
| 4820 | const result = try func.allocLocal(ty); | 4931 | const result = try func.allocLocal(ty); |
| ... | @@ -4828,14 +4939,14 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4828,14 +4939,14 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4828 | else => unreachable, | 4939 | else => unreachable, |
| 4829 | } | 4940 | } |
| 4830 | } | 4941 | } |
| 4831 | const elem_size = elem_ty.bitSize(func.target); | 4942 | const elem_size = elem_ty.bitSize(mod); |
| 4832 | const vector_len = @intCast(usize, ty.vectorLen()); | 4943 | const vector_len = @intCast(usize, ty.vectorLen(mod)); |
| 4833 | if ((!std.math.isPowerOfTwo(elem_size) or elem_size % 8 != 0) and vector_len > 1) { | 4944 | if ((!std.math.isPowerOfTwo(elem_size) or elem_size % 8 != 0) and vector_len > 1) { |
| 4834 | return func.fail("TODO: WebAssembly `@splat` for arbitrary element bitsize {d}", .{elem_size}); | 4945 | return func.fail("TODO: WebAssembly `@splat` for arbitrary element bitsize {d}", .{elem_size}); |
| 4835 | } | 4946 | } |
| 4836 | 4947 | ||
| 4837 | const result = try func.allocStack(ty); | 4948 | const result = try func.allocStack(ty); |
| 4838 | const elem_byte_size = @intCast(u32, elem_ty.abiSize(func.target)); | 4949 | const elem_byte_size = @intCast(u32, elem_ty.abiSize(mod)); |
| 4839 | var index: usize = 0; | 4950 | var index: usize = 0; |
| 4840 | var offset: u32 = 0; | 4951 | var offset: u32 = 0; |
| 4841 | while (index < vector_len) : (index += 1) { | 4952 | while (index < vector_len) : (index += 1) { |
| ... | @@ -4855,26 +4966,25 @@ fn airSelect(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4855,26 +4966,25 @@ fn airSelect(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4855 | } | 4966 | } |
| 4856 | 4967 | ||
| 4857 | fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 4968 | fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4858 | const inst_ty = func.air.typeOfIndex(inst); | 4969 | const mod = func.bin_file.base.options.module.?; |
| 4970 | const inst_ty = func.typeOfIndex(inst); | ||
| 4859 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 4971 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 4860 | const extra = func.air.extraData(Air.Shuffle, ty_pl.payload).data; | 4972 | const extra = func.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 4861 | 4973 | ||
| 4862 | const a = try func.resolveInst(extra.a); | 4974 | const a = try func.resolveInst(extra.a); |
| 4863 | const b = try func.resolveInst(extra.b); | 4975 | const b = try func.resolveInst(extra.b); |
| 4864 | const mask = func.air.values[extra.mask]; | 4976 | const mask = extra.mask.toValue(); |
| 4865 | const mask_len = extra.mask_len; | 4977 | const mask_len = extra.mask_len; |
| 4866 | 4978 | ||
| 4867 | const child_ty = inst_ty.childType(); | 4979 | const child_ty = inst_ty.childType(mod); |
| 4868 | const elem_size = child_ty.abiSize(func.target); | 4980 | const elem_size = child_ty.abiSize(mod); |
| 4869 | 4981 | ||
| 4870 | const module = func.bin_file.base.options.module.?; | ||
| 4871 | // TODO: One of them could be by ref; handle in loop | 4982 | // TODO: One of them could be by ref; handle in loop |
| 4872 | if (isByRef(func.air.typeOf(extra.a), func.target) or isByRef(inst_ty, func.target)) { | 4983 | if (isByRef(func.typeOf(extra.a), mod) or isByRef(inst_ty, mod)) { |
| 4873 | const result = try func.allocStack(inst_ty); | 4984 | const result = try func.allocStack(inst_ty); |
| 4874 | 4985 | ||
| 4875 | for (0..mask_len) |index| { | 4986 | for (0..mask_len) |index| { |
| 4876 | var buf: Value.ElemValueBuffer = undefined; | 4987 | const value = (try mask.elemValue(mod, index)).toSignedInt(mod); |
| 4877 | const value = mask.elemValueBuffer(module, index, &buf).toSignedInt(func.target); | ||
| 4878 | 4988 | ||
| 4879 | try func.emitWValue(result); | 4989 | try func.emitWValue(result); |
| 4880 | 4990 | ||
| ... | @@ -4894,8 +5004,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4894,8 +5004,7 @@ fn airShuffle(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4894 | 5004 | ||
| 4895 | var lanes = std.mem.asBytes(operands[1..]); | 5005 | var lanes = std.mem.asBytes(operands[1..]); |
| 4896 | for (0..@intCast(usize, mask_len)) |index| { | 5006 | for (0..@intCast(usize, mask_len)) |index| { |
| 4897 | var buf: Value.ElemValueBuffer = undefined; | 5007 | const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod); |
| 4898 | const mask_elem = mask.elemValueBuffer(module, index, &buf).toSignedInt(func.target); | ||
| 4899 | const base_index = if (mask_elem >= 0) | 5008 | const base_index = if (mask_elem >= 0) |
| 4900 | @intCast(u8, @intCast(i64, elem_size) * mask_elem) | 5009 | @intCast(u8, @intCast(i64, elem_size) * mask_elem) |
| 4901 | else | 5010 | else |
| ... | @@ -4926,25 +5035,26 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4926,25 +5035,26 @@ fn airReduce(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4926 | } | 5035 | } |
| 4927 | 5036 | ||
| 4928 | fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5037 | fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5038 | const mod = func.bin_file.base.options.module.?; | ||
| 4929 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 5039 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 4930 | const result_ty = func.air.typeOfIndex(inst); | 5040 | const result_ty = func.typeOfIndex(inst); |
| 4931 | const len = @intCast(usize, result_ty.arrayLen()); | 5041 | const len = @intCast(usize, result_ty.arrayLen(mod)); |
| 4932 | const elements = @ptrCast([]const Air.Inst.Ref, func.air.extra[ty_pl.payload..][0..len]); | 5042 | const elements = @ptrCast([]const Air.Inst.Ref, func.air.extra[ty_pl.payload..][0..len]); |
| 4933 | 5043 | ||
| 4934 | const result: WValue = result_value: { | 5044 | const result: WValue = result_value: { |
| 4935 | switch (result_ty.zigTypeTag()) { | 5045 | switch (result_ty.zigTypeTag(mod)) { |
| 4936 | .Array => { | 5046 | .Array => { |
| 4937 | const result = try func.allocStack(result_ty); | 5047 | const result = try func.allocStack(result_ty); |
| 4938 | const elem_ty = result_ty.childType(); | 5048 | const elem_ty = result_ty.childType(mod); |
| 4939 | const elem_size = @intCast(u32, elem_ty.abiSize(func.target)); | 5049 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); |
| 4940 | const sentinel = if (result_ty.sentinel()) |sent| blk: { | 5050 | const sentinel = if (result_ty.sentinel(mod)) |sent| blk: { |
| 4941 | break :blk try func.lowerConstant(sent, elem_ty); | 5051 | break :blk try func.lowerConstant(sent, elem_ty); |
| 4942 | } else null; | 5052 | } else null; |
| 4943 | 5053 | ||
| 4944 | // When the element type is by reference, we must copy the entire | 5054 | // When the element type is by reference, we must copy the entire |
| 4945 | // value. It is therefore safer to move the offset pointer and store | 5055 | // value. It is therefore safer to move the offset pointer and store |
| 4946 | // each value individually, instead of using store offsets. | 5056 | // each value individually, instead of using store offsets. |
| 4947 | if (isByRef(elem_ty, func.target)) { | 5057 | if (isByRef(elem_ty, mod)) { |
| 4948 | // copy stack pointer into a temporary local, which is | 5058 | // copy stack pointer into a temporary local, which is |
| 4949 | // moved for each element to store each value in the right position. | 5059 | // moved for each element to store each value in the right position. |
| 4950 | const offset = try func.buildPointerOffset(result, 0, .new); | 5060 | const offset = try func.buildPointerOffset(result, 0, .new); |
| ... | @@ -4972,18 +5082,18 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4972,18 +5082,18 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4972 | } | 5082 | } |
| 4973 | break :result_value result; | 5083 | break :result_value result; |
| 4974 | }, | 5084 | }, |
| 4975 | .Struct => switch (result_ty.containerLayout()) { | 5085 | .Struct => switch (result_ty.containerLayout(mod)) { |
| 4976 | .Packed => { | 5086 | .Packed => { |
| 4977 | if (isByRef(result_ty, func.target)) { | 5087 | if (isByRef(result_ty, mod)) { |
| 4978 | return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{}); | 5088 | return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{}); |
| 4979 | } | 5089 | } |
| 4980 | const struct_obj = result_ty.castTag(.@"struct").?.data; | 5090 | const struct_obj = mod.typeToStruct(result_ty).?; |
| 4981 | const fields = struct_obj.fields.values(); | 5091 | const fields = struct_obj.fields.values(); |
| 4982 | const backing_type = struct_obj.backing_int_ty; | 5092 | const backing_type = struct_obj.backing_int_ty; |
| 4983 | 5093 | ||
| 4984 | // ensure the result is zero'd | 5094 | // ensure the result is zero'd |
| 4985 | const result = try func.allocLocal(backing_type); | 5095 | const result = try func.allocLocal(backing_type); |
| 4986 | if (struct_obj.backing_int_ty.bitSize(func.target) <= 32) | 5096 | if (struct_obj.backing_int_ty.bitSize(mod) <= 32) |
| 4987 | try func.addImm32(0) | 5097 | try func.addImm32(0) |
| 4988 | else | 5098 | else |
| 4989 | try func.addImm64(0); | 5099 | try func.addImm64(0); |
| ... | @@ -4992,20 +5102,16 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4992,20 +5102,16 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4992 | var current_bit: u16 = 0; | 5102 | var current_bit: u16 = 0; |
| 4993 | for (elements, 0..) |elem, elem_index| { | 5103 | for (elements, 0..) |elem, elem_index| { |
| 4994 | const field = fields[elem_index]; | 5104 | const field = fields[elem_index]; |
| 4995 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 5105 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 4996 | 5106 | ||
| 4997 | const shift_val = if (struct_obj.backing_int_ty.bitSize(func.target) <= 32) | 5107 | const shift_val = if (struct_obj.backing_int_ty.bitSize(mod) <= 32) |
| 4998 | WValue{ .imm32 = current_bit } | 5108 | WValue{ .imm32 = current_bit } |
| 4999 | else | 5109 | else |
| 5000 | WValue{ .imm64 = current_bit }; | 5110 | WValue{ .imm64 = current_bit }; |
| 5001 | 5111 | ||
| 5002 | const value = try func.resolveInst(elem); | 5112 | const value = try func.resolveInst(elem); |
| 5003 | const value_bit_size = @intCast(u16, field.ty.bitSize(func.target)); | 5113 | const value_bit_size = @intCast(u16, field.ty.bitSize(mod)); |
| 5004 | var int_ty_payload: Type.Payload.Bits = .{ | 5114 | const int_ty = try mod.intType(.unsigned, value_bit_size); |
| 5005 | .base = .{ .tag = .int_unsigned }, | ||
| 5006 | .data = value_bit_size, | ||
| 5007 | }; | ||
| 5008 | const int_ty = Type.initPayload(&int_ty_payload.base); | ||
| 5009 | 5115 | ||
| 5010 | // load our current result on stack so we can perform all transformations | 5116 | // load our current result on stack so we can perform all transformations |
| 5011 | // using only stack values. Saving the cost of loads and stores. | 5117 | // using only stack values. Saving the cost of loads and stores. |
| ... | @@ -5027,10 +5133,10 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5027,10 +5133,10 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5027 | const result = try func.allocStack(result_ty); | 5133 | const result = try func.allocStack(result_ty); |
| 5028 | const offset = try func.buildPointerOffset(result, 0, .new); // pointer to offset | 5134 | const offset = try func.buildPointerOffset(result, 0, .new); // pointer to offset |
| 5029 | for (elements, 0..) |elem, elem_index| { | 5135 | for (elements, 0..) |elem, elem_index| { |
| 5030 | if (result_ty.structFieldValueComptime(elem_index) != null) continue; | 5136 | if ((try result_ty.structFieldValueComptime(mod, elem_index)) != null) continue; |
| 5031 | 5137 | ||
| 5032 | const elem_ty = result_ty.structFieldType(elem_index); | 5138 | const elem_ty = result_ty.structFieldType(elem_index, mod); |
| 5033 | const elem_size = @intCast(u32, elem_ty.abiSize(func.target)); | 5139 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); |
| 5034 | const value = try func.resolveInst(elem); | 5140 | const value = try func.resolveInst(elem); |
| 5035 | try func.store(offset, value, elem_ty, 0); | 5141 | try func.store(offset, value, elem_ty, 0); |
| 5036 | 5142 | ||
| ... | @@ -5058,39 +5164,36 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5058,39 +5164,36 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5058 | } | 5164 | } |
| 5059 | 5165 | ||
| 5060 | fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5166 | fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5167 | const mod = func.bin_file.base.options.module.?; | ||
| 5061 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 5168 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 5062 | const extra = func.air.extraData(Air.UnionInit, ty_pl.payload).data; | 5169 | const extra = func.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 5063 | 5170 | ||
| 5064 | const result = result: { | 5171 | const result = result: { |
| 5065 | const union_ty = func.air.typeOfIndex(inst); | 5172 | const union_ty = func.typeOfIndex(inst); |
| 5066 | const layout = union_ty.unionGetLayout(func.target); | 5173 | const layout = union_ty.unionGetLayout(mod); |
| 5067 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 5174 | const union_obj = mod.typeToUnion(union_ty).?; |
| 5068 | const field = union_obj.fields.values()[extra.field_index]; | 5175 | const field = union_obj.fields.values()[extra.field_index]; |
| 5069 | const field_name = union_obj.fields.keys()[extra.field_index]; | 5176 | const field_name = union_obj.fields.keys()[extra.field_index]; |
| 5070 | 5177 | ||
| 5071 | const tag_int = blk: { | 5178 | const tag_int = blk: { |
| 5072 | const tag_ty = union_ty.unionTagTypeHypothetical(); | 5179 | const tag_ty = union_ty.unionTagTypeHypothetical(mod); |
| 5073 | const enum_field_index = tag_ty.enumFieldIndex(field_name).?; | 5180 | const enum_field_index = tag_ty.enumFieldIndex(field_name, mod).?; |
| 5074 | var tag_val_payload: Value.Payload.U32 = .{ | 5181 | const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); |
| 5075 | .base = .{ .tag = .enum_field_index }, | ||
| 5076 | .data = @intCast(u32, enum_field_index), | ||
| 5077 | }; | ||
| 5078 | const tag_val = Value.initPayload(&tag_val_payload.base); | ||
| 5079 | break :blk try func.lowerConstant(tag_val, tag_ty); | 5182 | break :blk try func.lowerConstant(tag_val, tag_ty); |
| 5080 | }; | 5183 | }; |
| 5081 | if (layout.payload_size == 0) { | 5184 | if (layout.payload_size == 0) { |
| 5082 | if (layout.tag_size == 0) { | 5185 | if (layout.tag_size == 0) { |
| 5083 | break :result WValue{ .none = {} }; | 5186 | break :result WValue{ .none = {} }; |
| 5084 | } | 5187 | } |
| 5085 | assert(!isByRef(union_ty, func.target)); | 5188 | assert(!isByRef(union_ty, mod)); |
| 5086 | break :result tag_int; | 5189 | break :result tag_int; |
| 5087 | } | 5190 | } |
| 5088 | 5191 | ||
| 5089 | if (isByRef(union_ty, func.target)) { | 5192 | if (isByRef(union_ty, mod)) { |
| 5090 | const result_ptr = try func.allocStack(union_ty); | 5193 | const result_ptr = try func.allocStack(union_ty); |
| 5091 | const payload = try func.resolveInst(extra.init); | 5194 | const payload = try func.resolveInst(extra.init); |
| 5092 | if (layout.tag_align >= layout.payload_align) { | 5195 | if (layout.tag_align >= layout.payload_align) { |
| 5093 | if (isByRef(field.ty, func.target)) { | 5196 | if (isByRef(field.ty, mod)) { |
| 5094 | const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); | 5197 | const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); |
| 5095 | try func.store(payload_ptr, payload, field.ty, 0); | 5198 | try func.store(payload_ptr, payload, field.ty, 0); |
| 5096 | } else { | 5199 | } else { |
| ... | @@ -5114,26 +5217,14 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5114,26 +5217,14 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5114 | break :result result_ptr; | 5217 | break :result result_ptr; |
| 5115 | } else { | 5218 | } else { |
| 5116 | const operand = try func.resolveInst(extra.init); | 5219 | const operand = try func.resolveInst(extra.init); |
| 5117 | var payload: Type.Payload.Bits = .{ | 5220 | const union_int_type = try mod.intType(.unsigned, @intCast(u16, union_ty.bitSize(mod))); |
| 5118 | .base = .{ .tag = .int_unsigned }, | 5221 | if (field.ty.zigTypeTag(mod) == .Float) { |
| 5119 | .data = @intCast(u16, union_ty.bitSize(func.target)), | 5222 | const int_type = try mod.intType(.unsigned, @intCast(u16, field.ty.bitSize(mod))); |
| 5120 | }; | ||
| 5121 | const union_int_type = Type.initPayload(&payload.base); | ||
| 5122 | if (field.ty.zigTypeTag() == .Float) { | ||
| 5123 | var int_payload: Type.Payload.Bits = .{ | ||
| 5124 | .base = .{ .tag = .int_unsigned }, | ||
| 5125 | .data = @intCast(u16, field.ty.bitSize(func.target)), | ||
| 5126 | }; | ||
| 5127 | const int_type = Type.initPayload(&int_payload.base); | ||
| 5128 | const bitcasted = try func.bitcast(field.ty, int_type, operand); | 5223 | const bitcasted = try func.bitcast(field.ty, int_type, operand); |
| 5129 | const casted = try func.trunc(bitcasted, int_type, union_int_type); | 5224 | const casted = try func.trunc(bitcasted, int_type, union_int_type); |
| 5130 | break :result try casted.toLocal(func, field.ty); | 5225 | break :result try casted.toLocal(func, field.ty); |
| 5131 | } else if (field.ty.isPtrAtRuntime()) { | 5226 | } else if (field.ty.isPtrAtRuntime(mod)) { |
| 5132 | var int_payload: Type.Payload.Bits = .{ | 5227 | const int_type = try mod.intType(.unsigned, @intCast(u16, field.ty.bitSize(mod))); |
| 5133 | .base = .{ .tag = .int_unsigned }, | ||
| 5134 | .data = @intCast(u16, field.ty.bitSize(func.target)), | ||
| 5135 | }; | ||
| 5136 | const int_type = Type.initPayload(&int_payload.base); | ||
| 5137 | const casted = try func.intcast(operand, int_type, union_int_type); | 5228 | const casted = try func.intcast(operand, int_type, union_int_type); |
| 5138 | break :result try casted.toLocal(func, field.ty); | 5229 | break :result try casted.toLocal(func, field.ty); |
| 5139 | } | 5230 | } |
| ... | @@ -5153,7 +5244,7 @@ fn airPrefetch(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5153,7 +5244,7 @@ fn airPrefetch(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5153 | fn airWasmMemorySize(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5244 | fn airWasmMemorySize(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5154 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; | 5245 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 5155 | 5246 | ||
| 5156 | const result = try func.allocLocal(func.air.typeOfIndex(inst)); | 5247 | const result = try func.allocLocal(func.typeOfIndex(inst)); |
| 5157 | try func.addLabel(.memory_size, pl_op.payload); | 5248 | try func.addLabel(.memory_size, pl_op.payload); |
| 5158 | try func.addLabel(.local_set, result.local.value); | 5249 | try func.addLabel(.local_set, result.local.value); |
| 5159 | func.finishAir(inst, result, &.{pl_op.operand}); | 5250 | func.finishAir(inst, result, &.{pl_op.operand}); |
| ... | @@ -5163,7 +5254,7 @@ fn airWasmMemoryGrow(func: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -5163,7 +5254,7 @@ fn airWasmMemoryGrow(func: *CodeGen, inst: Air.Inst.Index) !void { |
| 5163 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; | 5254 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 5164 | 5255 | ||
| 5165 | const operand = try func.resolveInst(pl_op.operand); | 5256 | const operand = try func.resolveInst(pl_op.operand); |
| 5166 | const result = try func.allocLocal(func.air.typeOfIndex(inst)); | 5257 | const result = try func.allocLocal(func.typeOfIndex(inst)); |
| 5167 | try func.emitWValue(operand); | 5258 | try func.emitWValue(operand); |
| 5168 | try func.addLabel(.memory_grow, pl_op.payload); | 5259 | try func.addLabel(.memory_grow, pl_op.payload); |
| 5169 | try func.addLabel(.local_set, result.local.value); | 5260 | try func.addLabel(.local_set, result.local.value); |
| ... | @@ -5171,14 +5262,14 @@ fn airWasmMemoryGrow(func: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -5171,14 +5262,14 @@ fn airWasmMemoryGrow(func: *CodeGen, inst: Air.Inst.Index) !void { |
| 5171 | } | 5262 | } |
| 5172 | 5263 | ||
| 5173 | fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { | 5264 | fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 5174 | assert(operand_ty.hasRuntimeBitsIgnoreComptime()); | 5265 | const mod = func.bin_file.base.options.module.?; |
| 5266 | assert(operand_ty.hasRuntimeBitsIgnoreComptime(mod)); | ||
| 5175 | assert(op == .eq or op == .neq); | 5267 | assert(op == .eq or op == .neq); |
| 5176 | var buf: Type.Payload.ElemType = undefined; | 5268 | const payload_ty = operand_ty.optionalChild(mod); |
| 5177 | const payload_ty = operand_ty.optionalChild(&buf); | ||
| 5178 | 5269 | ||
| 5179 | // We store the final result in here that will be validated | 5270 | // We store the final result in here that will be validated |
| 5180 | // if the optional is truly equal. | 5271 | // if the optional is truly equal. |
| 5181 | var result = try func.ensureAllocLocal(Type.initTag(.i32)); | 5272 | var result = try func.ensureAllocLocal(Type.i32); |
| 5182 | defer result.free(func); | 5273 | defer result.free(func); |
| 5183 | 5274 | ||
| 5184 | try func.startBlock(.block, wasm.block_empty); | 5275 | try func.startBlock(.block, wasm.block_empty); |
| ... | @@ -5189,7 +5280,7 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: | ... | @@ -5189,7 +5280,7 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: |
| 5189 | 5280 | ||
| 5190 | _ = try func.load(lhs, payload_ty, 0); | 5281 | _ = try func.load(lhs, payload_ty, 0); |
| 5191 | _ = try func.load(rhs, payload_ty, 0); | 5282 | _ = try func.load(rhs, payload_ty, 0); |
| 5192 | const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, func.target) }); | 5283 | const opcode = buildOpcode(.{ .op = .ne, .valtype1 = typeToValtype(payload_ty, mod) }); |
| 5193 | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 5284 | try func.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 5194 | try func.addLabel(.br_if, 0); | 5285 | try func.addLabel(.br_if, 0); |
| 5195 | 5286 | ||
| ... | @@ -5207,10 +5298,11 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: | ... | @@ -5207,10 +5298,11 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: |
| 5207 | /// NOTE: Leaves the result of the comparison on top of the stack. | 5298 | /// NOTE: Leaves the result of the comparison on top of the stack. |
| 5208 | /// TODO: Lower this to compiler_rt call when bitsize > 128 | 5299 | /// TODO: Lower this to compiler_rt call when bitsize > 128 |
| 5209 | fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { | 5300 | fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 5210 | assert(operand_ty.abiSize(func.target) >= 16); | 5301 | const mod = func.bin_file.base.options.module.?; |
| 5302 | assert(operand_ty.abiSize(mod) >= 16); | ||
| 5211 | assert(!(lhs != .stack and rhs == .stack)); | 5303 | assert(!(lhs != .stack and rhs == .stack)); |
| 5212 | if (operand_ty.bitSize(func.target) > 128) { | 5304 | if (operand_ty.bitSize(mod) > 128) { |
| 5213 | return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(func.target)}); | 5305 | return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(mod)}); |
| 5214 | } | 5306 | } |
| 5215 | 5307 | ||
| 5216 | var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64); | 5308 | var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64); |
| ... | @@ -5233,7 +5325,7 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std | ... | @@ -5233,7 +5325,7 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std |
| 5233 | } | 5325 | } |
| 5234 | }, | 5326 | }, |
| 5235 | else => { | 5327 | else => { |
| 5236 | const ty = if (operand_ty.isSignedInt()) Type.i64 else Type.u64; | 5328 | const ty = if (operand_ty.isSignedInt(mod)) Type.i64 else Type.u64; |
| 5237 | // leave those value on top of the stack for '.select' | 5329 | // leave those value on top of the stack for '.select' |
| 5238 | const lhs_low_bit = try func.load(lhs, Type.u64, 8); | 5330 | const lhs_low_bit = try func.load(lhs, Type.u64, 8); |
| 5239 | const rhs_low_bit = try func.load(rhs, Type.u64, 8); | 5331 | const rhs_low_bit = try func.load(rhs, Type.u64, 8); |
| ... | @@ -5248,10 +5340,11 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std | ... | @@ -5248,10 +5340,11 @@ fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std |
| 5248 | } | 5340 | } |
| 5249 | 5341 | ||
| 5250 | fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5342 | fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5343 | const mod = func.bin_file.base.options.module.?; | ||
| 5251 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 5344 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 5252 | const un_ty = func.air.typeOf(bin_op.lhs).childType(); | 5345 | const un_ty = func.typeOf(bin_op.lhs).childType(mod); |
| 5253 | const tag_ty = func.air.typeOf(bin_op.rhs); | 5346 | const tag_ty = func.typeOf(bin_op.rhs); |
| 5254 | const layout = un_ty.unionGetLayout(func.target); | 5347 | const layout = un_ty.unionGetLayout(mod); |
| 5255 | if (layout.tag_size == 0) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); | 5348 | if (layout.tag_size == 0) return func.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); |
| 5256 | 5349 | ||
| 5257 | const union_ptr = try func.resolveInst(bin_op.lhs); | 5350 | const union_ptr = try func.resolveInst(bin_op.lhs); |
| ... | @@ -5271,11 +5364,12 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5271,11 +5364,12 @@ fn airSetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5271 | } | 5364 | } |
| 5272 | 5365 | ||
| 5273 | fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5366 | fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5367 | const mod = func.bin_file.base.options.module.?; | ||
| 5274 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 5368 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 5275 | 5369 | ||
| 5276 | const un_ty = func.air.typeOf(ty_op.operand); | 5370 | const un_ty = func.typeOf(ty_op.operand); |
| 5277 | const tag_ty = func.air.typeOfIndex(inst); | 5371 | const tag_ty = func.typeOfIndex(inst); |
| 5278 | const layout = un_ty.unionGetLayout(func.target); | 5372 | const layout = un_ty.unionGetLayout(mod); |
| 5279 | if (layout.tag_size == 0) return func.finishAir(inst, .none, &.{ty_op.operand}); | 5373 | if (layout.tag_size == 0) return func.finishAir(inst, .none, &.{ty_op.operand}); |
| 5280 | 5374 | ||
| 5281 | const operand = try func.resolveInst(ty_op.operand); | 5375 | const operand = try func.resolveInst(ty_op.operand); |
| ... | @@ -5292,9 +5386,9 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5292,9 +5386,9 @@ fn airGetUnionTag(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5292 | fn airFpext(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5386 | fn airFpext(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5293 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 5387 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 5294 | 5388 | ||
| 5295 | const dest_ty = func.air.typeOfIndex(inst); | 5389 | const dest_ty = func.typeOfIndex(inst); |
| 5296 | const operand = try func.resolveInst(ty_op.operand); | 5390 | const operand = try func.resolveInst(ty_op.operand); |
| 5297 | const extended = try func.fpext(operand, func.air.typeOf(ty_op.operand), dest_ty); | 5391 | const extended = try func.fpext(operand, func.typeOf(ty_op.operand), dest_ty); |
| 5298 | const result = try extended.toLocal(func, dest_ty); | 5392 | const result = try extended.toLocal(func, dest_ty); |
| 5299 | func.finishAir(inst, result, &.{ty_op.operand}); | 5393 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 5300 | } | 5394 | } |
| ... | @@ -5313,7 +5407,7 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError! | ... | @@ -5313,7 +5407,7 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError! |
| 5313 | // call __extendhfsf2(f16) f32 | 5407 | // call __extendhfsf2(f16) f32 |
| 5314 | const f32_result = try func.callIntrinsic( | 5408 | const f32_result = try func.callIntrinsic( |
| 5315 | "__extendhfsf2", | 5409 | "__extendhfsf2", |
| 5316 | &.{Type.f16}, | 5410 | &.{.f16_type}, |
| 5317 | Type.f32, | 5411 | Type.f32, |
| 5318 | &.{operand}, | 5412 | &.{operand}, |
| 5319 | ); | 5413 | ); |
| ... | @@ -5331,15 +5425,15 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError! | ... | @@ -5331,15 +5425,15 @@ fn fpext(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerError! |
| 5331 | target_util.compilerRtFloatAbbrev(wanted_bits), | 5425 | target_util.compilerRtFloatAbbrev(wanted_bits), |
| 5332 | }) catch unreachable; | 5426 | }) catch unreachable; |
| 5333 | 5427 | ||
| 5334 | return func.callIntrinsic(fn_name, &.{given}, wanted, &.{operand}); | 5428 | return func.callIntrinsic(fn_name, &.{given.ip_index}, wanted, &.{operand}); |
| 5335 | } | 5429 | } |
| 5336 | 5430 | ||
| 5337 | fn airFptrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5431 | fn airFptrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5338 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 5432 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 5339 | 5433 | ||
| 5340 | const dest_ty = func.air.typeOfIndex(inst); | 5434 | const dest_ty = func.typeOfIndex(inst); |
| 5341 | const operand = try func.resolveInst(ty_op.operand); | 5435 | const operand = try func.resolveInst(ty_op.operand); |
| 5342 | const truncated = try func.fptrunc(operand, func.air.typeOf(ty_op.operand), dest_ty); | 5436 | const truncated = try func.fptrunc(operand, func.typeOf(ty_op.operand), dest_ty); |
| 5343 | const result = try truncated.toLocal(func, dest_ty); | 5437 | const result = try truncated.toLocal(func, dest_ty); |
| 5344 | func.finishAir(inst, result, &.{ty_op.operand}); | 5438 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 5345 | } | 5439 | } |
| ... | @@ -5362,7 +5456,7 @@ fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro | ... | @@ -5362,7 +5456,7 @@ fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 5362 | } else operand; | 5456 | } else operand; |
| 5363 | 5457 | ||
| 5364 | // call __truncsfhf2(f32) f16 | 5458 | // call __truncsfhf2(f32) f16 |
| 5365 | return func.callIntrinsic("__truncsfhf2", &.{Type.f32}, Type.f16, &.{op}); | 5459 | return func.callIntrinsic("__truncsfhf2", &.{.f32_type}, Type.f16, &.{op}); |
| 5366 | } | 5460 | } |
| 5367 | 5461 | ||
| 5368 | var fn_name_buf: [12]u8 = undefined; | 5462 | var fn_name_buf: [12]u8 = undefined; |
| ... | @@ -5371,14 +5465,15 @@ fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro | ... | @@ -5371,14 +5465,15 @@ fn fptrunc(func: *CodeGen, operand: WValue, given: Type, wanted: Type) InnerErro |
| 5371 | target_util.compilerRtFloatAbbrev(wanted_bits), | 5465 | target_util.compilerRtFloatAbbrev(wanted_bits), |
| 5372 | }) catch unreachable; | 5466 | }) catch unreachable; |
| 5373 | 5467 | ||
| 5374 | return func.callIntrinsic(fn_name, &.{given}, wanted, &.{operand}); | 5468 | return func.callIntrinsic(fn_name, &.{given.ip_index}, wanted, &.{operand}); |
| 5375 | } | 5469 | } |
| 5376 | 5470 | ||
| 5377 | fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5471 | fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5472 | const mod = func.bin_file.base.options.module.?; | ||
| 5378 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 5473 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 5379 | 5474 | ||
| 5380 | const err_set_ty = func.air.typeOf(ty_op.operand).childType(); | 5475 | const err_set_ty = func.typeOf(ty_op.operand).childType(mod); |
| 5381 | const payload_ty = err_set_ty.errorUnionPayload(); | 5476 | const payload_ty = err_set_ty.errorUnionPayload(mod); |
| 5382 | const operand = try func.resolveInst(ty_op.operand); | 5477 | const operand = try func.resolveInst(ty_op.operand); |
| 5383 | 5478 | ||
| 5384 | // set error-tag to '0' to annotate error union is non-error | 5479 | // set error-tag to '0' to annotate error union is non-error |
| ... | @@ -5386,26 +5481,27 @@ fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi | ... | @@ -5386,26 +5481,27 @@ fn airErrUnionPayloadPtrSet(func: *CodeGen, inst: Air.Inst.Index) InnerError!voi |
| 5386 | operand, | 5481 | operand, |
| 5387 | .{ .imm32 = 0 }, | 5482 | .{ .imm32 = 0 }, |
| 5388 | Type.anyerror, | 5483 | Type.anyerror, |
| 5389 | @intCast(u32, errUnionErrorOffset(payload_ty, func.target)), | 5484 | @intCast(u32, errUnionErrorOffset(payload_ty, mod)), |
| 5390 | ); | 5485 | ); |
| 5391 | 5486 | ||
| 5392 | const result = result: { | 5487 | const result = result: { |
| 5393 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 5488 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 5394 | break :result func.reuseOperand(ty_op.operand, operand); | 5489 | break :result func.reuseOperand(ty_op.operand, operand); |
| 5395 | } | 5490 | } |
| 5396 | 5491 | ||
| 5397 | break :result try func.buildPointerOffset(operand, @intCast(u32, errUnionPayloadOffset(payload_ty, func.target)), .new); | 5492 | break :result try func.buildPointerOffset(operand, @intCast(u32, errUnionPayloadOffset(payload_ty, mod)), .new); |
| 5398 | }; | 5493 | }; |
| 5399 | func.finishAir(inst, result, &.{ty_op.operand}); | 5494 | func.finishAir(inst, result, &.{ty_op.operand}); |
| 5400 | } | 5495 | } |
| 5401 | 5496 | ||
| 5402 | fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5497 | fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5498 | const mod = func.bin_file.base.options.module.?; | ||
| 5403 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 5499 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 5404 | const extra = func.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; | 5500 | const extra = func.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 5405 | 5501 | ||
| 5406 | const field_ptr = try func.resolveInst(extra.field_ptr); | 5502 | const field_ptr = try func.resolveInst(extra.field_ptr); |
| 5407 | const parent_ty = func.air.getRefType(ty_pl.ty).childType(); | 5503 | const parent_ty = func.air.getRefType(ty_pl.ty).childType(mod); |
| 5408 | const field_offset = parent_ty.structFieldOffset(extra.field_index, func.target); | 5504 | const field_offset = parent_ty.structFieldOffset(extra.field_index, mod); |
| 5409 | 5505 | ||
| 5410 | const result = if (field_offset != 0) result: { | 5506 | const result = if (field_offset != 0) result: { |
| 5411 | const base = try func.buildPointerOffset(field_ptr, 0, .new); | 5507 | const base = try func.buildPointerOffset(field_ptr, 0, .new); |
| ... | @@ -5420,7 +5516,8 @@ fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5420,7 +5516,8 @@ fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5420 | } | 5516 | } |
| 5421 | 5517 | ||
| 5422 | fn sliceOrArrayPtr(func: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue { | 5518 | fn sliceOrArrayPtr(func: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue { |
| 5423 | if (ptr_ty.isSlice()) { | 5519 | const mod = func.bin_file.base.options.module.?; |
| 5520 | if (ptr_ty.isSlice(mod)) { | ||
| 5424 | return func.slicePtr(ptr); | 5521 | return func.slicePtr(ptr); |
| 5425 | } else { | 5522 | } else { |
| 5426 | return ptr; | 5523 | return ptr; |
| ... | @@ -5428,25 +5525,26 @@ fn sliceOrArrayPtr(func: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue | ... | @@ -5428,25 +5525,26 @@ fn sliceOrArrayPtr(func: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue |
| 5428 | } | 5525 | } |
| 5429 | 5526 | ||
| 5430 | fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5527 | fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5528 | const mod = func.bin_file.base.options.module.?; | ||
| 5431 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 5529 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 5432 | const dst = try func.resolveInst(bin_op.lhs); | 5530 | const dst = try func.resolveInst(bin_op.lhs); |
| 5433 | const dst_ty = func.air.typeOf(bin_op.lhs); | 5531 | const dst_ty = func.typeOf(bin_op.lhs); |
| 5434 | const ptr_elem_ty = dst_ty.childType(); | 5532 | const ptr_elem_ty = dst_ty.childType(mod); |
| 5435 | const src = try func.resolveInst(bin_op.rhs); | 5533 | const src = try func.resolveInst(bin_op.rhs); |
| 5436 | const src_ty = func.air.typeOf(bin_op.rhs); | 5534 | const src_ty = func.typeOf(bin_op.rhs); |
| 5437 | const len = switch (dst_ty.ptrSize()) { | 5535 | const len = switch (dst_ty.ptrSize(mod)) { |
| 5438 | .Slice => blk: { | 5536 | .Slice => blk: { |
| 5439 | const slice_len = try func.sliceLen(dst); | 5537 | const slice_len = try func.sliceLen(dst); |
| 5440 | if (ptr_elem_ty.abiSize(func.target) != 1) { | 5538 | if (ptr_elem_ty.abiSize(mod) != 1) { |
| 5441 | try func.emitWValue(slice_len); | 5539 | try func.emitWValue(slice_len); |
| 5442 | try func.emitWValue(.{ .imm32 = @intCast(u32, ptr_elem_ty.abiSize(func.target)) }); | 5540 | try func.emitWValue(.{ .imm32 = @intCast(u32, ptr_elem_ty.abiSize(mod)) }); |
| 5443 | try func.addTag(.i32_mul); | 5541 | try func.addTag(.i32_mul); |
| 5444 | try func.addLabel(.local_set, slice_len.local.value); | 5542 | try func.addLabel(.local_set, slice_len.local.value); |
| 5445 | } | 5543 | } |
| 5446 | break :blk slice_len; | 5544 | break :blk slice_len; |
| 5447 | }, | 5545 | }, |
| 5448 | .One => @as(WValue, .{ | 5546 | .One => @as(WValue, .{ |
| 5449 | .imm32 = @intCast(u32, ptr_elem_ty.arrayLen() * ptr_elem_ty.childType().abiSize(func.target)), | 5547 | .imm32 = @intCast(u32, ptr_elem_ty.arrayLen(mod) * ptr_elem_ty.childType(mod).abiSize(mod)), |
| 5450 | }), | 5548 | }), |
| 5451 | .C, .Many => unreachable, | 5549 | .C, .Many => unreachable, |
| 5452 | }; | 5550 | }; |
| ... | @@ -5467,17 +5565,18 @@ fn airRetAddr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5467,17 +5565,18 @@ fn airRetAddr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5467 | } | 5565 | } |
| 5468 | 5566 | ||
| 5469 | fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5567 | fn airPopcount(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5568 | const mod = func.bin_file.base.options.module.?; | ||
| 5470 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 5569 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 5471 | 5570 | ||
| 5472 | const operand = try func.resolveInst(ty_op.operand); | 5571 | const operand = try func.resolveInst(ty_op.operand); |
| 5473 | const op_ty = func.air.typeOf(ty_op.operand); | 5572 | const op_ty = func.typeOf(ty_op.operand); |
| 5474 | const result_ty = func.air.typeOfIndex(inst); | 5573 | const result_ty = func.typeOfIndex(inst); |
| 5475 | 5574 | ||
| 5476 | if (op_ty.zigTypeTag() == .Vector) { | 5575 | if (op_ty.zigTypeTag(mod) == .Vector) { |
| 5477 | return func.fail("TODO: Implement @popCount for vectors", .{}); | 5576 | return func.fail("TODO: Implement @popCount for vectors", .{}); |
| 5478 | } | 5577 | } |
| 5479 | 5578 | ||
| 5480 | const int_info = op_ty.intInfo(func.target); | 5579 | const int_info = op_ty.intInfo(mod); |
| 5481 | const bits = int_info.bits; | 5580 | const bits = int_info.bits; |
| 5482 | const wasm_bits = toWasmBits(bits) orelse { | 5581 | const wasm_bits = toWasmBits(bits) orelse { |
| 5483 | return func.fail("TODO: Implement @popCount for integers with bitsize '{d}'", .{bits}); | 5582 | return func.fail("TODO: Implement @popCount for integers with bitsize '{d}'", .{bits}); |
| ... | @@ -5526,8 +5625,9 @@ fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5526,8 +5625,9 @@ fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5526 | // As the names are global and the slice elements are constant, we do not have | 5625 | // As the names are global and the slice elements are constant, we do not have |
| 5527 | // to make a copy of the ptr+value but can point towards them directly. | 5626 | // to make a copy of the ptr+value but can point towards them directly. |
| 5528 | const error_table_symbol = try func.bin_file.getErrorTableSymbol(); | 5627 | const error_table_symbol = try func.bin_file.getErrorTableSymbol(); |
| 5529 | const name_ty = Type.initTag(.const_slice_u8_sentinel_0); | 5628 | const name_ty = Type.slice_const_u8_sentinel_0; |
| 5530 | const abi_size = name_ty.abiSize(func.target); | 5629 | const mod = func.bin_file.base.options.module.?; |
| 5630 | const abi_size = name_ty.abiSize(mod); | ||
| 5531 | 5631 | ||
| 5532 | const error_name_value: WValue = .{ .memory = error_table_symbol }; // emitting this will create a relocation | 5632 | const error_name_value: WValue = .{ .memory = error_table_symbol }; // emitting this will create a relocation |
| 5533 | try func.emitWValue(error_name_value); | 5633 | try func.emitWValue(error_name_value); |
| ... | @@ -5565,20 +5665,21 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro | ... | @@ -5565,20 +5665,21 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 5565 | 5665 | ||
| 5566 | const lhs_op = try func.resolveInst(extra.lhs); | 5666 | const lhs_op = try func.resolveInst(extra.lhs); |
| 5567 | const rhs_op = try func.resolveInst(extra.rhs); | 5667 | const rhs_op = try func.resolveInst(extra.rhs); |
| 5568 | const lhs_ty = func.air.typeOf(extra.lhs); | 5668 | const lhs_ty = func.typeOf(extra.lhs); |
| 5669 | const mod = func.bin_file.base.options.module.?; | ||
| 5569 | 5670 | ||
| 5570 | if (lhs_ty.zigTypeTag() == .Vector) { | 5671 | if (lhs_ty.zigTypeTag(mod) == .Vector) { |
| 5571 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); | 5672 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); |
| 5572 | } | 5673 | } |
| 5573 | 5674 | ||
| 5574 | const int_info = lhs_ty.intInfo(func.target); | 5675 | const int_info = lhs_ty.intInfo(mod); |
| 5575 | const is_signed = int_info.signedness == .signed; | 5676 | const is_signed = int_info.signedness == .signed; |
| 5576 | const wasm_bits = toWasmBits(int_info.bits) orelse { | 5677 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 5577 | return func.fail("TODO: Implement {{add/sub}}_with_overflow for integer bitsize: {d}", .{int_info.bits}); | 5678 | return func.fail("TODO: Implement {{add/sub}}_with_overflow for integer bitsize: {d}", .{int_info.bits}); |
| 5578 | }; | 5679 | }; |
| 5579 | 5680 | ||
| 5580 | if (wasm_bits == 128) { | 5681 | if (wasm_bits == 128) { |
| 5581 | const result = try func.addSubWithOverflowBigInt(lhs_op, rhs_op, lhs_ty, func.air.typeOfIndex(inst), op); | 5682 | const result = try func.addSubWithOverflowBigInt(lhs_op, rhs_op, lhs_ty, func.typeOfIndex(inst), op); |
| 5582 | return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs }); | 5683 | return func.finishAir(inst, result, &.{ extra.lhs, extra.rhs }); |
| 5583 | } | 5684 | } |
| 5584 | 5685 | ||
| ... | @@ -5628,17 +5729,18 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro | ... | @@ -5628,17 +5729,18 @@ fn airAddSubWithOverflow(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerErro |
| 5628 | var overflow_local = try overflow_bit.toLocal(func, Type.u32); | 5729 | var overflow_local = try overflow_bit.toLocal(func, Type.u32); |
| 5629 | defer overflow_local.free(func); | 5730 | defer overflow_local.free(func); |
| 5630 | 5731 | ||
| 5631 | const result_ptr = try func.allocStack(func.air.typeOfIndex(inst)); | 5732 | const result_ptr = try func.allocStack(func.typeOfIndex(inst)); |
| 5632 | try func.store(result_ptr, result, lhs_ty, 0); | 5733 | try func.store(result_ptr, result, lhs_ty, 0); |
| 5633 | const offset = @intCast(u32, lhs_ty.abiSize(func.target)); | 5734 | const offset = @intCast(u32, lhs_ty.abiSize(mod)); |
| 5634 | try func.store(result_ptr, overflow_local, Type.initTag(.u1), offset); | 5735 | try func.store(result_ptr, overflow_local, Type.u1, offset); |
| 5635 | 5736 | ||
| 5636 | func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); | 5737 | func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); |
| 5637 | } | 5738 | } |
| 5638 | 5739 | ||
| 5639 | fn addSubWithOverflowBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, result_ty: Type, op: Op) InnerError!WValue { | 5740 | fn addSubWithOverflowBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, result_ty: Type, op: Op) InnerError!WValue { |
| 5741 | const mod = func.bin_file.base.options.module.?; | ||
| 5640 | assert(op == .add or op == .sub); | 5742 | assert(op == .add or op == .sub); |
| 5641 | const int_info = ty.intInfo(func.target); | 5743 | const int_info = ty.intInfo(mod); |
| 5642 | const is_signed = int_info.signedness == .signed; | 5744 | const is_signed = int_info.signedness == .signed; |
| 5643 | if (int_info.bits != 128) { | 5745 | if (int_info.bits != 128) { |
| 5644 | return func.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits}); | 5746 | return func.fail("TODO: Implement @{{add/sub}}WithOverflow for integer bitsize '{d}'", .{int_info.bits}); |
| ... | @@ -5689,31 +5791,32 @@ fn addSubWithOverflowBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, | ... | @@ -5689,31 +5791,32 @@ fn addSubWithOverflowBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, |
| 5689 | 5791 | ||
| 5690 | break :blk WValue{ .stack = {} }; | 5792 | break :blk WValue{ .stack = {} }; |
| 5691 | }; | 5793 | }; |
| 5692 | var overflow_local = try overflow_bit.toLocal(func, Type.initTag(.u1)); | 5794 | var overflow_local = try overflow_bit.toLocal(func, Type.u1); |
| 5693 | defer overflow_local.free(func); | 5795 | defer overflow_local.free(func); |
| 5694 | 5796 | ||
| 5695 | const result_ptr = try func.allocStack(result_ty); | 5797 | const result_ptr = try func.allocStack(result_ty); |
| 5696 | try func.store(result_ptr, high_op_res, Type.u64, 0); | 5798 | try func.store(result_ptr, high_op_res, Type.u64, 0); |
| 5697 | try func.store(result_ptr, tmp_op, Type.u64, 8); | 5799 | try func.store(result_ptr, tmp_op, Type.u64, 8); |
| 5698 | try func.store(result_ptr, overflow_local, Type.initTag(.u1), 16); | 5800 | try func.store(result_ptr, overflow_local, Type.u1, 16); |
| 5699 | 5801 | ||
| 5700 | return result_ptr; | 5802 | return result_ptr; |
| 5701 | } | 5803 | } |
| 5702 | 5804 | ||
| 5703 | fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5805 | fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5806 | const mod = func.bin_file.base.options.module.?; | ||
| 5704 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 5807 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 5705 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; | 5808 | const extra = func.air.extraData(Air.Bin, ty_pl.payload).data; |
| 5706 | 5809 | ||
| 5707 | const lhs = try func.resolveInst(extra.lhs); | 5810 | const lhs = try func.resolveInst(extra.lhs); |
| 5708 | const rhs = try func.resolveInst(extra.rhs); | 5811 | const rhs = try func.resolveInst(extra.rhs); |
| 5709 | const lhs_ty = func.air.typeOf(extra.lhs); | 5812 | const lhs_ty = func.typeOf(extra.lhs); |
| 5710 | const rhs_ty = func.air.typeOf(extra.rhs); | 5813 | const rhs_ty = func.typeOf(extra.rhs); |
| 5711 | 5814 | ||
| 5712 | if (lhs_ty.zigTypeTag() == .Vector) { | 5815 | if (lhs_ty.zigTypeTag(mod) == .Vector) { |
| 5713 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); | 5816 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); |
| 5714 | } | 5817 | } |
| 5715 | 5818 | ||
| 5716 | const int_info = lhs_ty.intInfo(func.target); | 5819 | const int_info = lhs_ty.intInfo(mod); |
| 5717 | const is_signed = int_info.signedness == .signed; | 5820 | const is_signed = int_info.signedness == .signed; |
| 5718 | const wasm_bits = toWasmBits(int_info.bits) orelse { | 5821 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 5719 | return func.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); | 5822 | return func.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); |
| ... | @@ -5721,7 +5824,7 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5721,7 +5824,7 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5721 | 5824 | ||
| 5722 | // Ensure rhs is coerced to lhs as they must have the same WebAssembly types | 5825 | // Ensure rhs is coerced to lhs as they must have the same WebAssembly types |
| 5723 | // before we can perform any binary operation. | 5826 | // before we can perform any binary operation. |
| 5724 | const rhs_wasm_bits = toWasmBits(rhs_ty.intInfo(func.target).bits).?; | 5827 | const rhs_wasm_bits = toWasmBits(rhs_ty.intInfo(mod).bits).?; |
| 5725 | const rhs_final = if (wasm_bits != rhs_wasm_bits) blk: { | 5828 | const rhs_final = if (wasm_bits != rhs_wasm_bits) blk: { |
| 5726 | const rhs_casted = try func.intcast(rhs, rhs_ty, lhs_ty); | 5829 | const rhs_casted = try func.intcast(rhs, rhs_ty, lhs_ty); |
| 5727 | break :blk try rhs_casted.toLocal(func, lhs_ty); | 5830 | break :blk try rhs_casted.toLocal(func, lhs_ty); |
| ... | @@ -5745,13 +5848,13 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5745,13 +5848,13 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5745 | const shr = try func.binOp(result, rhs_final, lhs_ty, .shr); | 5848 | const shr = try func.binOp(result, rhs_final, lhs_ty, .shr); |
| 5746 | break :blk try func.cmp(.{ .stack = {} }, shr, lhs_ty, .neq); | 5849 | break :blk try func.cmp(.{ .stack = {} }, shr, lhs_ty, .neq); |
| 5747 | }; | 5850 | }; |
| 5748 | var overflow_local = try overflow_bit.toLocal(func, Type.initTag(.u1)); | 5851 | var overflow_local = try overflow_bit.toLocal(func, Type.u1); |
| 5749 | defer overflow_local.free(func); | 5852 | defer overflow_local.free(func); |
| 5750 | 5853 | ||
| 5751 | const result_ptr = try func.allocStack(func.air.typeOfIndex(inst)); | 5854 | const result_ptr = try func.allocStack(func.typeOfIndex(inst)); |
| 5752 | try func.store(result_ptr, result, lhs_ty, 0); | 5855 | try func.store(result_ptr, result, lhs_ty, 0); |
| 5753 | const offset = @intCast(u32, lhs_ty.abiSize(func.target)); | 5856 | const offset = @intCast(u32, lhs_ty.abiSize(mod)); |
| 5754 | try func.store(result_ptr, overflow_local, Type.initTag(.u1), offset); | 5857 | try func.store(result_ptr, overflow_local, Type.u1, offset); |
| 5755 | 5858 | ||
| 5756 | func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); | 5859 | func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); |
| 5757 | } | 5860 | } |
| ... | @@ -5762,18 +5865,19 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5762,18 +5865,19 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5762 | 5865 | ||
| 5763 | const lhs = try func.resolveInst(extra.lhs); | 5866 | const lhs = try func.resolveInst(extra.lhs); |
| 5764 | const rhs = try func.resolveInst(extra.rhs); | 5867 | const rhs = try func.resolveInst(extra.rhs); |
| 5765 | const lhs_ty = func.air.typeOf(extra.lhs); | 5868 | const lhs_ty = func.typeOf(extra.lhs); |
| 5869 | const mod = func.bin_file.base.options.module.?; | ||
| 5766 | 5870 | ||
| 5767 | if (lhs_ty.zigTypeTag() == .Vector) { | 5871 | if (lhs_ty.zigTypeTag(mod) == .Vector) { |
| 5768 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); | 5872 | return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); |
| 5769 | } | 5873 | } |
| 5770 | 5874 | ||
| 5771 | // We store the bit if it's overflowed or not in this. As it's zero-initialized | 5875 | // We store the bit if it's overflowed or not in this. As it's zero-initialized |
| 5772 | // we only need to update it if an overflow (or underflow) occurred. | 5876 | // we only need to update it if an overflow (or underflow) occurred. |
| 5773 | var overflow_bit = try func.ensureAllocLocal(Type.initTag(.u1)); | 5877 | var overflow_bit = try func.ensureAllocLocal(Type.u1); |
| 5774 | defer overflow_bit.free(func); | 5878 | defer overflow_bit.free(func); |
| 5775 | 5879 | ||
| 5776 | const int_info = lhs_ty.intInfo(func.target); | 5880 | const int_info = lhs_ty.intInfo(mod); |
| 5777 | const wasm_bits = toWasmBits(int_info.bits) orelse { | 5881 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 5778 | return func.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits}); | 5882 | return func.fail("TODO: Implement `@mulWithOverflow` for integer bitsize: {d}", .{int_info.bits}); |
| 5779 | }; | 5883 | }; |
| ... | @@ -5827,7 +5931,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5827,7 +5931,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5827 | try func.addLabel(.local_set, overflow_bit.local.value); | 5931 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 5828 | break :blk try func.wrapOperand(bin_op, lhs_ty); | 5932 | break :blk try func.wrapOperand(bin_op, lhs_ty); |
| 5829 | } else if (int_info.bits == 64 and int_info.signedness == .unsigned) blk: { | 5933 | } else if (int_info.bits == 64 and int_info.signedness == .unsigned) blk: { |
| 5830 | const new_ty = Type.initTag(.u128); | 5934 | const new_ty = Type.u128; |
| 5831 | var lhs_upcast = try (try func.intcast(lhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); | 5935 | var lhs_upcast = try (try func.intcast(lhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); |
| 5832 | defer lhs_upcast.free(func); | 5936 | defer lhs_upcast.free(func); |
| 5833 | var rhs_upcast = try (try func.intcast(rhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); | 5937 | var rhs_upcast = try (try func.intcast(rhs, lhs_ty, new_ty)).toLocal(func, lhs_ty); |
| ... | @@ -5847,8 +5951,8 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5847,8 +5951,8 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5847 | 5951 | ||
| 5848 | const bin_op = try func.callIntrinsic( | 5952 | const bin_op = try func.callIntrinsic( |
| 5849 | "__multi3", | 5953 | "__multi3", |
| 5850 | &[_]Type{Type.i64} ** 4, | 5954 | &[_]InternPool.Index{.i64_type} ** 4, |
| 5851 | Type.initTag(.i128), | 5955 | Type.i128, |
| 5852 | &.{ lhs, lhs_shifted, rhs, rhs_shifted }, | 5956 | &.{ lhs, lhs_shifted, rhs, rhs_shifted }, |
| 5853 | ); | 5957 | ); |
| 5854 | const res = try func.allocLocal(lhs_ty); | 5958 | const res = try func.allocLocal(lhs_ty); |
| ... | @@ -5871,20 +5975,20 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5871,20 +5975,20 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5871 | 5975 | ||
| 5872 | const mul1 = try func.callIntrinsic( | 5976 | const mul1 = try func.callIntrinsic( |
| 5873 | "__multi3", | 5977 | "__multi3", |
| 5874 | &[_]Type{Type.i64} ** 4, | 5978 | &[_]InternPool.Index{.i64_type} ** 4, |
| 5875 | Type.initTag(.i128), | 5979 | Type.i128, |
| 5876 | &.{ lhs_lsb, zero, rhs_msb, zero }, | 5980 | &.{ lhs_lsb, zero, rhs_msb, zero }, |
| 5877 | ); | 5981 | ); |
| 5878 | const mul2 = try func.callIntrinsic( | 5982 | const mul2 = try func.callIntrinsic( |
| 5879 | "__multi3", | 5983 | "__multi3", |
| 5880 | &[_]Type{Type.i64} ** 4, | 5984 | &[_]InternPool.Index{.i64_type} ** 4, |
| 5881 | Type.initTag(.i128), | 5985 | Type.i128, |
| 5882 | &.{ rhs_lsb, zero, lhs_msb, zero }, | 5986 | &.{ rhs_lsb, zero, lhs_msb, zero }, |
| 5883 | ); | 5987 | ); |
| 5884 | const mul3 = try func.callIntrinsic( | 5988 | const mul3 = try func.callIntrinsic( |
| 5885 | "__multi3", | 5989 | "__multi3", |
| 5886 | &[_]Type{Type.i64} ** 4, | 5990 | &[_]InternPool.Index{.i64_type} ** 4, |
| 5887 | Type.initTag(.i128), | 5991 | Type.i128, |
| 5888 | &.{ lhs_msb, zero, rhs_msb, zero }, | 5992 | &.{ lhs_msb, zero, rhs_msb, zero }, |
| 5889 | ); | 5993 | ); |
| 5890 | 5994 | ||
| ... | @@ -5912,7 +6016,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5912,7 +6016,7 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5912 | _ = try func.binOp(lsb_or, mul_add_lt, Type.bool, .@"or"); | 6016 | _ = try func.binOp(lsb_or, mul_add_lt, Type.bool, .@"or"); |
| 5913 | try func.addLabel(.local_set, overflow_bit.local.value); | 6017 | try func.addLabel(.local_set, overflow_bit.local.value); |
| 5914 | 6018 | ||
| 5915 | const tmp_result = try func.allocStack(Type.initTag(.u128)); | 6019 | const tmp_result = try func.allocStack(Type.u128); |
| 5916 | try func.emitWValue(tmp_result); | 6020 | try func.emitWValue(tmp_result); |
| 5917 | const mul3_msb = try func.load(mul3, Type.u64, 0); | 6021 | const mul3_msb = try func.load(mul3, Type.u64, 0); |
| 5918 | try func.store(.stack, mul3_msb, Type.u64, tmp_result.offset()); | 6022 | try func.store(.stack, mul3_msb, Type.u64, tmp_result.offset()); |
| ... | @@ -5922,23 +6026,24 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5922,23 +6026,24 @@ fn airMulWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5922 | var bin_op_local = try bin_op.toLocal(func, lhs_ty); | 6026 | var bin_op_local = try bin_op.toLocal(func, lhs_ty); |
| 5923 | defer bin_op_local.free(func); | 6027 | defer bin_op_local.free(func); |
| 5924 | 6028 | ||
| 5925 | const result_ptr = try func.allocStack(func.air.typeOfIndex(inst)); | 6029 | const result_ptr = try func.allocStack(func.typeOfIndex(inst)); |
| 5926 | try func.store(result_ptr, bin_op_local, lhs_ty, 0); | 6030 | try func.store(result_ptr, bin_op_local, lhs_ty, 0); |
| 5927 | const offset = @intCast(u32, lhs_ty.abiSize(func.target)); | 6031 | const offset = @intCast(u32, lhs_ty.abiSize(mod)); |
| 5928 | try func.store(result_ptr, overflow_bit, Type.initTag(.u1), offset); | 6032 | try func.store(result_ptr, overflow_bit, Type.u1, offset); |
| 5929 | 6033 | ||
| 5930 | func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); | 6034 | func.finishAir(inst, result_ptr, &.{ extra.lhs, extra.rhs }); |
| 5931 | } | 6035 | } |
| 5932 | 6036 | ||
| 5933 | fn airMaxMin(func: *CodeGen, inst: Air.Inst.Index, op: enum { max, min }) InnerError!void { | 6037 | fn airMaxMin(func: *CodeGen, inst: Air.Inst.Index, op: enum { max, min }) InnerError!void { |
| 6038 | const mod = func.bin_file.base.options.module.?; | ||
| 5934 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 6039 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 5935 | 6040 | ||
| 5936 | const ty = func.air.typeOfIndex(inst); | 6041 | const ty = func.typeOfIndex(inst); |
| 5937 | if (ty.zigTypeTag() == .Vector) { | 6042 | if (ty.zigTypeTag(mod) == .Vector) { |
| 5938 | return func.fail("TODO: `@maximum` and `@minimum` for vectors", .{}); | 6043 | return func.fail("TODO: `@maximum` and `@minimum` for vectors", .{}); |
| 5939 | } | 6044 | } |
| 5940 | 6045 | ||
| 5941 | if (ty.abiSize(func.target) > 16) { | 6046 | if (ty.abiSize(mod) > 16) { |
| 5942 | return func.fail("TODO: `@maximum` and `@minimum` for types larger than 16 bytes", .{}); | 6047 | return func.fail("TODO: `@maximum` and `@minimum` for types larger than 16 bytes", .{}); |
| 5943 | } | 6048 | } |
| 5944 | 6049 | ||
| ... | @@ -5954,18 +6059,19 @@ fn airMaxMin(func: *CodeGen, inst: Air.Inst.Index, op: enum { max, min }) InnerE | ... | @@ -5954,18 +6059,19 @@ fn airMaxMin(func: *CodeGen, inst: Air.Inst.Index, op: enum { max, min }) InnerE |
| 5954 | try func.addTag(.select); | 6059 | try func.addTag(.select); |
| 5955 | 6060 | ||
| 5956 | // store result in local | 6061 | // store result in local |
| 5957 | const result_ty = if (isByRef(ty, func.target)) Type.u32 else ty; | 6062 | const result_ty = if (isByRef(ty, mod)) Type.u32 else ty; |
| 5958 | const result = try func.allocLocal(result_ty); | 6063 | const result = try func.allocLocal(result_ty); |
| 5959 | try func.addLabel(.local_set, result.local.value); | 6064 | try func.addLabel(.local_set, result.local.value); |
| 5960 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); | 6065 | func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 5961 | } | 6066 | } |
| 5962 | 6067 | ||
| 5963 | fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6068 | fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6069 | const mod = func.bin_file.base.options.module.?; | ||
| 5964 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; | 6070 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 5965 | const bin_op = func.air.extraData(Air.Bin, pl_op.payload).data; | 6071 | const bin_op = func.air.extraData(Air.Bin, pl_op.payload).data; |
| 5966 | 6072 | ||
| 5967 | const ty = func.air.typeOfIndex(inst); | 6073 | const ty = func.typeOfIndex(inst); |
| 5968 | if (ty.zigTypeTag() == .Vector) { | 6074 | if (ty.zigTypeTag(mod) == .Vector) { |
| 5969 | return func.fail("TODO: `@mulAdd` for vectors", .{}); | 6075 | return func.fail("TODO: `@mulAdd` for vectors", .{}); |
| 5970 | } | 6076 | } |
| 5971 | 6077 | ||
| ... | @@ -5980,7 +6086,7 @@ fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5980,7 +6086,7 @@ fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5980 | // call to compiler-rt `fn fmaf(f32, f32, f32) f32` | 6086 | // call to compiler-rt `fn fmaf(f32, f32, f32) f32` |
| 5981 | var result = try func.callIntrinsic( | 6087 | var result = try func.callIntrinsic( |
| 5982 | "fmaf", | 6088 | "fmaf", |
| 5983 | &.{ Type.f32, Type.f32, Type.f32 }, | 6089 | &.{ .f32_type, .f32_type, .f32_type }, |
| 5984 | Type.f32, | 6090 | Type.f32, |
| 5985 | &.{ rhs_ext, lhs_ext, addend_ext }, | 6091 | &.{ rhs_ext, lhs_ext, addend_ext }, |
| 5986 | ); | 6092 | ); |
| ... | @@ -5994,16 +6100,17 @@ fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5994,16 +6100,17 @@ fn airMulAdd(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5994 | } | 6100 | } |
| 5995 | 6101 | ||
| 5996 | fn airClz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6102 | fn airClz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6103 | const mod = func.bin_file.base.options.module.?; | ||
| 5997 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 6104 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 5998 | 6105 | ||
| 5999 | const ty = func.air.typeOf(ty_op.operand); | 6106 | const ty = func.typeOf(ty_op.operand); |
| 6000 | const result_ty = func.air.typeOfIndex(inst); | 6107 | const result_ty = func.typeOfIndex(inst); |
| 6001 | if (ty.zigTypeTag() == .Vector) { | 6108 | if (ty.zigTypeTag(mod) == .Vector) { |
| 6002 | return func.fail("TODO: `@clz` for vectors", .{}); | 6109 | return func.fail("TODO: `@clz` for vectors", .{}); |
| 6003 | } | 6110 | } |
| 6004 | 6111 | ||
| 6005 | const operand = try func.resolveInst(ty_op.operand); | 6112 | const operand = try func.resolveInst(ty_op.operand); |
| 6006 | const int_info = ty.intInfo(func.target); | 6113 | const int_info = ty.intInfo(mod); |
| 6007 | const wasm_bits = toWasmBits(int_info.bits) orelse { | 6114 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 6008 | return func.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits}); | 6115 | return func.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits}); |
| 6009 | }; | 6116 | }; |
| ... | @@ -6046,17 +6153,18 @@ fn airClz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6046,17 +6153,18 @@ fn airClz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6046 | } | 6153 | } |
| 6047 | 6154 | ||
| 6048 | fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6155 | fn airCtz(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6156 | const mod = func.bin_file.base.options.module.?; | ||
| 6049 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 6157 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 6050 | 6158 | ||
| 6051 | const ty = func.air.typeOf(ty_op.operand); | 6159 | const ty = func.typeOf(ty_op.operand); |
| 6052 | const result_ty = func.air.typeOfIndex(inst); | 6160 | const result_ty = func.typeOfIndex(inst); |
| 6053 | 6161 | ||
| 6054 | if (ty.zigTypeTag() == .Vector) { | 6162 | if (ty.zigTypeTag(mod) == .Vector) { |
| 6055 | return func.fail("TODO: `@ctz` for vectors", .{}); | 6163 | return func.fail("TODO: `@ctz` for vectors", .{}); |
| 6056 | } | 6164 | } |
| 6057 | 6165 | ||
| 6058 | const operand = try func.resolveInst(ty_op.operand); | 6166 | const operand = try func.resolveInst(ty_op.operand); |
| 6059 | const int_info = ty.intInfo(func.target); | 6167 | const int_info = ty.intInfo(mod); |
| 6060 | const wasm_bits = toWasmBits(int_info.bits) orelse { | 6168 | const wasm_bits = toWasmBits(int_info.bits) orelse { |
| 6061 | return func.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits}); | 6169 | return func.fail("TODO: `@clz` for integers with bitsize '{d}'", .{int_info.bits}); |
| 6062 | }; | 6170 | }; |
| ... | @@ -6113,7 +6221,7 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void { | ... | @@ -6113,7 +6221,7 @@ fn airDbgVar(func: *CodeGen, inst: Air.Inst.Index, is_ptr: bool) !void { |
| 6113 | if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{}); | 6221 | if (func.debug_output != .dwarf) return func.finishAir(inst, .none, &.{}); |
| 6114 | 6222 | ||
| 6115 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; | 6223 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 6116 | const ty = func.air.typeOf(pl_op.operand); | 6224 | const ty = func.typeOf(pl_op.operand); |
| 6117 | const operand = try func.resolveInst(pl_op.operand); | 6225 | const operand = try func.resolveInst(pl_op.operand); |
| 6118 | 6226 | ||
| 6119 | log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), operand }); | 6227 | log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), operand }); |
| ... | @@ -6151,17 +6259,18 @@ fn airTry(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6151,17 +6259,18 @@ fn airTry(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6151 | const err_union = try func.resolveInst(pl_op.operand); | 6259 | const err_union = try func.resolveInst(pl_op.operand); |
| 6152 | const extra = func.air.extraData(Air.Try, pl_op.payload); | 6260 | const extra = func.air.extraData(Air.Try, pl_op.payload); |
| 6153 | const body = func.air.extra[extra.end..][0..extra.data.body_len]; | 6261 | const body = func.air.extra[extra.end..][0..extra.data.body_len]; |
| 6154 | const err_union_ty = func.air.typeOf(pl_op.operand); | 6262 | const err_union_ty = func.typeOf(pl_op.operand); |
| 6155 | const result = try lowerTry(func, inst, err_union, body, err_union_ty, false); | 6263 | const result = try lowerTry(func, inst, err_union, body, err_union_ty, false); |
| 6156 | func.finishAir(inst, result, &.{pl_op.operand}); | 6264 | func.finishAir(inst, result, &.{pl_op.operand}); |
| 6157 | } | 6265 | } |
| 6158 | 6266 | ||
| 6159 | fn airTryPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6267 | fn airTryPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6268 | const mod = func.bin_file.base.options.module.?; | ||
| 6160 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 6269 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 6161 | const extra = func.air.extraData(Air.TryPtr, ty_pl.payload); | 6270 | const extra = func.air.extraData(Air.TryPtr, ty_pl.payload); |
| 6162 | const err_union_ptr = try func.resolveInst(extra.data.ptr); | 6271 | const err_union_ptr = try func.resolveInst(extra.data.ptr); |
| 6163 | const body = func.air.extra[extra.end..][0..extra.data.body_len]; | 6272 | const body = func.air.extra[extra.end..][0..extra.data.body_len]; |
| 6164 | const err_union_ty = func.air.typeOf(extra.data.ptr).childType(); | 6273 | const err_union_ty = func.typeOf(extra.data.ptr).childType(mod); |
| 6165 | const result = try lowerTry(func, inst, err_union_ptr, body, err_union_ty, true); | 6274 | const result = try lowerTry(func, inst, err_union_ptr, body, err_union_ty, true); |
| 6166 | func.finishAir(inst, result, &.{extra.data.ptr}); | 6275 | func.finishAir(inst, result, &.{extra.data.ptr}); |
| 6167 | } | 6276 | } |
| ... | @@ -6174,24 +6283,25 @@ fn lowerTry( | ... | @@ -6174,24 +6283,25 @@ fn lowerTry( |
| 6174 | err_union_ty: Type, | 6283 | err_union_ty: Type, |
| 6175 | operand_is_ptr: bool, | 6284 | operand_is_ptr: bool, |
| 6176 | ) InnerError!WValue { | 6285 | ) InnerError!WValue { |
| 6286 | const mod = func.bin_file.base.options.module.?; | ||
| 6177 | if (operand_is_ptr) { | 6287 | if (operand_is_ptr) { |
| 6178 | return func.fail("TODO: lowerTry for pointers", .{}); | 6288 | return func.fail("TODO: lowerTry for pointers", .{}); |
| 6179 | } | 6289 | } |
| 6180 | 6290 | ||
| 6181 | const pl_ty = err_union_ty.errorUnionPayload(); | 6291 | const pl_ty = err_union_ty.errorUnionPayload(mod); |
| 6182 | const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime(); | 6292 | const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime(mod); |
| 6183 | 6293 | ||
| 6184 | if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 6294 | if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 6185 | // Block we can jump out of when error is not set | 6295 | // Block we can jump out of when error is not set |
| 6186 | try func.startBlock(.block, wasm.block_empty); | 6296 | try func.startBlock(.block, wasm.block_empty); |
| 6187 | 6297 | ||
| 6188 | // check if the error tag is set for the error union. | 6298 | // check if the error tag is set for the error union. |
| 6189 | try func.emitWValue(err_union); | 6299 | try func.emitWValue(err_union); |
| 6190 | if (pl_has_bits) { | 6300 | if (pl_has_bits) { |
| 6191 | const err_offset = @intCast(u32, errUnionErrorOffset(pl_ty, func.target)); | 6301 | const err_offset = @intCast(u32, errUnionErrorOffset(pl_ty, mod)); |
| 6192 | try func.addMemArg(.i32_load16_u, .{ | 6302 | try func.addMemArg(.i32_load16_u, .{ |
| 6193 | .offset = err_union.offset() + err_offset, | 6303 | .offset = err_union.offset() + err_offset, |
| 6194 | .alignment = Type.anyerror.abiAlignment(func.target), | 6304 | .alignment = Type.anyerror.abiAlignment(mod), |
| 6195 | }); | 6305 | }); |
| 6196 | } | 6306 | } |
| 6197 | try func.addTag(.i32_eqz); | 6307 | try func.addTag(.i32_eqz); |
| ... | @@ -6213,8 +6323,8 @@ fn lowerTry( | ... | @@ -6213,8 +6323,8 @@ fn lowerTry( |
| 6213 | return WValue{ .none = {} }; | 6323 | return WValue{ .none = {} }; |
| 6214 | } | 6324 | } |
| 6215 | 6325 | ||
| 6216 | const pl_offset = @intCast(u32, errUnionPayloadOffset(pl_ty, func.target)); | 6326 | const pl_offset = @intCast(u32, errUnionPayloadOffset(pl_ty, mod)); |
| 6217 | if (isByRef(pl_ty, func.target)) { | 6327 | if (isByRef(pl_ty, mod)) { |
| 6218 | return buildPointerOffset(func, err_union, pl_offset, .new); | 6328 | return buildPointerOffset(func, err_union, pl_offset, .new); |
| 6219 | } | 6329 | } |
| 6220 | const payload = try func.load(err_union, pl_ty, pl_offset); | 6330 | const payload = try func.load(err_union, pl_ty, pl_offset); |
| ... | @@ -6222,15 +6332,16 @@ fn lowerTry( | ... | @@ -6222,15 +6332,16 @@ fn lowerTry( |
| 6222 | } | 6332 | } |
| 6223 | 6333 | ||
| 6224 | fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6334 | fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6335 | const mod = func.bin_file.base.options.module.?; | ||
| 6225 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 6336 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 6226 | 6337 | ||
| 6227 | const ty = func.air.typeOfIndex(inst); | 6338 | const ty = func.typeOfIndex(inst); |
| 6228 | const operand = try func.resolveInst(ty_op.operand); | 6339 | const operand = try func.resolveInst(ty_op.operand); |
| 6229 | 6340 | ||
| 6230 | if (ty.zigTypeTag() == .Vector) { | 6341 | if (ty.zigTypeTag(mod) == .Vector) { |
| 6231 | return func.fail("TODO: @byteSwap for vectors", .{}); | 6342 | return func.fail("TODO: @byteSwap for vectors", .{}); |
| 6232 | } | 6343 | } |
| 6233 | const int_info = ty.intInfo(func.target); | 6344 | const int_info = ty.intInfo(mod); |
| 6234 | 6345 | ||
| 6235 | // bytes are no-op | 6346 | // bytes are no-op |
| 6236 | if (int_info.bits == 8) { | 6347 | if (int_info.bits == 8) { |
| ... | @@ -6292,13 +6403,14 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6292,13 +6403,14 @@ fn airByteSwap(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6292 | } | 6403 | } |
| 6293 | 6404 | ||
| 6294 | fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6405 | fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6406 | const mod = func.bin_file.base.options.module.?; | ||
| 6295 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 6407 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 6296 | 6408 | ||
| 6297 | const ty = func.air.typeOfIndex(inst); | 6409 | const ty = func.typeOfIndex(inst); |
| 6298 | const lhs = try func.resolveInst(bin_op.lhs); | 6410 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6299 | const rhs = try func.resolveInst(bin_op.rhs); | 6411 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6300 | 6412 | ||
| 6301 | const result = if (ty.isSignedInt()) | 6413 | const result = if (ty.isSignedInt(mod)) |
| 6302 | try func.divSigned(lhs, rhs, ty) | 6414 | try func.divSigned(lhs, rhs, ty) |
| 6303 | else | 6415 | else |
| 6304 | try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); | 6416 | try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); |
| ... | @@ -6306,13 +6418,14 @@ fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6306,13 +6418,14 @@ fn airDiv(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6306 | } | 6418 | } |
| 6307 | 6419 | ||
| 6308 | fn airDivTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6420 | fn airDivTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6421 | const mod = func.bin_file.base.options.module.?; | ||
| 6309 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 6422 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 6310 | 6423 | ||
| 6311 | const ty = func.air.typeOfIndex(inst); | 6424 | const ty = func.typeOfIndex(inst); |
| 6312 | const lhs = try func.resolveInst(bin_op.lhs); | 6425 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6313 | const rhs = try func.resolveInst(bin_op.rhs); | 6426 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6314 | 6427 | ||
| 6315 | const div_result = if (ty.isSignedInt()) | 6428 | const div_result = if (ty.isSignedInt(mod)) |
| 6316 | try func.divSigned(lhs, rhs, ty) | 6429 | try func.divSigned(lhs, rhs, ty) |
| 6317 | else | 6430 | else |
| 6318 | try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); | 6431 | try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); |
| ... | @@ -6328,15 +6441,16 @@ fn airDivTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6328,15 +6441,16 @@ fn airDivTrunc(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6328 | fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6441 | fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6329 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 6442 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 6330 | 6443 | ||
| 6331 | const ty = func.air.typeOfIndex(inst); | 6444 | const mod = func.bin_file.base.options.module.?; |
| 6445 | const ty = func.typeOfIndex(inst); | ||
| 6332 | const lhs = try func.resolveInst(bin_op.lhs); | 6446 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6333 | const rhs = try func.resolveInst(bin_op.rhs); | 6447 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6334 | 6448 | ||
| 6335 | if (ty.isUnsignedInt()) { | 6449 | if (ty.isUnsignedInt(mod)) { |
| 6336 | const result = try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); | 6450 | const result = try (try func.binOp(lhs, rhs, ty, .div)).toLocal(func, ty); |
| 6337 | return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); | 6451 | return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); |
| 6338 | } else if (ty.isSignedInt()) { | 6452 | } else if (ty.isSignedInt(mod)) { |
| 6339 | const int_bits = ty.intInfo(func.target).bits; | 6453 | const int_bits = ty.intInfo(mod).bits; |
| 6340 | const wasm_bits = toWasmBits(int_bits) orelse { | 6454 | const wasm_bits = toWasmBits(int_bits) orelse { |
| 6341 | return func.fail("TODO: `@divFloor` for signed integers larger than '{d}' bits", .{int_bits}); | 6455 | return func.fail("TODO: `@divFloor` for signed integers larger than '{d}' bits", .{int_bits}); |
| 6342 | }; | 6456 | }; |
| ... | @@ -6414,7 +6528,8 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6414,7 +6528,8 @@ fn airDivFloor(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6414 | } | 6528 | } |
| 6415 | 6529 | ||
| 6416 | fn divSigned(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue { | 6530 | fn divSigned(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type) InnerError!WValue { |
| 6417 | const int_bits = ty.intInfo(func.target).bits; | 6531 | const mod = func.bin_file.base.options.module.?; |
| 6532 | const int_bits = ty.intInfo(mod).bits; | ||
| 6418 | const wasm_bits = toWasmBits(int_bits) orelse { | 6533 | const wasm_bits = toWasmBits(int_bits) orelse { |
| 6419 | return func.fail("TODO: Implement signed division for integers with bitsize '{d}'", .{int_bits}); | 6534 | return func.fail("TODO: Implement signed division for integers with bitsize '{d}'", .{int_bits}); |
| 6420 | }; | 6535 | }; |
| ... | @@ -6441,7 +6556,8 @@ fn divSigned(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type) InnerError!WVal | ... | @@ -6441,7 +6556,8 @@ fn divSigned(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type) InnerError!WVal |
| 6441 | /// Retrieves the absolute value of a signed integer | 6556 | /// Retrieves the absolute value of a signed integer |
| 6442 | /// NOTE: Leaves the result value on the stack. | 6557 | /// NOTE: Leaves the result value on the stack. |
| 6443 | fn signAbsValue(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { | 6558 | fn signAbsValue(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { |
| 6444 | const int_bits = ty.intInfo(func.target).bits; | 6559 | const mod = func.bin_file.base.options.module.?; |
| 6560 | const int_bits = ty.intInfo(mod).bits; | ||
| 6445 | const wasm_bits = toWasmBits(int_bits) orelse { | 6561 | const wasm_bits = toWasmBits(int_bits) orelse { |
| 6446 | return func.fail("TODO: signAbsValue for signed integers larger than '{d}' bits", .{int_bits}); | 6562 | return func.fail("TODO: signAbsValue for signed integers larger than '{d}' bits", .{int_bits}); |
| 6447 | }; | 6563 | }; |
| ... | @@ -6476,11 +6592,12 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | ... | @@ -6476,11 +6592,12 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 6476 | assert(op == .add or op == .sub); | 6592 | assert(op == .add or op == .sub); |
| 6477 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 6593 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 6478 | 6594 | ||
| 6479 | const ty = func.air.typeOfIndex(inst); | 6595 | const mod = func.bin_file.base.options.module.?; |
| 6596 | const ty = func.typeOfIndex(inst); | ||
| 6480 | const lhs = try func.resolveInst(bin_op.lhs); | 6597 | const lhs = try func.resolveInst(bin_op.lhs); |
| 6481 | const rhs = try func.resolveInst(bin_op.rhs); | 6598 | const rhs = try func.resolveInst(bin_op.rhs); |
| 6482 | 6599 | ||
| 6483 | const int_info = ty.intInfo(func.target); | 6600 | const int_info = ty.intInfo(mod); |
| 6484 | const is_signed = int_info.signedness == .signed; | 6601 | const is_signed = int_info.signedness == .signed; |
| 6485 | 6602 | ||
| 6486 | if (int_info.bits > 64) { | 6603 | if (int_info.bits > 64) { |
| ... | @@ -6523,7 +6640,8 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { | ... | @@ -6523,7 +6640,8 @@ fn airSatBinOp(func: *CodeGen, inst: Air.Inst.Index, op: Op) InnerError!void { |
| 6523 | } | 6640 | } |
| 6524 | 6641 | ||
| 6525 | fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op: Op) InnerError!WValue { | 6642 | fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, op: Op) InnerError!WValue { |
| 6526 | const int_info = ty.intInfo(func.target); | 6643 | const mod = func.bin_file.base.options.module.?; |
| 6644 | const int_info = ty.intInfo(mod); | ||
| 6527 | const wasm_bits = toWasmBits(int_info.bits).?; | 6645 | const wasm_bits = toWasmBits(int_info.bits).?; |
| 6528 | const is_wasm_bits = wasm_bits == int_info.bits; | 6646 | const is_wasm_bits = wasm_bits == int_info.bits; |
| 6529 | 6647 | ||
| ... | @@ -6588,8 +6706,9 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, | ... | @@ -6588,8 +6706,9 @@ fn signedSat(func: *CodeGen, lhs_operand: WValue, rhs_operand: WValue, ty: Type, |
| 6588 | fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6706 | fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6589 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 6707 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 6590 | 6708 | ||
| 6591 | const ty = func.air.typeOfIndex(inst); | 6709 | const mod = func.bin_file.base.options.module.?; |
| 6592 | const int_info = ty.intInfo(func.target); | 6710 | const ty = func.typeOfIndex(inst); |
| 6711 | const int_info = ty.intInfo(mod); | ||
| 6593 | const is_signed = int_info.signedness == .signed; | 6712 | const is_signed = int_info.signedness == .signed; |
| 6594 | if (int_info.bits > 64) { | 6713 | if (int_info.bits > 64) { |
| 6595 | return func.fail("TODO: Saturating shifting left for integers with bitsize '{d}'", .{int_info.bits}); | 6714 | return func.fail("TODO: Saturating shifting left for integers with bitsize '{d}'", .{int_info.bits}); |
| ... | @@ -6697,7 +6816,7 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6697,7 +6816,7 @@ fn airShlSat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6697 | fn callIntrinsic( | 6816 | fn callIntrinsic( |
| 6698 | func: *CodeGen, | 6817 | func: *CodeGen, |
| 6699 | name: []const u8, | 6818 | name: []const u8, |
| 6700 | param_types: []const Type, | 6819 | param_types: []const InternPool.Index, |
| 6701 | return_type: Type, | 6820 | return_type: Type, |
| 6702 | args: []const WValue, | 6821 | args: []const WValue, |
| 6703 | ) InnerError!WValue { | 6822 | ) InnerError!WValue { |
| ... | @@ -6707,12 +6826,13 @@ fn callIntrinsic( | ... | @@ -6707,12 +6826,13 @@ fn callIntrinsic( |
| 6707 | }; | 6826 | }; |
| 6708 | 6827 | ||
| 6709 | // Always pass over C-ABI | 6828 | // Always pass over C-ABI |
| 6710 | var func_type = try genFunctype(func.gpa, .C, param_types, return_type, func.target); | 6829 | const mod = func.bin_file.base.options.module.?; |
| 6830 | var func_type = try genFunctype(func.gpa, .C, param_types, return_type, mod); | ||
| 6711 | defer func_type.deinit(func.gpa); | 6831 | defer func_type.deinit(func.gpa); |
| 6712 | const func_type_index = try func.bin_file.putOrGetFuncType(func_type); | 6832 | const func_type_index = try func.bin_file.putOrGetFuncType(func_type); |
| 6713 | try func.bin_file.addOrUpdateImport(name, symbol_index, null, func_type_index); | 6833 | try func.bin_file.addOrUpdateImport(name, symbol_index, null, func_type_index); |
| 6714 | 6834 | ||
| 6715 | const want_sret_param = firstParamSRet(.C, return_type, func.target); | 6835 | const want_sret_param = firstParamSRet(.C, return_type, mod); |
| 6716 | // if we want return as first param, we allocate a pointer to stack, | 6836 | // if we want return as first param, we allocate a pointer to stack, |
| 6717 | // and emit it as our first argument | 6837 | // and emit it as our first argument |
| 6718 | const sret = if (want_sret_param) blk: { | 6838 | const sret = if (want_sret_param) blk: { |
| ... | @@ -6724,16 +6844,16 @@ fn callIntrinsic( | ... | @@ -6724,16 +6844,16 @@ fn callIntrinsic( |
| 6724 | // Lower all arguments to the stack before we call our function | 6844 | // Lower all arguments to the stack before we call our function |
| 6725 | for (args, 0..) |arg, arg_i| { | 6845 | for (args, 0..) |arg, arg_i| { |
| 6726 | assert(!(want_sret_param and arg == .stack)); | 6846 | assert(!(want_sret_param and arg == .stack)); |
| 6727 | assert(param_types[arg_i].hasRuntimeBitsIgnoreComptime()); | 6847 | assert(param_types[arg_i].toType().hasRuntimeBitsIgnoreComptime(mod)); |
| 6728 | try func.lowerArg(.C, param_types[arg_i], arg); | 6848 | try func.lowerArg(.C, param_types[arg_i].toType(), arg); |
| 6729 | } | 6849 | } |
| 6730 | 6850 | ||
| 6731 | // Actually call our intrinsic | 6851 | // Actually call our intrinsic |
| 6732 | try func.addLabel(.call, symbol_index); | 6852 | try func.addLabel(.call, symbol_index); |
| 6733 | 6853 | ||
| 6734 | if (!return_type.hasRuntimeBitsIgnoreComptime()) { | 6854 | if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6735 | return WValue.none; | 6855 | return WValue.none; |
| 6736 | } else if (return_type.isNoReturn()) { | 6856 | } else if (return_type.isNoReturn(mod)) { |
| 6737 | try func.addTag(.@"unreachable"); | 6857 | try func.addTag(.@"unreachable"); |
| 6738 | return WValue.none; | 6858 | return WValue.none; |
| 6739 | } else if (want_sret_param) { | 6859 | } else if (want_sret_param) { |
| ... | @@ -6746,11 +6866,11 @@ fn callIntrinsic( | ... | @@ -6746,11 +6866,11 @@ fn callIntrinsic( |
| 6746 | fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6866 | fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6747 | const un_op = func.air.instructions.items(.data)[inst].un_op; | 6867 | const un_op = func.air.instructions.items(.data)[inst].un_op; |
| 6748 | const operand = try func.resolveInst(un_op); | 6868 | const operand = try func.resolveInst(un_op); |
| 6749 | const enum_ty = func.air.typeOf(un_op); | 6869 | const enum_ty = func.typeOf(un_op); |
| 6750 | 6870 | ||
| 6751 | const func_sym_index = try func.getTagNameFunction(enum_ty); | 6871 | const func_sym_index = try func.getTagNameFunction(enum_ty); |
| 6752 | 6872 | ||
| 6753 | const result_ptr = try func.allocStack(func.air.typeOfIndex(inst)); | 6873 | const result_ptr = try func.allocStack(func.typeOfIndex(inst)); |
| 6754 | try func.lowerToStack(result_ptr); | 6874 | try func.lowerToStack(result_ptr); |
| 6755 | try func.emitWValue(operand); | 6875 | try func.emitWValue(operand); |
| 6756 | try func.addLabel(.call, func_sym_index); | 6876 | try func.addLabel(.call, func_sym_index); |
| ... | @@ -6759,15 +6879,14 @@ fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6759,15 +6879,14 @@ fn airTagName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6759 | } | 6879 | } |
| 6760 | 6880 | ||
| 6761 | fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { | 6881 | fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6762 | const enum_decl_index = enum_ty.getOwnerDecl(); | 6882 | const mod = func.bin_file.base.options.module.?; |
| 6763 | const module = func.bin_file.base.options.module.?; | 6883 | const enum_decl_index = enum_ty.getOwnerDecl(mod); |
| 6764 | 6884 | ||
| 6765 | var arena_allocator = std.heap.ArenaAllocator.init(func.gpa); | 6885 | var arena_allocator = std.heap.ArenaAllocator.init(func.gpa); |
| 6766 | defer arena_allocator.deinit(); | 6886 | defer arena_allocator.deinit(); |
| 6767 | const arena = arena_allocator.allocator(); | 6887 | const arena = arena_allocator.allocator(); |
| 6768 | 6888 | ||
| 6769 | const fqn = try module.declPtr(enum_decl_index).getFullyQualifiedName(module); | 6889 | const fqn = mod.intern_pool.stringToSlice(try mod.declPtr(enum_decl_index).getFullyQualifiedName(mod)); |
| 6770 | defer module.gpa.free(fqn); | ||
| 6771 | const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); | 6890 | const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); |
| 6772 | 6891 | ||
| 6773 | // check if we already generated code for this. | 6892 | // check if we already generated code for this. |
| ... | @@ -6775,10 +6894,9 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { | ... | @@ -6775,10 +6894,9 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6775 | return loc.index; | 6894 | return loc.index; |
| 6776 | } | 6895 | } |
| 6777 | 6896 | ||
| 6778 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | 6897 | const int_tag_ty = enum_ty.intTagType(mod); |
| 6779 | const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer); | ||
| 6780 | 6898 | ||
| 6781 | if (int_tag_ty.bitSize(func.target) > 64) { | 6899 | if (int_tag_ty.bitSize(mod) > 64) { |
| 6782 | return func.fail("TODO: Implement @tagName for enums with tag size larger than 64 bits", .{}); | 6900 | return func.fail("TODO: Implement @tagName for enums with tag size larger than 64 bits", .{}); |
| 6783 | } | 6901 | } |
| 6784 | 6902 | ||
| ... | @@ -6798,36 +6916,22 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { | ... | @@ -6798,36 +6916,22 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6798 | 6916 | ||
| 6799 | // TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse. | 6917 | // TODO: Make switch implementation generic so we can use a jump table for this when the tags are not sparse. |
| 6800 | // generate an if-else chain for each tag value as well as constant. | 6918 | // generate an if-else chain for each tag value as well as constant. |
| 6801 | for (enum_ty.enumFields().keys(), 0..) |tag_name, field_index| { | 6919 | for (enum_ty.enumFields(mod), 0..) |tag_name_ip, field_index_usize| { |
| 6920 | const field_index = @intCast(u32, field_index_usize); | ||
| 6921 | const tag_name = mod.intern_pool.stringToSlice(tag_name_ip); | ||
| 6802 | // for each tag name, create an unnamed const, | 6922 | // for each tag name, create an unnamed const, |
| 6803 | // and then get a pointer to its value. | 6923 | // and then get a pointer to its value. |
| 6804 | var name_ty_payload: Type.Payload.Len = .{ | 6924 | const name_ty = try mod.arrayType(.{ |
| 6805 | .base = .{ .tag = .array_u8_sentinel_0 }, | 6925 | .len = tag_name.len, |
| 6806 | .data = @intCast(u64, tag_name.len), | 6926 | .child = .u8_type, |
| 6807 | }; | 6927 | .sentinel = .zero_u8, |
| 6808 | const name_ty = Type.initPayload(&name_ty_payload.base); | ||
| 6809 | const string_bytes = &module.string_literal_bytes; | ||
| 6810 | try string_bytes.ensureUnusedCapacity(module.gpa, tag_name.len); | ||
| 6811 | const gop = try module.string_literal_table.getOrPutContextAdapted(module.gpa, tag_name, Module.StringLiteralAdapter{ | ||
| 6812 | .bytes = string_bytes, | ||
| 6813 | }, Module.StringLiteralContext{ | ||
| 6814 | .bytes = string_bytes, | ||
| 6815 | }); | 6928 | }); |
| 6816 | if (!gop.found_existing) { | 6929 | const name_val = try mod.intern(.{ .aggregate = .{ |
| 6817 | gop.key_ptr.* = .{ | 6930 | .ty = name_ty.toIntern(), |
| 6818 | .index = @intCast(u32, string_bytes.items.len), | 6931 | .storage = .{ .bytes = tag_name }, |
| 6819 | .len = @intCast(u32, tag_name.len), | 6932 | } }); |
| 6820 | }; | ||
| 6821 | string_bytes.appendSliceAssumeCapacity(tag_name); | ||
| 6822 | gop.value_ptr.* = .none; | ||
| 6823 | } | ||
| 6824 | var name_val_payload: Value.Payload.StrLit = .{ | ||
| 6825 | .base = .{ .tag = .str_lit }, | ||
| 6826 | .data = gop.key_ptr.*, | ||
| 6827 | }; | ||
| 6828 | const name_val = Value.initPayload(&name_val_payload.base); | ||
| 6829 | const tag_sym_index = try func.bin_file.lowerUnnamedConst( | 6933 | const tag_sym_index = try func.bin_file.lowerUnnamedConst( |
| 6830 | .{ .ty = name_ty, .val = name_val }, | 6934 | .{ .ty = name_ty, .val = name_val.toValue() }, |
| 6831 | enum_decl_index, | 6935 | enum_decl_index, |
| 6832 | ); | 6936 | ); |
| 6833 | 6937 | ||
| ... | @@ -6839,11 +6943,8 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { | ... | @@ -6839,11 +6943,8 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6839 | try writer.writeByte(std.wasm.opcode(.local_get)); | 6943 | try writer.writeByte(std.wasm.opcode(.local_get)); |
| 6840 | try leb.writeULEB128(writer, @as(u32, 1)); | 6944 | try leb.writeULEB128(writer, @as(u32, 1)); |
| 6841 | 6945 | ||
| 6842 | var tag_val_payload: Value.Payload.U32 = .{ | 6946 | const tag_val = try mod.enumValueFieldIndex(enum_ty, field_index); |
| 6843 | .base = .{ .tag = .enum_field_index }, | 6947 | const tag_value = try func.lowerConstant(tag_val, enum_ty); |
| 6844 | .data = @intCast(u32, field_index), | ||
| 6845 | }; | ||
| 6846 | const tag_value = try func.lowerConstant(Value.initPayload(&tag_val_payload.base), enum_ty); | ||
| 6847 | 6948 | ||
| 6848 | switch (tag_value) { | 6949 | switch (tag_value) { |
| 6849 | .imm32 => |value| { | 6950 | .imm32 => |value| { |
| ... | @@ -6928,27 +7029,27 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { | ... | @@ -6928,27 +7029,27 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6928 | // finish function body | 7029 | // finish function body |
| 6929 | try writer.writeByte(std.wasm.opcode(.end)); | 7030 | try writer.writeByte(std.wasm.opcode(.end)); |
| 6930 | 7031 | ||
| 6931 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | 7032 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 6932 | const func_type = try genFunctype(arena, .Unspecified, &.{int_tag_ty}, slice_ty, func.target); | 7033 | const func_type = try genFunctype(arena, .Unspecified, &.{int_tag_ty.ip_index}, slice_ty, mod); |
| 6933 | return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs); | 7034 | return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs); |
| 6934 | } | 7035 | } |
| 6935 | 7036 | ||
| 6936 | fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 7037 | fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7038 | const mod = func.bin_file.base.options.module.?; | ||
| 6937 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; | 7039 | const ty_op = func.air.instructions.items(.data)[inst].ty_op; |
| 6938 | 7040 | ||
| 6939 | const operand = try func.resolveInst(ty_op.operand); | 7041 | const operand = try func.resolveInst(ty_op.operand); |
| 6940 | const error_set_ty = func.air.getRefType(ty_op.ty); | 7042 | const error_set_ty = func.air.getRefType(ty_op.ty); |
| 6941 | const result = try func.allocLocal(Type.bool); | 7043 | const result = try func.allocLocal(Type.bool); |
| 6942 | 7044 | ||
| 6943 | const names = error_set_ty.errorSetNames(); | 7045 | const names = error_set_ty.errorSetNames(mod); |
| 6944 | var values = try std.ArrayList(u32).initCapacity(func.gpa, names.len); | 7046 | var values = try std.ArrayList(u32).initCapacity(func.gpa, names.len); |
| 6945 | defer values.deinit(); | 7047 | defer values.deinit(); |
| 6946 | 7048 | ||
| 6947 | const module = func.bin_file.base.options.module.?; | ||
| 6948 | var lowest: ?u32 = null; | 7049 | var lowest: ?u32 = null; |
| 6949 | var highest: ?u32 = null; | 7050 | var highest: ?u32 = null; |
| 6950 | for (names) |name| { | 7051 | for (names) |name| { |
| 6951 | const err_int = module.global_error_set.get(name).?; | 7052 | const err_int = @intCast(Module.ErrorInt, mod.global_error_set.getIndex(name).?); |
| 6952 | if (lowest) |*l| { | 7053 | if (lowest) |*l| { |
| 6953 | if (err_int < l.*) { | 7054 | if (err_int < l.*) { |
| 6954 | l.* = err_int; | 7055 | l.* = err_int; |
| ... | @@ -7019,12 +7120,13 @@ inline fn useAtomicFeature(func: *const CodeGen) bool { | ... | @@ -7019,12 +7120,13 @@ inline fn useAtomicFeature(func: *const CodeGen) bool { |
| 7019 | } | 7120 | } |
| 7020 | 7121 | ||
| 7021 | fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 7122 | fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7123 | const mod = func.bin_file.base.options.module.?; | ||
| 7022 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; | 7124 | const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; |
| 7023 | const extra = func.air.extraData(Air.Cmpxchg, ty_pl.payload).data; | 7125 | const extra = func.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 7024 | 7126 | ||
| 7025 | const ptr_ty = func.air.typeOf(extra.ptr); | 7127 | const ptr_ty = func.typeOf(extra.ptr); |
| 7026 | const ty = ptr_ty.childType(); | 7128 | const ty = ptr_ty.childType(mod); |
| 7027 | const result_ty = func.air.typeOfIndex(inst); | 7129 | const result_ty = func.typeOfIndex(inst); |
| 7028 | 7130 | ||
| 7029 | const ptr_operand = try func.resolveInst(extra.ptr); | 7131 | const ptr_operand = try func.resolveInst(extra.ptr); |
| 7030 | const expected_val = try func.resolveInst(extra.expected_value); | 7132 | const expected_val = try func.resolveInst(extra.expected_value); |
| ... | @@ -7037,7 +7139,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7037,7 +7139,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7037 | try func.emitWValue(ptr_operand); | 7139 | try func.emitWValue(ptr_operand); |
| 7038 | try func.lowerToStack(expected_val); | 7140 | try func.lowerToStack(expected_val); |
| 7039 | try func.lowerToStack(new_val); | 7141 | try func.lowerToStack(new_val); |
| 7040 | try func.addAtomicMemArg(switch (ty.abiSize(func.target)) { | 7142 | try func.addAtomicMemArg(switch (ty.abiSize(mod)) { |
| 7041 | 1 => .i32_atomic_rmw8_cmpxchg_u, | 7143 | 1 => .i32_atomic_rmw8_cmpxchg_u, |
| 7042 | 2 => .i32_atomic_rmw16_cmpxchg_u, | 7144 | 2 => .i32_atomic_rmw16_cmpxchg_u, |
| 7043 | 4 => .i32_atomic_rmw_cmpxchg, | 7145 | 4 => .i32_atomic_rmw_cmpxchg, |
| ... | @@ -7045,14 +7147,14 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7045,14 +7147,14 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7045 | else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), | 7147 | else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), |
| 7046 | }, .{ | 7148 | }, .{ |
| 7047 | .offset = ptr_operand.offset(), | 7149 | .offset = ptr_operand.offset(), |
| 7048 | .alignment = ty.abiAlignment(func.target), | 7150 | .alignment = ty.abiAlignment(mod), |
| 7049 | }); | 7151 | }); |
| 7050 | try func.addLabel(.local_tee, val_local.local.value); | 7152 | try func.addLabel(.local_tee, val_local.local.value); |
| 7051 | _ = try func.cmp(.stack, expected_val, ty, .eq); | 7153 | _ = try func.cmp(.stack, expected_val, ty, .eq); |
| 7052 | try func.addLabel(.local_set, cmp_result.local.value); | 7154 | try func.addLabel(.local_set, cmp_result.local.value); |
| 7053 | break :val val_local; | 7155 | break :val val_local; |
| 7054 | } else val: { | 7156 | } else val: { |
| 7055 | if (ty.abiSize(func.target) > 8) { | 7157 | if (ty.abiSize(mod) > 8) { |
| 7056 | return func.fail("TODO: Implement `@cmpxchg` for types larger than abi size of 8 bytes", .{}); | 7158 | return func.fail("TODO: Implement `@cmpxchg` for types larger than abi size of 8 bytes", .{}); |
| 7057 | } | 7159 | } |
| 7058 | const ptr_val = try WValue.toLocal(try func.load(ptr_operand, ty, 0), func, ty); | 7160 | const ptr_val = try WValue.toLocal(try func.load(ptr_operand, ty, 0), func, ty); |
| ... | @@ -7068,7 +7170,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7068,7 +7170,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7068 | break :val ptr_val; | 7170 | break :val ptr_val; |
| 7069 | }; | 7171 | }; |
| 7070 | 7172 | ||
| 7071 | const result_ptr = if (isByRef(result_ty, func.target)) val: { | 7173 | const result_ptr = if (isByRef(result_ty, mod)) val: { |
| 7072 | try func.emitWValue(cmp_result); | 7174 | try func.emitWValue(cmp_result); |
| 7073 | try func.addImm32(-1); | 7175 | try func.addImm32(-1); |
| 7074 | try func.addTag(.i32_xor); | 7176 | try func.addTag(.i32_xor); |
| ... | @@ -7076,7 +7178,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7076,7 +7178,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7076 | try func.addTag(.i32_and); | 7178 | try func.addTag(.i32_and); |
| 7077 | const and_result = try WValue.toLocal(.stack, func, Type.bool); | 7179 | const and_result = try WValue.toLocal(.stack, func, Type.bool); |
| 7078 | const result_ptr = try func.allocStack(result_ty); | 7180 | const result_ptr = try func.allocStack(result_ty); |
| 7079 | try func.store(result_ptr, and_result, Type.bool, @intCast(u32, ty.abiSize(func.target))); | 7181 | try func.store(result_ptr, and_result, Type.bool, @intCast(u32, ty.abiSize(mod))); |
| 7080 | try func.store(result_ptr, ptr_val, ty, 0); | 7182 | try func.store(result_ptr, ptr_val, ty, 0); |
| 7081 | break :val result_ptr; | 7183 | break :val result_ptr; |
| 7082 | } else val: { | 7184 | } else val: { |
| ... | @@ -7087,16 +7189,17 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7087,16 +7189,17 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7087 | break :val try WValue.toLocal(.stack, func, result_ty); | 7189 | break :val try WValue.toLocal(.stack, func, result_ty); |
| 7088 | }; | 7190 | }; |
| 7089 | 7191 | ||
| 7090 | return func.finishAir(inst, result_ptr, &.{ extra.ptr, extra.new_value, extra.expected_value }); | 7192 | return func.finishAir(inst, result_ptr, &.{ extra.ptr, extra.expected_value, extra.new_value }); |
| 7091 | } | 7193 | } |
| 7092 | 7194 | ||
| 7093 | fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 7195 | fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7196 | const mod = func.bin_file.base.options.module.?; | ||
| 7094 | const atomic_load = func.air.instructions.items(.data)[inst].atomic_load; | 7197 | const atomic_load = func.air.instructions.items(.data)[inst].atomic_load; |
| 7095 | const ptr = try func.resolveInst(atomic_load.ptr); | 7198 | const ptr = try func.resolveInst(atomic_load.ptr); |
| 7096 | const ty = func.air.typeOfIndex(inst); | 7199 | const ty = func.typeOfIndex(inst); |
| 7097 | 7200 | ||
| 7098 | if (func.useAtomicFeature()) { | 7201 | if (func.useAtomicFeature()) { |
| 7099 | const tag: wasm.AtomicsOpcode = switch (ty.abiSize(func.target)) { | 7202 | const tag: wasm.AtomicsOpcode = switch (ty.abiSize(mod)) { |
| 7100 | 1 => .i32_atomic_load8_u, | 7203 | 1 => .i32_atomic_load8_u, |
| 7101 | 2 => .i32_atomic_load16_u, | 7204 | 2 => .i32_atomic_load16_u, |
| 7102 | 4 => .i32_atomic_load, | 7205 | 4 => .i32_atomic_load, |
| ... | @@ -7106,7 +7209,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7106,7 +7209,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7106 | try func.emitWValue(ptr); | 7209 | try func.emitWValue(ptr); |
| 7107 | try func.addAtomicMemArg(tag, .{ | 7210 | try func.addAtomicMemArg(tag, .{ |
| 7108 | .offset = ptr.offset(), | 7211 | .offset = ptr.offset(), |
| 7109 | .alignment = ty.abiAlignment(func.target), | 7212 | .alignment = ty.abiAlignment(mod), |
| 7110 | }); | 7213 | }); |
| 7111 | } else { | 7214 | } else { |
| 7112 | _ = try func.load(ptr, ty, 0); | 7215 | _ = try func.load(ptr, ty, 0); |
| ... | @@ -7117,12 +7220,13 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7117,12 +7220,13 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7117 | } | 7220 | } |
| 7118 | 7221 | ||
| 7119 | fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 7222 | fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7223 | const mod = func.bin_file.base.options.module.?; | ||
| 7120 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; | 7224 | const pl_op = func.air.instructions.items(.data)[inst].pl_op; |
| 7121 | const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data; | 7225 | const extra = func.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 7122 | 7226 | ||
| 7123 | const ptr = try func.resolveInst(pl_op.operand); | 7227 | const ptr = try func.resolveInst(pl_op.operand); |
| 7124 | const operand = try func.resolveInst(extra.operand); | 7228 | const operand = try func.resolveInst(extra.operand); |
| 7125 | const ty = func.air.typeOfIndex(inst); | 7229 | const ty = func.typeOfIndex(inst); |
| 7126 | const op: std.builtin.AtomicRmwOp = extra.op(); | 7230 | const op: std.builtin.AtomicRmwOp = extra.op(); |
| 7127 | 7231 | ||
| 7128 | if (func.useAtomicFeature()) { | 7232 | if (func.useAtomicFeature()) { |
| ... | @@ -7140,7 +7244,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7140,7 +7244,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7140 | try func.emitWValue(ptr); | 7244 | try func.emitWValue(ptr); |
| 7141 | try func.emitWValue(value); | 7245 | try func.emitWValue(value); |
| 7142 | if (op == .Nand) { | 7246 | if (op == .Nand) { |
| 7143 | const wasm_bits = toWasmBits(@intCast(u16, ty.bitSize(func.target))).?; | 7247 | const wasm_bits = toWasmBits(@intCast(u16, ty.bitSize(mod))).?; |
| 7144 | 7248 | ||
| 7145 | const and_res = try func.binOp(value, operand, ty, .@"and"); | 7249 | const and_res = try func.binOp(value, operand, ty, .@"and"); |
| 7146 | if (wasm_bits == 32) | 7250 | if (wasm_bits == 32) |
| ... | @@ -7157,7 +7261,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7157,7 +7261,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7157 | try func.addTag(.select); | 7261 | try func.addTag(.select); |
| 7158 | } | 7262 | } |
| 7159 | try func.addAtomicMemArg( | 7263 | try func.addAtomicMemArg( |
| 7160 | switch (ty.abiSize(func.target)) { | 7264 | switch (ty.abiSize(mod)) { |
| 7161 | 1 => .i32_atomic_rmw8_cmpxchg_u, | 7265 | 1 => .i32_atomic_rmw8_cmpxchg_u, |
| 7162 | 2 => .i32_atomic_rmw16_cmpxchg_u, | 7266 | 2 => .i32_atomic_rmw16_cmpxchg_u, |
| 7163 | 4 => .i32_atomic_rmw_cmpxchg, | 7267 | 4 => .i32_atomic_rmw_cmpxchg, |
| ... | @@ -7166,7 +7270,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7166,7 +7270,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7166 | }, | 7270 | }, |
| 7167 | .{ | 7271 | .{ |
| 7168 | .offset = ptr.offset(), | 7272 | .offset = ptr.offset(), |
| 7169 | .alignment = ty.abiAlignment(func.target), | 7273 | .alignment = ty.abiAlignment(mod), |
| 7170 | }, | 7274 | }, |
| 7171 | ); | 7275 | ); |
| 7172 | const select_res = try func.allocLocal(ty); | 7276 | const select_res = try func.allocLocal(ty); |
| ... | @@ -7185,7 +7289,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7185,7 +7289,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7185 | else => { | 7289 | else => { |
| 7186 | try func.emitWValue(ptr); | 7290 | try func.emitWValue(ptr); |
| 7187 | try func.emitWValue(operand); | 7291 | try func.emitWValue(operand); |
| 7188 | const tag: wasm.AtomicsOpcode = switch (ty.abiSize(func.target)) { | 7292 | const tag: wasm.AtomicsOpcode = switch (ty.abiSize(mod)) { |
| 7189 | 1 => switch (op) { | 7293 | 1 => switch (op) { |
| 7190 | .Xchg => .i32_atomic_rmw8_xchg_u, | 7294 | .Xchg => .i32_atomic_rmw8_xchg_u, |
| 7191 | .Add => .i32_atomic_rmw8_add_u, | 7295 | .Add => .i32_atomic_rmw8_add_u, |
| ... | @@ -7226,7 +7330,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7226,7 +7330,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7226 | }; | 7330 | }; |
| 7227 | try func.addAtomicMemArg(tag, .{ | 7331 | try func.addAtomicMemArg(tag, .{ |
| 7228 | .offset = ptr.offset(), | 7332 | .offset = ptr.offset(), |
| 7229 | .alignment = ty.abiAlignment(func.target), | 7333 | .alignment = ty.abiAlignment(mod), |
| 7230 | }); | 7334 | }); |
| 7231 | const result = try WValue.toLocal(.stack, func, ty); | 7335 | const result = try WValue.toLocal(.stack, func, ty); |
| 7232 | return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand }); | 7336 | return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand }); |
| ... | @@ -7255,7 +7359,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7255,7 +7359,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7255 | .Xor => .xor, | 7359 | .Xor => .xor, |
| 7256 | else => unreachable, | 7360 | else => unreachable, |
| 7257 | }); | 7361 | }); |
| 7258 | if (ty.isInt() and (op == .Add or op == .Sub)) { | 7362 | if (ty.isInt(mod) and (op == .Add or op == .Sub)) { |
| 7259 | _ = try func.wrapOperand(.stack, ty); | 7363 | _ = try func.wrapOperand(.stack, ty); |
| 7260 | } | 7364 | } |
| 7261 | try func.store(.stack, .stack, ty, ptr.offset()); | 7365 | try func.store(.stack, .stack, ty, ptr.offset()); |
| ... | @@ -7271,7 +7375,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7271,7 +7375,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7271 | try func.store(.stack, .stack, ty, ptr.offset()); | 7375 | try func.store(.stack, .stack, ty, ptr.offset()); |
| 7272 | }, | 7376 | }, |
| 7273 | .Nand => { | 7377 | .Nand => { |
| 7274 | const wasm_bits = toWasmBits(@intCast(u16, ty.bitSize(func.target))).?; | 7378 | const wasm_bits = toWasmBits(@intCast(u16, ty.bitSize(mod))).?; |
| 7275 | 7379 | ||
| 7276 | try func.emitWValue(ptr); | 7380 | try func.emitWValue(ptr); |
| 7277 | const and_res = try func.binOp(result, operand, ty, .@"and"); | 7381 | const and_res = try func.binOp(result, operand, ty, .@"and"); |
| ... | @@ -7302,15 +7406,16 @@ fn airFence(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7302,15 +7406,16 @@ fn airFence(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7302 | } | 7406 | } |
| 7303 | 7407 | ||
| 7304 | fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 7408 | fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7409 | const mod = func.bin_file.base.options.module.?; | ||
| 7305 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; | 7410 | const bin_op = func.air.instructions.items(.data)[inst].bin_op; |
| 7306 | 7411 | ||
| 7307 | const ptr = try func.resolveInst(bin_op.lhs); | 7412 | const ptr = try func.resolveInst(bin_op.lhs); |
| 7308 | const operand = try func.resolveInst(bin_op.rhs); | 7413 | const operand = try func.resolveInst(bin_op.rhs); |
| 7309 | const ptr_ty = func.air.typeOf(bin_op.lhs); | 7414 | const ptr_ty = func.typeOf(bin_op.lhs); |
| 7310 | const ty = ptr_ty.childType(); | 7415 | const ty = ptr_ty.childType(mod); |
| 7311 | 7416 | ||
| 7312 | if (func.useAtomicFeature()) { | 7417 | if (func.useAtomicFeature()) { |
| 7313 | const tag: wasm.AtomicsOpcode = switch (ty.abiSize(func.target)) { | 7418 | const tag: wasm.AtomicsOpcode = switch (ty.abiSize(mod)) { |
| 7314 | 1 => .i32_atomic_store8, | 7419 | 1 => .i32_atomic_store8, |
| 7315 | 2 => .i32_atomic_store16, | 7420 | 2 => .i32_atomic_store16, |
| 7316 | 4 => .i32_atomic_store, | 7421 | 4 => .i32_atomic_store, |
| ... | @@ -7321,7 +7426,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7321,7 +7426,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7321 | try func.lowerToStack(operand); | 7426 | try func.lowerToStack(operand); |
| 7322 | try func.addAtomicMemArg(tag, .{ | 7427 | try func.addAtomicMemArg(tag, .{ |
| 7323 | .offset = ptr.offset(), | 7428 | .offset = ptr.offset(), |
| 7324 | .alignment = ty.abiAlignment(func.target), | 7429 | .alignment = ty.abiAlignment(mod), |
| 7325 | }); | 7430 | }); |
| 7326 | } else { | 7431 | } else { |
| 7327 | try func.store(ptr, operand, ty, 0); | 7432 | try func.store(ptr, operand, ty, 0); |
| ... | @@ -7338,3 +7443,13 @@ fn airFrameAddress(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7338,3 +7443,13 @@ fn airFrameAddress(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7338 | const result = try WValue.toLocal(.stack, func, Type.usize); | 7443 | const result = try WValue.toLocal(.stack, func, Type.usize); |
| 7339 | return func.finishAir(inst, result, &.{}); | 7444 | return func.finishAir(inst, result, &.{}); |
| 7340 | } | 7445 | } |
| 7446 | |||
| 7447 | fn typeOf(func: *CodeGen, inst: Air.Inst.Ref) Type { | ||
| 7448 | const mod = func.bin_file.base.options.module.?; | ||
| 7449 | return func.air.typeOf(inst, &mod.intern_pool); | ||
| 7450 | } | ||
| 7451 | |||
| 7452 | fn typeOfIndex(func: *CodeGen, inst: Air.Inst.Index) Type { | ||
| 7453 | const mod = func.bin_file.base.options.module.?; | ||
| 7454 | return func.air.typeOfIndex(inst, &mod.intern_pool); | ||
| 7455 | } |
src/arch/wasm/Emit.zig+1-1| ... | @@ -254,7 +254,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { | ... | @@ -254,7 +254,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError { |
| 254 | @setCold(true); | 254 | @setCold(true); |
| 255 | std.debug.assert(emit.error_msg == null); | 255 | std.debug.assert(emit.error_msg == null); |
| 256 | const mod = emit.bin_file.base.options.module.?; | 256 | const mod = emit.bin_file.base.options.module.?; |
| 257 | emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.base.allocator, mod.declPtr(emit.decl_index).srcLoc(), format, args); | 257 | emit.error_msg = try Module.ErrorMsg.create(emit.bin_file.base.allocator, mod.declPtr(emit.decl_index).srcLoc(mod), format, args); |
| 258 | return error.EmitFail; | 258 | return error.EmitFail; |
| 259 | } | 259 | } |
| 260 | 260 |
src/arch/wasm/abi.zig+33-30| ... | @@ -5,9 +5,11 @@ | ... | @@ -5,9 +5,11 @@ |
| 5 | //! Note: Above mentioned document is not an official specification, therefore called a convention. | 5 | //! Note: Above mentioned document is not an official specification, therefore called a convention. |
| 6 | 6 | ||
| 7 | const std = @import("std"); | 7 | const std = @import("std"); |
| 8 | const Type = @import("../../type.zig").Type; | ||
| 9 | const Target = std.Target; | 8 | const Target = std.Target; |
| 10 | 9 | ||
| 10 | const Type = @import("../../type.zig").Type; | ||
| 11 | const Module = @import("../../Module.zig"); | ||
| 12 | |||
| 11 | /// Defines how to pass a type as part of a function signature, | 13 | /// Defines how to pass a type as part of a function signature, |
| 12 | /// both for parameters as well as return values. | 14 | /// both for parameters as well as return values. |
| 13 | pub const Class = enum { direct, indirect, none }; | 15 | pub const Class = enum { direct, indirect, none }; |
| ... | @@ -19,27 +21,28 @@ const direct: [2]Class = .{ .direct, .none }; | ... | @@ -19,27 +21,28 @@ const direct: [2]Class = .{ .direct, .none }; |
| 19 | /// Classifies a given Zig type to determine how they must be passed | 21 | /// Classifies a given Zig type to determine how they must be passed |
| 20 | /// or returned as value within a wasm function. | 22 | /// or returned as value within a wasm function. |
| 21 | /// When all elements result in `.none`, no value must be passed in or returned. | 23 | /// When all elements result in `.none`, no value must be passed in or returned. |
| 22 | pub fn classifyType(ty: Type, target: Target) [2]Class { | 24 | pub fn classifyType(ty: Type, mod: *Module) [2]Class { |
| 23 | if (!ty.hasRuntimeBitsIgnoreComptime()) return none; | 25 | const target = mod.getTarget(); |
| 24 | switch (ty.zigTypeTag()) { | 26 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return none; |
| 27 | switch (ty.zigTypeTag(mod)) { | ||
| 25 | .Struct => { | 28 | .Struct => { |
| 26 | if (ty.containerLayout() == .Packed) { | 29 | if (ty.containerLayout(mod) == .Packed) { |
| 27 | if (ty.bitSize(target) <= 64) return direct; | 30 | if (ty.bitSize(mod) <= 64) return direct; |
| 28 | return .{ .direct, .direct }; | 31 | return .{ .direct, .direct }; |
| 29 | } | 32 | } |
| 30 | // When the struct type is non-scalar | 33 | // When the struct type is non-scalar |
| 31 | if (ty.structFieldCount() > 1) return memory; | 34 | if (ty.structFieldCount(mod) > 1) return memory; |
| 32 | // When the struct's alignment is non-natural | 35 | // When the struct's alignment is non-natural |
| 33 | const field = ty.structFields().values()[0]; | 36 | const field = ty.structFields(mod).values()[0]; |
| 34 | if (field.abi_align != 0) { | 37 | if (field.abi_align != 0) { |
| 35 | if (field.abi_align > field.ty.abiAlignment(target)) { | 38 | if (field.abi_align > field.ty.abiAlignment(mod)) { |
| 36 | return memory; | 39 | return memory; |
| 37 | } | 40 | } |
| 38 | } | 41 | } |
| 39 | return classifyType(field.ty, target); | 42 | return classifyType(field.ty, mod); |
| 40 | }, | 43 | }, |
| 41 | .Int, .Enum, .ErrorSet, .Vector => { | 44 | .Int, .Enum, .ErrorSet, .Vector => { |
| 42 | const int_bits = ty.intInfo(target).bits; | 45 | const int_bits = ty.intInfo(mod).bits; |
| 43 | if (int_bits <= 64) return direct; | 46 | if (int_bits <= 64) return direct; |
| 44 | if (int_bits <= 128) return .{ .direct, .direct }; | 47 | if (int_bits <= 128) return .{ .direct, .direct }; |
| 45 | return memory; | 48 | return memory; |
| ... | @@ -53,22 +56,22 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { | ... | @@ -53,22 +56,22 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 53 | .Bool => return direct, | 56 | .Bool => return direct, |
| 54 | .Array => return memory, | 57 | .Array => return memory, |
| 55 | .Optional => { | 58 | .Optional => { |
| 56 | std.debug.assert(ty.isPtrLikeOptional()); | 59 | std.debug.assert(ty.isPtrLikeOptional(mod)); |
| 57 | return direct; | 60 | return direct; |
| 58 | }, | 61 | }, |
| 59 | .Pointer => { | 62 | .Pointer => { |
| 60 | std.debug.assert(!ty.isSlice()); | 63 | std.debug.assert(!ty.isSlice(mod)); |
| 61 | return direct; | 64 | return direct; |
| 62 | }, | 65 | }, |
| 63 | .Union => { | 66 | .Union => { |
| 64 | if (ty.containerLayout() == .Packed) { | 67 | if (ty.containerLayout(mod) == .Packed) { |
| 65 | if (ty.bitSize(target) <= 64) return direct; | 68 | if (ty.bitSize(mod) <= 64) return direct; |
| 66 | return .{ .direct, .direct }; | 69 | return .{ .direct, .direct }; |
| 67 | } | 70 | } |
| 68 | const layout = ty.unionGetLayout(target); | 71 | const layout = ty.unionGetLayout(mod); |
| 69 | std.debug.assert(layout.tag_size == 0); | 72 | std.debug.assert(layout.tag_size == 0); |
| 70 | if (ty.unionFields().count() > 1) return memory; | 73 | if (ty.unionFields(mod).count() > 1) return memory; |
| 71 | return classifyType(ty.unionFields().values()[0].ty, target); | 74 | return classifyType(ty.unionFields(mod).values()[0].ty, mod); |
| 72 | }, | 75 | }, |
| 73 | .ErrorUnion, | 76 | .ErrorUnion, |
| 74 | .Frame, | 77 | .Frame, |
| ... | @@ -90,29 +93,29 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { | ... | @@ -90,29 +93,29 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 90 | /// Returns the scalar type a given type can represent. | 93 | /// Returns the scalar type a given type can represent. |
| 91 | /// Asserts given type can be represented as scalar, such as | 94 | /// Asserts given type can be represented as scalar, such as |
| 92 | /// a struct with a single scalar field. | 95 | /// a struct with a single scalar field. |
| 93 | pub fn scalarType(ty: Type, target: std.Target) Type { | 96 | pub fn scalarType(ty: Type, mod: *Module) Type { |
| 94 | switch (ty.zigTypeTag()) { | 97 | switch (ty.zigTypeTag(mod)) { |
| 95 | .Struct => { | 98 | .Struct => { |
| 96 | switch (ty.containerLayout()) { | 99 | switch (ty.containerLayout(mod)) { |
| 97 | .Packed => { | 100 | .Packed => { |
| 98 | const struct_obj = ty.castTag(.@"struct").?.data; | 101 | const struct_obj = mod.typeToStruct(ty).?; |
| 99 | return scalarType(struct_obj.backing_int_ty, target); | 102 | return scalarType(struct_obj.backing_int_ty, mod); |
| 100 | }, | 103 | }, |
| 101 | else => { | 104 | else => { |
| 102 | std.debug.assert(ty.structFieldCount() == 1); | 105 | std.debug.assert(ty.structFieldCount(mod) == 1); |
| 103 | return scalarType(ty.structFieldType(0), target); | 106 | return scalarType(ty.structFieldType(0, mod), mod); |
| 104 | }, | 107 | }, |
| 105 | } | 108 | } |
| 106 | }, | 109 | }, |
| 107 | .Union => { | 110 | .Union => { |
| 108 | if (ty.containerLayout() != .Packed) { | 111 | if (ty.containerLayout(mod) != .Packed) { |
| 109 | const layout = ty.unionGetLayout(target); | 112 | const layout = ty.unionGetLayout(mod); |
| 110 | if (layout.payload_size == 0 and layout.tag_size != 0) { | 113 | if (layout.payload_size == 0 and layout.tag_size != 0) { |
| 111 | return scalarType(ty.unionTagTypeSafety().?, target); | 114 | return scalarType(ty.unionTagTypeSafety(mod).?, mod); |
| 112 | } | 115 | } |
| 113 | std.debug.assert(ty.unionFields().count() == 1); | 116 | std.debug.assert(ty.unionFields(mod).count() == 1); |
| 114 | } | 117 | } |
| 115 | return scalarType(ty.unionFields().values()[0].ty, target); | 118 | return scalarType(ty.unionFields(mod).values()[0].ty, mod); |
| 116 | }, | 119 | }, |
| 117 | else => return ty, | 120 | else => return ty, |
| 118 | } | 121 | } |
src/arch/x86_64/CodeGen.zig+784-772| ... | @@ -26,6 +26,7 @@ const Liveness = @import("../../Liveness.zig"); | ... | @@ -26,6 +26,7 @@ const Liveness = @import("../../Liveness.zig"); |
| 26 | const Lower = @import("Lower.zig"); | 26 | const Lower = @import("Lower.zig"); |
| 27 | const Mir = @import("Mir.zig"); | 27 | const Mir = @import("Mir.zig"); |
| 28 | const Module = @import("../../Module.zig"); | 28 | const Module = @import("../../Module.zig"); |
| 29 | const InternPool = @import("../../InternPool.zig"); | ||
| 29 | const Target = std.Target; | 30 | const Target = std.Target; |
| 30 | const Type = @import("../../type.zig").Type; | 31 | const Type = @import("../../type.zig").Type; |
| 31 | const TypedValue = @import("../../TypedValue.zig"); | 32 | const TypedValue = @import("../../TypedValue.zig"); |
| ... | @@ -112,10 +113,10 @@ const Owner = union(enum) { | ... | @@ -112,10 +113,10 @@ const Owner = union(enum) { |
| 112 | mod_fn: *const Module.Fn, | 113 | mod_fn: *const Module.Fn, |
| 113 | lazy_sym: link.File.LazySymbol, | 114 | lazy_sym: link.File.LazySymbol, |
| 114 | 115 | ||
| 115 | fn getDecl(owner: Owner) Module.Decl.Index { | 116 | fn getDecl(owner: Owner, mod: *Module) Module.Decl.Index { |
| 116 | return switch (owner) { | 117 | return switch (owner) { |
| 117 | .mod_fn => |mod_fn| mod_fn.owner_decl, | 118 | .mod_fn => |mod_fn| mod_fn.owner_decl, |
| 118 | .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(), | 119 | .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(mod), |
| 119 | }; | 120 | }; |
| 120 | } | 121 | } |
| 121 | 122 | ||
| ... | @@ -447,7 +448,7 @@ const InstTracking = struct { | ... | @@ -447,7 +448,7 @@ const InstTracking = struct { |
| 447 | else => unreachable, | 448 | else => unreachable, |
| 448 | } | 449 | } |
| 449 | tracking_log.debug("spill %{d} from {} to {}", .{ inst, self.short, self.long }); | 450 | tracking_log.debug("spill %{d} from {} to {}", .{ inst, self.short, self.long }); |
| 450 | try function.genCopy(function.air.typeOfIndex(inst), self.long, self.short); | 451 | try function.genCopy(function.typeOfIndex(inst), self.long, self.short); |
| 451 | } | 452 | } |
| 452 | 453 | ||
| 453 | fn reuseFrame(self: *InstTracking) void { | 454 | fn reuseFrame(self: *InstTracking) void { |
| ... | @@ -537,7 +538,7 @@ const InstTracking = struct { | ... | @@ -537,7 +538,7 @@ const InstTracking = struct { |
| 537 | inst: Air.Inst.Index, | 538 | inst: Air.Inst.Index, |
| 538 | target: InstTracking, | 539 | target: InstTracking, |
| 539 | ) !void { | 540 | ) !void { |
| 540 | const ty = function.air.typeOfIndex(inst); | 541 | const ty = function.typeOfIndex(inst); |
| 541 | if ((self.long == .none or self.long == .reserved_frame) and target.long == .load_frame) | 542 | if ((self.long == .none or self.long == .reserved_frame) and target.long == .load_frame) |
| 542 | try function.genCopy(ty, target.long, self.short); | 543 | try function.genCopy(ty, target.long, self.short); |
| 543 | try function.genCopy(ty, target.short, self.short); | 544 | try function.genCopy(ty, target.short, self.short); |
| ... | @@ -605,14 +606,14 @@ const FrameAlloc = struct { | ... | @@ -605,14 +606,14 @@ const FrameAlloc = struct { |
| 605 | .ref_count = 0, | 606 | .ref_count = 0, |
| 606 | }; | 607 | }; |
| 607 | } | 608 | } |
| 608 | fn initType(ty: Type, target: Target) FrameAlloc { | 609 | fn initType(ty: Type, mod: *Module) FrameAlloc { |
| 609 | return init(.{ .size = ty.abiSize(target), .alignment = ty.abiAlignment(target) }); | 610 | return init(.{ .size = ty.abiSize(mod), .alignment = ty.abiAlignment(mod) }); |
| 610 | } | 611 | } |
| 611 | }; | 612 | }; |
| 612 | 613 | ||
| 613 | const StackAllocation = struct { | 614 | const StackAllocation = struct { |
| 614 | inst: ?Air.Inst.Index, | 615 | inst: ?Air.Inst.Index, |
| 615 | /// TODO do we need size? should be determined by inst.ty.abiSize(self.target.*) | 616 | /// TODO do we need size? should be determined by inst.ty.abiSize(mod) |
| 616 | size: u32, | 617 | size: u32, |
| 617 | }; | 618 | }; |
| 618 | 619 | ||
| ... | @@ -631,7 +632,7 @@ const Self = @This(); | ... | @@ -631,7 +632,7 @@ const Self = @This(); |
| 631 | pub fn generate( | 632 | pub fn generate( |
| 632 | bin_file: *link.File, | 633 | bin_file: *link.File, |
| 633 | src_loc: Module.SrcLoc, | 634 | src_loc: Module.SrcLoc, |
| 634 | module_fn: *Module.Fn, | 635 | module_fn_index: Module.Fn.Index, |
| 635 | air: Air, | 636 | air: Air, |
| 636 | liveness: Liveness, | 637 | liveness: Liveness, |
| 637 | code: *std.ArrayList(u8), | 638 | code: *std.ArrayList(u8), |
| ... | @@ -642,6 +643,7 @@ pub fn generate( | ... | @@ -642,6 +643,7 @@ pub fn generate( |
| 642 | } | 643 | } |
| 643 | 644 | ||
| 644 | const mod = bin_file.options.module.?; | 645 | const mod = bin_file.options.module.?; |
| 646 | const module_fn = mod.funcPtr(module_fn_index); | ||
| 645 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); | 647 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 646 | assert(fn_owner_decl.has_tv); | 648 | assert(fn_owner_decl.has_tv); |
| 647 | const fn_type = fn_owner_decl.ty; | 649 | const fn_type = fn_owner_decl.ty; |
| ... | @@ -686,7 +688,7 @@ pub fn generate( | ... | @@ -686,7 +688,7 @@ pub fn generate( |
| 686 | @enumToInt(FrameIndex.stack_frame), | 688 | @enumToInt(FrameIndex.stack_frame), |
| 687 | FrameAlloc.init(.{ | 689 | FrameAlloc.init(.{ |
| 688 | .size = 0, | 690 | .size = 0, |
| 689 | .alignment = if (mod.align_stack_fns.get(module_fn)) |set_align_stack| | 691 | .alignment = if (mod.align_stack_fns.get(module_fn_index)) |set_align_stack| |
| 690 | set_align_stack.alignment | 692 | set_align_stack.alignment |
| 691 | else | 693 | else |
| 692 | 1, | 694 | 1, |
| ... | @@ -697,7 +699,8 @@ pub fn generate( | ... | @@ -697,7 +699,8 @@ pub fn generate( |
| 697 | FrameAlloc.init(.{ .size = 0, .alignment = 1 }), | 699 | FrameAlloc.init(.{ .size = 0, .alignment = 1 }), |
| 698 | ); | 700 | ); |
| 699 | 701 | ||
| 700 | var call_info = function.resolveCallingConventionValues(fn_type, &.{}, .args_frame) catch |err| switch (err) { | 702 | const fn_info = mod.typeToFunc(fn_type).?; |
| 703 | var call_info = function.resolveCallingConventionValues(fn_info, &.{}, .args_frame) catch |err| switch (err) { | ||
| 701 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, | 704 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| 702 | error.OutOfRegisters => return Result{ | 705 | error.OutOfRegisters => return Result{ |
| 703 | .fail = try ErrorMsg.create( | 706 | .fail = try ErrorMsg.create( |
| ... | @@ -714,12 +717,12 @@ pub fn generate( | ... | @@ -714,12 +717,12 @@ pub fn generate( |
| 714 | function.args = call_info.args; | 717 | function.args = call_info.args; |
| 715 | function.ret_mcv = call_info.return_value; | 718 | function.ret_mcv = call_info.return_value; |
| 716 | function.frame_allocs.set(@enumToInt(FrameIndex.ret_addr), FrameAlloc.init(.{ | 719 | function.frame_allocs.set(@enumToInt(FrameIndex.ret_addr), FrameAlloc.init(.{ |
| 717 | .size = Type.usize.abiSize(function.target.*), | 720 | .size = Type.usize.abiSize(mod), |
| 718 | .alignment = @min(Type.usize.abiAlignment(function.target.*), call_info.stack_align), | 721 | .alignment = @min(Type.usize.abiAlignment(mod), call_info.stack_align), |
| 719 | })); | 722 | })); |
| 720 | function.frame_allocs.set(@enumToInt(FrameIndex.base_ptr), FrameAlloc.init(.{ | 723 | function.frame_allocs.set(@enumToInt(FrameIndex.base_ptr), FrameAlloc.init(.{ |
| 721 | .size = Type.usize.abiSize(function.target.*), | 724 | .size = Type.usize.abiSize(mod), |
| 722 | .alignment = @min(Type.usize.abiAlignment(function.target.*) * 2, call_info.stack_align), | 725 | .alignment = @min(Type.usize.abiAlignment(mod) * 2, call_info.stack_align), |
| 723 | })); | 726 | })); |
| 724 | function.frame_allocs.set( | 727 | function.frame_allocs.set( |
| 725 | @enumToInt(FrameIndex.args_frame), | 728 | @enumToInt(FrameIndex.args_frame), |
| ... | @@ -1565,7 +1568,8 @@ fn asmMemoryRegisterImmediate( | ... | @@ -1565,7 +1568,8 @@ fn asmMemoryRegisterImmediate( |
| 1565 | } | 1568 | } |
| 1566 | 1569 | ||
| 1567 | fn gen(self: *Self) InnerError!void { | 1570 | fn gen(self: *Self) InnerError!void { |
| 1568 | const cc = self.fn_type.fnCallingConvention(); | 1571 | const mod = self.bin_file.options.module.?; |
| 1572 | const cc = self.fn_type.fnCallingConvention(mod); | ||
| 1569 | if (cc != .Naked) { | 1573 | if (cc != .Naked) { |
| 1570 | try self.asmRegister(.{ ._, .push }, .rbp); | 1574 | try self.asmRegister(.{ ._, .push }, .rbp); |
| 1571 | const backpatch_push_callee_preserved_regs = try self.asmPlaceholder(); | 1575 | const backpatch_push_callee_preserved_regs = try self.asmPlaceholder(); |
| ... | @@ -1582,7 +1586,7 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -1582,7 +1586,7 @@ fn gen(self: *Self) InnerError!void { |
| 1582 | // register which the callee is free to clobber. Therefore, we purposely | 1586 | // register which the callee is free to clobber. Therefore, we purposely |
| 1583 | // spill it to stack immediately. | 1587 | // spill it to stack immediately. |
| 1584 | const frame_index = | 1588 | const frame_index = |
| 1585 | try self.allocFrameIndex(FrameAlloc.initType(Type.usize, self.target.*)); | 1589 | try self.allocFrameIndex(FrameAlloc.initType(Type.usize, mod)); |
| 1586 | try self.genSetMem( | 1590 | try self.genSetMem( |
| 1587 | .{ .frame = frame_index }, | 1591 | .{ .frame = frame_index }, |
| 1588 | 0, | 1592 | 0, |
| ... | @@ -1724,6 +1728,8 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -1724,6 +1728,8 @@ fn gen(self: *Self) InnerError!void { |
| 1724 | } | 1728 | } |
| 1725 | 1729 | ||
| 1726 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | 1730 | fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1731 | const mod = self.bin_file.options.module.?; | ||
| 1732 | const ip = &mod.intern_pool; | ||
| 1727 | const air_tags = self.air.instructions.items(.tag); | 1733 | const air_tags = self.air.instructions.items(.tag); |
| 1728 | 1734 | ||
| 1729 | for (body) |inst| { | 1735 | for (body) |inst| { |
| ... | @@ -1732,7 +1738,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1732,7 +1738,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1732 | try self.mir_to_air_map.put(self.gpa, mir_inst, inst); | 1738 | try self.mir_to_air_map.put(self.gpa, mir_inst, inst); |
| 1733 | } | 1739 | } |
| 1734 | 1740 | ||
| 1735 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue; | 1741 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) continue; |
| 1736 | wip_mir_log.debug("{}", .{self.fmtAir(inst)}); | 1742 | wip_mir_log.debug("{}", .{self.fmtAir(inst)}); |
| 1737 | verbose_tracking_log.debug("{}", .{self.fmtTracking()}); | 1743 | verbose_tracking_log.debug("{}", .{self.fmtTracking()}); |
| 1738 | 1744 | ||
| ... | @@ -1916,8 +1922,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1916,8 +1922,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1916 | .ptr_elem_val => try self.airPtrElemVal(inst), | 1922 | .ptr_elem_val => try self.airPtrElemVal(inst), |
| 1917 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), | 1923 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 1918 | 1924 | ||
| 1919 | .constant => unreachable, // excluded from function bodies | 1925 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, |
| 1920 | .const_ty => unreachable, // excluded from function bodies | ||
| 1921 | .unreach => if (self.wantSafety()) try self.airTrap() else self.finishAirBookkeeping(), | 1926 | .unreach => if (self.wantSafety()) try self.airTrap() else self.finishAirBookkeeping(), |
| 1922 | 1927 | ||
| 1923 | .optional_payload => try self.airOptionalPayload(inst), | 1928 | .optional_payload => try self.airOptionalPayload(inst), |
| ... | @@ -1999,7 +2004,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1999,7 +2004,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1999 | } | 2004 | } |
| 2000 | 2005 | ||
| 2001 | fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { | 2006 | fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2002 | switch (lazy_sym.ty.zigTypeTag()) { | 2007 | const mod = self.bin_file.options.module.?; |
| 2008 | switch (lazy_sym.ty.zigTypeTag(mod)) { | ||
| 2003 | .Enum => { | 2009 | .Enum => { |
| 2004 | const enum_ty = lazy_sym.ty; | 2010 | const enum_ty = lazy_sym.ty; |
| 2005 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); | 2011 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); |
| ... | @@ -2011,7 +2017,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -2011,7 +2017,7 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2011 | const ret_reg = param_regs[0]; | 2017 | const ret_reg = param_regs[0]; |
| 2012 | const enum_mcv = MCValue{ .register = param_regs[1] }; | 2018 | const enum_mcv = MCValue{ .register = param_regs[1] }; |
| 2013 | 2019 | ||
| 2014 | var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount()); | 2020 | var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount(mod)); |
| 2015 | defer self.gpa.free(exitlude_jump_relocs); | 2021 | defer self.gpa.free(exitlude_jump_relocs); |
| 2016 | 2022 | ||
| 2017 | const data_reg = try self.register_manager.allocReg(null, gp); | 2023 | const data_reg = try self.register_manager.allocReg(null, gp); |
| ... | @@ -2020,16 +2026,10 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -2020,16 +2026,10 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2020 | try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty }); | 2026 | try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty }); |
| 2021 | 2027 | ||
| 2022 | var data_off: i32 = 0; | 2028 | var data_off: i32 = 0; |
| 2023 | for ( | 2029 | for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, index_usize| { |
| 2024 | exitlude_jump_relocs, | 2030 | const index = @intCast(u32, index_usize); |
| 2025 | enum_ty.enumFields().keys(), | 2031 | const tag_name = mod.intern_pool.stringToSlice(enum_ty.enumFields(mod)[index_usize]); |
| 2026 | 0.., | 2032 | const tag_val = try mod.enumValueFieldIndex(enum_ty, index); |
| 2027 | ) |*exitlude_jump_reloc, tag_name, index| { | ||
| 2028 | var tag_pl = Value.Payload.U32{ | ||
| 2029 | .base = .{ .tag = .enum_field_index }, | ||
| 2030 | .data = @intCast(u32, index), | ||
| 2031 | }; | ||
| 2032 | const tag_val = Value.initPayload(&tag_pl.base); | ||
| 2033 | const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val }); | 2033 | const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val }); |
| 2034 | try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv); | 2034 | try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv); |
| 2035 | const skip_reloc = try self.asmJccReloc(undefined, .ne); | 2035 | const skip_reloc = try self.asmJccReloc(undefined, .ne); |
| ... | @@ -2092,10 +2092,8 @@ fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) void { | ... | @@ -2092,10 +2092,8 @@ fn feed(self: *Self, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) void { |
| 2092 | 2092 | ||
| 2093 | /// Asserts there is already capacity to insert into top branch inst_table. | 2093 | /// Asserts there is already capacity to insert into top branch inst_table. |
| 2094 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { | 2094 | fn processDeath(self: *Self, inst: Air.Inst.Index) void { |
| 2095 | switch (self.air.instructions.items(.tag)[inst]) { | 2095 | assert(self.air.instructions.items(.tag)[inst] != .interned); |
| 2096 | .constant, .const_ty => unreachable, | 2096 | self.inst_tracking.getPtr(inst).?.die(self, inst); |
| 2097 | else => self.inst_tracking.getPtr(inst).?.die(self, inst), | ||
| 2098 | } | ||
| 2099 | } | 2097 | } |
| 2100 | 2098 | ||
| 2101 | /// Called when there are no operands, and the instruction is always unreferenced. | 2099 | /// Called when there are no operands, and the instruction is always unreferenced. |
| ... | @@ -2126,10 +2124,7 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -2126,10 +2124,7 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 2126 | const dies = @truncate(u1, tomb_bits) != 0; | 2124 | const dies = @truncate(u1, tomb_bits) != 0; |
| 2127 | tomb_bits >>= 1; | 2125 | tomb_bits >>= 1; |
| 2128 | if (!dies) continue; | 2126 | if (!dies) continue; |
| 2129 | const op_int = @enumToInt(op); | 2127 | self.processDeath(Air.refToIndexAllowNone(op) orelse continue); |
| 2130 | if (op_int < Air.Inst.Ref.typed_value_map.len) continue; | ||
| 2131 | const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len); | ||
| 2132 | self.processDeath(op_index); | ||
| 2133 | } | 2128 | } |
| 2134 | self.finishAirResult(inst, result); | 2129 | self.finishAirResult(inst, result); |
| 2135 | } | 2130 | } |
| ... | @@ -2252,19 +2247,19 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { | ... | @@ -2252,19 +2247,19 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 2252 | 2247 | ||
| 2253 | /// Use a pointer instruction as the basis for allocating stack memory. | 2248 | /// Use a pointer instruction as the basis for allocating stack memory. |
| 2254 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { | 2249 | fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { |
| 2255 | const ptr_ty = self.air.typeOfIndex(inst); | 2250 | const mod = self.bin_file.options.module.?; |
| 2256 | const val_ty = ptr_ty.childType(); | 2251 | const ptr_ty = self.typeOfIndex(inst); |
| 2252 | const val_ty = ptr_ty.childType(mod); | ||
| 2257 | return self.allocFrameIndex(FrameAlloc.init(.{ | 2253 | return self.allocFrameIndex(FrameAlloc.init(.{ |
| 2258 | .size = math.cast(u32, val_ty.abiSize(self.target.*)) orelse { | 2254 | .size = math.cast(u32, val_ty.abiSize(mod)) orelse { |
| 2259 | const mod = self.bin_file.options.module.?; | ||
| 2260 | return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(mod)}); | 2255 | return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(mod)}); |
| 2261 | }, | 2256 | }, |
| 2262 | .alignment = @max(ptr_ty.ptrAlignment(self.target.*), 1), | 2257 | .alignment = @max(ptr_ty.ptrAlignment(mod), 1), |
| 2263 | })); | 2258 | })); |
| 2264 | } | 2259 | } |
| 2265 | 2260 | ||
| 2266 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | 2261 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 2267 | return self.allocRegOrMemAdvanced(self.air.typeOfIndex(inst), inst, reg_ok); | 2262 | return self.allocRegOrMemAdvanced(self.typeOfIndex(inst), inst, reg_ok); |
| 2268 | } | 2263 | } |
| 2269 | 2264 | ||
| 2270 | fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue { | 2265 | fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue { |
| ... | @@ -2272,20 +2267,20 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue { | ... | @@ -2272,20 +2267,20 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue { |
| 2272 | } | 2267 | } |
| 2273 | 2268 | ||
| 2274 | fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { | 2269 | fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { |
| 2275 | const abi_size = math.cast(u32, ty.abiSize(self.target.*)) orelse { | 2270 | const mod = self.bin_file.options.module.?; |
| 2276 | const mod = self.bin_file.options.module.?; | 2271 | const abi_size = math.cast(u32, ty.abiSize(mod)) orelse { |
| 2277 | return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)}); | 2272 | return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)}); |
| 2278 | }; | 2273 | }; |
| 2279 | 2274 | ||
| 2280 | if (reg_ok) need_mem: { | 2275 | if (reg_ok) need_mem: { |
| 2281 | if (abi_size <= @as(u32, switch (ty.zigTypeTag()) { | 2276 | if (abi_size <= @as(u32, switch (ty.zigTypeTag(mod)) { |
| 2282 | .Float => switch (ty.floatBits(self.target.*)) { | 2277 | .Float => switch (ty.floatBits(self.target.*)) { |
| 2283 | 16, 32, 64, 128 => 16, | 2278 | 16, 32, 64, 128 => 16, |
| 2284 | 80 => break :need_mem, | 2279 | 80 => break :need_mem, |
| 2285 | else => unreachable, | 2280 | else => unreachable, |
| 2286 | }, | 2281 | }, |
| 2287 | .Vector => switch (ty.childType().zigTypeTag()) { | 2282 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { |
| 2288 | .Float => switch (ty.childType().floatBits(self.target.*)) { | 2283 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 2289 | 16, 32, 64, 128 => if (self.hasFeature(.avx)) 32 else 16, | 2284 | 16, 32, 64, 128 => if (self.hasFeature(.avx)) 32 else 16, |
| 2290 | 80 => break :need_mem, | 2285 | 80 => break :need_mem, |
| 2291 | else => unreachable, | 2286 | else => unreachable, |
| ... | @@ -2294,18 +2289,18 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b | ... | @@ -2294,18 +2289,18 @@ fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: b |
| 2294 | }, | 2289 | }, |
| 2295 | else => 8, | 2290 | else => 8, |
| 2296 | })) { | 2291 | })) { |
| 2297 | if (self.register_manager.tryAllocReg(inst, regClassForType(ty))) |reg| { | 2292 | if (self.register_manager.tryAllocReg(inst, regClassForType(ty, mod))) |reg| { |
| 2298 | return MCValue{ .register = registerAlias(reg, abi_size) }; | 2293 | return MCValue{ .register = registerAlias(reg, abi_size) }; |
| 2299 | } | 2294 | } |
| 2300 | } | 2295 | } |
| 2301 | } | 2296 | } |
| 2302 | 2297 | ||
| 2303 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(ty, self.target.*)); | 2298 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(ty, mod)); |
| 2304 | return .{ .load_frame = .{ .index = frame_index } }; | 2299 | return .{ .load_frame = .{ .index = frame_index } }; |
| 2305 | } | 2300 | } |
| 2306 | 2301 | ||
| 2307 | fn regClassForType(ty: Type) RegisterManager.RegisterBitSet { | 2302 | fn regClassForType(ty: Type, mod: *Module) RegisterManager.RegisterBitSet { |
| 2308 | return switch (ty.zigTypeTag()) { | 2303 | return switch (ty.zigTypeTag(mod)) { |
| 2309 | .Float, .Vector => sse, | 2304 | .Float, .Vector => sse, |
| 2310 | else => gp, | 2305 | else => gp, |
| 2311 | }; | 2306 | }; |
| ... | @@ -2449,7 +2444,8 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void { | ... | @@ -2449,7 +2444,8 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void { |
| 2449 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 2444 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 2450 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 2445 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 2451 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 2446 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 2452 | const reg = try self.register_manager.allocReg(null, regClassForType(ty)); | 2447 | const mod = self.bin_file.options.module.?; |
| 2448 | const reg = try self.register_manager.allocReg(null, regClassForType(ty, mod)); | ||
| 2453 | try self.genSetReg(reg, ty, mcv); | 2449 | try self.genSetReg(reg, ty, mcv); |
| 2454 | return reg; | 2450 | return reg; |
| 2455 | } | 2451 | } |
| ... | @@ -2464,7 +2460,8 @@ fn copyToRegisterWithInstTracking( | ... | @@ -2464,7 +2460,8 @@ fn copyToRegisterWithInstTracking( |
| 2464 | ty: Type, | 2460 | ty: Type, |
| 2465 | mcv: MCValue, | 2461 | mcv: MCValue, |
| 2466 | ) !MCValue { | 2462 | ) !MCValue { |
| 2467 | const reg: Register = try self.register_manager.allocReg(reg_owner, regClassForType(ty)); | 2463 | const mod = self.bin_file.options.module.?; |
| 2464 | const reg: Register = try self.register_manager.allocReg(reg_owner, regClassForType(ty, mod)); | ||
| 2468 | try self.genSetReg(reg, ty, mcv); | 2465 | try self.genSetReg(reg, ty, mcv); |
| 2469 | return MCValue{ .register = reg }; | 2466 | return MCValue{ .register = reg }; |
| 2470 | } | 2467 | } |
| ... | @@ -2481,7 +2478,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2481,7 +2478,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2481 | .load_frame => .{ .register_offset = .{ | 2478 | .load_frame => .{ .register_offset = .{ |
| 2482 | .reg = (try self.copyToRegisterWithInstTracking( | 2479 | .reg = (try self.copyToRegisterWithInstTracking( |
| 2483 | inst, | 2480 | inst, |
| 2484 | self.air.typeOfIndex(inst), | 2481 | self.typeOfIndex(inst), |
| 2485 | self.ret_mcv.long, | 2482 | self.ret_mcv.long, |
| 2486 | )).register, | 2483 | )).register, |
| 2487 | .off = self.ret_mcv.short.indirect.off, | 2484 | .off = self.ret_mcv.short.indirect.off, |
| ... | @@ -2492,9 +2489,9 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2492,9 +2489,9 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 2492 | 2489 | ||
| 2493 | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { | 2490 | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2494 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2491 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2495 | const dst_ty = self.air.typeOfIndex(inst); | 2492 | const dst_ty = self.typeOfIndex(inst); |
| 2496 | const dst_bits = dst_ty.floatBits(self.target.*); | 2493 | const dst_bits = dst_ty.floatBits(self.target.*); |
| 2497 | const src_ty = self.air.typeOf(ty_op.operand); | 2494 | const src_ty = self.typeOf(ty_op.operand); |
| 2498 | const src_bits = src_ty.floatBits(self.target.*); | 2495 | const src_bits = src_ty.floatBits(self.target.*); |
| 2499 | 2496 | ||
| 2500 | const src_mcv = try self.resolveInst(ty_op.operand); | 2497 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | @@ -2558,9 +2555,9 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2558,9 +2555,9 @@ fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2558 | 2555 | ||
| 2559 | fn airFpext(self: *Self, inst: Air.Inst.Index) !void { | 2556 | fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 2560 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2557 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2561 | const dst_ty = self.air.typeOfIndex(inst); | 2558 | const dst_ty = self.typeOfIndex(inst); |
| 2562 | const dst_bits = dst_ty.floatBits(self.target.*); | 2559 | const dst_bits = dst_ty.floatBits(self.target.*); |
| 2563 | const src_ty = self.air.typeOf(ty_op.operand); | 2560 | const src_ty = self.typeOf(ty_op.operand); |
| 2564 | const src_bits = src_ty.floatBits(self.target.*); | 2561 | const src_bits = src_ty.floatBits(self.target.*); |
| 2565 | 2562 | ||
| 2566 | const src_mcv = try self.resolveInst(ty_op.operand); | 2563 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | @@ -2618,14 +2615,15 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2618,14 +2615,15 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 2618 | } | 2615 | } |
| 2619 | 2616 | ||
| 2620 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | 2617 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2618 | const mod = self.bin_file.options.module.?; | ||
| 2621 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2619 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2622 | const result: MCValue = result: { | 2620 | const result: MCValue = result: { |
| 2623 | const src_ty = self.air.typeOf(ty_op.operand); | 2621 | const src_ty = self.typeOf(ty_op.operand); |
| 2624 | const src_int_info = src_ty.intInfo(self.target.*); | 2622 | const src_int_info = src_ty.intInfo(mod); |
| 2625 | 2623 | ||
| 2626 | const dst_ty = self.air.typeOfIndex(inst); | 2624 | const dst_ty = self.typeOfIndex(inst); |
| 2627 | const dst_int_info = dst_ty.intInfo(self.target.*); | 2625 | const dst_int_info = dst_ty.intInfo(mod); |
| 2628 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 2626 | const abi_size = @intCast(u32, dst_ty.abiSize(mod)); |
| 2629 | 2627 | ||
| 2630 | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; | 2628 | const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty; |
| 2631 | const extend = switch (src_int_info.signedness) { | 2629 | const extend = switch (src_int_info.signedness) { |
| ... | @@ -2670,14 +2668,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2670,14 +2668,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2670 | 2668 | ||
| 2671 | const high_bits = src_int_info.bits % 64; | 2669 | const high_bits = src_int_info.bits % 64; |
| 2672 | if (high_bits > 0) { | 2670 | if (high_bits > 0) { |
| 2673 | var high_pl = Type.Payload.Bits{ | 2671 | const high_ty = try mod.intType(extend, high_bits); |
| 2674 | .base = .{ .tag = switch (extend) { | ||
| 2675 | .signed => .int_signed, | ||
| 2676 | .unsigned => .int_unsigned, | ||
| 2677 | } }, | ||
| 2678 | .data = high_bits, | ||
| 2679 | }; | ||
| 2680 | const high_ty = Type.initPayload(&high_pl.base); | ||
| 2681 | try self.truncateRegister(high_ty, high_reg); | 2672 | try self.truncateRegister(high_ty, high_reg); |
| 2682 | try self.genCopy(Type.usize, high_mcv, .{ .register = high_reg }); | 2673 | try self.genCopy(Type.usize, high_mcv, .{ .register = high_reg }); |
| 2683 | } | 2674 | } |
| ... | @@ -2706,12 +2697,13 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2706,12 +2697,13 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2706 | } | 2697 | } |
| 2707 | 2698 | ||
| 2708 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 2699 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2700 | const mod = self.bin_file.options.module.?; | ||
| 2709 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2701 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2710 | 2702 | ||
| 2711 | const dst_ty = self.air.typeOfIndex(inst); | 2703 | const dst_ty = self.typeOfIndex(inst); |
| 2712 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 2704 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(mod)); |
| 2713 | const src_ty = self.air.typeOf(ty_op.operand); | 2705 | const src_ty = self.typeOf(ty_op.operand); |
| 2714 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | 2706 | const src_abi_size = @intCast(u32, src_ty.abiSize(mod)); |
| 2715 | 2707 | ||
| 2716 | const result = result: { | 2708 | const result = result: { |
| 2717 | const src_mcv = try self.resolveInst(ty_op.operand); | 2709 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | @@ -2724,13 +2716,13 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2724,13 +2716,13 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2724 | else | 2716 | else |
| 2725 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); | 2717 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 2726 | 2718 | ||
| 2727 | if (dst_ty.zigTypeTag() == .Vector) { | 2719 | if (dst_ty.zigTypeTag(mod) == .Vector) { |
| 2728 | assert(src_ty.zigTypeTag() == .Vector and dst_ty.vectorLen() == src_ty.vectorLen()); | 2720 | assert(src_ty.zigTypeTag(mod) == .Vector and dst_ty.vectorLen(mod) == src_ty.vectorLen(mod)); |
| 2729 | const dst_info = dst_ty.childType().intInfo(self.target.*); | 2721 | const dst_info = dst_ty.childType(mod).intInfo(mod); |
| 2730 | const src_info = src_ty.childType().intInfo(self.target.*); | 2722 | const src_info = src_ty.childType(mod).intInfo(mod); |
| 2731 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (dst_info.bits) { | 2723 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (dst_info.bits) { |
| 2732 | 8 => switch (src_info.bits) { | 2724 | 8 => switch (src_info.bits) { |
| 2733 | 16 => switch (dst_ty.vectorLen()) { | 2725 | 16 => switch (dst_ty.vectorLen(mod)) { |
| 2734 | 1...8 => if (self.hasFeature(.avx)) .{ .vp_b, .ackusw } else .{ .p_b, .ackusw }, | 2726 | 1...8 => if (self.hasFeature(.avx)) .{ .vp_b, .ackusw } else .{ .p_b, .ackusw }, |
| 2735 | 9...16 => if (self.hasFeature(.avx2)) .{ .vp_b, .ackusw } else null, | 2727 | 9...16 => if (self.hasFeature(.avx2)) .{ .vp_b, .ackusw } else null, |
| 2736 | else => null, | 2728 | else => null, |
| ... | @@ -2738,7 +2730,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2738,7 +2730,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2738 | else => null, | 2730 | else => null, |
| 2739 | }, | 2731 | }, |
| 2740 | 16 => switch (src_info.bits) { | 2732 | 16 => switch (src_info.bits) { |
| 2741 | 32 => switch (dst_ty.vectorLen()) { | 2733 | 32 => switch (dst_ty.vectorLen(mod)) { |
| 2742 | 1...4 => if (self.hasFeature(.avx)) | 2734 | 1...4 => if (self.hasFeature(.avx)) |
| 2743 | .{ .vp_w, .ackusd } | 2735 | .{ .vp_w, .ackusd } |
| 2744 | else if (self.hasFeature(.sse4_1)) | 2736 | else if (self.hasFeature(.sse4_1)) |
| ... | @@ -2755,29 +2747,21 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2755,29 +2747,21 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2755 | dst_ty.fmt(self.bin_file.options.module.?), | 2747 | dst_ty.fmt(self.bin_file.options.module.?), |
| 2756 | }); | 2748 | }); |
| 2757 | 2749 | ||
| 2758 | var mask_pl = Value.Payload.U64{ | 2750 | const elem_ty = src_ty.childType(mod); |
| 2759 | .base = .{ .tag = .int_u64 }, | 2751 | const mask_val = try mod.intValue(elem_ty, @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - dst_info.bits)); |
| 2760 | .data = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - dst_info.bits), | ||
| 2761 | }; | ||
| 2762 | const mask_val = Value.initPayload(&mask_pl.base); | ||
| 2763 | 2752 | ||
| 2764 | var splat_pl = Value.Payload.SubValue{ | 2753 | const splat_ty = try mod.vectorType(.{ |
| 2765 | .base = .{ .tag = .repeated }, | 2754 | .len = @intCast(u32, @divExact(@as(u64, if (src_abi_size > 16) 256 else 128), src_info.bits)), |
| 2766 | .data = mask_val, | 2755 | .child = elem_ty.ip_index, |
| 2767 | }; | 2756 | }); |
| 2768 | const splat_val = Value.initPayload(&splat_pl.base); | 2757 | const splat_abi_size = @intCast(u32, splat_ty.abiSize(mod)); |
| 2769 | 2758 | ||
| 2770 | var full_pl = Type.Payload.Array{ | 2759 | const splat_val = try mod.intern(.{ .aggregate = .{ |
| 2771 | .base = .{ .tag = .vector }, | 2760 | .ty = splat_ty.ip_index, |
| 2772 | .data = .{ | 2761 | .storage = .{ .repeated_elem = mask_val.ip_index }, |
| 2773 | .len = @divExact(@as(u64, if (src_abi_size > 16) 256 else 128), src_info.bits), | 2762 | } }); |
| 2774 | .elem_type = src_ty.childType(), | ||
| 2775 | }, | ||
| 2776 | }; | ||
| 2777 | const full_ty = Type.initPayload(&full_pl.base); | ||
| 2778 | const full_abi_size = @intCast(u32, full_ty.abiSize(self.target.*)); | ||
| 2779 | 2763 | ||
| 2780 | const splat_mcv = try self.genTypedValue(.{ .ty = full_ty, .val = splat_val }); | 2764 | const splat_mcv = try self.genTypedValue(.{ .ty = splat_ty, .val = splat_val.toValue() }); |
| 2781 | const splat_addr_mcv: MCValue = switch (splat_mcv) { | 2765 | const splat_addr_mcv: MCValue = switch (splat_mcv) { |
| 2782 | .memory, .indirect, .load_frame => splat_mcv.address(), | 2766 | .memory, .indirect, .load_frame => splat_mcv.address(), |
| 2783 | else => .{ .register = try self.copyToTmpRegister(Type.usize, splat_mcv.address()) }, | 2767 | else => .{ .register = try self.copyToTmpRegister(Type.usize, splat_mcv.address()) }, |
| ... | @@ -2789,14 +2773,14 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2789,14 +2773,14 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2789 | .{ .vp_, .@"and" }, | 2773 | .{ .vp_, .@"and" }, |
| 2790 | dst_reg, | 2774 | dst_reg, |
| 2791 | dst_reg, | 2775 | dst_reg, |
| 2792 | splat_addr_mcv.deref().mem(Memory.PtrSize.fromSize(full_abi_size)), | 2776 | splat_addr_mcv.deref().mem(Memory.PtrSize.fromSize(splat_abi_size)), |
| 2793 | ); | 2777 | ); |
| 2794 | try self.asmRegisterRegisterRegister(mir_tag, dst_reg, dst_reg, dst_reg); | 2778 | try self.asmRegisterRegisterRegister(mir_tag, dst_reg, dst_reg, dst_reg); |
| 2795 | } else { | 2779 | } else { |
| 2796 | try self.asmRegisterMemory( | 2780 | try self.asmRegisterMemory( |
| 2797 | .{ .p_, .@"and" }, | 2781 | .{ .p_, .@"and" }, |
| 2798 | dst_reg, | 2782 | dst_reg, |
| 2799 | splat_addr_mcv.deref().mem(Memory.PtrSize.fromSize(full_abi_size)), | 2783 | splat_addr_mcv.deref().mem(Memory.PtrSize.fromSize(splat_abi_size)), |
| 2800 | ); | 2784 | ); |
| 2801 | try self.asmRegisterRegister(mir_tag, dst_reg, dst_reg); | 2785 | try self.asmRegisterRegister(mir_tag, dst_reg, dst_reg); |
| 2802 | } | 2786 | } |
| ... | @@ -2819,7 +2803,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2819,7 +2803,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2819 | 2803 | ||
| 2820 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | 2804 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 2821 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2805 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2822 | const ty = self.air.typeOfIndex(inst); | 2806 | const ty = self.typeOfIndex(inst); |
| 2823 | 2807 | ||
| 2824 | const operand = try self.resolveInst(un_op); | 2808 | const operand = try self.resolveInst(un_op); |
| 2825 | const dst_mcv = if (self.reuseOperand(inst, un_op, 0, operand)) | 2809 | const dst_mcv = if (self.reuseOperand(inst, un_op, 0, operand)) |
| ... | @@ -2831,20 +2815,21 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2831,20 +2815,21 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 2831 | } | 2815 | } |
| 2832 | 2816 | ||
| 2833 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { | 2817 | fn airSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 2818 | const mod = self.bin_file.options.module.?; | ||
| 2834 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2819 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2835 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2820 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2836 | 2821 | ||
| 2837 | const slice_ty = self.air.typeOfIndex(inst); | 2822 | const slice_ty = self.typeOfIndex(inst); |
| 2838 | const ptr = try self.resolveInst(bin_op.lhs); | 2823 | const ptr = try self.resolveInst(bin_op.lhs); |
| 2839 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2824 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2840 | const len = try self.resolveInst(bin_op.rhs); | 2825 | const len = try self.resolveInst(bin_op.rhs); |
| 2841 | const len_ty = self.air.typeOf(bin_op.rhs); | 2826 | const len_ty = self.typeOf(bin_op.rhs); |
| 2842 | 2827 | ||
| 2843 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(slice_ty, self.target.*)); | 2828 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(slice_ty, mod)); |
| 2844 | try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, ptr); | 2829 | try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, ptr); |
| 2845 | try self.genSetMem( | 2830 | try self.genSetMem( |
| 2846 | .{ .frame = frame_index }, | 2831 | .{ .frame = frame_index }, |
| 2847 | @intCast(i32, ptr_ty.abiSize(self.target.*)), | 2832 | @intCast(i32, ptr_ty.abiSize(mod)), |
| 2848 | len_ty, | 2833 | len_ty, |
| 2849 | len, | 2834 | len, |
| 2850 | ); | 2835 | ); |
| ... | @@ -2873,23 +2858,24 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void | ... | @@ -2873,23 +2858,24 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void |
| 2873 | } | 2858 | } |
| 2874 | 2859 | ||
| 2875 | fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { | 2860 | fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| 2861 | const mod = self.bin_file.options.module.?; | ||
| 2876 | const air_tag = self.air.instructions.items(.tag); | 2862 | const air_tag = self.air.instructions.items(.tag); |
| 2877 | const air_data = self.air.instructions.items(.data); | 2863 | const air_data = self.air.instructions.items(.data); |
| 2878 | 2864 | ||
| 2879 | const dst_ty = self.air.typeOf(dst_air); | 2865 | const dst_ty = self.typeOf(dst_air); |
| 2880 | const dst_info = dst_ty.intInfo(self.target.*); | 2866 | const dst_info = dst_ty.intInfo(mod); |
| 2881 | if (Air.refToIndex(dst_air)) |inst| { | 2867 | if (Air.refToIndex(dst_air)) |inst| { |
| 2882 | switch (air_tag[inst]) { | 2868 | switch (air_tag[inst]) { |
| 2883 | .constant => { | 2869 | .interned => { |
| 2884 | const src_val = self.air.values[air_data[inst].ty_pl.payload]; | 2870 | const src_val = air_data[inst].interned.toValue(); |
| 2885 | var space: Value.BigIntSpace = undefined; | 2871 | var space: Value.BigIntSpace = undefined; |
| 2886 | const src_int = src_val.toBigInt(&space, self.target.*); | 2872 | const src_int = src_val.toBigInt(&space, mod); |
| 2887 | return @intCast(u16, src_int.bitCountTwosComp()) + | 2873 | return @intCast(u16, src_int.bitCountTwosComp()) + |
| 2888 | @boolToInt(src_int.positive and dst_info.signedness == .signed); | 2874 | @boolToInt(src_int.positive and dst_info.signedness == .signed); |
| 2889 | }, | 2875 | }, |
| 2890 | .intcast => { | 2876 | .intcast => { |
| 2891 | const src_ty = self.air.typeOf(air_data[inst].ty_op.operand); | 2877 | const src_ty = self.typeOf(air_data[inst].ty_op.operand); |
| 2892 | const src_info = src_ty.intInfo(self.target.*); | 2878 | const src_info = src_ty.intInfo(mod); |
| 2893 | return @min(switch (src_info.signedness) { | 2879 | return @min(switch (src_info.signedness) { |
| 2894 | .signed => switch (dst_info.signedness) { | 2880 | .signed => switch (dst_info.signedness) { |
| 2895 | .signed => src_info.bits, | 2881 | .signed => src_info.bits, |
| ... | @@ -2908,20 +2894,18 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { | ... | @@ -2908,20 +2894,18 @@ fn activeIntBits(self: *Self, dst_air: Air.Inst.Ref) u16 { |
| 2908 | } | 2894 | } |
| 2909 | 2895 | ||
| 2910 | fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { | 2896 | fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2897 | const mod = self.bin_file.options.module.?; | ||
| 2911 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2898 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2912 | const result = result: { | 2899 | const result = result: { |
| 2913 | const tag = self.air.instructions.items(.tag)[inst]; | 2900 | const tag = self.air.instructions.items(.tag)[inst]; |
| 2914 | const dst_ty = self.air.typeOfIndex(inst); | 2901 | const dst_ty = self.typeOfIndex(inst); |
| 2915 | switch (dst_ty.zigTypeTag()) { | 2902 | switch (dst_ty.zigTypeTag(mod)) { |
| 2916 | .Float, .Vector => break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs), | 2903 | .Float, .Vector => break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs), |
| 2917 | else => {}, | 2904 | else => {}, |
| 2918 | } | 2905 | } |
| 2919 | 2906 | ||
| 2920 | const dst_info = dst_ty.intInfo(self.target.*); | 2907 | const dst_info = dst_ty.intInfo(mod); |
| 2921 | var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { | 2908 | const src_ty = try mod.intType(dst_info.signedness, switch (tag) { |
| 2922 | .signed => .int_signed, | ||
| 2923 | .unsigned => .int_unsigned, | ||
| 2924 | } }, .data = switch (tag) { | ||
| 2925 | else => unreachable, | 2909 | else => unreachable, |
| 2926 | .mul, .mulwrap => math.max3( | 2910 | .mul, .mulwrap => math.max3( |
| 2927 | self.activeIntBits(bin_op.lhs), | 2911 | self.activeIntBits(bin_op.lhs), |
| ... | @@ -2929,8 +2913,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2929,8 +2913,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2929 | dst_info.bits / 2, | 2913 | dst_info.bits / 2, |
| 2930 | ), | 2914 | ), |
| 2931 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_info.bits, | 2915 | .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_info.bits, |
| 2932 | } }; | 2916 | }); |
| 2933 | const src_ty = Type.initPayload(&src_pl.base); | ||
| 2934 | 2917 | ||
| 2935 | try self.spillEflagsIfOccupied(); | 2918 | try self.spillEflagsIfOccupied(); |
| 2936 | try self.spillRegisters(&.{ .rax, .rdx }); | 2919 | try self.spillRegisters(&.{ .rax, .rdx }); |
| ... | @@ -2942,8 +2925,9 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2942,8 +2925,9 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2942 | } | 2925 | } |
| 2943 | 2926 | ||
| 2944 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | 2927 | fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2928 | const mod = self.bin_file.options.module.?; | ||
| 2945 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2929 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2946 | const ty = self.air.typeOf(bin_op.lhs); | 2930 | const ty = self.typeOf(bin_op.lhs); |
| 2947 | 2931 | ||
| 2948 | const lhs_mcv = try self.resolveInst(bin_op.lhs); | 2932 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 2949 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) | 2933 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) |
| ... | @@ -2968,7 +2952,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2968,7 +2952,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2968 | 2952 | ||
| 2969 | const reg_bits = self.regBitSize(ty); | 2953 | const reg_bits = self.regBitSize(ty); |
| 2970 | const reg_extra_bits = self.regExtraBits(ty); | 2954 | const reg_extra_bits = self.regExtraBits(ty); |
| 2971 | const cc: Condition = if (ty.isSignedInt()) cc: { | 2955 | const cc: Condition = if (ty.isSignedInt(mod)) cc: { |
| 2972 | if (reg_extra_bits > 0) { | 2956 | if (reg_extra_bits > 0) { |
| 2973 | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); | 2957 | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| 2974 | } | 2958 | } |
| ... | @@ -2994,7 +2978,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2994,7 +2978,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 2994 | break :cc .o; | 2978 | break :cc .o; |
| 2995 | } else cc: { | 2979 | } else cc: { |
| 2996 | try self.genSetReg(limit_reg, ty, .{ | 2980 | try self.genSetReg(limit_reg, ty, .{ |
| 2997 | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - ty.bitSize(self.target.*)), | 2981 | .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - ty.bitSize(mod)), |
| 2998 | }); | 2982 | }); |
| 2999 | 2983 | ||
| 3000 | try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv); | 2984 | try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv); |
| ... | @@ -3005,14 +2989,14 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3005,14 +2989,14 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3005 | break :cc .c; | 2989 | break :cc .c; |
| 3006 | }; | 2990 | }; |
| 3007 | 2991 | ||
| 3008 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); | 2992 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(mod)), 2); |
| 3009 | try self.asmCmovccRegisterRegister( | 2993 | try self.asmCmovccRegisterRegister( |
| 3010 | registerAlias(dst_reg, cmov_abi_size), | 2994 | registerAlias(dst_reg, cmov_abi_size), |
| 3011 | registerAlias(limit_reg, cmov_abi_size), | 2995 | registerAlias(limit_reg, cmov_abi_size), |
| 3012 | cc, | 2996 | cc, |
| 3013 | ); | 2997 | ); |
| 3014 | 2998 | ||
| 3015 | if (reg_extra_bits > 0 and ty.isSignedInt()) { | 2999 | if (reg_extra_bits > 0 and ty.isSignedInt(mod)) { |
| 3016 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); | 3000 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| 3017 | } | 3001 | } |
| 3018 | 3002 | ||
| ... | @@ -3020,8 +3004,9 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3020,8 +3004,9 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3020 | } | 3004 | } |
| 3021 | 3005 | ||
| 3022 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | 3006 | fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3007 | const mod = self.bin_file.options.module.?; | ||
| 3023 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 3008 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3024 | const ty = self.air.typeOf(bin_op.lhs); | 3009 | const ty = self.typeOf(bin_op.lhs); |
| 3025 | 3010 | ||
| 3026 | const lhs_mcv = try self.resolveInst(bin_op.lhs); | 3011 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 3027 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) | 3012 | const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) |
| ... | @@ -3046,7 +3031,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3046,7 +3031,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3046 | 3031 | ||
| 3047 | const reg_bits = self.regBitSize(ty); | 3032 | const reg_bits = self.regBitSize(ty); |
| 3048 | const reg_extra_bits = self.regExtraBits(ty); | 3033 | const reg_extra_bits = self.regExtraBits(ty); |
| 3049 | const cc: Condition = if (ty.isSignedInt()) cc: { | 3034 | const cc: Condition = if (ty.isSignedInt(mod)) cc: { |
| 3050 | if (reg_extra_bits > 0) { | 3035 | if (reg_extra_bits > 0) { |
| 3051 | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); | 3036 | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| 3052 | } | 3037 | } |
| ... | @@ -3076,14 +3061,14 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3076,14 +3061,14 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3076 | break :cc .c; | 3061 | break :cc .c; |
| 3077 | }; | 3062 | }; |
| 3078 | 3063 | ||
| 3079 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); | 3064 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(mod)), 2); |
| 3080 | try self.asmCmovccRegisterRegister( | 3065 | try self.asmCmovccRegisterRegister( |
| 3081 | registerAlias(dst_reg, cmov_abi_size), | 3066 | registerAlias(dst_reg, cmov_abi_size), |
| 3082 | registerAlias(limit_reg, cmov_abi_size), | 3067 | registerAlias(limit_reg, cmov_abi_size), |
| 3083 | cc, | 3068 | cc, |
| 3084 | ); | 3069 | ); |
| 3085 | 3070 | ||
| 3086 | if (reg_extra_bits > 0 and ty.isSignedInt()) { | 3071 | if (reg_extra_bits > 0 and ty.isSignedInt(mod)) { |
| 3087 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); | 3072 | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| 3088 | } | 3073 | } |
| 3089 | 3074 | ||
| ... | @@ -3091,8 +3076,9 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3091,8 +3076,9 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3091 | } | 3076 | } |
| 3092 | 3077 | ||
| 3093 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | 3078 | fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3079 | const mod = self.bin_file.options.module.?; | ||
| 3094 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 3080 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3095 | const ty = self.air.typeOf(bin_op.lhs); | 3081 | const ty = self.typeOf(bin_op.lhs); |
| 3096 | 3082 | ||
| 3097 | try self.spillRegisters(&.{ .rax, .rdx }); | 3083 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 3098 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); | 3084 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| ... | @@ -3118,7 +3104,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3118,7 +3104,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3118 | defer self.register_manager.unlockReg(limit_lock); | 3104 | defer self.register_manager.unlockReg(limit_lock); |
| 3119 | 3105 | ||
| 3120 | const reg_bits = self.regBitSize(ty); | 3106 | const reg_bits = self.regBitSize(ty); |
| 3121 | const cc: Condition = if (ty.isSignedInt()) cc: { | 3107 | const cc: Condition = if (ty.isSignedInt(mod)) cc: { |
| 3122 | try self.genSetReg(limit_reg, ty, lhs_mcv); | 3108 | try self.genSetReg(limit_reg, ty, lhs_mcv); |
| 3123 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv); | 3109 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv); |
| 3124 | try self.genShiftBinOpMir(.{ ._, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); | 3110 | try self.genShiftBinOpMir(.{ ._, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| ... | @@ -3134,7 +3120,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3134,7 +3120,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3134 | }; | 3120 | }; |
| 3135 | 3121 | ||
| 3136 | const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, ty, lhs_mcv, rhs_mcv); | 3122 | const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, ty, lhs_mcv, rhs_mcv); |
| 3137 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2); | 3123 | const cmov_abi_size = @max(@intCast(u32, ty.abiSize(mod)), 2); |
| 3138 | try self.asmCmovccRegisterRegister( | 3124 | try self.asmCmovccRegisterRegister( |
| 3139 | registerAlias(dst_mcv.register, cmov_abi_size), | 3125 | registerAlias(dst_mcv.register, cmov_abi_size), |
| 3140 | registerAlias(limit_reg, cmov_abi_size), | 3126 | registerAlias(limit_reg, cmov_abi_size), |
| ... | @@ -3145,12 +3131,13 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3145,12 +3131,13 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3145 | } | 3131 | } |
| 3146 | 3132 | ||
| 3147 | fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 3133 | fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3134 | const mod = self.bin_file.options.module.?; | ||
| 3148 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 3135 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3149 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 3136 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3150 | const result: MCValue = result: { | 3137 | const result: MCValue = result: { |
| 3151 | const tag = self.air.instructions.items(.tag)[inst]; | 3138 | const tag = self.air.instructions.items(.tag)[inst]; |
| 3152 | const ty = self.air.typeOf(bin_op.lhs); | 3139 | const ty = self.typeOf(bin_op.lhs); |
| 3153 | switch (ty.zigTypeTag()) { | 3140 | switch (ty.zigTypeTag(mod)) { |
| 3154 | .Vector => return self.fail("TODO implement add/sub with overflow for Vector type", .{}), | 3141 | .Vector => return self.fail("TODO implement add/sub with overflow for Vector type", .{}), |
| 3155 | .Int => { | 3142 | .Int => { |
| 3156 | try self.spillEflagsIfOccupied(); | 3143 | try self.spillEflagsIfOccupied(); |
| ... | @@ -3160,13 +3147,13 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3160,13 +3147,13 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3160 | .sub_with_overflow => .sub, | 3147 | .sub_with_overflow => .sub, |
| 3161 | else => unreachable, | 3148 | else => unreachable, |
| 3162 | }, bin_op.lhs, bin_op.rhs); | 3149 | }, bin_op.lhs, bin_op.rhs); |
| 3163 | const int_info = ty.intInfo(self.target.*); | 3150 | const int_info = ty.intInfo(mod); |
| 3164 | const cc: Condition = switch (int_info.signedness) { | 3151 | const cc: Condition = switch (int_info.signedness) { |
| 3165 | .unsigned => .c, | 3152 | .unsigned => .c, |
| 3166 | .signed => .o, | 3153 | .signed => .o, |
| 3167 | }; | 3154 | }; |
| 3168 | 3155 | ||
| 3169 | const tuple_ty = self.air.typeOfIndex(inst); | 3156 | const tuple_ty = self.typeOfIndex(inst); |
| 3170 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { | 3157 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 3171 | switch (partial_mcv) { | 3158 | switch (partial_mcv) { |
| 3172 | .register => |reg| { | 3159 | .register => |reg| { |
| ... | @@ -3177,16 +3164,16 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3177,16 +3164,16 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3177 | } | 3164 | } |
| 3178 | 3165 | ||
| 3179 | const frame_index = | 3166 | const frame_index = |
| 3180 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | 3167 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); |
| 3181 | try self.genSetMem( | 3168 | try self.genSetMem( |
| 3182 | .{ .frame = frame_index }, | 3169 | .{ .frame = frame_index }, |
| 3183 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), | 3170 | @intCast(i32, tuple_ty.structFieldOffset(1, mod)), |
| 3184 | Type.u1, | 3171 | Type.u1, |
| 3185 | .{ .eflags = cc }, | 3172 | .{ .eflags = cc }, |
| 3186 | ); | 3173 | ); |
| 3187 | try self.genSetMem( | 3174 | try self.genSetMem( |
| 3188 | .{ .frame = frame_index }, | 3175 | .{ .frame = frame_index }, |
| 3189 | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), | 3176 | @intCast(i32, tuple_ty.structFieldOffset(0, mod)), |
| 3190 | ty, | 3177 | ty, |
| 3191 | partial_mcv, | 3178 | partial_mcv, |
| 3192 | ); | 3179 | ); |
| ... | @@ -3194,7 +3181,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3194,7 +3181,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3194 | } | 3181 | } |
| 3195 | 3182 | ||
| 3196 | const frame_index = | 3183 | const frame_index = |
| 3197 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | 3184 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); |
| 3198 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); | 3185 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 3199 | break :result .{ .load_frame = .{ .index = frame_index } }; | 3186 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 3200 | }, | 3187 | }, |
| ... | @@ -3205,12 +3192,13 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3205,12 +3192,13 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3205 | } | 3192 | } |
| 3206 | 3193 | ||
| 3207 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 3194 | fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3195 | const mod = self.bin_file.options.module.?; | ||
| 3208 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 3196 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3209 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 3197 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3210 | const result: MCValue = result: { | 3198 | const result: MCValue = result: { |
| 3211 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 3199 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 3212 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 3200 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 3213 | switch (lhs_ty.zigTypeTag()) { | 3201 | switch (lhs_ty.zigTypeTag(mod)) { |
| 3214 | .Vector => return self.fail("TODO implement shl with overflow for Vector type", .{}), | 3202 | .Vector => return self.fail("TODO implement shl with overflow for Vector type", .{}), |
| 3215 | .Int => { | 3203 | .Int => { |
| 3216 | try self.spillEflagsIfOccupied(); | 3204 | try self.spillEflagsIfOccupied(); |
| ... | @@ -3219,7 +3207,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3219,7 +3207,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3219 | const lhs = try self.resolveInst(bin_op.lhs); | 3207 | const lhs = try self.resolveInst(bin_op.lhs); |
| 3220 | const rhs = try self.resolveInst(bin_op.rhs); | 3208 | const rhs = try self.resolveInst(bin_op.rhs); |
| 3221 | 3209 | ||
| 3222 | const int_info = lhs_ty.intInfo(self.target.*); | 3210 | const int_info = lhs_ty.intInfo(mod); |
| 3223 | 3211 | ||
| 3224 | const partial_mcv = try self.genShiftBinOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty); | 3212 | const partial_mcv = try self.genShiftBinOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty); |
| 3225 | const partial_lock = switch (partial_mcv) { | 3213 | const partial_lock = switch (partial_mcv) { |
| ... | @@ -3238,7 +3226,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3238,7 +3226,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3238 | try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, tmp_mcv, lhs); | 3226 | try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, tmp_mcv, lhs); |
| 3239 | const cc = Condition.ne; | 3227 | const cc = Condition.ne; |
| 3240 | 3228 | ||
| 3241 | const tuple_ty = self.air.typeOfIndex(inst); | 3229 | const tuple_ty = self.typeOfIndex(inst); |
| 3242 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { | 3230 | if (int_info.bits >= 8 and math.isPowerOfTwo(int_info.bits)) { |
| 3243 | switch (partial_mcv) { | 3231 | switch (partial_mcv) { |
| 3244 | .register => |reg| { | 3232 | .register => |reg| { |
| ... | @@ -3249,24 +3237,24 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3249,24 +3237,24 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3249 | } | 3237 | } |
| 3250 | 3238 | ||
| 3251 | const frame_index = | 3239 | const frame_index = |
| 3252 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | 3240 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); |
| 3253 | try self.genSetMem( | 3241 | try self.genSetMem( |
| 3254 | .{ .frame = frame_index }, | 3242 | .{ .frame = frame_index }, |
| 3255 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), | 3243 | @intCast(i32, tuple_ty.structFieldOffset(1, mod)), |
| 3256 | tuple_ty.structFieldType(1), | 3244 | tuple_ty.structFieldType(1, mod), |
| 3257 | .{ .eflags = cc }, | 3245 | .{ .eflags = cc }, |
| 3258 | ); | 3246 | ); |
| 3259 | try self.genSetMem( | 3247 | try self.genSetMem( |
| 3260 | .{ .frame = frame_index }, | 3248 | .{ .frame = frame_index }, |
| 3261 | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), | 3249 | @intCast(i32, tuple_ty.structFieldOffset(0, mod)), |
| 3262 | tuple_ty.structFieldType(0), | 3250 | tuple_ty.structFieldType(0, mod), |
| 3263 | partial_mcv, | 3251 | partial_mcv, |
| 3264 | ); | 3252 | ); |
| 3265 | break :result .{ .load_frame = .{ .index = frame_index } }; | 3253 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 3266 | } | 3254 | } |
| 3267 | 3255 | ||
| 3268 | const frame_index = | 3256 | const frame_index = |
| 3269 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | 3257 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); |
| 3270 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); | 3258 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 3271 | break :result .{ .load_frame = .{ .index = frame_index } }; | 3259 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 3272 | }, | 3260 | }, |
| ... | @@ -3283,29 +3271,20 @@ fn genSetFrameTruncatedOverflowCompare( | ... | @@ -3283,29 +3271,20 @@ fn genSetFrameTruncatedOverflowCompare( |
| 3283 | src_mcv: MCValue, | 3271 | src_mcv: MCValue, |
| 3284 | overflow_cc: ?Condition, | 3272 | overflow_cc: ?Condition, |
| 3285 | ) !void { | 3273 | ) !void { |
| 3274 | const mod = self.bin_file.options.module.?; | ||
| 3286 | const src_lock = switch (src_mcv) { | 3275 | const src_lock = switch (src_mcv) { |
| 3287 | .register => |reg| self.register_manager.lockReg(reg), | 3276 | .register => |reg| self.register_manager.lockReg(reg), |
| 3288 | else => null, | 3277 | else => null, |
| 3289 | }; | 3278 | }; |
| 3290 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); | 3279 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 3291 | 3280 | ||
| 3292 | const ty = tuple_ty.structFieldType(0); | 3281 | const ty = tuple_ty.structFieldType(0, mod); |
| 3293 | const int_info = ty.intInfo(self.target.*); | 3282 | const int_info = ty.intInfo(mod); |
| 3294 | 3283 | ||
| 3295 | var hi_limb_pl = Type.Payload.Bits{ | 3284 | const hi_limb_bits = (int_info.bits - 1) % 64 + 1; |
| 3296 | .base = .{ .tag = switch (int_info.signedness) { | 3285 | const hi_limb_ty = try mod.intType(int_info.signedness, hi_limb_bits); |
| 3297 | .signed => .int_signed, | ||
| 3298 | .unsigned => .int_unsigned, | ||
| 3299 | } }, | ||
| 3300 | .data = (int_info.bits - 1) % 64 + 1, | ||
| 3301 | }; | ||
| 3302 | const hi_limb_ty = Type.initPayload(&hi_limb_pl.base); | ||
| 3303 | 3286 | ||
| 3304 | var rest_pl = Type.Payload.Bits{ | 3287 | const rest_ty = try mod.intType(.unsigned, int_info.bits - hi_limb_bits); |
| 3305 | .base = .{ .tag = .int_unsigned }, | ||
| 3306 | .data = int_info.bits - hi_limb_pl.data, | ||
| 3307 | }; | ||
| 3308 | const rest_ty = Type.initPayload(&rest_pl.base); | ||
| 3309 | 3288 | ||
| 3310 | const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp); | 3289 | const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp); |
| 3311 | const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); | 3290 | const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); |
| ... | @@ -3335,7 +3314,7 @@ fn genSetFrameTruncatedOverflowCompare( | ... | @@ -3335,7 +3314,7 @@ fn genSetFrameTruncatedOverflowCompare( |
| 3335 | ); | 3314 | ); |
| 3336 | } | 3315 | } |
| 3337 | 3316 | ||
| 3338 | const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)); | 3317 | const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, mod)); |
| 3339 | if (hi_limb_off > 0) try self.genSetMem(.{ .frame = frame_index }, payload_off, rest_ty, src_mcv); | 3318 | if (hi_limb_off > 0) try self.genSetMem(.{ .frame = frame_index }, payload_off, rest_ty, src_mcv); |
| 3340 | try self.genSetMem( | 3319 | try self.genSetMem( |
| 3341 | .{ .frame = frame_index }, | 3320 | .{ .frame = frame_index }, |
| ... | @@ -3345,23 +3324,24 @@ fn genSetFrameTruncatedOverflowCompare( | ... | @@ -3345,23 +3324,24 @@ fn genSetFrameTruncatedOverflowCompare( |
| 3345 | ); | 3324 | ); |
| 3346 | try self.genSetMem( | 3325 | try self.genSetMem( |
| 3347 | .{ .frame = frame_index }, | 3326 | .{ .frame = frame_index }, |
| 3348 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), | 3327 | @intCast(i32, tuple_ty.structFieldOffset(1, mod)), |
| 3349 | tuple_ty.structFieldType(1), | 3328 | tuple_ty.structFieldType(1, mod), |
| 3350 | if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne }, | 3329 | if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne }, |
| 3351 | ); | 3330 | ); |
| 3352 | } | 3331 | } |
| 3353 | 3332 | ||
| 3354 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 3333 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3334 | const mod = self.bin_file.options.module.?; | ||
| 3355 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 3335 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3356 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 3336 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3357 | const dst_ty = self.air.typeOf(bin_op.lhs); | 3337 | const dst_ty = self.typeOf(bin_op.lhs); |
| 3358 | const result: MCValue = switch (dst_ty.zigTypeTag()) { | 3338 | const result: MCValue = switch (dst_ty.zigTypeTag(mod)) { |
| 3359 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), | 3339 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| 3360 | .Int => result: { | 3340 | .Int => result: { |
| 3361 | try self.spillEflagsIfOccupied(); | 3341 | try self.spillEflagsIfOccupied(); |
| 3362 | try self.spillRegisters(&.{ .rax, .rdx }); | 3342 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 3363 | 3343 | ||
| 3364 | const dst_info = dst_ty.intInfo(self.target.*); | 3344 | const dst_info = dst_ty.intInfo(mod); |
| 3365 | const cc: Condition = switch (dst_info.signedness) { | 3345 | const cc: Condition = switch (dst_info.signedness) { |
| 3366 | .unsigned => .c, | 3346 | .unsigned => .c, |
| 3367 | .signed => .o, | 3347 | .signed => .o, |
| ... | @@ -3369,16 +3349,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3369,16 +3349,13 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3369 | 3349 | ||
| 3370 | const lhs_active_bits = self.activeIntBits(bin_op.lhs); | 3350 | const lhs_active_bits = self.activeIntBits(bin_op.lhs); |
| 3371 | const rhs_active_bits = self.activeIntBits(bin_op.rhs); | 3351 | const rhs_active_bits = self.activeIntBits(bin_op.rhs); |
| 3372 | var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { | 3352 | const src_bits = math.max3(lhs_active_bits, rhs_active_bits, dst_info.bits / 2); |
| 3373 | .signed => .int_signed, | 3353 | const src_ty = try mod.intType(dst_info.signedness, src_bits); |
| 3374 | .unsigned => .int_unsigned, | ||
| 3375 | } }, .data = math.max3(lhs_active_bits, rhs_active_bits, dst_info.bits / 2) }; | ||
| 3376 | const src_ty = Type.initPayload(&src_pl.base); | ||
| 3377 | 3354 | ||
| 3378 | const lhs = try self.resolveInst(bin_op.lhs); | 3355 | const lhs = try self.resolveInst(bin_op.lhs); |
| 3379 | const rhs = try self.resolveInst(bin_op.rhs); | 3356 | const rhs = try self.resolveInst(bin_op.rhs); |
| 3380 | 3357 | ||
| 3381 | const tuple_ty = self.air.typeOfIndex(inst); | 3358 | const tuple_ty = self.typeOfIndex(inst); |
| 3382 | const extra_bits = if (dst_info.bits <= 64) | 3359 | const extra_bits = if (dst_info.bits <= 64) |
| 3383 | self.regExtraBits(dst_ty) | 3360 | self.regExtraBits(dst_ty) |
| 3384 | else | 3361 | else |
| ... | @@ -3391,27 +3368,27 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3391,27 +3368,27 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3391 | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; | 3368 | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; |
| 3392 | } else { | 3369 | } else { |
| 3393 | const frame_index = | 3370 | const frame_index = |
| 3394 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | 3371 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); |
| 3395 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); | 3372 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 3396 | break :result .{ .load_frame = .{ .index = frame_index } }; | 3373 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 3397 | }, | 3374 | }, |
| 3398 | else => { | 3375 | else => { |
| 3399 | // For now, this is the only supported multiply that doesn't fit in a register. | 3376 | // For now, this is the only supported multiply that doesn't fit in a register. |
| 3400 | assert(dst_info.bits <= 128 and src_pl.data == 64); | 3377 | assert(dst_info.bits <= 128 and src_bits == 64); |
| 3401 | 3378 | ||
| 3402 | const frame_index = | 3379 | const frame_index = |
| 3403 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | 3380 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, mod)); |
| 3404 | if (dst_info.bits >= lhs_active_bits + rhs_active_bits) { | 3381 | if (dst_info.bits >= lhs_active_bits + rhs_active_bits) { |
| 3405 | try self.genSetMem( | 3382 | try self.genSetMem( |
| 3406 | .{ .frame = frame_index }, | 3383 | .{ .frame = frame_index }, |
| 3407 | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), | 3384 | @intCast(i32, tuple_ty.structFieldOffset(0, mod)), |
| 3408 | tuple_ty.structFieldType(0), | 3385 | tuple_ty.structFieldType(0, mod), |
| 3409 | partial_mcv, | 3386 | partial_mcv, |
| 3410 | ); | 3387 | ); |
| 3411 | try self.genSetMem( | 3388 | try self.genSetMem( |
| 3412 | .{ .frame = frame_index }, | 3389 | .{ .frame = frame_index }, |
| 3413 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), | 3390 | @intCast(i32, tuple_ty.structFieldOffset(1, mod)), |
| 3414 | tuple_ty.structFieldType(1), | 3391 | tuple_ty.structFieldType(1, mod), |
| 3415 | .{ .immediate = 0 }, // cc being set is impossible | 3392 | .{ .immediate = 0 }, // cc being set is impossible |
| 3416 | ); | 3393 | ); |
| 3417 | } else try self.genSetFrameTruncatedOverflowCompare( | 3394 | } else try self.genSetFrameTruncatedOverflowCompare( |
| ... | @@ -3433,7 +3410,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3433,7 +3410,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 3433 | /// Clobbers .rax and .rdx registers. | 3410 | /// Clobbers .rax and .rdx registers. |
| 3434 | /// Quotient is saved in .rax and remainder in .rdx. | 3411 | /// Quotient is saved in .rax and remainder in .rdx. |
| 3435 | fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue, rhs: MCValue) !void { | 3412 | fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue, rhs: MCValue) !void { |
| 3436 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 3413 | const mod = self.bin_file.options.module.?; |
| 3414 | const abi_size = @intCast(u32, ty.abiSize(mod)); | ||
| 3437 | if (abi_size > 8) { | 3415 | if (abi_size > 8) { |
| 3438 | return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{}); | 3416 | return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{}); |
| 3439 | } | 3417 | } |
| ... | @@ -3472,8 +3450,9 @@ fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue | ... | @@ -3472,8 +3450,9 @@ fn genIntMulDivOpMir(self: *Self, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue |
| 3472 | /// Always returns a register. | 3450 | /// Always returns a register. |
| 3473 | /// Clobbers .rax and .rdx registers. | 3451 | /// Clobbers .rax and .rdx registers. |
| 3474 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { | 3452 | fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue { |
| 3475 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 3453 | const mod = self.bin_file.options.module.?; |
| 3476 | const int_info = ty.intInfo(self.target.*); | 3454 | const abi_size = @intCast(u32, ty.abiSize(mod)); |
| 3455 | const int_info = ty.intInfo(mod); | ||
| 3477 | const dividend: Register = switch (lhs) { | 3456 | const dividend: Register = switch (lhs) { |
| 3478 | .register => |reg| reg, | 3457 | .register => |reg| reg, |
| 3479 | else => try self.copyToTmpRegister(ty, lhs), | 3458 | else => try self.copyToTmpRegister(ty, lhs), |
| ... | @@ -3531,8 +3510,8 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3531,8 +3510,8 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 3531 | try self.register_manager.getReg(.rcx, null); | 3510 | try self.register_manager.getReg(.rcx, null); |
| 3532 | const lhs = try self.resolveInst(bin_op.lhs); | 3511 | const lhs = try self.resolveInst(bin_op.lhs); |
| 3533 | const rhs = try self.resolveInst(bin_op.rhs); | 3512 | const rhs = try self.resolveInst(bin_op.rhs); |
| 3534 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 3513 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 3535 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 3514 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 3536 | 3515 | ||
| 3537 | const result = try self.genShiftBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); | 3516 | const result = try self.genShiftBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty); |
| 3538 | 3517 | ||
| ... | @@ -3549,7 +3528,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3549,7 +3528,7 @@ fn airShlSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3549 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { | 3528 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3550 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3529 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3551 | const result: MCValue = result: { | 3530 | const result: MCValue = result: { |
| 3552 | const pl_ty = self.air.typeOfIndex(inst); | 3531 | const pl_ty = self.typeOfIndex(inst); |
| 3553 | const opt_mcv = try self.resolveInst(ty_op.operand); | 3532 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 3554 | 3533 | ||
| 3555 | if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) { | 3534 | if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) { |
| ... | @@ -3574,7 +3553,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3574,7 +3553,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3574 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { | 3553 | fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3575 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3554 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3576 | 3555 | ||
| 3577 | const dst_ty = self.air.typeOfIndex(inst); | 3556 | const dst_ty = self.typeOfIndex(inst); |
| 3578 | const opt_mcv = try self.resolveInst(ty_op.operand); | 3557 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 3579 | 3558 | ||
| 3580 | const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) | 3559 | const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) |
| ... | @@ -3585,14 +3564,15 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3585,14 +3564,15 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3585 | } | 3564 | } |
| 3586 | 3565 | ||
| 3587 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | 3566 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3567 | const mod = self.bin_file.options.module.?; | ||
| 3588 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3568 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3589 | const result = result: { | 3569 | const result = result: { |
| 3590 | const dst_ty = self.air.typeOfIndex(inst); | 3570 | const dst_ty = self.typeOfIndex(inst); |
| 3591 | const src_ty = self.air.typeOf(ty_op.operand); | 3571 | const src_ty = self.typeOf(ty_op.operand); |
| 3592 | const opt_ty = src_ty.childType(); | 3572 | const opt_ty = src_ty.childType(mod); |
| 3593 | const src_mcv = try self.resolveInst(ty_op.operand); | 3573 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3594 | 3574 | ||
| 3595 | if (opt_ty.optionalReprIsPayload()) { | 3575 | if (opt_ty.optionalReprIsPayload(mod)) { |
| 3596 | break :result if (self.liveness.isUnused(inst)) | 3576 | break :result if (self.liveness.isUnused(inst)) |
| 3597 | .unreach | 3577 | .unreach |
| 3598 | else if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | 3578 | else if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| ... | @@ -3609,8 +3589,8 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3609,8 +3589,8 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3609 | else | 3589 | else |
| 3610 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); | 3590 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 3611 | 3591 | ||
| 3612 | const pl_ty = dst_ty.childType(); | 3592 | const pl_ty = dst_ty.childType(mod); |
| 3613 | const pl_abi_size = @intCast(i32, pl_ty.abiSize(self.target.*)); | 3593 | const pl_abi_size = @intCast(i32, pl_ty.abiSize(mod)); |
| 3614 | try self.genSetMem(.{ .reg = dst_mcv.getReg().? }, pl_abi_size, Type.bool, .{ .immediate = 1 }); | 3594 | try self.genSetMem(.{ .reg = dst_mcv.getReg().? }, pl_abi_size, Type.bool, .{ .immediate = 1 }); |
| 3615 | break :result if (self.liveness.isUnused(inst)) .unreach else dst_mcv; | 3595 | break :result if (self.liveness.isUnused(inst)) .unreach else dst_mcv; |
| 3616 | }; | 3596 | }; |
| ... | @@ -3618,22 +3598,23 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3618,22 +3598,23 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3618 | } | 3598 | } |
| 3619 | 3599 | ||
| 3620 | fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | 3600 | fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 3601 | const mod = self.bin_file.options.module.?; | ||
| 3621 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3602 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3622 | const err_union_ty = self.air.typeOf(ty_op.operand); | 3603 | const err_union_ty = self.typeOf(ty_op.operand); |
| 3623 | const err_ty = err_union_ty.errorUnionSet(); | 3604 | const err_ty = err_union_ty.errorUnionSet(mod); |
| 3624 | const payload_ty = err_union_ty.errorUnionPayload(); | 3605 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 3625 | const operand = try self.resolveInst(ty_op.operand); | 3606 | const operand = try self.resolveInst(ty_op.operand); |
| 3626 | 3607 | ||
| 3627 | const result: MCValue = result: { | 3608 | const result: MCValue = result: { |
| 3628 | if (err_ty.errorSetIsEmpty()) { | 3609 | if (err_ty.errorSetIsEmpty(mod)) { |
| 3629 | break :result MCValue{ .immediate = 0 }; | 3610 | break :result MCValue{ .immediate = 0 }; |
| 3630 | } | 3611 | } |
| 3631 | 3612 | ||
| 3632 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3613 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3633 | break :result operand; | 3614 | break :result operand; |
| 3634 | } | 3615 | } |
| 3635 | 3616 | ||
| 3636 | const err_off = errUnionErrorOffset(payload_ty, self.target.*); | 3617 | const err_off = errUnionErrorOffset(payload_ty, mod); |
| 3637 | switch (operand) { | 3618 | switch (operand) { |
| 3638 | .register => |reg| { | 3619 | .register => |reg| { |
| 3639 | // TODO reuse operand | 3620 | // TODO reuse operand |
| ... | @@ -3666,7 +3647,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3666,7 +3647,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 3666 | 3647 | ||
| 3667 | fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | 3648 | fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3668 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3649 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3669 | const err_union_ty = self.air.typeOf(ty_op.operand); | 3650 | const err_union_ty = self.typeOf(ty_op.operand); |
| 3670 | const operand = try self.resolveInst(ty_op.operand); | 3651 | const operand = try self.resolveInst(ty_op.operand); |
| 3671 | const result = try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, operand); | 3652 | const result = try self.genUnwrapErrorUnionPayloadMir(inst, err_union_ty, operand); |
| 3672 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3653 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -3678,12 +3659,13 @@ fn genUnwrapErrorUnionPayloadMir( | ... | @@ -3678,12 +3659,13 @@ fn genUnwrapErrorUnionPayloadMir( |
| 3678 | err_union_ty: Type, | 3659 | err_union_ty: Type, |
| 3679 | err_union: MCValue, | 3660 | err_union: MCValue, |
| 3680 | ) !MCValue { | 3661 | ) !MCValue { |
| 3681 | const payload_ty = err_union_ty.errorUnionPayload(); | 3662 | const mod = self.bin_file.options.module.?; |
| 3663 | const payload_ty = err_union_ty.errorUnionPayload(mod); | ||
| 3682 | 3664 | ||
| 3683 | const result: MCValue = result: { | 3665 | const result: MCValue = result: { |
| 3684 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result .none; | 3666 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none; |
| 3685 | 3667 | ||
| 3686 | const payload_off = errUnionPayloadOffset(payload_ty, self.target.*); | 3668 | const payload_off = errUnionPayloadOffset(payload_ty, mod); |
| 3687 | switch (err_union) { | 3669 | switch (err_union) { |
| 3688 | .load_frame => |frame_addr| break :result .{ .load_frame = .{ | 3670 | .load_frame => |frame_addr| break :result .{ .load_frame = .{ |
| 3689 | .index = frame_addr.index, | 3671 | .index = frame_addr.index, |
| ... | @@ -3720,9 +3702,10 @@ fn genUnwrapErrorUnionPayloadMir( | ... | @@ -3720,9 +3702,10 @@ fn genUnwrapErrorUnionPayloadMir( |
| 3720 | 3702 | ||
| 3721 | // *(E!T) -> E | 3703 | // *(E!T) -> E |
| 3722 | fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 3704 | fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3705 | const mod = self.bin_file.options.module.?; | ||
| 3723 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3706 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3724 | 3707 | ||
| 3725 | const src_ty = self.air.typeOf(ty_op.operand); | 3708 | const src_ty = self.typeOf(ty_op.operand); |
| 3726 | const src_mcv = try self.resolveInst(ty_op.operand); | 3709 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3727 | const src_reg = switch (src_mcv) { | 3710 | const src_reg = switch (src_mcv) { |
| 3728 | .register => |reg| reg, | 3711 | .register => |reg| reg, |
| ... | @@ -3736,11 +3719,11 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3736,11 +3719,11 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3736 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 3719 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 3737 | defer self.register_manager.unlockReg(dst_lock); | 3720 | defer self.register_manager.unlockReg(dst_lock); |
| 3738 | 3721 | ||
| 3739 | const eu_ty = src_ty.childType(); | 3722 | const eu_ty = src_ty.childType(mod); |
| 3740 | const pl_ty = eu_ty.errorUnionPayload(); | 3723 | const pl_ty = eu_ty.errorUnionPayload(mod); |
| 3741 | const err_ty = eu_ty.errorUnionSet(); | 3724 | const err_ty = eu_ty.errorUnionSet(mod); |
| 3742 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); | 3725 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, mod)); |
| 3743 | const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*)); | 3726 | const err_abi_size = @intCast(u32, err_ty.abiSize(mod)); |
| 3744 | try self.asmRegisterMemory( | 3727 | try self.asmRegisterMemory( |
| 3745 | .{ ._, .mov }, | 3728 | .{ ._, .mov }, |
| 3746 | registerAlias(dst_reg, err_abi_size), | 3729 | registerAlias(dst_reg, err_abi_size), |
| ... | @@ -3755,9 +3738,10 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3755,9 +3738,10 @@ fn airUnwrapErrUnionErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3755 | 3738 | ||
| 3756 | // *(E!T) -> *T | 3739 | // *(E!T) -> *T |
| 3757 | fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { | 3740 | fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3741 | const mod = self.bin_file.options.module.?; | ||
| 3758 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3742 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3759 | 3743 | ||
| 3760 | const src_ty = self.air.typeOf(ty_op.operand); | 3744 | const src_ty = self.typeOf(ty_op.operand); |
| 3761 | const src_mcv = try self.resolveInst(ty_op.operand); | 3745 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3762 | const src_reg = switch (src_mcv) { | 3746 | const src_reg = switch (src_mcv) { |
| 3763 | .register => |reg| reg, | 3747 | .register => |reg| reg, |
| ... | @@ -3766,7 +3750,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3766,7 +3750,7 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3766 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); | 3750 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 3767 | defer self.register_manager.unlockReg(src_lock); | 3751 | defer self.register_manager.unlockReg(src_lock); |
| 3768 | 3752 | ||
| 3769 | const dst_ty = self.air.typeOfIndex(inst); | 3753 | const dst_ty = self.typeOfIndex(inst); |
| 3770 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | 3754 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3771 | src_reg | 3755 | src_reg |
| 3772 | else | 3756 | else |
| ... | @@ -3775,10 +3759,10 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3775,10 +3759,10 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3775 | const dst_lock = self.register_manager.lockReg(dst_reg); | 3759 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 3776 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 3760 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 3777 | 3761 | ||
| 3778 | const eu_ty = src_ty.childType(); | 3762 | const eu_ty = src_ty.childType(mod); |
| 3779 | const pl_ty = eu_ty.errorUnionPayload(); | 3763 | const pl_ty = eu_ty.errorUnionPayload(mod); |
| 3780 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); | 3764 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, mod)); |
| 3781 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 3765 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(mod)); |
| 3782 | try self.asmRegisterMemory( | 3766 | try self.asmRegisterMemory( |
| 3783 | .{ ._, .lea }, | 3767 | .{ ._, .lea }, |
| 3784 | registerAlias(dst_reg, dst_abi_size), | 3768 | registerAlias(dst_reg, dst_abi_size), |
| ... | @@ -3789,9 +3773,10 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3789,9 +3773,10 @@ fn airUnwrapErrUnionPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3789 | } | 3773 | } |
| 3790 | 3774 | ||
| 3791 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | 3775 | fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3776 | const mod = self.bin_file.options.module.?; | ||
| 3792 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3777 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3793 | const result: MCValue = result: { | 3778 | const result: MCValue = result: { |
| 3794 | const src_ty = self.air.typeOf(ty_op.operand); | 3779 | const src_ty = self.typeOf(ty_op.operand); |
| 3795 | const src_mcv = try self.resolveInst(ty_op.operand); | 3780 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3796 | const src_reg = switch (src_mcv) { | 3781 | const src_reg = switch (src_mcv) { |
| 3797 | .register => |reg| reg, | 3782 | .register => |reg| reg, |
| ... | @@ -3800,11 +3785,11 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3800,11 +3785,11 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3800 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); | 3785 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 3801 | defer self.register_manager.unlockReg(src_lock); | 3786 | defer self.register_manager.unlockReg(src_lock); |
| 3802 | 3787 | ||
| 3803 | const eu_ty = src_ty.childType(); | 3788 | const eu_ty = src_ty.childType(mod); |
| 3804 | const pl_ty = eu_ty.errorUnionPayload(); | 3789 | const pl_ty = eu_ty.errorUnionPayload(mod); |
| 3805 | const err_ty = eu_ty.errorUnionSet(); | 3790 | const err_ty = eu_ty.errorUnionSet(mod); |
| 3806 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); | 3791 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, mod)); |
| 3807 | const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*)); | 3792 | const err_abi_size = @intCast(u32, err_ty.abiSize(mod)); |
| 3808 | try self.asmMemoryImmediate( | 3793 | try self.asmMemoryImmediate( |
| 3809 | .{ ._, .mov }, | 3794 | .{ ._, .mov }, |
| 3810 | Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{ | 3795 | Memory.sib(Memory.PtrSize.fromSize(err_abi_size), .{ |
| ... | @@ -3816,7 +3801,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3816,7 +3801,7 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3816 | 3801 | ||
| 3817 | if (self.liveness.isUnused(inst)) break :result .unreach; | 3802 | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 3818 | 3803 | ||
| 3819 | const dst_ty = self.air.typeOfIndex(inst); | 3804 | const dst_ty = self.typeOfIndex(inst); |
| 3820 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | 3805 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3821 | src_reg | 3806 | src_reg |
| 3822 | else | 3807 | else |
| ... | @@ -3824,8 +3809,8 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3824,8 +3809,8 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { |
| 3824 | const dst_lock = self.register_manager.lockReg(dst_reg); | 3809 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 3825 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 3810 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 3826 | 3811 | ||
| 3827 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); | 3812 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, mod)); |
| 3828 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 3813 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(mod)); |
| 3829 | try self.asmRegisterMemory( | 3814 | try self.asmRegisterMemory( |
| 3830 | .{ ._, .lea }, | 3815 | .{ ._, .lea }, |
| 3831 | registerAlias(dst_reg, dst_abi_size), | 3816 | registerAlias(dst_reg, dst_abi_size), |
| ... | @@ -3853,14 +3838,15 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3853,14 +3838,15 @@ fn airSaveErrReturnTraceIndex(self: *Self, inst: Air.Inst.Index) !void { |
| 3853 | } | 3838 | } |
| 3854 | 3839 | ||
| 3855 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | 3840 | fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3841 | const mod = self.bin_file.options.module.?; | ||
| 3856 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3842 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3857 | const result: MCValue = result: { | 3843 | const result: MCValue = result: { |
| 3858 | const pl_ty = self.air.typeOf(ty_op.operand); | 3844 | const pl_ty = self.typeOf(ty_op.operand); |
| 3859 | if (!pl_ty.hasRuntimeBits()) break :result .{ .immediate = 1 }; | 3845 | if (!pl_ty.hasRuntimeBits(mod)) break :result .{ .immediate = 1 }; |
| 3860 | 3846 | ||
| 3861 | const opt_ty = self.air.typeOfIndex(inst); | 3847 | const opt_ty = self.typeOfIndex(inst); |
| 3862 | const pl_mcv = try self.resolveInst(ty_op.operand); | 3848 | const pl_mcv = try self.resolveInst(ty_op.operand); |
| 3863 | const same_repr = opt_ty.optionalReprIsPayload(); | 3849 | const same_repr = opt_ty.optionalReprIsPayload(mod); |
| 3864 | if (same_repr and self.reuseOperand(inst, ty_op.operand, 0, pl_mcv)) break :result pl_mcv; | 3850 | if (same_repr and self.reuseOperand(inst, ty_op.operand, 0, pl_mcv)) break :result pl_mcv; |
| 3865 | 3851 | ||
| 3866 | const pl_lock: ?RegisterLock = switch (pl_mcv) { | 3852 | const pl_lock: ?RegisterLock = switch (pl_mcv) { |
| ... | @@ -3873,7 +3859,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3873,7 +3859,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3873 | try self.genCopy(pl_ty, opt_mcv, pl_mcv); | 3859 | try self.genCopy(pl_ty, opt_mcv, pl_mcv); |
| 3874 | 3860 | ||
| 3875 | if (!same_repr) { | 3861 | if (!same_repr) { |
| 3876 | const pl_abi_size = @intCast(i32, pl_ty.abiSize(self.target.*)); | 3862 | const pl_abi_size = @intCast(i32, pl_ty.abiSize(mod)); |
| 3877 | switch (opt_mcv) { | 3863 | switch (opt_mcv) { |
| 3878 | else => unreachable, | 3864 | else => unreachable, |
| 3879 | 3865 | ||
| ... | @@ -3900,19 +3886,20 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3900,19 +3886,20 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 3900 | 3886 | ||
| 3901 | /// T to E!T | 3887 | /// T to E!T |
| 3902 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | 3888 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3889 | const mod = self.bin_file.options.module.?; | ||
| 3903 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3890 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3904 | 3891 | ||
| 3905 | const eu_ty = self.air.getRefType(ty_op.ty); | 3892 | const eu_ty = self.air.getRefType(ty_op.ty); |
| 3906 | const pl_ty = eu_ty.errorUnionPayload(); | 3893 | const pl_ty = eu_ty.errorUnionPayload(mod); |
| 3907 | const err_ty = eu_ty.errorUnionSet(); | 3894 | const err_ty = eu_ty.errorUnionSet(mod); |
| 3908 | const operand = try self.resolveInst(ty_op.operand); | 3895 | const operand = try self.resolveInst(ty_op.operand); |
| 3909 | 3896 | ||
| 3910 | const result: MCValue = result: { | 3897 | const result: MCValue = result: { |
| 3911 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) break :result .{ .immediate = 0 }; | 3898 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .{ .immediate = 0 }; |
| 3912 | 3899 | ||
| 3913 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(eu_ty, self.target.*)); | 3900 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(eu_ty, mod)); |
| 3914 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); | 3901 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, mod)); |
| 3915 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); | 3902 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, mod)); |
| 3916 | try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, operand); | 3903 | try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, operand); |
| 3917 | try self.genSetMem(.{ .frame = frame_index }, err_off, err_ty, .{ .immediate = 0 }); | 3904 | try self.genSetMem(.{ .frame = frame_index }, err_off, err_ty, .{ .immediate = 0 }); |
| 3918 | break :result .{ .load_frame = .{ .index = frame_index } }; | 3905 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| ... | @@ -3922,18 +3909,19 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3922,18 +3909,19 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 3922 | 3909 | ||
| 3923 | /// E to E!T | 3910 | /// E to E!T |
| 3924 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | 3911 | fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 3912 | const mod = self.bin_file.options.module.?; | ||
| 3925 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3913 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3926 | 3914 | ||
| 3927 | const eu_ty = self.air.getRefType(ty_op.ty); | 3915 | const eu_ty = self.air.getRefType(ty_op.ty); |
| 3928 | const pl_ty = eu_ty.errorUnionPayload(); | 3916 | const pl_ty = eu_ty.errorUnionPayload(mod); |
| 3929 | const err_ty = eu_ty.errorUnionSet(); | 3917 | const err_ty = eu_ty.errorUnionSet(mod); |
| 3930 | 3918 | ||
| 3931 | const result: MCValue = result: { | 3919 | const result: MCValue = result: { |
| 3932 | if (!pl_ty.hasRuntimeBitsIgnoreComptime()) break :result try self.resolveInst(ty_op.operand); | 3920 | if (!pl_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result try self.resolveInst(ty_op.operand); |
| 3933 | 3921 | ||
| 3934 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(eu_ty, self.target.*)); | 3922 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(eu_ty, mod)); |
| 3935 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, self.target.*)); | 3923 | const pl_off = @intCast(i32, errUnionPayloadOffset(pl_ty, mod)); |
| 3936 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, self.target.*)); | 3924 | const err_off = @intCast(i32, errUnionErrorOffset(pl_ty, mod)); |
| 3937 | try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef); | 3925 | try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef); |
| 3938 | const operand = try self.resolveInst(ty_op.operand); | 3926 | const operand = try self.resolveInst(ty_op.operand); |
| 3939 | try self.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand); | 3927 | try self.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand); |
| ... | @@ -3949,7 +3937,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3949,7 +3937,7 @@ fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3949 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; | 3937 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 3950 | 3938 | ||
| 3951 | const dst_mcv = try self.allocRegOrMem(inst, true); | 3939 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 3952 | const dst_ty = self.air.typeOfIndex(inst); | 3940 | const dst_ty = self.typeOfIndex(inst); |
| 3953 | try self.genCopy(dst_ty, dst_mcv, src_mcv); | 3941 | try self.genCopy(dst_ty, dst_mcv, src_mcv); |
| 3954 | break :result dst_mcv; | 3942 | break :result dst_mcv; |
| 3955 | }; | 3943 | }; |
| ... | @@ -3974,9 +3962,10 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3974,9 +3962,10 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void { |
| 3974 | } | 3962 | } |
| 3975 | 3963 | ||
| 3976 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | 3964 | fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3965 | const mod = self.bin_file.options.module.?; | ||
| 3977 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3966 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3978 | 3967 | ||
| 3979 | const src_ty = self.air.typeOf(ty_op.operand); | 3968 | const src_ty = self.typeOf(ty_op.operand); |
| 3980 | const src_mcv = try self.resolveInst(ty_op.operand); | 3969 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 3981 | const src_reg = switch (src_mcv) { | 3970 | const src_reg = switch (src_mcv) { |
| 3982 | .register => |reg| reg, | 3971 | .register => |reg| reg, |
| ... | @@ -3985,7 +3974,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3985,7 +3974,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3985 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); | 3974 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 3986 | defer self.register_manager.unlockReg(src_lock); | 3975 | defer self.register_manager.unlockReg(src_lock); |
| 3987 | 3976 | ||
| 3988 | const dst_ty = self.air.typeOfIndex(inst); | 3977 | const dst_ty = self.typeOfIndex(inst); |
| 3989 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) | 3978 | const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 3990 | src_reg | 3979 | src_reg |
| 3991 | else | 3980 | else |
| ... | @@ -3994,7 +3983,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3994,7 +3983,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 3994 | const dst_lock = self.register_manager.lockReg(dst_reg); | 3983 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 3995 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 3984 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 3996 | 3985 | ||
| 3997 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 3986 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(mod)); |
| 3998 | try self.asmRegisterMemory( | 3987 | try self.asmRegisterMemory( |
| 3999 | .{ ._, .lea }, | 3988 | .{ ._, .lea }, |
| 4000 | registerAlias(dst_reg, dst_abi_size), | 3989 | registerAlias(dst_reg, dst_abi_size), |
| ... | @@ -4010,7 +3999,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4010,7 +3999,7 @@ fn airPtrSliceLenPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4010 | fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { | 3999 | fn airPtrSlicePtrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4011 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4000 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4012 | 4001 | ||
| 4013 | const dst_ty = self.air.typeOfIndex(inst); | 4002 | const dst_ty = self.typeOfIndex(inst); |
| 4014 | const opt_mcv = try self.resolveInst(ty_op.operand); | 4003 | const opt_mcv = try self.resolveInst(ty_op.operand); |
| 4015 | 4004 | ||
| 4016 | const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) | 4005 | const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) |
| ... | @@ -4041,7 +4030,8 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi | ... | @@ -4041,7 +4030,8 @@ fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Regi |
| 4041 | } | 4030 | } |
| 4042 | 4031 | ||
| 4043 | fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { | 4032 | fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 4044 | const slice_ty = self.air.typeOf(lhs); | 4033 | const mod = self.bin_file.options.module.?; |
| 4034 | const slice_ty = self.typeOf(lhs); | ||
| 4045 | const slice_mcv = try self.resolveInst(lhs); | 4035 | const slice_mcv = try self.resolveInst(lhs); |
| 4046 | const slice_mcv_lock: ?RegisterLock = switch (slice_mcv) { | 4036 | const slice_mcv_lock: ?RegisterLock = switch (slice_mcv) { |
| 4047 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4037 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -4049,12 +4039,11 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { | ... | @@ -4049,12 +4039,11 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 4049 | }; | 4039 | }; |
| 4050 | defer if (slice_mcv_lock) |lock| self.register_manager.unlockReg(lock); | 4040 | defer if (slice_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 4051 | 4041 | ||
| 4052 | const elem_ty = slice_ty.childType(); | 4042 | const elem_ty = slice_ty.childType(mod); |
| 4053 | const elem_size = elem_ty.abiSize(self.target.*); | 4043 | const elem_size = elem_ty.abiSize(mod); |
| 4054 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 4044 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(mod); |
| 4055 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | ||
| 4056 | 4045 | ||
| 4057 | const index_ty = self.air.typeOf(rhs); | 4046 | const index_ty = self.typeOf(rhs); |
| 4058 | const index_mcv = try self.resolveInst(rhs); | 4047 | const index_mcv = try self.resolveInst(rhs); |
| 4059 | const index_mcv_lock: ?RegisterLock = switch (index_mcv) { | 4048 | const index_mcv_lock: ?RegisterLock = switch (index_mcv) { |
| 4060 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4049 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -4077,11 +4066,11 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { | ... | @@ -4077,11 +4066,11 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 4077 | } | 4066 | } |
| 4078 | 4067 | ||
| 4079 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { | 4068 | fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4069 | const mod = self.bin_file.options.module.?; | ||
| 4080 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 4070 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4081 | const slice_ty = self.air.typeOf(bin_op.lhs); | 4071 | const slice_ty = self.typeOf(bin_op.lhs); |
| 4082 | 4072 | ||
| 4083 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 4073 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(mod); |
| 4084 | const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf); | ||
| 4085 | const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs); | 4074 | const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs); |
| 4086 | const dst_mcv = try self.allocRegOrMem(inst, false); | 4075 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 4087 | try self.load(dst_mcv, slice_ptr_field_type, elem_ptr); | 4076 | try self.load(dst_mcv, slice_ptr_field_type, elem_ptr); |
| ... | @@ -4097,9 +4086,10 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4097,9 +4086,10 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4097 | } | 4086 | } |
| 4098 | 4087 | ||
| 4099 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | 4088 | fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4089 | const mod = self.bin_file.options.module.?; | ||
| 4100 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 4090 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4101 | 4091 | ||
| 4102 | const array_ty = self.air.typeOf(bin_op.lhs); | 4092 | const array_ty = self.typeOf(bin_op.lhs); |
| 4103 | const array = try self.resolveInst(bin_op.lhs); | 4093 | const array = try self.resolveInst(bin_op.lhs); |
| 4104 | const array_lock: ?RegisterLock = switch (array) { | 4094 | const array_lock: ?RegisterLock = switch (array) { |
| 4105 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4095 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -4107,10 +4097,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4107,10 +4097,10 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4107 | }; | 4097 | }; |
| 4108 | defer if (array_lock) |lock| self.register_manager.unlockReg(lock); | 4098 | defer if (array_lock) |lock| self.register_manager.unlockReg(lock); |
| 4109 | 4099 | ||
| 4110 | const elem_ty = array_ty.childType(); | 4100 | const elem_ty = array_ty.childType(mod); |
| 4111 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 4101 | const elem_abi_size = elem_ty.abiSize(mod); |
| 4112 | 4102 | ||
| 4113 | const index_ty = self.air.typeOf(bin_op.rhs); | 4103 | const index_ty = self.typeOf(bin_op.rhs); |
| 4114 | const index = try self.resolveInst(bin_op.rhs); | 4104 | const index = try self.resolveInst(bin_op.rhs); |
| 4115 | const index_lock: ?RegisterLock = switch (index) { | 4105 | const index_lock: ?RegisterLock = switch (index) { |
| 4116 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4106 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -4125,7 +4115,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4125,7 +4115,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4125 | const addr_reg = try self.register_manager.allocReg(null, gp); | 4115 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 4126 | switch (array) { | 4116 | switch (array) { |
| 4127 | .register => { | 4117 | .register => { |
| 4128 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, self.target.*)); | 4118 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(array_ty, mod)); |
| 4129 | try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array); | 4119 | try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array); |
| 4130 | try self.asmRegisterMemory( | 4120 | try self.asmRegisterMemory( |
| 4131 | .{ ._, .lea }, | 4121 | .{ ._, .lea }, |
| ... | @@ -4162,15 +4152,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4162,15 +4152,16 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4162 | } | 4152 | } |
| 4163 | 4153 | ||
| 4164 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { | 4154 | fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4155 | const mod = self.bin_file.options.module.?; | ||
| 4165 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 4156 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4166 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 4157 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 4167 | 4158 | ||
| 4168 | // this is identical to the `airPtrElemPtr` codegen expect here an | 4159 | // this is identical to the `airPtrElemPtr` codegen expect here an |
| 4169 | // additional `mov` is needed at the end to get the actual value | 4160 | // additional `mov` is needed at the end to get the actual value |
| 4170 | 4161 | ||
| 4171 | const elem_ty = ptr_ty.elemType2(); | 4162 | const elem_ty = ptr_ty.elemType2(mod); |
| 4172 | const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | 4163 | const elem_abi_size = @intCast(u32, elem_ty.abiSize(mod)); |
| 4173 | const index_ty = self.air.typeOf(bin_op.rhs); | 4164 | const index_ty = self.typeOf(bin_op.rhs); |
| 4174 | const index_mcv = try self.resolveInst(bin_op.rhs); | 4165 | const index_mcv = try self.resolveInst(bin_op.rhs); |
| 4175 | const index_lock = switch (index_mcv) { | 4166 | const index_lock = switch (index_mcv) { |
| 4176 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4167 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -4207,10 +4198,11 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4207,10 +4198,11 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4207 | } | 4198 | } |
| 4208 | 4199 | ||
| 4209 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | 4200 | fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4201 | const mod = self.bin_file.options.module.?; | ||
| 4210 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 4202 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 4211 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 4203 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 4212 | 4204 | ||
| 4213 | const ptr_ty = self.air.typeOf(extra.lhs); | 4205 | const ptr_ty = self.typeOf(extra.lhs); |
| 4214 | const ptr = try self.resolveInst(extra.lhs); | 4206 | const ptr = try self.resolveInst(extra.lhs); |
| 4215 | const ptr_lock: ?RegisterLock = switch (ptr) { | 4207 | const ptr_lock: ?RegisterLock = switch (ptr) { |
| 4216 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4208 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -4218,9 +4210,9 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4218,9 +4210,9 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4218 | }; | 4210 | }; |
| 4219 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); | 4211 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 4220 | 4212 | ||
| 4221 | const elem_ty = ptr_ty.elemType2(); | 4213 | const elem_ty = ptr_ty.elemType2(mod); |
| 4222 | const elem_abi_size = elem_ty.abiSize(self.target.*); | 4214 | const elem_abi_size = elem_ty.abiSize(mod); |
| 4223 | const index_ty = self.air.typeOf(extra.rhs); | 4215 | const index_ty = self.typeOf(extra.rhs); |
| 4224 | const index = try self.resolveInst(extra.rhs); | 4216 | const index = try self.resolveInst(extra.rhs); |
| 4225 | const index_lock: ?RegisterLock = switch (index) { | 4217 | const index_lock: ?RegisterLock = switch (index) { |
| 4226 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 4218 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -4239,11 +4231,12 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4239,11 +4231,12 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 4239 | } | 4231 | } |
| 4240 | 4232 | ||
| 4241 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | 4233 | fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4234 | const mod = self.bin_file.options.module.?; | ||
| 4242 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 4235 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 4243 | const ptr_union_ty = self.air.typeOf(bin_op.lhs); | 4236 | const ptr_union_ty = self.typeOf(bin_op.lhs); |
| 4244 | const union_ty = ptr_union_ty.childType(); | 4237 | const union_ty = ptr_union_ty.childType(mod); |
| 4245 | const tag_ty = self.air.typeOf(bin_op.rhs); | 4238 | const tag_ty = self.typeOf(bin_op.rhs); |
| 4246 | const layout = union_ty.unionGetLayout(self.target.*); | 4239 | const layout = union_ty.unionGetLayout(mod); |
| 4247 | 4240 | ||
| 4248 | if (layout.tag_size == 0) { | 4241 | if (layout.tag_size == 0) { |
| 4249 | return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); | 4242 | return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); |
| ... | @@ -4275,20 +4268,19 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4275,20 +4268,19 @@ fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4275 | break :blk MCValue{ .register = reg }; | 4268 | break :blk MCValue{ .register = reg }; |
| 4276 | } else ptr; | 4269 | } else ptr; |
| 4277 | 4270 | ||
| 4278 | var ptr_tag_pl = ptr_union_ty.ptrInfo(); | 4271 | const ptr_tag_ty = try mod.adjustPtrTypeChild(ptr_union_ty, tag_ty); |
| 4279 | ptr_tag_pl.data.pointee_type = tag_ty; | ||
| 4280 | const ptr_tag_ty = Type.initPayload(&ptr_tag_pl.base); | ||
| 4281 | try self.store(ptr_tag_ty, adjusted_ptr, tag); | 4272 | try self.store(ptr_tag_ty, adjusted_ptr, tag); |
| 4282 | 4273 | ||
| 4283 | return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); | 4274 | return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 4284 | } | 4275 | } |
| 4285 | 4276 | ||
| 4286 | fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | 4277 | fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4278 | const mod = self.bin_file.options.module.?; | ||
| 4287 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4279 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4288 | 4280 | ||
| 4289 | const tag_ty = self.air.typeOfIndex(inst); | 4281 | const tag_ty = self.typeOfIndex(inst); |
| 4290 | const union_ty = self.air.typeOf(ty_op.operand); | 4282 | const union_ty = self.typeOf(ty_op.operand); |
| 4291 | const layout = union_ty.unionGetLayout(self.target.*); | 4283 | const layout = union_ty.unionGetLayout(mod); |
| 4292 | 4284 | ||
| 4293 | if (layout.tag_size == 0) { | 4285 | if (layout.tag_size == 0) { |
| 4294 | return self.finishAir(inst, .none, .{ ty_op.operand, .none, .none }); | 4286 | return self.finishAir(inst, .none, .{ ty_op.operand, .none, .none }); |
| ... | @@ -4302,7 +4294,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4302,7 +4294,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4302 | }; | 4294 | }; |
| 4303 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | 4295 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 4304 | 4296 | ||
| 4305 | const tag_abi_size = tag_ty.abiSize(self.target.*); | 4297 | const tag_abi_size = tag_ty.abiSize(mod); |
| 4306 | const dst_mcv: MCValue = blk: { | 4298 | const dst_mcv: MCValue = blk: { |
| 4307 | switch (operand) { | 4299 | switch (operand) { |
| 4308 | .load_frame => |frame_addr| { | 4300 | .load_frame => |frame_addr| { |
| ... | @@ -4337,10 +4329,11 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4337,10 +4329,11 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 4337 | } | 4329 | } |
| 4338 | 4330 | ||
| 4339 | fn airClz(self: *Self, inst: Air.Inst.Index) !void { | 4331 | fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4332 | const mod = self.bin_file.options.module.?; | ||
| 4340 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4333 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4341 | const result = result: { | 4334 | const result = result: { |
| 4342 | const dst_ty = self.air.typeOfIndex(inst); | 4335 | const dst_ty = self.typeOfIndex(inst); |
| 4343 | const src_ty = self.air.typeOf(ty_op.operand); | 4336 | const src_ty = self.typeOf(ty_op.operand); |
| 4344 | 4337 | ||
| 4345 | const src_mcv = try self.resolveInst(ty_op.operand); | 4338 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 4346 | const mat_src_mcv = switch (src_mcv) { | 4339 | const mat_src_mcv = switch (src_mcv) { |
| ... | @@ -4358,7 +4351,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4358,7 +4351,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4358 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 4351 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 4359 | defer self.register_manager.unlockReg(dst_lock); | 4352 | defer self.register_manager.unlockReg(dst_lock); |
| 4360 | 4353 | ||
| 4361 | const src_bits = src_ty.bitSize(self.target.*); | 4354 | const src_bits = src_ty.bitSize(mod); |
| 4362 | if (self.hasFeature(.lzcnt)) { | 4355 | if (self.hasFeature(.lzcnt)) { |
| 4363 | if (src_bits <= 8) { | 4356 | if (src_bits <= 8) { |
| 4364 | const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv); | 4357 | const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv); |
| ... | @@ -4405,7 +4398,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4405,7 +4398,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4405 | } | 4398 | } |
| 4406 | 4399 | ||
| 4407 | if (src_bits > 64) | 4400 | if (src_bits > 64) |
| 4408 | return self.fail("TODO airClz of {}", .{src_ty.fmt(self.bin_file.options.module.?)}); | 4401 | return self.fail("TODO airClz of {}", .{src_ty.fmt(mod)}); |
| 4409 | if (math.isPowerOfTwo(src_bits)) { | 4402 | if (math.isPowerOfTwo(src_bits)) { |
| 4410 | const imm_reg = try self.copyToTmpRegister(dst_ty, .{ | 4403 | const imm_reg = try self.copyToTmpRegister(dst_ty, .{ |
| 4411 | .immediate = src_bits ^ (src_bits - 1), | 4404 | .immediate = src_bits ^ (src_bits - 1), |
| ... | @@ -4422,7 +4415,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4422,7 +4415,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4422 | try self.genBinOpMir(.{ ._, .bsr }, Type.u16, dst_mcv, .{ .register = wide_reg }); | 4415 | try self.genBinOpMir(.{ ._, .bsr }, Type.u16, dst_mcv, .{ .register = wide_reg }); |
| 4423 | } else try self.genBinOpMir(.{ ._, .bsr }, src_ty, dst_mcv, mat_src_mcv); | 4416 | } else try self.genBinOpMir(.{ ._, .bsr }, src_ty, dst_mcv, mat_src_mcv); |
| 4424 | 4417 | ||
| 4425 | const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2); | 4418 | const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(mod)), 2); |
| 4426 | try self.asmCmovccRegisterRegister( | 4419 | try self.asmCmovccRegisterRegister( |
| 4427 | registerAlias(dst_reg, cmov_abi_size), | 4420 | registerAlias(dst_reg, cmov_abi_size), |
| 4428 | registerAlias(imm_reg, cmov_abi_size), | 4421 | registerAlias(imm_reg, cmov_abi_size), |
| ... | @@ -4449,7 +4442,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4449,7 +4442,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4449 | .{ .register = wide_reg }, | 4442 | .{ .register = wide_reg }, |
| 4450 | ); | 4443 | ); |
| 4451 | 4444 | ||
| 4452 | const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2); | 4445 | const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(mod)), 2); |
| 4453 | try self.asmCmovccRegisterRegister( | 4446 | try self.asmCmovccRegisterRegister( |
| 4454 | registerAlias(imm_reg, cmov_abi_size), | 4447 | registerAlias(imm_reg, cmov_abi_size), |
| 4455 | registerAlias(dst_reg, cmov_abi_size), | 4448 | registerAlias(dst_reg, cmov_abi_size), |
| ... | @@ -4465,11 +4458,12 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4465,11 +4458,12 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 4465 | } | 4458 | } |
| 4466 | 4459 | ||
| 4467 | fn airCtz(self: *Self, inst: Air.Inst.Index) !void { | 4460 | fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 4461 | const mod = self.bin_file.options.module.?; | ||
| 4468 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4462 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4469 | const result = result: { | 4463 | const result = result: { |
| 4470 | const dst_ty = self.air.typeOfIndex(inst); | 4464 | const dst_ty = self.typeOfIndex(inst); |
| 4471 | const src_ty = self.air.typeOf(ty_op.operand); | 4465 | const src_ty = self.typeOf(ty_op.operand); |
| 4472 | const src_bits = src_ty.bitSize(self.target.*); | 4466 | const src_bits = src_ty.bitSize(mod); |
| 4473 | 4467 | ||
| 4474 | const src_mcv = try self.resolveInst(ty_op.operand); | 4468 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 4475 | const mat_src_mcv = switch (src_mcv) { | 4469 | const mat_src_mcv = switch (src_mcv) { |
| ... | @@ -4548,7 +4542,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4548,7 +4542,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 4548 | try self.genBinOpMir(.{ ._, .bsf }, Type.u16, dst_mcv, .{ .register = wide_reg }); | 4542 | try self.genBinOpMir(.{ ._, .bsf }, Type.u16, dst_mcv, .{ .register = wide_reg }); |
| 4549 | } else try self.genBinOpMir(.{ ._, .bsf }, src_ty, dst_mcv, mat_src_mcv); | 4543 | } else try self.genBinOpMir(.{ ._, .bsf }, src_ty, dst_mcv, mat_src_mcv); |
| 4550 | 4544 | ||
| 4551 | const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(self.target.*)), 2); | 4545 | const cmov_abi_size = @max(@intCast(u32, dst_ty.abiSize(mod)), 2); |
| 4552 | try self.asmCmovccRegisterRegister( | 4546 | try self.asmCmovccRegisterRegister( |
| 4553 | registerAlias(dst_reg, cmov_abi_size), | 4547 | registerAlias(dst_reg, cmov_abi_size), |
| 4554 | registerAlias(width_reg, cmov_abi_size), | 4548 | registerAlias(width_reg, cmov_abi_size), |
| ... | @@ -4560,10 +4554,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4560,10 +4554,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 4560 | } | 4554 | } |
| 4561 | 4555 | ||
| 4562 | fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { | 4556 | fn airPopcount(self: *Self, inst: Air.Inst.Index) !void { |
| 4557 | const mod = self.bin_file.options.module.?; | ||
| 4563 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4558 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4564 | const result: MCValue = result: { | 4559 | const result: MCValue = result: { |
| 4565 | const src_ty = self.air.typeOf(ty_op.operand); | 4560 | const src_ty = self.typeOf(ty_op.operand); |
| 4566 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | 4561 | const src_abi_size = @intCast(u32, src_ty.abiSize(mod)); |
| 4567 | const src_mcv = try self.resolveInst(ty_op.operand); | 4562 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 4568 | 4563 | ||
| 4569 | if (self.hasFeature(.popcnt)) { | 4564 | if (self.hasFeature(.popcnt)) { |
| ... | @@ -4729,16 +4724,17 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m | ... | @@ -4729,16 +4724,17 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m |
| 4729 | } | 4724 | } |
| 4730 | 4725 | ||
| 4731 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { | 4726 | fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 4727 | const mod = self.bin_file.options.module.?; | ||
| 4732 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4728 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4733 | 4729 | ||
| 4734 | const src_ty = self.air.typeOf(ty_op.operand); | 4730 | const src_ty = self.typeOf(ty_op.operand); |
| 4735 | const src_mcv = try self.resolveInst(ty_op.operand); | 4731 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 4736 | 4732 | ||
| 4737 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, true); | 4733 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, true); |
| 4738 | switch (self.regExtraBits(src_ty)) { | 4734 | switch (self.regExtraBits(src_ty)) { |
| 4739 | 0 => {}, | 4735 | 0 => {}, |
| 4740 | else => |extra| try self.genBinOpMir( | 4736 | else => |extra| try self.genBinOpMir( |
| 4741 | if (src_ty.isSignedInt()) .{ ._r, .sa } else .{ ._r, .sh }, | 4737 | if (src_ty.isSignedInt(mod)) .{ ._r, .sa } else .{ ._r, .sh }, |
| 4742 | src_ty, | 4738 | src_ty, |
| 4743 | dst_mcv, | 4739 | dst_mcv, |
| 4744 | .{ .immediate = extra }, | 4740 | .{ .immediate = extra }, |
| ... | @@ -4749,10 +4745,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4749,10 +4745,11 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 4749 | } | 4745 | } |
| 4750 | 4746 | ||
| 4751 | fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { | 4747 | fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 4748 | const mod = self.bin_file.options.module.?; | ||
| 4752 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4749 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4753 | 4750 | ||
| 4754 | const src_ty = self.air.typeOf(ty_op.operand); | 4751 | const src_ty = self.typeOf(ty_op.operand); |
| 4755 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | 4752 | const src_abi_size = @intCast(u32, src_ty.abiSize(mod)); |
| 4756 | const src_mcv = try self.resolveInst(ty_op.operand); | 4753 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 4757 | 4754 | ||
| 4758 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, false); | 4755 | const dst_mcv = try self.byteSwap(inst, src_ty, src_mcv, false); |
| ... | @@ -4847,7 +4844,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4847,7 +4844,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 4847 | switch (self.regExtraBits(src_ty)) { | 4844 | switch (self.regExtraBits(src_ty)) { |
| 4848 | 0 => {}, | 4845 | 0 => {}, |
| 4849 | else => |extra| try self.genBinOpMir( | 4846 | else => |extra| try self.genBinOpMir( |
| 4850 | if (src_ty.isSignedInt()) .{ ._r, .sa } else .{ ._r, .sh }, | 4847 | if (src_ty.isSignedInt(mod)) .{ ._r, .sa } else .{ ._r, .sh }, |
| 4851 | src_ty, | 4848 | src_ty, |
| 4852 | dst_mcv, | 4849 | dst_mcv, |
| 4853 | .{ .immediate = extra }, | 4850 | .{ .immediate = extra }, |
| ... | @@ -4858,17 +4855,18 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4858,17 +4855,18 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 4858 | } | 4855 | } |
| 4859 | 4856 | ||
| 4860 | fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { | 4857 | fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 4858 | const mod = self.bin_file.options.module.?; | ||
| 4861 | const tag = self.air.instructions.items(.tag)[inst]; | 4859 | const tag = self.air.instructions.items(.tag)[inst]; |
| 4862 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4860 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4863 | const ty = self.air.typeOf(un_op); | 4861 | const ty = self.typeOf(un_op); |
| 4864 | const abi_size: u32 = switch (ty.abiSize(self.target.*)) { | 4862 | const abi_size: u32 = switch (ty.abiSize(mod)) { |
| 4865 | 1...16 => 16, | 4863 | 1...16 => 16, |
| 4866 | 17...32 => 32, | 4864 | 17...32 => 32, |
| 4867 | else => return self.fail("TODO implement airFloatSign for {}", .{ | 4865 | else => return self.fail("TODO implement airFloatSign for {}", .{ |
| 4868 | ty.fmt(self.bin_file.options.module.?), | 4866 | ty.fmt(mod), |
| 4869 | }), | 4867 | }), |
| 4870 | }; | 4868 | }; |
| 4871 | const scalar_bits = ty.scalarType().floatBits(self.target.*); | 4869 | const scalar_bits = ty.scalarType(mod).floatBits(self.target.*); |
| 4872 | 4870 | ||
| 4873 | const src_mcv = try self.resolveInst(un_op); | 4871 | const src_mcv = try self.resolveInst(un_op); |
| 4874 | const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; | 4872 | const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| ... | @@ -4884,42 +4882,14 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4884,42 +4882,14 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 4884 | const dst_lock = self.register_manager.lockReg(dst_reg); | 4882 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 4885 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 4883 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 4886 | 4884 | ||
| 4887 | var arena = std.heap.ArenaAllocator.init(self.gpa); | 4885 | const vec_ty = try mod.vectorType(.{ |
| 4888 | defer arena.deinit(); | 4886 | .len = @divExact(abi_size * 8, scalar_bits), |
| 4889 | 4887 | .child = (try mod.intType(.signed, scalar_bits)).ip_index, | |
| 4890 | const ExpectedContents = struct { | 4888 | }); |
| 4891 | scalar: union { | ||
| 4892 | i64: Value.Payload.I64, | ||
| 4893 | big: struct { | ||
| 4894 | limbs: [ | ||
| 4895 | @max( | ||
| 4896 | std.math.big.int.Managed.default_capacity, | ||
| 4897 | std.math.big.int.calcTwosCompLimbCount(128), | ||
| 4898 | ) | ||
| 4899 | ]std.math.big.Limb, | ||
| 4900 | pl: Value.Payload.BigInt, | ||
| 4901 | }, | ||
| 4902 | }, | ||
| 4903 | repeated: Value.Payload.SubValue, | ||
| 4904 | }; | ||
| 4905 | var stack align(@alignOf(ExpectedContents)) = | ||
| 4906 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); | ||
| 4907 | 4889 | ||
| 4908 | var int_pl = Type.Payload.Bits{ | ||
| 4909 | .base = .{ .tag = .int_signed }, | ||
| 4910 | .data = scalar_bits, | ||
| 4911 | }; | ||
| 4912 | var vec_pl = Type.Payload.Array{ | ||
| 4913 | .base = .{ .tag = .vector }, | ||
| 4914 | .data = .{ | ||
| 4915 | .len = @divExact(abi_size * 8, scalar_bits), | ||
| 4916 | .elem_type = Type.initPayload(&int_pl.base), | ||
| 4917 | }, | ||
| 4918 | }; | ||
| 4919 | const vec_ty = Type.initPayload(&vec_pl.base); | ||
| 4920 | const sign_val = switch (tag) { | 4890 | const sign_val = switch (tag) { |
| 4921 | .neg => try vec_ty.minInt(stack.get(), self.target.*), | 4891 | .neg => try vec_ty.minInt(mod, vec_ty), |
| 4922 | .fabs => try vec_ty.maxInt(stack.get(), self.target.*), | 4892 | .fabs => try vec_ty.maxInt(mod, vec_ty), |
| 4923 | else => unreachable, | 4893 | else => unreachable, |
| 4924 | }; | 4894 | }; |
| 4925 | 4895 | ||
| ... | @@ -4993,7 +4963,7 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4993,7 +4963,7 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 4993 | 4963 | ||
| 4994 | fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void { | 4964 | fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void { |
| 4995 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4965 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4996 | const ty = self.air.typeOf(un_op); | 4966 | const ty = self.typeOf(un_op); |
| 4997 | 4967 | ||
| 4998 | const src_mcv = try self.resolveInst(un_op); | 4968 | const src_mcv = try self.resolveInst(un_op); |
| 4999 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv)) | 4969 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv)) |
| ... | @@ -5008,25 +4978,26 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void { | ... | @@ -5008,25 +4978,26 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: u4) !void { |
| 5008 | } | 4978 | } |
| 5009 | 4979 | ||
| 5010 | fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4) !void { | 4980 | fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4) !void { |
| 4981 | const mod = self.bin_file.options.module.?; | ||
| 5011 | if (!self.hasFeature(.sse4_1)) | 4982 | if (!self.hasFeature(.sse4_1)) |
| 5012 | return self.fail("TODO implement genRound without sse4_1 feature", .{}); | 4983 | return self.fail("TODO implement genRound without sse4_1 feature", .{}); |
| 5013 | 4984 | ||
| 5014 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag()) { | 4985 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) { |
| 5015 | .Float => switch (ty.floatBits(self.target.*)) { | 4986 | .Float => switch (ty.floatBits(self.target.*)) { |
| 5016 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round }, | 4987 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round }, |
| 5017 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round }, | 4988 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round }, |
| 5018 | 16, 80, 128 => null, | 4989 | 16, 80, 128 => null, |
| 5019 | else => unreachable, | 4990 | else => unreachable, |
| 5020 | }, | 4991 | }, |
| 5021 | .Vector => switch (ty.childType().zigTypeTag()) { | 4992 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { |
| 5022 | .Float => switch (ty.childType().floatBits(self.target.*)) { | 4993 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 5023 | 32 => switch (ty.vectorLen()) { | 4994 | 32 => switch (ty.vectorLen(mod)) { |
| 5024 | 1 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round }, | 4995 | 1 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round }, |
| 5025 | 2...4 => if (self.hasFeature(.avx)) .{ .v_ps, .round } else .{ ._ps, .round }, | 4996 | 2...4 => if (self.hasFeature(.avx)) .{ .v_ps, .round } else .{ ._ps, .round }, |
| 5026 | 5...8 => if (self.hasFeature(.avx)) .{ .v_ps, .round } else null, | 4997 | 5...8 => if (self.hasFeature(.avx)) .{ .v_ps, .round } else null, |
| 5027 | else => null, | 4998 | else => null, |
| 5028 | }, | 4999 | }, |
| 5029 | 64 => switch (ty.vectorLen()) { | 5000 | 64 => switch (ty.vectorLen(mod)) { |
| 5030 | 1 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round }, | 5001 | 1 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round }, |
| 5031 | 2 => if (self.hasFeature(.avx)) .{ .v_pd, .round } else .{ ._pd, .round }, | 5002 | 2 => if (self.hasFeature(.avx)) .{ .v_pd, .round } else .{ ._pd, .round }, |
| 5032 | 3...4 => if (self.hasFeature(.avx)) .{ .v_pd, .round } else null, | 5003 | 3...4 => if (self.hasFeature(.avx)) .{ .v_pd, .round } else null, |
| ... | @@ -5041,7 +5012,7 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4 | ... | @@ -5041,7 +5012,7 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4 |
| 5041 | })) |tag| tag else return self.fail("TODO implement genRound for {}", .{ | 5012 | })) |tag| tag else return self.fail("TODO implement genRound for {}", .{ |
| 5042 | ty.fmt(self.bin_file.options.module.?), | 5013 | ty.fmt(self.bin_file.options.module.?), |
| 5043 | }); | 5014 | }); |
| 5044 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 5015 | const abi_size = @intCast(u32, ty.abiSize(mod)); |
| 5045 | const dst_alias = registerAlias(dst_reg, abi_size); | 5016 | const dst_alias = registerAlias(dst_reg, abi_size); |
| 5046 | switch (mir_tag[0]) { | 5017 | switch (mir_tag[0]) { |
| 5047 | .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( | 5018 | .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemoryImmediate( |
| ... | @@ -5078,9 +5049,10 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4 | ... | @@ -5078,9 +5049,10 @@ fn genRound(self: *Self, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: u4 |
| 5078 | } | 5049 | } |
| 5079 | 5050 | ||
| 5080 | fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { | 5051 | fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 5052 | const mod = self.bin_file.options.module.?; | ||
| 5081 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 5053 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5082 | const ty = self.air.typeOf(un_op); | 5054 | const ty = self.typeOf(un_op); |
| 5083 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 5055 | const abi_size = @intCast(u32, ty.abiSize(mod)); |
| 5084 | 5056 | ||
| 5085 | const src_mcv = try self.resolveInst(un_op); | 5057 | const src_mcv = try self.resolveInst(un_op); |
| 5086 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv)) | 5058 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv)) |
| ... | @@ -5092,7 +5064,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5092,7 +5064,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 5092 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 5064 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5093 | 5065 | ||
| 5094 | const result: MCValue = result: { | 5066 | const result: MCValue = result: { |
| 5095 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag()) { | 5067 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) { |
| 5096 | .Float => switch (ty.floatBits(self.target.*)) { | 5068 | .Float => switch (ty.floatBits(self.target.*)) { |
| 5097 | 16 => if (self.hasFeature(.f16c)) { | 5069 | 16 => if (self.hasFeature(.f16c)) { |
| 5098 | const mat_src_reg = if (src_mcv.isRegister()) | 5070 | const mat_src_reg = if (src_mcv.isRegister()) |
| ... | @@ -5114,9 +5086,9 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5114,9 +5086,9 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 5114 | 80, 128 => null, | 5086 | 80, 128 => null, |
| 5115 | else => unreachable, | 5087 | else => unreachable, |
| 5116 | }, | 5088 | }, |
| 5117 | .Vector => switch (ty.childType().zigTypeTag()) { | 5089 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { |
| 5118 | .Float => switch (ty.childType().floatBits(self.target.*)) { | 5090 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 5119 | 16 => if (self.hasFeature(.f16c)) switch (ty.vectorLen()) { | 5091 | 16 => if (self.hasFeature(.f16c)) switch (ty.vectorLen(mod)) { |
| 5120 | 1 => { | 5092 | 1 => { |
| 5121 | try self.asmRegisterRegister( | 5093 | try self.asmRegisterRegister( |
| 5122 | .{ .v_ps, .cvtph2 }, | 5094 | .{ .v_ps, .cvtph2 }, |
| ... | @@ -5167,13 +5139,13 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5167,13 +5139,13 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 5167 | }, | 5139 | }, |
| 5168 | else => null, | 5140 | else => null, |
| 5169 | } else null, | 5141 | } else null, |
| 5170 | 32 => switch (ty.vectorLen()) { | 5142 | 32 => switch (ty.vectorLen(mod)) { |
| 5171 | 1 => if (self.hasFeature(.avx)) .{ .v_ss, .sqrt } else .{ ._ss, .sqrt }, | 5143 | 1 => if (self.hasFeature(.avx)) .{ .v_ss, .sqrt } else .{ ._ss, .sqrt }, |
| 5172 | 2...4 => if (self.hasFeature(.avx)) .{ .v_ps, .sqrt } else .{ ._ps, .sqrt }, | 5144 | 2...4 => if (self.hasFeature(.avx)) .{ .v_ps, .sqrt } else .{ ._ps, .sqrt }, |
| 5173 | 5...8 => if (self.hasFeature(.avx)) .{ .v_ps, .sqrt } else null, | 5145 | 5...8 => if (self.hasFeature(.avx)) .{ .v_ps, .sqrt } else null, |
| 5174 | else => null, | 5146 | else => null, |
| 5175 | }, | 5147 | }, |
| 5176 | 64 => switch (ty.vectorLen()) { | 5148 | 64 => switch (ty.vectorLen(mod)) { |
| 5177 | 1 => if (self.hasFeature(.avx)) .{ .v_sd, .sqrt } else .{ ._sd, .sqrt }, | 5149 | 1 => if (self.hasFeature(.avx)) .{ .v_sd, .sqrt } else .{ ._sd, .sqrt }, |
| 5178 | 2 => if (self.hasFeature(.avx)) .{ .v_pd, .sqrt } else .{ ._pd, .sqrt }, | 5150 | 2 => if (self.hasFeature(.avx)) .{ .v_pd, .sqrt } else .{ ._pd, .sqrt }, |
| 5179 | 3...4 => if (self.hasFeature(.avx)) .{ .v_pd, .sqrt } else null, | 5151 | 3...4 => if (self.hasFeature(.avx)) .{ .v_pd, .sqrt } else null, |
| ... | @@ -5186,7 +5158,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5186,7 +5158,7 @@ fn airSqrt(self: *Self, inst: Air.Inst.Index) !void { |
| 5186 | }, | 5158 | }, |
| 5187 | else => unreachable, | 5159 | else => unreachable, |
| 5188 | })) |tag| tag else return self.fail("TODO implement airSqrt for {}", .{ | 5160 | })) |tag| tag else return self.fail("TODO implement airSqrt for {}", .{ |
| 5189 | ty.fmt(self.bin_file.options.module.?), | 5161 | ty.fmt(mod), |
| 5190 | }); | 5162 | }); |
| 5191 | switch (mir_tag[0]) { | 5163 | switch (mir_tag[0]) { |
| 5192 | .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( | 5164 | .v_ss, .v_sd => if (src_mcv.isMemory()) try self.asmRegisterRegisterMemory( |
| ... | @@ -5274,10 +5246,11 @@ fn reuseOperandAdvanced( | ... | @@ -5274,10 +5246,11 @@ fn reuseOperandAdvanced( |
| 5274 | } | 5246 | } |
| 5275 | 5247 | ||
| 5276 | fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { | 5248 | fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { |
| 5277 | const ptr_info = ptr_ty.ptrInfo().data; | 5249 | const mod = self.bin_file.options.module.?; |
| 5250 | const ptr_info = ptr_ty.ptrInfo(mod); | ||
| 5278 | 5251 | ||
| 5279 | const val_ty = ptr_info.pointee_type; | 5252 | const val_ty = ptr_info.pointee_type; |
| 5280 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); | 5253 | const val_abi_size = @intCast(u32, val_ty.abiSize(mod)); |
| 5281 | const limb_abi_size: u32 = @min(val_abi_size, 8); | 5254 | const limb_abi_size: u32 = @min(val_abi_size, 8); |
| 5282 | const limb_abi_bits = limb_abi_size * 8; | 5255 | const limb_abi_bits = limb_abi_size * 8; |
| 5283 | const val_byte_off = @intCast(i32, ptr_info.bit_offset / limb_abi_bits * limb_abi_size); | 5256 | const val_byte_off = @intCast(i32, ptr_info.bit_offset / limb_abi_bits * limb_abi_size); |
| ... | @@ -5347,7 +5320,8 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn | ... | @@ -5347,7 +5320,8 @@ fn packedLoad(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) Inn |
| 5347 | } | 5320 | } |
| 5348 | 5321 | ||
| 5349 | fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { | 5322 | fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void { |
| 5350 | const dst_ty = ptr_ty.childType(); | 5323 | const mod = self.bin_file.options.module.?; |
| 5324 | const dst_ty = ptr_ty.childType(mod); | ||
| 5351 | switch (ptr_mcv) { | 5325 | switch (ptr_mcv) { |
| 5352 | .none, | 5326 | .none, |
| 5353 | .unreach, | 5327 | .unreach, |
| ... | @@ -5382,20 +5356,21 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro | ... | @@ -5382,20 +5356,21 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 5382 | } | 5356 | } |
| 5383 | 5357 | ||
| 5384 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | 5358 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 5359 | const mod = self.bin_file.options.module.?; | ||
| 5385 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5360 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5386 | const elem_ty = self.air.typeOfIndex(inst); | 5361 | const elem_ty = self.typeOfIndex(inst); |
| 5387 | const result: MCValue = result: { | 5362 | const result: MCValue = result: { |
| 5388 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none; | 5363 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none; |
| 5389 | 5364 | ||
| 5390 | try self.spillRegisters(&.{ .rdi, .rsi, .rcx }); | 5365 | try self.spillRegisters(&.{ .rdi, .rsi, .rcx }); |
| 5391 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx }); | 5366 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx }); |
| 5392 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); | 5367 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 5393 | 5368 | ||
| 5394 | const ptr_ty = self.air.typeOf(ty_op.operand); | 5369 | const ptr_ty = self.typeOf(ty_op.operand); |
| 5395 | const elem_size = elem_ty.abiSize(self.target.*); | 5370 | const elem_size = elem_ty.abiSize(mod); |
| 5396 | 5371 | ||
| 5397 | const elem_rc = regClassForType(elem_ty); | 5372 | const elem_rc = regClassForType(elem_ty, mod); |
| 5398 | const ptr_rc = regClassForType(ptr_ty); | 5373 | const ptr_rc = regClassForType(ptr_ty, mod); |
| 5399 | 5374 | ||
| 5400 | const ptr_mcv = try self.resolveInst(ty_op.operand); | 5375 | const ptr_mcv = try self.resolveInst(ty_op.operand); |
| 5401 | const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and | 5376 | const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and |
| ... | @@ -5405,7 +5380,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5405,7 +5380,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 5405 | else | 5380 | else |
| 5406 | try self.allocRegOrMem(inst, true); | 5381 | try self.allocRegOrMem(inst, true); |
| 5407 | 5382 | ||
| 5408 | if (ptr_ty.ptrInfo().data.host_size > 0) { | 5383 | if (ptr_ty.ptrInfo(mod).host_size > 0) { |
| 5409 | try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv); | 5384 | try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv); |
| 5410 | } else { | 5385 | } else { |
| 5411 | try self.load(dst_mcv, ptr_ty, ptr_mcv); | 5386 | try self.load(dst_mcv, ptr_ty, ptr_mcv); |
| ... | @@ -5416,13 +5391,14 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5416,13 +5391,14 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 5416 | } | 5391 | } |
| 5417 | 5392 | ||
| 5418 | fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void { | 5393 | fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| 5419 | const ptr_info = ptr_ty.ptrInfo().data; | 5394 | const mod = self.bin_file.options.module.?; |
| 5420 | const src_ty = ptr_ty.childType(); | 5395 | const ptr_info = ptr_ty.ptrInfo(mod); |
| 5396 | const src_ty = ptr_ty.childType(mod); | ||
| 5421 | 5397 | ||
| 5422 | const limb_abi_size: u16 = @min(ptr_info.host_size, 8); | 5398 | const limb_abi_size: u16 = @min(ptr_info.host_size, 8); |
| 5423 | const limb_abi_bits = limb_abi_size * 8; | 5399 | const limb_abi_bits = limb_abi_size * 8; |
| 5424 | 5400 | ||
| 5425 | const src_bit_size = src_ty.bitSize(self.target.*); | 5401 | const src_bit_size = src_ty.bitSize(mod); |
| 5426 | const src_byte_off = @intCast(i32, ptr_info.bit_offset / limb_abi_bits * limb_abi_size); | 5402 | const src_byte_off = @intCast(i32, ptr_info.bit_offset / limb_abi_bits * limb_abi_size); |
| 5427 | const src_bit_off = ptr_info.bit_offset % limb_abi_bits; | 5403 | const src_bit_off = ptr_info.bit_offset % limb_abi_bits; |
| 5428 | 5404 | ||
| ... | @@ -5489,7 +5465,8 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In | ... | @@ -5489,7 +5465,8 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In |
| 5489 | } | 5465 | } |
| 5490 | 5466 | ||
| 5491 | fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void { | 5467 | fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| 5492 | const src_ty = ptr_ty.childType(); | 5468 | const mod = self.bin_file.options.module.?; |
| 5469 | const src_ty = ptr_ty.childType(mod); | ||
| 5493 | switch (ptr_mcv) { | 5470 | switch (ptr_mcv) { |
| 5494 | .none, | 5471 | .none, |
| 5495 | .unreach, | 5472 | .unreach, |
| ... | @@ -5524,6 +5501,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr | ... | @@ -5524,6 +5501,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr |
| 5524 | } | 5501 | } |
| 5525 | 5502 | ||
| 5526 | fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | 5503 | fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 5504 | const mod = self.bin_file.options.module.?; | ||
| 5527 | if (safety) { | 5505 | if (safety) { |
| 5528 | // TODO if the value is undef, write 0xaa bytes to dest | 5506 | // TODO if the value is undef, write 0xaa bytes to dest |
| 5529 | } else { | 5507 | } else { |
| ... | @@ -5531,9 +5509,9 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -5531,9 +5509,9 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 5531 | } | 5509 | } |
| 5532 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 5510 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5533 | const ptr_mcv = try self.resolveInst(bin_op.lhs); | 5511 | const ptr_mcv = try self.resolveInst(bin_op.lhs); |
| 5534 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 5512 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 5535 | const src_mcv = try self.resolveInst(bin_op.rhs); | 5513 | const src_mcv = try self.resolveInst(bin_op.rhs); |
| 5536 | if (ptr_ty.ptrInfo().data.host_size > 0) { | 5514 | if (ptr_ty.ptrInfo(mod).host_size > 0) { |
| 5537 | try self.packedStore(ptr_ty, ptr_mcv, src_mcv); | 5515 | try self.packedStore(ptr_ty, ptr_mcv, src_mcv); |
| 5538 | } else { | 5516 | } else { |
| 5539 | try self.store(ptr_ty, ptr_mcv, src_mcv); | 5517 | try self.store(ptr_ty, ptr_mcv, src_mcv); |
| ... | @@ -5555,14 +5533,15 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { | ... | @@ -5555,14 +5533,15 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { |
| 5555 | } | 5533 | } |
| 5556 | 5534 | ||
| 5557 | fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { | 5535 | fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { |
| 5558 | const ptr_field_ty = self.air.typeOfIndex(inst); | 5536 | const mod = self.bin_file.options.module.?; |
| 5559 | const ptr_container_ty = self.air.typeOf(operand); | 5537 | const ptr_field_ty = self.typeOfIndex(inst); |
| 5560 | const container_ty = ptr_container_ty.childType(); | 5538 | const ptr_container_ty = self.typeOf(operand); |
| 5561 | const field_offset = @intCast(i32, switch (container_ty.containerLayout()) { | 5539 | const container_ty = ptr_container_ty.childType(mod); |
| 5562 | .Auto, .Extern => container_ty.structFieldOffset(index, self.target.*), | 5540 | const field_offset = @intCast(i32, switch (container_ty.containerLayout(mod)) { |
| 5563 | .Packed => if (container_ty.zigTypeTag() == .Struct and | 5541 | .Auto, .Extern => container_ty.structFieldOffset(index, mod), |
| 5564 | ptr_field_ty.ptrInfo().data.host_size == 0) | 5542 | .Packed => if (container_ty.zigTypeTag(mod) == .Struct and |
| 5565 | container_ty.packedStructFieldByteOffset(index, self.target.*) | 5543 | ptr_field_ty.ptrInfo(mod).host_size == 0) |
| 5544 | container_ty.packedStructFieldByteOffset(index, mod) | ||
| 5566 | else | 5545 | else |
| 5567 | 0, | 5546 | 0, |
| 5568 | }); | 5547 | }); |
| ... | @@ -5577,24 +5556,25 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 | ... | @@ -5577,24 +5556,25 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32 |
| 5577 | } | 5556 | } |
| 5578 | 5557 | ||
| 5579 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | 5558 | fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5559 | const mod = self.bin_file.options.module.?; | ||
| 5580 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5560 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5581 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 5561 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 5582 | const result: MCValue = result: { | 5562 | const result: MCValue = result: { |
| 5583 | const operand = extra.struct_operand; | 5563 | const operand = extra.struct_operand; |
| 5584 | const index = extra.field_index; | 5564 | const index = extra.field_index; |
| 5585 | 5565 | ||
| 5586 | const container_ty = self.air.typeOf(operand); | 5566 | const container_ty = self.typeOf(operand); |
| 5587 | const container_rc = regClassForType(container_ty); | 5567 | const container_rc = regClassForType(container_ty, mod); |
| 5588 | const field_ty = container_ty.structFieldType(index); | 5568 | const field_ty = container_ty.structFieldType(index, mod); |
| 5589 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) break :result .none; | 5569 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none; |
| 5590 | const field_rc = regClassForType(field_ty); | 5570 | const field_rc = regClassForType(field_ty, mod); |
| 5591 | const field_is_gp = field_rc.supersetOf(gp); | 5571 | const field_is_gp = field_rc.supersetOf(gp); |
| 5592 | 5572 | ||
| 5593 | const src_mcv = try self.resolveInst(operand); | 5573 | const src_mcv = try self.resolveInst(operand); |
| 5594 | const field_off = switch (container_ty.containerLayout()) { | 5574 | const field_off = switch (container_ty.containerLayout(mod)) { |
| 5595 | .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*) * 8), | 5575 | .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, mod) * 8), |
| 5596 | .Packed => if (container_ty.castTag(.@"struct")) |struct_obj| | 5576 | .Packed => if (mod.typeToStruct(container_ty)) |struct_obj| |
| 5597 | struct_obj.data.packedFieldBitOffset(self.target.*, index) | 5577 | struct_obj.packedFieldBitOffset(mod, index) |
| 5598 | else | 5578 | else |
| 5599 | 0, | 5579 | 0, |
| 5600 | }; | 5580 | }; |
| ... | @@ -5611,7 +5591,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5611,7 +5591,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5611 | break :result dst_mcv; | 5591 | break :result dst_mcv; |
| 5612 | } | 5592 | } |
| 5613 | 5593 | ||
| 5614 | const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*)); | 5594 | const field_abi_size = @intCast(u32, field_ty.abiSize(mod)); |
| 5615 | const limb_abi_size: u32 = @min(field_abi_size, 8); | 5595 | const limb_abi_size: u32 = @min(field_abi_size, 8); |
| 5616 | const limb_abi_bits = limb_abi_size * 8; | 5596 | const limb_abi_bits = limb_abi_size * 8; |
| 5617 | const field_byte_off = @intCast(i32, field_off / limb_abi_bits * limb_abi_size); | 5597 | const field_byte_off = @intCast(i32, field_off / limb_abi_bits * limb_abi_size); |
| ... | @@ -5733,12 +5713,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5733,12 +5713,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 5733 | } | 5713 | } |
| 5734 | 5714 | ||
| 5735 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | 5715 | fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5716 | const mod = self.bin_file.options.module.?; | ||
| 5736 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5717 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5737 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; | 5718 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 5738 | 5719 | ||
| 5739 | const inst_ty = self.air.typeOfIndex(inst); | 5720 | const inst_ty = self.typeOfIndex(inst); |
| 5740 | const parent_ty = inst_ty.childType(); | 5721 | const parent_ty = inst_ty.childType(mod); |
| 5741 | const field_offset = @intCast(i32, parent_ty.structFieldOffset(extra.field_index, self.target.*)); | 5722 | const field_offset = @intCast(i32, parent_ty.structFieldOffset(extra.field_index, mod)); |
| 5742 | 5723 | ||
| 5743 | const src_mcv = try self.resolveInst(extra.field_ptr); | 5724 | const src_mcv = try self.resolveInst(extra.field_ptr); |
| 5744 | const dst_mcv = if (src_mcv.isRegisterOffset() and | 5725 | const dst_mcv = if (src_mcv.isRegisterOffset() and |
| ... | @@ -5751,9 +5732,10 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5751,9 +5732,10 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 5751 | } | 5732 | } |
| 5752 | 5733 | ||
| 5753 | fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { | 5734 | fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { |
| 5754 | const src_ty = self.air.typeOf(src_air); | 5735 | const mod = self.bin_file.options.module.?; |
| 5736 | const src_ty = self.typeOf(src_air); | ||
| 5755 | const src_mcv = try self.resolveInst(src_air); | 5737 | const src_mcv = try self.resolveInst(src_air); |
| 5756 | if (src_ty.zigTypeTag() == .Vector) { | 5738 | if (src_ty.zigTypeTag(mod) == .Vector) { |
| 5757 | return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)}); | 5739 | return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)}); |
| 5758 | } | 5740 | } |
| 5759 | 5741 | ||
| ... | @@ -5786,28 +5768,22 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: | ... | @@ -5786,28 +5768,22 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 5786 | 5768 | ||
| 5787 | switch (tag) { | 5769 | switch (tag) { |
| 5788 | .not => { | 5770 | .not => { |
| 5789 | const limb_abi_size = @intCast(u16, @min(src_ty.abiSize(self.target.*), 8)); | 5771 | const limb_abi_size = @intCast(u16, @min(src_ty.abiSize(mod), 8)); |
| 5790 | const int_info = if (src_ty.tag() == .bool) | 5772 | const int_info = if (src_ty.ip_index == .bool_type) |
| 5791 | std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 } | 5773 | std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 } |
| 5792 | else | 5774 | else |
| 5793 | src_ty.intInfo(self.target.*); | 5775 | src_ty.intInfo(mod); |
| 5794 | var byte_off: i32 = 0; | 5776 | var byte_off: i32 = 0; |
| 5795 | while (byte_off * 8 < int_info.bits) : (byte_off += limb_abi_size) { | 5777 | while (byte_off * 8 < int_info.bits) : (byte_off += limb_abi_size) { |
| 5796 | var limb_pl = Type.Payload.Bits{ | 5778 | const limb_bits = @intCast(u16, @min(int_info.bits - byte_off * 8, limb_abi_size * 8)); |
| 5797 | .base = .{ .tag = switch (int_info.signedness) { | 5779 | const limb_ty = try mod.intType(int_info.signedness, limb_bits); |
| 5798 | .signed => .int_signed, | ||
| 5799 | .unsigned => .int_unsigned, | ||
| 5800 | } }, | ||
| 5801 | .data = @intCast(u16, @min(int_info.bits - byte_off * 8, limb_abi_size * 8)), | ||
| 5802 | }; | ||
| 5803 | const limb_ty = Type.initPayload(&limb_pl.base); | ||
| 5804 | const limb_mcv = switch (byte_off) { | 5780 | const limb_mcv = switch (byte_off) { |
| 5805 | 0 => dst_mcv, | 5781 | 0 => dst_mcv, |
| 5806 | else => dst_mcv.address().offset(byte_off).deref(), | 5782 | else => dst_mcv.address().offset(byte_off).deref(), |
| 5807 | }; | 5783 | }; |
| 5808 | 5784 | ||
| 5809 | if (limb_pl.base.tag == .int_unsigned and self.regExtraBits(limb_ty) > 0) { | 5785 | if (int_info.signedness == .unsigned and self.regExtraBits(limb_ty) > 0) { |
| 5810 | const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_pl.data); | 5786 | const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_bits); |
| 5811 | try self.genBinOpMir(.{ ._, .xor }, limb_ty, limb_mcv, .{ .immediate = mask }); | 5787 | try self.genBinOpMir(.{ ._, .xor }, limb_ty, limb_mcv, .{ .immediate = mask }); |
| 5812 | } else try self.genUnOpMir(.{ ._, .not }, limb_ty, limb_mcv); | 5788 | } else try self.genUnOpMir(.{ ._, .not }, limb_ty, limb_mcv); |
| 5813 | } | 5789 | } |
| ... | @@ -5819,7 +5795,8 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: | ... | @@ -5819,7 +5795,8 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 5819 | } | 5795 | } |
| 5820 | 5796 | ||
| 5821 | fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void { | 5797 | fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void { |
| 5822 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 5798 | const mod = self.bin_file.options.module.?; |
| 5799 | const abi_size = @intCast(u32, dst_ty.abiSize(mod)); | ||
| 5823 | if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ | 5800 | if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ |
| 5824 | mir_tag, | 5801 | mir_tag, |
| 5825 | dst_ty.fmt(self.bin_file.options.module.?), | 5802 | dst_ty.fmt(self.bin_file.options.module.?), |
| ... | @@ -5866,6 +5843,7 @@ fn genShiftBinOpMir( | ... | @@ -5866,6 +5843,7 @@ fn genShiftBinOpMir( |
| 5866 | lhs_mcv: MCValue, | 5843 | lhs_mcv: MCValue, |
| 5867 | shift_mcv: MCValue, | 5844 | shift_mcv: MCValue, |
| 5868 | ) !void { | 5845 | ) !void { |
| 5846 | const mod = self.bin_file.options.module.?; | ||
| 5869 | const rhs_mcv: MCValue = rhs: { | 5847 | const rhs_mcv: MCValue = rhs: { |
| 5870 | switch (shift_mcv) { | 5848 | switch (shift_mcv) { |
| 5871 | .immediate => |imm| switch (imm) { | 5849 | .immediate => |imm| switch (imm) { |
| ... | @@ -5880,7 +5858,7 @@ fn genShiftBinOpMir( | ... | @@ -5880,7 +5858,7 @@ fn genShiftBinOpMir( |
| 5880 | break :rhs .{ .register = .rcx }; | 5858 | break :rhs .{ .register = .rcx }; |
| 5881 | }; | 5859 | }; |
| 5882 | 5860 | ||
| 5883 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 5861 | const abi_size = @intCast(u32, ty.abiSize(mod)); |
| 5884 | if (abi_size <= 8) { | 5862 | if (abi_size <= 8) { |
| 5885 | switch (lhs_mcv) { | 5863 | switch (lhs_mcv) { |
| 5886 | .register => |lhs_reg| switch (rhs_mcv) { | 5864 | .register => |lhs_reg| switch (rhs_mcv) { |
| ... | @@ -6099,13 +6077,14 @@ fn genShiftBinOp( | ... | @@ -6099,13 +6077,14 @@ fn genShiftBinOp( |
| 6099 | lhs_ty: Type, | 6077 | lhs_ty: Type, |
| 6100 | rhs_ty: Type, | 6078 | rhs_ty: Type, |
| 6101 | ) !MCValue { | 6079 | ) !MCValue { |
| 6102 | if (lhs_ty.zigTypeTag() == .Vector) { | 6080 | const mod = self.bin_file.options.module.?; |
| 6081 | if (lhs_ty.zigTypeTag(mod) == .Vector) { | ||
| 6103 | return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()}); | 6082 | return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()}); |
| 6104 | } | 6083 | } |
| 6105 | 6084 | ||
| 6106 | assert(rhs_ty.abiSize(self.target.*) == 1); | 6085 | assert(rhs_ty.abiSize(mod) == 1); |
| 6107 | 6086 | ||
| 6108 | const lhs_abi_size = lhs_ty.abiSize(self.target.*); | 6087 | const lhs_abi_size = lhs_ty.abiSize(mod); |
| 6109 | if (lhs_abi_size > 16) { | 6088 | if (lhs_abi_size > 16) { |
| 6110 | return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()}); | 6089 | return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()}); |
| 6111 | } | 6090 | } |
| ... | @@ -6136,7 +6115,7 @@ fn genShiftBinOp( | ... | @@ -6136,7 +6115,7 @@ fn genShiftBinOp( |
| 6136 | break :dst dst_mcv; | 6115 | break :dst dst_mcv; |
| 6137 | }; | 6116 | }; |
| 6138 | 6117 | ||
| 6139 | const signedness = lhs_ty.intInfo(self.target.*).signedness; | 6118 | const signedness = lhs_ty.intInfo(mod).signedness; |
| 6140 | try self.genShiftBinOpMir(switch (air_tag) { | 6119 | try self.genShiftBinOpMir(switch (air_tag) { |
| 6141 | .shl, .shl_exact => switch (signedness) { | 6120 | .shl, .shl_exact => switch (signedness) { |
| 6142 | .signed => .{ ._l, .sa }, | 6121 | .signed => .{ ._l, .sa }, |
| ... | @@ -6163,11 +6142,12 @@ fn genMulDivBinOp( | ... | @@ -6163,11 +6142,12 @@ fn genMulDivBinOp( |
| 6163 | lhs: MCValue, | 6142 | lhs: MCValue, |
| 6164 | rhs: MCValue, | 6143 | rhs: MCValue, |
| 6165 | ) !MCValue { | 6144 | ) !MCValue { |
| 6166 | if (dst_ty.zigTypeTag() == .Vector or dst_ty.zigTypeTag() == .Float) { | 6145 | const mod = self.bin_file.options.module.?; |
| 6146 | if (dst_ty.zigTypeTag(mod) == .Vector or dst_ty.zigTypeTag(mod) == .Float) { | ||
| 6167 | return self.fail("TODO implement genMulDivBinOp for {}", .{dst_ty.fmtDebug()}); | 6147 | return self.fail("TODO implement genMulDivBinOp for {}", .{dst_ty.fmtDebug()}); |
| 6168 | } | 6148 | } |
| 6169 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 6149 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(mod)); |
| 6170 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); | 6150 | const src_abi_size = @intCast(u32, src_ty.abiSize(mod)); |
| 6171 | if (switch (tag) { | 6151 | if (switch (tag) { |
| 6172 | else => unreachable, | 6152 | else => unreachable, |
| 6173 | .mul, .mulwrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2, | 6153 | .mul, .mulwrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2, |
| ... | @@ -6184,7 +6164,7 @@ fn genMulDivBinOp( | ... | @@ -6184,7 +6164,7 @@ fn genMulDivBinOp( |
| 6184 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); | 6164 | const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx }); |
| 6185 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); | 6165 | defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 6186 | 6166 | ||
| 6187 | const signedness = ty.intInfo(self.target.*).signedness; | 6167 | const signedness = ty.intInfo(mod).signedness; |
| 6188 | switch (tag) { | 6168 | switch (tag) { |
| 6189 | .mul, | 6169 | .mul, |
| 6190 | .mulwrap, | 6170 | .mulwrap, |
| ... | @@ -6338,13 +6318,14 @@ fn genBinOp( | ... | @@ -6338,13 +6318,14 @@ fn genBinOp( |
| 6338 | lhs_air: Air.Inst.Ref, | 6318 | lhs_air: Air.Inst.Ref, |
| 6339 | rhs_air: Air.Inst.Ref, | 6319 | rhs_air: Air.Inst.Ref, |
| 6340 | ) !MCValue { | 6320 | ) !MCValue { |
| 6341 | const lhs_ty = self.air.typeOf(lhs_air); | 6321 | const mod = self.bin_file.options.module.?; |
| 6342 | const rhs_ty = self.air.typeOf(rhs_air); | 6322 | const lhs_ty = self.typeOf(lhs_air); |
| 6343 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); | 6323 | const rhs_ty = self.typeOf(rhs_air); |
| 6324 | const abi_size = @intCast(u32, lhs_ty.abiSize(mod)); | ||
| 6344 | 6325 | ||
| 6345 | const maybe_mask_reg = switch (air_tag) { | 6326 | const maybe_mask_reg = switch (air_tag) { |
| 6346 | else => null, | 6327 | else => null, |
| 6347 | .max, .min => if (lhs_ty.scalarType().isRuntimeFloat()) registerAlias( | 6328 | .max, .min => if (lhs_ty.scalarType(mod).isRuntimeFloat()) registerAlias( |
| 6348 | if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: { | 6329 | if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: { |
| 6349 | try self.register_manager.getReg(.xmm0, null); | 6330 | try self.register_manager.getReg(.xmm0, null); |
| 6350 | break :mask .xmm0; | 6331 | break :mask .xmm0; |
| ... | @@ -6384,7 +6365,7 @@ fn genBinOp( | ... | @@ -6384,7 +6365,7 @@ fn genBinOp( |
| 6384 | 6365 | ||
| 6385 | else => false, | 6366 | else => false, |
| 6386 | }; | 6367 | }; |
| 6387 | const vec_op = switch (lhs_ty.zigTypeTag()) { | 6368 | const vec_op = switch (lhs_ty.zigTypeTag(mod)) { |
| 6388 | else => false, | 6369 | else => false, |
| 6389 | .Float, .Vector => true, | 6370 | .Float, .Vector => true, |
| 6390 | }; | 6371 | }; |
| ... | @@ -6456,7 +6437,7 @@ fn genBinOp( | ... | @@ -6456,7 +6437,7 @@ fn genBinOp( |
| 6456 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); | 6437 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 6457 | defer self.register_manager.unlockReg(tmp_lock); | 6438 | defer self.register_manager.unlockReg(tmp_lock); |
| 6458 | 6439 | ||
| 6459 | const elem_size = lhs_ty.elemType2().abiSize(self.target.*); | 6440 | const elem_size = lhs_ty.elemType2(mod).abiSize(mod); |
| 6460 | try self.genIntMulComplexOpMir(rhs_ty, tmp_mcv, .{ .immediate = elem_size }); | 6441 | try self.genIntMulComplexOpMir(rhs_ty, tmp_mcv, .{ .immediate = elem_size }); |
| 6461 | try self.genBinOpMir( | 6442 | try self.genBinOpMir( |
| 6462 | switch (air_tag) { | 6443 | switch (air_tag) { |
| ... | @@ -6506,7 +6487,7 @@ fn genBinOp( | ... | @@ -6506,7 +6487,7 @@ fn genBinOp( |
| 6506 | 6487 | ||
| 6507 | try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, dst_mcv, mat_src_mcv); | 6488 | try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, dst_mcv, mat_src_mcv); |
| 6508 | 6489 | ||
| 6509 | const int_info = lhs_ty.intInfo(self.target.*); | 6490 | const int_info = lhs_ty.intInfo(mod); |
| 6510 | const cc: Condition = switch (int_info.signedness) { | 6491 | const cc: Condition = switch (int_info.signedness) { |
| 6511 | .unsigned => switch (air_tag) { | 6492 | .unsigned => switch (air_tag) { |
| 6512 | .min => .a, | 6493 | .min => .a, |
| ... | @@ -6520,7 +6501,7 @@ fn genBinOp( | ... | @@ -6520,7 +6501,7 @@ fn genBinOp( |
| 6520 | }, | 6501 | }, |
| 6521 | }; | 6502 | }; |
| 6522 | 6503 | ||
| 6523 | const cmov_abi_size = @max(@intCast(u32, lhs_ty.abiSize(self.target.*)), 2); | 6504 | const cmov_abi_size = @max(@intCast(u32, lhs_ty.abiSize(mod)), 2); |
| 6524 | const tmp_reg = switch (dst_mcv) { | 6505 | const tmp_reg = switch (dst_mcv) { |
| 6525 | .register => |reg| reg, | 6506 | .register => |reg| reg, |
| 6526 | else => try self.copyToTmpRegister(lhs_ty, dst_mcv), | 6507 | else => try self.copyToTmpRegister(lhs_ty, dst_mcv), |
| ... | @@ -6581,7 +6562,7 @@ fn genBinOp( | ... | @@ -6581,7 +6562,7 @@ fn genBinOp( |
| 6581 | } | 6562 | } |
| 6582 | 6563 | ||
| 6583 | const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size); | 6564 | const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size); |
| 6584 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { | 6565 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 6585 | else => unreachable, | 6566 | else => unreachable, |
| 6586 | .Float => switch (lhs_ty.floatBits(self.target.*)) { | 6567 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 6587 | 16 => if (self.hasFeature(.f16c)) { | 6568 | 16 => if (self.hasFeature(.f16c)) { |
| ... | @@ -6657,10 +6638,10 @@ fn genBinOp( | ... | @@ -6657,10 +6638,10 @@ fn genBinOp( |
| 6657 | 80, 128 => null, | 6638 | 80, 128 => null, |
| 6658 | else => unreachable, | 6639 | else => unreachable, |
| 6659 | }, | 6640 | }, |
| 6660 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | 6641 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 6661 | else => null, | 6642 | else => null, |
| 6662 | .Int => switch (lhs_ty.childType().intInfo(self.target.*).bits) { | 6643 | .Int => switch (lhs_ty.childType(mod).intInfo(mod).bits) { |
| 6663 | 8 => switch (lhs_ty.vectorLen()) { | 6644 | 8 => switch (lhs_ty.vectorLen(mod)) { |
| 6664 | 1...16 => switch (air_tag) { | 6645 | 1...16 => switch (air_tag) { |
| 6665 | .add, | 6646 | .add, |
| 6666 | .addwrap, | 6647 | .addwrap, |
| ... | @@ -6671,7 +6652,7 @@ fn genBinOp( | ... | @@ -6671,7 +6652,7 @@ fn genBinOp( |
| 6671 | .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" }, | 6652 | .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" }, |
| 6672 | .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" }, | 6653 | .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" }, |
| 6673 | .xor => if (self.hasFeature(.avx)) .{ .vp_, .xor } else .{ .p_, .xor }, | 6654 | .xor => if (self.hasFeature(.avx)) .{ .vp_, .xor } else .{ .p_, .xor }, |
| 6674 | .min => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6655 | .min => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6675 | .signed => if (self.hasFeature(.avx)) | 6656 | .signed => if (self.hasFeature(.avx)) |
| 6676 | .{ .vp_b, .mins } | 6657 | .{ .vp_b, .mins } |
| 6677 | else if (self.hasFeature(.sse4_1)) | 6658 | else if (self.hasFeature(.sse4_1)) |
| ... | @@ -6685,7 +6666,7 @@ fn genBinOp( | ... | @@ -6685,7 +6666,7 @@ fn genBinOp( |
| 6685 | else | 6666 | else |
| 6686 | null, | 6667 | null, |
| 6687 | }, | 6668 | }, |
| 6688 | .max => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6669 | .max => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6689 | .signed => if (self.hasFeature(.avx)) | 6670 | .signed => if (self.hasFeature(.avx)) |
| 6690 | .{ .vp_b, .maxs } | 6671 | .{ .vp_b, .maxs } |
| 6691 | else if (self.hasFeature(.sse4_1)) | 6672 | else if (self.hasFeature(.sse4_1)) |
| ... | @@ -6711,11 +6692,11 @@ fn genBinOp( | ... | @@ -6711,11 +6692,11 @@ fn genBinOp( |
| 6711 | .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null, | 6692 | .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null, |
| 6712 | .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null, | 6693 | .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null, |
| 6713 | .xor => if (self.hasFeature(.avx2)) .{ .vp_, .xor } else null, | 6694 | .xor => if (self.hasFeature(.avx2)) .{ .vp_, .xor } else null, |
| 6714 | .min => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6695 | .min => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6715 | .signed => if (self.hasFeature(.avx2)) .{ .vp_b, .mins } else null, | 6696 | .signed => if (self.hasFeature(.avx2)) .{ .vp_b, .mins } else null, |
| 6716 | .unsigned => if (self.hasFeature(.avx)) .{ .vp_b, .minu } else null, | 6697 | .unsigned => if (self.hasFeature(.avx)) .{ .vp_b, .minu } else null, |
| 6717 | }, | 6698 | }, |
| 6718 | .max => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6699 | .max => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6719 | .signed => if (self.hasFeature(.avx2)) .{ .vp_b, .maxs } else null, | 6700 | .signed => if (self.hasFeature(.avx2)) .{ .vp_b, .maxs } else null, |
| 6720 | .unsigned => if (self.hasFeature(.avx2)) .{ .vp_b, .maxu } else null, | 6701 | .unsigned => if (self.hasFeature(.avx2)) .{ .vp_b, .maxu } else null, |
| 6721 | }, | 6702 | }, |
| ... | @@ -6723,7 +6704,7 @@ fn genBinOp( | ... | @@ -6723,7 +6704,7 @@ fn genBinOp( |
| 6723 | }, | 6704 | }, |
| 6724 | else => null, | 6705 | else => null, |
| 6725 | }, | 6706 | }, |
| 6726 | 16 => switch (lhs_ty.vectorLen()) { | 6707 | 16 => switch (lhs_ty.vectorLen(mod)) { |
| 6727 | 1...8 => switch (air_tag) { | 6708 | 1...8 => switch (air_tag) { |
| 6728 | .add, | 6709 | .add, |
| 6729 | .addwrap, | 6710 | .addwrap, |
| ... | @@ -6737,7 +6718,7 @@ fn genBinOp( | ... | @@ -6737,7 +6718,7 @@ fn genBinOp( |
| 6737 | .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" }, | 6718 | .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" }, |
| 6738 | .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" }, | 6719 | .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" }, |
| 6739 | .xor => if (self.hasFeature(.avx)) .{ .vp_, .xor } else .{ .p_, .xor }, | 6720 | .xor => if (self.hasFeature(.avx)) .{ .vp_, .xor } else .{ .p_, .xor }, |
| 6740 | .min => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6721 | .min => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6741 | .signed => if (self.hasFeature(.avx)) | 6722 | .signed => if (self.hasFeature(.avx)) |
| 6742 | .{ .vp_w, .mins } | 6723 | .{ .vp_w, .mins } |
| 6743 | else | 6724 | else |
| ... | @@ -6747,7 +6728,7 @@ fn genBinOp( | ... | @@ -6747,7 +6728,7 @@ fn genBinOp( |
| 6747 | else | 6728 | else |
| 6748 | .{ .p_w, .minu }, | 6729 | .{ .p_w, .minu }, |
| 6749 | }, | 6730 | }, |
| 6750 | .max => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6731 | .max => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6751 | .signed => if (self.hasFeature(.avx)) | 6732 | .signed => if (self.hasFeature(.avx)) |
| 6752 | .{ .vp_w, .maxs } | 6733 | .{ .vp_w, .maxs } |
| 6753 | else | 6734 | else |
| ... | @@ -6772,11 +6753,11 @@ fn genBinOp( | ... | @@ -6772,11 +6753,11 @@ fn genBinOp( |
| 6772 | .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null, | 6753 | .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null, |
| 6773 | .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null, | 6754 | .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null, |
| 6774 | .xor => if (self.hasFeature(.avx2)) .{ .vp_, .xor } else null, | 6755 | .xor => if (self.hasFeature(.avx2)) .{ .vp_, .xor } else null, |
| 6775 | .min => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6756 | .min => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6776 | .signed => if (self.hasFeature(.avx2)) .{ .vp_w, .mins } else null, | 6757 | .signed => if (self.hasFeature(.avx2)) .{ .vp_w, .mins } else null, |
| 6777 | .unsigned => if (self.hasFeature(.avx)) .{ .vp_w, .minu } else null, | 6758 | .unsigned => if (self.hasFeature(.avx)) .{ .vp_w, .minu } else null, |
| 6778 | }, | 6759 | }, |
| 6779 | .max => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6760 | .max => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6780 | .signed => if (self.hasFeature(.avx2)) .{ .vp_w, .maxs } else null, | 6761 | .signed => if (self.hasFeature(.avx2)) .{ .vp_w, .maxs } else null, |
| 6781 | .unsigned => if (self.hasFeature(.avx2)) .{ .vp_w, .maxu } else null, | 6762 | .unsigned => if (self.hasFeature(.avx2)) .{ .vp_w, .maxu } else null, |
| 6782 | }, | 6763 | }, |
| ... | @@ -6784,7 +6765,7 @@ fn genBinOp( | ... | @@ -6784,7 +6765,7 @@ fn genBinOp( |
| 6784 | }, | 6765 | }, |
| 6785 | else => null, | 6766 | else => null, |
| 6786 | }, | 6767 | }, |
| 6787 | 32 => switch (lhs_ty.vectorLen()) { | 6768 | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 6788 | 1...4 => switch (air_tag) { | 6769 | 1...4 => switch (air_tag) { |
| 6789 | .add, | 6770 | .add, |
| 6790 | .addwrap, | 6771 | .addwrap, |
| ... | @@ -6803,7 +6784,7 @@ fn genBinOp( | ... | @@ -6803,7 +6784,7 @@ fn genBinOp( |
| 6803 | .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" }, | 6784 | .bit_and => if (self.hasFeature(.avx)) .{ .vp_, .@"and" } else .{ .p_, .@"and" }, |
| 6804 | .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" }, | 6785 | .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" }, |
| 6805 | .xor => if (self.hasFeature(.avx)) .{ .vp_, .xor } else .{ .p_, .xor }, | 6786 | .xor => if (self.hasFeature(.avx)) .{ .vp_, .xor } else .{ .p_, .xor }, |
| 6806 | .min => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6787 | .min => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6807 | .signed => if (self.hasFeature(.avx)) | 6788 | .signed => if (self.hasFeature(.avx)) |
| 6808 | .{ .vp_d, .mins } | 6789 | .{ .vp_d, .mins } |
| 6809 | else if (self.hasFeature(.sse4_1)) | 6790 | else if (self.hasFeature(.sse4_1)) |
| ... | @@ -6817,7 +6798,7 @@ fn genBinOp( | ... | @@ -6817,7 +6798,7 @@ fn genBinOp( |
| 6817 | else | 6798 | else |
| 6818 | null, | 6799 | null, |
| 6819 | }, | 6800 | }, |
| 6820 | .max => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6801 | .max => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6821 | .signed => if (self.hasFeature(.avx)) | 6802 | .signed => if (self.hasFeature(.avx)) |
| 6822 | .{ .vp_d, .maxs } | 6803 | .{ .vp_d, .maxs } |
| 6823 | else if (self.hasFeature(.sse4_1)) | 6804 | else if (self.hasFeature(.sse4_1)) |
| ... | @@ -6846,11 +6827,11 @@ fn genBinOp( | ... | @@ -6846,11 +6827,11 @@ fn genBinOp( |
| 6846 | .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null, | 6827 | .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null, |
| 6847 | .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null, | 6828 | .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null, |
| 6848 | .xor => if (self.hasFeature(.avx2)) .{ .vp_, .xor } else null, | 6829 | .xor => if (self.hasFeature(.avx2)) .{ .vp_, .xor } else null, |
| 6849 | .min => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6830 | .min => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6850 | .signed => if (self.hasFeature(.avx2)) .{ .vp_d, .mins } else null, | 6831 | .signed => if (self.hasFeature(.avx2)) .{ .vp_d, .mins } else null, |
| 6851 | .unsigned => if (self.hasFeature(.avx)) .{ .vp_d, .minu } else null, | 6832 | .unsigned => if (self.hasFeature(.avx)) .{ .vp_d, .minu } else null, |
| 6852 | }, | 6833 | }, |
| 6853 | .max => switch (lhs_ty.childType().intInfo(self.target.*).signedness) { | 6834 | .max => switch (lhs_ty.childType(mod).intInfo(mod).signedness) { |
| 6854 | .signed => if (self.hasFeature(.avx2)) .{ .vp_d, .maxs } else null, | 6835 | .signed => if (self.hasFeature(.avx2)) .{ .vp_d, .maxs } else null, |
| 6855 | .unsigned => if (self.hasFeature(.avx2)) .{ .vp_d, .maxu } else null, | 6836 | .unsigned => if (self.hasFeature(.avx2)) .{ .vp_d, .maxu } else null, |
| 6856 | }, | 6837 | }, |
| ... | @@ -6858,7 +6839,7 @@ fn genBinOp( | ... | @@ -6858,7 +6839,7 @@ fn genBinOp( |
| 6858 | }, | 6839 | }, |
| 6859 | else => null, | 6840 | else => null, |
| 6860 | }, | 6841 | }, |
| 6861 | 64 => switch (lhs_ty.vectorLen()) { | 6842 | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 6862 | 1...2 => switch (air_tag) { | 6843 | 1...2 => switch (air_tag) { |
| 6863 | .add, | 6844 | .add, |
| 6864 | .addwrap, | 6845 | .addwrap, |
| ... | @@ -6887,8 +6868,8 @@ fn genBinOp( | ... | @@ -6887,8 +6868,8 @@ fn genBinOp( |
| 6887 | }, | 6868 | }, |
| 6888 | else => null, | 6869 | else => null, |
| 6889 | }, | 6870 | }, |
| 6890 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | 6871 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 6891 | 16 => if (self.hasFeature(.f16c)) switch (lhs_ty.vectorLen()) { | 6872 | 16 => if (self.hasFeature(.f16c)) switch (lhs_ty.vectorLen(mod)) { |
| 6892 | 1 => { | 6873 | 1 => { |
| 6893 | const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128(); | 6874 | const tmp_reg = (try self.register_manager.allocReg(null, sse)).to128(); |
| 6894 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); | 6875 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| ... | @@ -7063,7 +7044,7 @@ fn genBinOp( | ... | @@ -7063,7 +7044,7 @@ fn genBinOp( |
| 7063 | }, | 7044 | }, |
| 7064 | else => null, | 7045 | else => null, |
| 7065 | } else null, | 7046 | } else null, |
| 7066 | 32 => switch (lhs_ty.vectorLen()) { | 7047 | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 7067 | 1 => switch (air_tag) { | 7048 | 1 => switch (air_tag) { |
| 7068 | .add => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add }, | 7049 | .add => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add }, |
| 7069 | .sub => if (self.hasFeature(.avx)) .{ .v_ss, .sub } else .{ ._ss, .sub }, | 7050 | .sub => if (self.hasFeature(.avx)) .{ .v_ss, .sub } else .{ ._ss, .sub }, |
| ... | @@ -7101,7 +7082,7 @@ fn genBinOp( | ... | @@ -7101,7 +7082,7 @@ fn genBinOp( |
| 7101 | } else null, | 7082 | } else null, |
| 7102 | else => null, | 7083 | else => null, |
| 7103 | }, | 7084 | }, |
| 7104 | 64 => switch (lhs_ty.vectorLen()) { | 7085 | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 7105 | 1 => switch (air_tag) { | 7086 | 1 => switch (air_tag) { |
| 7106 | .add => if (self.hasFeature(.avx)) .{ .v_sd, .add } else .{ ._sd, .add }, | 7087 | .add => if (self.hasFeature(.avx)) .{ .v_sd, .add } else .{ ._sd, .add }, |
| 7107 | .sub => if (self.hasFeature(.avx)) .{ .v_sd, .sub } else .{ ._sd, .sub }, | 7088 | .sub => if (self.hasFeature(.avx)) .{ .v_sd, .sub } else .{ ._sd, .sub }, |
| ... | @@ -7206,21 +7187,21 @@ fn genBinOp( | ... | @@ -7206,21 +7187,21 @@ fn genBinOp( |
| 7206 | const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size); | 7187 | const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size); |
| 7207 | 7188 | ||
| 7208 | try self.asmRegisterRegisterRegisterImmediate( | 7189 | try self.asmRegisterRegisterRegisterImmediate( |
| 7209 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { | 7190 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 7210 | .Float => switch (lhs_ty.floatBits(self.target.*)) { | 7191 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7211 | 32 => .{ .v_ss, .cmp }, | 7192 | 32 => .{ .v_ss, .cmp }, |
| 7212 | 64 => .{ .v_sd, .cmp }, | 7193 | 64 => .{ .v_sd, .cmp }, |
| 7213 | 16, 80, 128 => null, | 7194 | 16, 80, 128 => null, |
| 7214 | else => unreachable, | 7195 | else => unreachable, |
| 7215 | }, | 7196 | }, |
| 7216 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | 7197 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 7217 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | 7198 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 7218 | 32 => switch (lhs_ty.vectorLen()) { | 7199 | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 7219 | 1 => .{ .v_ss, .cmp }, | 7200 | 1 => .{ .v_ss, .cmp }, |
| 7220 | 2...8 => .{ .v_ps, .cmp }, | 7201 | 2...8 => .{ .v_ps, .cmp }, |
| 7221 | else => null, | 7202 | else => null, |
| 7222 | }, | 7203 | }, |
| 7223 | 64 => switch (lhs_ty.vectorLen()) { | 7204 | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 7224 | 1 => .{ .v_sd, .cmp }, | 7205 | 1 => .{ .v_sd, .cmp }, |
| 7225 | 2...4 => .{ .v_pd, .cmp }, | 7206 | 2...4 => .{ .v_pd, .cmp }, |
| 7226 | else => null, | 7207 | else => null, |
| ... | @@ -7240,20 +7221,20 @@ fn genBinOp( | ... | @@ -7240,20 +7221,20 @@ fn genBinOp( |
| 7240 | Immediate.u(3), // unord | 7221 | Immediate.u(3), // unord |
| 7241 | ); | 7222 | ); |
| 7242 | try self.asmRegisterRegisterRegisterRegister( | 7223 | try self.asmRegisterRegisterRegisterRegister( |
| 7243 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { | 7224 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 7244 | .Float => switch (lhs_ty.floatBits(self.target.*)) { | 7225 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7245 | 32 => .{ .v_ps, .blendv }, | 7226 | 32 => .{ .v_ps, .blendv }, |
| 7246 | 64 => .{ .v_pd, .blendv }, | 7227 | 64 => .{ .v_pd, .blendv }, |
| 7247 | 16, 80, 128 => null, | 7228 | 16, 80, 128 => null, |
| 7248 | else => unreachable, | 7229 | else => unreachable, |
| 7249 | }, | 7230 | }, |
| 7250 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | 7231 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 7251 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | 7232 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 7252 | 32 => switch (lhs_ty.vectorLen()) { | 7233 | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 7253 | 1...8 => .{ .v_ps, .blendv }, | 7234 | 1...8 => .{ .v_ps, .blendv }, |
| 7254 | else => null, | 7235 | else => null, |
| 7255 | }, | 7236 | }, |
| 7256 | 64 => switch (lhs_ty.vectorLen()) { | 7237 | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 7257 | 1...4 => .{ .v_pd, .blendv }, | 7238 | 1...4 => .{ .v_pd, .blendv }, |
| 7258 | else => null, | 7239 | else => null, |
| 7259 | }, | 7240 | }, |
| ... | @@ -7274,21 +7255,21 @@ fn genBinOp( | ... | @@ -7274,21 +7255,21 @@ fn genBinOp( |
| 7274 | } else { | 7255 | } else { |
| 7275 | const has_blend = self.hasFeature(.sse4_1); | 7256 | const has_blend = self.hasFeature(.sse4_1); |
| 7276 | try self.asmRegisterRegisterImmediate( | 7257 | try self.asmRegisterRegisterImmediate( |
| 7277 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { | 7258 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 7278 | .Float => switch (lhs_ty.floatBits(self.target.*)) { | 7259 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7279 | 32 => .{ ._ss, .cmp }, | 7260 | 32 => .{ ._ss, .cmp }, |
| 7280 | 64 => .{ ._sd, .cmp }, | 7261 | 64 => .{ ._sd, .cmp }, |
| 7281 | 16, 80, 128 => null, | 7262 | 16, 80, 128 => null, |
| 7282 | else => unreachable, | 7263 | else => unreachable, |
| 7283 | }, | 7264 | }, |
| 7284 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | 7265 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 7285 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | 7266 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 7286 | 32 => switch (lhs_ty.vectorLen()) { | 7267 | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 7287 | 1 => .{ ._ss, .cmp }, | 7268 | 1 => .{ ._ss, .cmp }, |
| 7288 | 2...4 => .{ ._ps, .cmp }, | 7269 | 2...4 => .{ ._ps, .cmp }, |
| 7289 | else => null, | 7270 | else => null, |
| 7290 | }, | 7271 | }, |
| 7291 | 64 => switch (lhs_ty.vectorLen()) { | 7272 | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 7292 | 1 => .{ ._sd, .cmp }, | 7273 | 1 => .{ ._sd, .cmp }, |
| 7293 | 2 => .{ ._pd, .cmp }, | 7274 | 2 => .{ ._pd, .cmp }, |
| 7294 | else => null, | 7275 | else => null, |
| ... | @@ -7307,20 +7288,20 @@ fn genBinOp( | ... | @@ -7307,20 +7288,20 @@ fn genBinOp( |
| 7307 | Immediate.u(if (has_blend) 3 else 7), // unord, ord | 7288 | Immediate.u(if (has_blend) 3 else 7), // unord, ord |
| 7308 | ); | 7289 | ); |
| 7309 | if (has_blend) try self.asmRegisterRegisterRegister( | 7290 | if (has_blend) try self.asmRegisterRegisterRegister( |
| 7310 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { | 7291 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 7311 | .Float => switch (lhs_ty.floatBits(self.target.*)) { | 7292 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7312 | 32 => .{ ._ps, .blendv }, | 7293 | 32 => .{ ._ps, .blendv }, |
| 7313 | 64 => .{ ._pd, .blendv }, | 7294 | 64 => .{ ._pd, .blendv }, |
| 7314 | 16, 80, 128 => null, | 7295 | 16, 80, 128 => null, |
| 7315 | else => unreachable, | 7296 | else => unreachable, |
| 7316 | }, | 7297 | }, |
| 7317 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | 7298 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 7318 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | 7299 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 7319 | 32 => switch (lhs_ty.vectorLen()) { | 7300 | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 7320 | 1...4 => .{ ._ps, .blendv }, | 7301 | 1...4 => .{ ._ps, .blendv }, |
| 7321 | else => null, | 7302 | else => null, |
| 7322 | }, | 7303 | }, |
| 7323 | 64 => switch (lhs_ty.vectorLen()) { | 7304 | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 7324 | 1...2 => .{ ._pd, .blendv }, | 7305 | 1...2 => .{ ._pd, .blendv }, |
| 7325 | else => null, | 7306 | else => null, |
| 7326 | }, | 7307 | }, |
| ... | @@ -7338,20 +7319,20 @@ fn genBinOp( | ... | @@ -7338,20 +7319,20 @@ fn genBinOp( |
| 7338 | mask_reg, | 7319 | mask_reg, |
| 7339 | ) else { | 7320 | ) else { |
| 7340 | try self.asmRegisterRegister( | 7321 | try self.asmRegisterRegister( |
| 7341 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { | 7322 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 7342 | .Float => switch (lhs_ty.floatBits(self.target.*)) { | 7323 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7343 | 32 => .{ ._ps, .@"and" }, | 7324 | 32 => .{ ._ps, .@"and" }, |
| 7344 | 64 => .{ ._pd, .@"and" }, | 7325 | 64 => .{ ._pd, .@"and" }, |
| 7345 | 16, 80, 128 => null, | 7326 | 16, 80, 128 => null, |
| 7346 | else => unreachable, | 7327 | else => unreachable, |
| 7347 | }, | 7328 | }, |
| 7348 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | 7329 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 7349 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | 7330 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 7350 | 32 => switch (lhs_ty.vectorLen()) { | 7331 | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 7351 | 1...4 => .{ ._ps, .@"and" }, | 7332 | 1...4 => .{ ._ps, .@"and" }, |
| 7352 | else => null, | 7333 | else => null, |
| 7353 | }, | 7334 | }, |
| 7354 | 64 => switch (lhs_ty.vectorLen()) { | 7335 | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 7355 | 1...2 => .{ ._pd, .@"and" }, | 7336 | 1...2 => .{ ._pd, .@"and" }, |
| 7356 | else => null, | 7337 | else => null, |
| 7357 | }, | 7338 | }, |
| ... | @@ -7368,20 +7349,20 @@ fn genBinOp( | ... | @@ -7368,20 +7349,20 @@ fn genBinOp( |
| 7368 | mask_reg, | 7349 | mask_reg, |
| 7369 | ); | 7350 | ); |
| 7370 | try self.asmRegisterRegister( | 7351 | try self.asmRegisterRegister( |
| 7371 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { | 7352 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 7372 | .Float => switch (lhs_ty.floatBits(self.target.*)) { | 7353 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7373 | 32 => .{ ._ps, .andn }, | 7354 | 32 => .{ ._ps, .andn }, |
| 7374 | 64 => .{ ._pd, .andn }, | 7355 | 64 => .{ ._pd, .andn }, |
| 7375 | 16, 80, 128 => null, | 7356 | 16, 80, 128 => null, |
| 7376 | else => unreachable, | 7357 | else => unreachable, |
| 7377 | }, | 7358 | }, |
| 7378 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | 7359 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 7379 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | 7360 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 7380 | 32 => switch (lhs_ty.vectorLen()) { | 7361 | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 7381 | 1...4 => .{ ._ps, .andn }, | 7362 | 1...4 => .{ ._ps, .andn }, |
| 7382 | else => null, | 7363 | else => null, |
| 7383 | }, | 7364 | }, |
| 7384 | 64 => switch (lhs_ty.vectorLen()) { | 7365 | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 7385 | 1...2 => .{ ._pd, .andn }, | 7366 | 1...2 => .{ ._pd, .andn }, |
| 7386 | else => null, | 7367 | else => null, |
| 7387 | }, | 7368 | }, |
| ... | @@ -7398,20 +7379,20 @@ fn genBinOp( | ... | @@ -7398,20 +7379,20 @@ fn genBinOp( |
| 7398 | lhs_copy_reg.?, | 7379 | lhs_copy_reg.?, |
| 7399 | ); | 7380 | ); |
| 7400 | try self.asmRegisterRegister( | 7381 | try self.asmRegisterRegister( |
| 7401 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag()) { | 7382 | if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(mod)) { |
| 7402 | .Float => switch (lhs_ty.floatBits(self.target.*)) { | 7383 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 7403 | 32 => .{ ._ps, .@"or" }, | 7384 | 32 => .{ ._ps, .@"or" }, |
| 7404 | 64 => .{ ._pd, .@"or" }, | 7385 | 64 => .{ ._pd, .@"or" }, |
| 7405 | 16, 80, 128 => null, | 7386 | 16, 80, 128 => null, |
| 7406 | else => unreachable, | 7387 | else => unreachable, |
| 7407 | }, | 7388 | }, |
| 7408 | .Vector => switch (lhs_ty.childType().zigTypeTag()) { | 7389 | .Vector => switch (lhs_ty.childType(mod).zigTypeTag(mod)) { |
| 7409 | .Float => switch (lhs_ty.childType().floatBits(self.target.*)) { | 7390 | .Float => switch (lhs_ty.childType(mod).floatBits(self.target.*)) { |
| 7410 | 32 => switch (lhs_ty.vectorLen()) { | 7391 | 32 => switch (lhs_ty.vectorLen(mod)) { |
| 7411 | 1...4 => .{ ._ps, .@"or" }, | 7392 | 1...4 => .{ ._ps, .@"or" }, |
| 7412 | else => null, | 7393 | else => null, |
| 7413 | }, | 7394 | }, |
| 7414 | 64 => switch (lhs_ty.vectorLen()) { | 7395 | 64 => switch (lhs_ty.vectorLen(mod)) { |
| 7415 | 1...2 => .{ ._pd, .@"or" }, | 7396 | 1...2 => .{ ._pd, .@"or" }, |
| 7416 | else => null, | 7397 | else => null, |
| 7417 | }, | 7398 | }, |
| ... | @@ -7442,7 +7423,8 @@ fn genBinOpMir( | ... | @@ -7442,7 +7423,8 @@ fn genBinOpMir( |
| 7442 | dst_mcv: MCValue, | 7423 | dst_mcv: MCValue, |
| 7443 | src_mcv: MCValue, | 7424 | src_mcv: MCValue, |
| 7444 | ) !void { | 7425 | ) !void { |
| 7445 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 7426 | const mod = self.bin_file.options.module.?; |
| 7427 | const abi_size = @intCast(u32, ty.abiSize(mod)); | ||
| 7446 | switch (dst_mcv) { | 7428 | switch (dst_mcv) { |
| 7447 | .none, | 7429 | .none, |
| 7448 | .unreach, | 7430 | .unreach, |
| ... | @@ -7562,11 +7544,7 @@ fn genBinOpMir( | ... | @@ -7562,11 +7544,7 @@ fn genBinOpMir( |
| 7562 | .load_got, | 7544 | .load_got, |
| 7563 | .load_tlv, | 7545 | .load_tlv, |
| 7564 | => { | 7546 | => { |
| 7565 | var ptr_pl = Type.Payload.ElemType{ | 7547 | const ptr_ty = try mod.singleConstPtrType(ty); |
| 7566 | .base = .{ .tag = .single_const_pointer }, | ||
| 7567 | .data = ty, | ||
| 7568 | }; | ||
| 7569 | const ptr_ty = Type.initPayload(&ptr_pl.base); | ||
| 7570 | const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address()); | 7548 | const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address()); |
| 7571 | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ | 7549 | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ |
| 7572 | .indirect = .{ .reg = addr_reg }, | 7550 | .indirect = .{ .reg = addr_reg }, |
| ... | @@ -7640,7 +7618,7 @@ fn genBinOpMir( | ... | @@ -7640,7 +7618,7 @@ fn genBinOpMir( |
| 7640 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); | 7618 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); |
| 7641 | 7619 | ||
| 7642 | const ty_signedness = | 7620 | const ty_signedness = |
| 7643 | if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned; | 7621 | if (ty.isAbiInt(mod)) ty.intInfo(mod).signedness else .unsigned; |
| 7644 | const limb_ty = if (abi_size <= 8) ty else switch (ty_signedness) { | 7622 | const limb_ty = if (abi_size <= 8) ty else switch (ty_signedness) { |
| 7645 | .signed => Type.usize, | 7623 | .signed => Type.usize, |
| 7646 | .unsigned => Type.isize, | 7624 | .unsigned => Type.isize, |
| ... | @@ -7796,7 +7774,8 @@ fn genBinOpMir( | ... | @@ -7796,7 +7774,8 @@ fn genBinOpMir( |
| 7796 | /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. | 7774 | /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv. |
| 7797 | /// Does not support byte-size operands. | 7775 | /// Does not support byte-size operands. |
| 7798 | fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { | 7776 | fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| 7799 | const abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); | 7777 | const mod = self.bin_file.options.module.?; |
| 7778 | const abi_size = @intCast(u32, dst_ty.abiSize(mod)); | ||
| 7800 | switch (dst_mcv) { | 7779 | switch (dst_mcv) { |
| 7801 | .none, | 7780 | .none, |
| 7802 | .unreach, | 7781 | .unreach, |
| ... | @@ -7896,6 +7875,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -7896,6 +7875,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 7896 | } | 7875 | } |
| 7897 | 7876 | ||
| 7898 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { | 7877 | fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 7878 | const mod = self.bin_file.options.module.?; | ||
| 7899 | // skip zero-bit arguments as they don't have a corresponding arg instruction | 7879 | // skip zero-bit arguments as they don't have a corresponding arg instruction |
| 7900 | var arg_index = self.arg_index; | 7880 | var arg_index = self.arg_index; |
| 7901 | while (self.args[arg_index] == .none) arg_index += 1; | 7881 | while (self.args[arg_index] == .none) arg_index += 1; |
| ... | @@ -7909,9 +7889,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7909,9 +7889,9 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 7909 | else => return self.fail("TODO implement arg for {}", .{dst_mcv}), | 7889 | else => return self.fail("TODO implement arg for {}", .{dst_mcv}), |
| 7910 | } | 7890 | } |
| 7911 | 7891 | ||
| 7912 | const ty = self.air.typeOfIndex(inst); | 7892 | const ty = self.typeOfIndex(inst); |
| 7913 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; | 7893 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 7914 | const name = self.owner.mod_fn.getParamName(self.bin_file.options.module.?, src_index); | 7894 | const name = self.owner.mod_fn.getParamName(mod, src_index); |
| 7915 | try self.genArgDbgInfo(ty, name, dst_mcv); | 7895 | try self.genArgDbgInfo(ty, name, dst_mcv); |
| 7916 | 7896 | ||
| 7917 | break :result dst_mcv; | 7897 | break :result dst_mcv; |
| ... | @@ -7920,6 +7900,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7920,6 +7900,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 7920 | } | 7900 | } |
| 7921 | 7901 | ||
| 7922 | fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { | 7902 | fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { |
| 7903 | const mod = self.bin_file.options.module.?; | ||
| 7923 | switch (self.debug_output) { | 7904 | switch (self.debug_output) { |
| 7924 | .dwarf => |dw| { | 7905 | .dwarf => |dw| { |
| 7925 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { | 7906 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { |
| ... | @@ -7938,7 +7919,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { | ... | @@ -7938,7 +7919,7 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { |
| 7938 | // TODO: this might need adjusting like the linkers do. | 7919 | // TODO: this might need adjusting like the linkers do. |
| 7939 | // Instead of flattening the owner and passing Decl.Index here we may | 7920 | // Instead of flattening the owner and passing Decl.Index here we may |
| 7940 | // want to special case LazySymbol in DWARF linker too. | 7921 | // want to special case LazySymbol in DWARF linker too. |
| 7941 | try dw.genArgDbgInfo(name, ty, self.owner.getDecl(), loc); | 7922 | try dw.genArgDbgInfo(name, ty, self.owner.getDecl(mod), loc); |
| 7942 | }, | 7923 | }, |
| 7943 | .plan9 => {}, | 7924 | .plan9 => {}, |
| 7944 | .none => {}, | 7925 | .none => {}, |
| ... | @@ -7952,6 +7933,7 @@ fn genVarDbgInfo( | ... | @@ -7952,6 +7933,7 @@ fn genVarDbgInfo( |
| 7952 | mcv: MCValue, | 7933 | mcv: MCValue, |
| 7953 | name: [:0]const u8, | 7934 | name: [:0]const u8, |
| 7954 | ) !void { | 7935 | ) !void { |
| 7936 | const mod = self.bin_file.options.module.?; | ||
| 7955 | const is_ptr = switch (tag) { | 7937 | const is_ptr = switch (tag) { |
| 7956 | .dbg_var_ptr => true, | 7938 | .dbg_var_ptr => true, |
| 7957 | .dbg_var_val => false, | 7939 | .dbg_var_val => false, |
| ... | @@ -7982,7 +7964,7 @@ fn genVarDbgInfo( | ... | @@ -7982,7 +7964,7 @@ fn genVarDbgInfo( |
| 7982 | // TODO: this might need adjusting like the linkers do. | 7964 | // TODO: this might need adjusting like the linkers do. |
| 7983 | // Instead of flattening the owner and passing Decl.Index here we may | 7965 | // Instead of flattening the owner and passing Decl.Index here we may |
| 7984 | // want to special case LazySymbol in DWARF linker too. | 7966 | // want to special case LazySymbol in DWARF linker too. |
| 7985 | try dw.genVarDbgInfo(name, ty, self.owner.getDecl(), is_ptr, loc); | 7967 | try dw.genVarDbgInfo(name, ty, self.owner.getDecl(mod), is_ptr, loc); |
| 7986 | }, | 7968 | }, |
| 7987 | .plan9 => {}, | 7969 | .plan9 => {}, |
| 7988 | .none => {}, | 7970 | .none => {}, |
| ... | @@ -8022,20 +8004,23 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8022,20 +8004,23 @@ fn airFence(self: *Self, inst: Air.Inst.Index) !void { |
| 8022 | } | 8004 | } |
| 8023 | 8005 | ||
| 8024 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { | 8006 | fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void { |
| 8007 | const mod = self.bin_file.options.module.?; | ||
| 8025 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{}); | 8008 | if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{}); |
| 8026 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 8009 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8027 | const callee = pl_op.operand; | 8010 | const callee = pl_op.operand; |
| 8028 | const extra = self.air.extraData(Air.Call, pl_op.payload); | 8011 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 8029 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); | 8012 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); |
| 8030 | const ty = self.air.typeOf(callee); | 8013 | const ty = self.typeOf(callee); |
| 8031 | 8014 | ||
| 8032 | const fn_ty = switch (ty.zigTypeTag()) { | 8015 | const fn_ty = switch (ty.zigTypeTag(mod)) { |
| 8033 | .Fn => ty, | 8016 | .Fn => ty, |
| 8034 | .Pointer => ty.childType(), | 8017 | .Pointer => ty.childType(mod), |
| 8035 | else => unreachable, | 8018 | else => unreachable, |
| 8036 | }; | 8019 | }; |
| 8037 | 8020 | ||
| 8038 | var info = try self.resolveCallingConventionValues(fn_ty, args[fn_ty.fnParamLen()..], .call_frame); | 8021 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 8022 | |||
| 8023 | var info = try self.resolveCallingConventionValues(fn_info, args[fn_info.param_types.len..], .call_frame); | ||
| 8039 | defer info.deinit(self); | 8024 | defer info.deinit(self); |
| 8040 | 8025 | ||
| 8041 | // We need a properly aligned and sized call frame to be able to call this function. | 8026 | // We need a properly aligned and sized call frame to be able to call this function. |
| ... | @@ -8062,7 +8047,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -8062,7 +8047,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8062 | else => unreachable, | 8047 | else => unreachable, |
| 8063 | } | 8048 | } |
| 8064 | for (args, info.args) |arg, mc_arg| { | 8049 | for (args, info.args) |arg, mc_arg| { |
| 8065 | const arg_ty = self.air.typeOf(arg); | 8050 | const arg_ty = self.typeOf(arg); |
| 8066 | const arg_mcv = try self.resolveInst(arg); | 8051 | const arg_mcv = try self.resolveInst(arg); |
| 8067 | switch (mc_arg) { | 8052 | switch (mc_arg) { |
| 8068 | .none => {}, | 8053 | .none => {}, |
| ... | @@ -8076,8 +8061,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -8076,8 +8061,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8076 | const ret_lock = switch (info.return_value.long) { | 8061 | const ret_lock = switch (info.return_value.long) { |
| 8077 | .none, .unreach => null, | 8062 | .none, .unreach => null, |
| 8078 | .indirect => |reg_off| lock: { | 8063 | .indirect => |reg_off| lock: { |
| 8079 | const ret_ty = fn_ty.fnReturnType(); | 8064 | const ret_ty = fn_info.return_type.toType(); |
| 8080 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(ret_ty, self.target.*)); | 8065 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(ret_ty, mod)); |
| 8081 | try self.genSetReg(reg_off.reg, Type.usize, .{ | 8066 | try self.genSetReg(reg_off.reg, Type.usize, .{ |
| 8082 | .lea_frame = .{ .index = frame_index, .off = -reg_off.off }, | 8067 | .lea_frame = .{ .index = frame_index, .off = -reg_off.off }, |
| 8083 | }); | 8068 | }); |
| ... | @@ -8089,7 +8074,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -8089,7 +8074,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8089 | defer if (ret_lock) |lock| self.register_manager.unlockReg(lock); | 8074 | defer if (ret_lock) |lock| self.register_manager.unlockReg(lock); |
| 8090 | 8075 | ||
| 8091 | for (args, info.args) |arg, mc_arg| { | 8076 | for (args, info.args) |arg, mc_arg| { |
| 8092 | const arg_ty = self.air.typeOf(arg); | 8077 | const arg_ty = self.typeOf(arg); |
| 8093 | const arg_mcv = try self.resolveInst(arg); | 8078 | const arg_mcv = try self.resolveInst(arg); |
| 8094 | switch (mc_arg) { | 8079 | switch (mc_arg) { |
| 8095 | .none, .load_frame => {}, | 8080 | .none, .load_frame => {}, |
| ... | @@ -8100,15 +8085,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -8100,15 +8085,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8100 | 8085 | ||
| 8101 | // Due to incremental compilation, how function calls are generated depends | 8086 | // Due to incremental compilation, how function calls are generated depends |
| 8102 | // on linking. | 8087 | // on linking. |
| 8103 | const mod = self.bin_file.options.module.?; | 8088 | if (try self.air.value(callee, mod)) |func_value| { |
| 8104 | if (self.air.value(callee)) |func_value| { | 8089 | const func_key = mod.intern_pool.indexToKey(func_value.ip_index); |
| 8105 | if (if (func_value.castTag(.function)) |func_payload| | 8090 | if (switch (func_key) { |
| 8106 | func_payload.data.owner_decl | 8091 | .func => |func| mod.funcPtr(func.index).owner_decl, |
| 8107 | else if (func_value.castTag(.decl_ref)) |decl_ref_payload| | 8092 | .ptr => |ptr| switch (ptr.addr) { |
| 8108 | decl_ref_payload.data | 8093 | .decl => |decl| decl, |
| 8109 | else | 8094 | else => null, |
| 8110 | null) |owner_decl| | 8095 | }, |
| 8111 | { | 8096 | else => null, |
| 8097 | }) |owner_decl| { | ||
| 8112 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | 8098 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 8113 | const atom_index = try elf_file.getOrCreateAtomForDecl(owner_decl); | 8099 | const atom_index = try elf_file.getOrCreateAtomForDecl(owner_decl); |
| 8114 | const atom = elf_file.getAtom(atom_index); | 8100 | const atom = elf_file.getAtom(atom_index); |
| ... | @@ -8141,10 +8127,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -8141,10 +8127,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8141 | .disp = @intCast(i32, fn_got_addr), | 8127 | .disp = @intCast(i32, fn_got_addr), |
| 8142 | })); | 8128 | })); |
| 8143 | } else unreachable; | 8129 | } else unreachable; |
| 8144 | } else if (func_value.castTag(.extern_fn)) |func_payload| { | 8130 | } else if (func_value.getExternFunc(mod)) |extern_func| { |
| 8145 | const extern_fn = func_payload.data; | 8131 | const decl_name = mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name); |
| 8146 | const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); | 8132 | const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name); |
| 8147 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); | ||
| 8148 | if (self.bin_file.cast(link.File.Coff)) |coff_file| { | 8133 | if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 8149 | const atom_index = try self.owner.getSymbolIndex(self); | 8134 | const atom_index = try self.owner.getSymbolIndex(self); |
| 8150 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); | 8135 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); |
| ... | @@ -8178,7 +8163,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -8178,7 +8163,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8178 | return self.fail("TODO implement calling bitcasted functions", .{}); | 8163 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| 8179 | } | 8164 | } |
| 8180 | } else { | 8165 | } else { |
| 8181 | assert(ty.zigTypeTag() == .Pointer); | 8166 | assert(ty.zigTypeTag(mod) == .Pointer); |
| 8182 | const mcv = try self.resolveInst(callee); | 8167 | const mcv = try self.resolveInst(callee); |
| 8183 | try self.genSetReg(.rax, Type.usize, mcv); | 8168 | try self.genSetReg(.rax, Type.usize, mcv); |
| 8184 | try self.asmRegister(.{ ._, .call }, .rax); | 8169 | try self.asmRegister(.{ ._, .call }, .rax); |
| ... | @@ -8193,9 +8178,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -8193,9 +8178,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8193 | } | 8178 | } |
| 8194 | 8179 | ||
| 8195 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { | 8180 | fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 8181 | const mod = self.bin_file.options.module.?; | ||
| 8196 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8182 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8197 | const operand = try self.resolveInst(un_op); | 8183 | const operand = try self.resolveInst(un_op); |
| 8198 | const ret_ty = self.fn_type.fnReturnType(); | 8184 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 8199 | switch (self.ret_mcv.short) { | 8185 | switch (self.ret_mcv.short) { |
| 8200 | .none => {}, | 8186 | .none => {}, |
| 8201 | .register => try self.genCopy(ret_ty, self.ret_mcv.short, operand), | 8187 | .register => try self.genCopy(ret_ty, self.ret_mcv.short, operand), |
| ... | @@ -8219,7 +8205,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8219,7 +8205,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 8219 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | 8205 | fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 8220 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8206 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8221 | const ptr = try self.resolveInst(un_op); | 8207 | const ptr = try self.resolveInst(un_op); |
| 8222 | const ptr_ty = self.air.typeOf(un_op); | 8208 | const ptr_ty = self.typeOf(un_op); |
| 8223 | switch (self.ret_mcv.short) { | 8209 | switch (self.ret_mcv.short) { |
| 8224 | .none => {}, | 8210 | .none => {}, |
| 8225 | .register => try self.load(self.ret_mcv.short, ptr_ty, ptr), | 8211 | .register => try self.load(self.ret_mcv.short, ptr_ty, ptr), |
| ... | @@ -8234,8 +8220,9 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8234,8 +8220,9 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 8234 | } | 8220 | } |
| 8235 | 8221 | ||
| 8236 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | 8222 | fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8223 | const mod = self.bin_file.options.module.?; | ||
| 8237 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 8224 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8238 | const ty = self.air.typeOf(bin_op.lhs); | 8225 | const ty = self.typeOf(bin_op.lhs); |
| 8239 | 8226 | ||
| 8240 | try self.spillEflagsIfOccupied(); | 8227 | try self.spillEflagsIfOccupied(); |
| 8241 | self.eflags_inst = inst; | 8228 | self.eflags_inst = inst; |
| ... | @@ -8255,9 +8242,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -8255,9 +8242,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8255 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 8242 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 8256 | 8243 | ||
| 8257 | const result = MCValue{ | 8244 | const result = MCValue{ |
| 8258 | .eflags = switch (ty.zigTypeTag()) { | 8245 | .eflags = switch (ty.zigTypeTag(mod)) { |
| 8259 | else => result: { | 8246 | else => result: { |
| 8260 | const abi_size = @intCast(u16, ty.abiSize(self.target.*)); | 8247 | const abi_size = @intCast(u16, ty.abiSize(mod)); |
| 8261 | const may_flip: enum { | 8248 | const may_flip: enum { |
| 8262 | may_flip, | 8249 | may_flip, |
| 8263 | must_flip, | 8250 | must_flip, |
| ... | @@ -8290,7 +8277,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -8290,7 +8277,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8290 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); | 8277 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 8291 | 8278 | ||
| 8292 | break :result Condition.fromCompareOperator( | 8279 | break :result Condition.fromCompareOperator( |
| 8293 | if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned, | 8280 | if (ty.isAbiInt(mod)) ty.intInfo(mod).signedness else .unsigned, |
| 8294 | result_op: { | 8281 | result_op: { |
| 8295 | const flipped_op = if (flipped) op.reverse() else op; | 8282 | const flipped_op = if (flipped) op.reverse() else op; |
| 8296 | if (abi_size > 8) switch (flipped_op) { | 8283 | if (abi_size > 8) switch (flipped_op) { |
| ... | @@ -8404,7 +8391,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -8404,7 +8391,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8404 | try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp2_reg, tmp1_reg); | 8391 | try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp2_reg, tmp1_reg); |
| 8405 | try self.genBinOpMir(.{ ._ss, .ucomi }, ty, tmp1_mcv, tmp2_mcv); | 8392 | try self.genBinOpMir(.{ ._ss, .ucomi }, ty, tmp1_mcv, tmp2_mcv); |
| 8406 | } else return self.fail("TODO implement airCmp for {}", .{ | 8393 | } else return self.fail("TODO implement airCmp for {}", .{ |
| 8407 | ty.fmt(self.bin_file.options.module.?), | 8394 | ty.fmt(mod), |
| 8408 | }), | 8395 | }), |
| 8409 | 32 => try self.genBinOpMir( | 8396 | 32 => try self.genBinOpMir( |
| 8410 | .{ ._ss, .ucomi }, | 8397 | .{ ._ss, .ucomi }, |
| ... | @@ -8419,7 +8406,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -8419,7 +8406,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8419 | src_mcv, | 8406 | src_mcv, |
| 8420 | ), | 8407 | ), |
| 8421 | else => return self.fail("TODO implement airCmp for {}", .{ | 8408 | else => return self.fail("TODO implement airCmp for {}", .{ |
| 8422 | ty.fmt(self.bin_file.options.module.?), | 8409 | ty.fmt(mod), |
| 8423 | }), | 8410 | }), |
| 8424 | } | 8411 | } |
| 8425 | 8412 | ||
| ... | @@ -8453,8 +8440,8 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8453,8 +8440,8 @@ fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 8453 | try self.spillEflagsIfOccupied(); | 8440 | try self.spillEflagsIfOccupied(); |
| 8454 | self.eflags_inst = inst; | 8441 | self.eflags_inst = inst; |
| 8455 | 8442 | ||
| 8456 | const op_ty = self.air.typeOf(un_op); | 8443 | const op_ty = self.typeOf(un_op); |
| 8457 | const op_abi_size = @intCast(u32, op_ty.abiSize(self.target.*)); | 8444 | const op_abi_size = @intCast(u32, op_ty.abiSize(mod)); |
| 8458 | const op_mcv = try self.resolveInst(un_op); | 8445 | const op_mcv = try self.resolveInst(un_op); |
| 8459 | const dst_reg = switch (op_mcv) { | 8446 | const dst_reg = switch (op_mcv) { |
| 8460 | .register => |reg| reg, | 8447 | .register => |reg| reg, |
| ... | @@ -8473,16 +8460,17 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8473,16 +8460,17 @@ fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 8473 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 8460 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8474 | const extra = self.air.extraData(Air.Try, pl_op.payload); | 8461 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 8475 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 8462 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 8476 | const err_union_ty = self.air.typeOf(pl_op.operand); | 8463 | const err_union_ty = self.typeOf(pl_op.operand); |
| 8477 | const result = try self.genTry(inst, pl_op.operand, body, err_union_ty, false); | 8464 | const result = try self.genTry(inst, pl_op.operand, body, err_union_ty, false); |
| 8478 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 8465 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 8479 | } | 8466 | } |
| 8480 | 8467 | ||
| 8481 | fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { | 8468 | fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8469 | const mod = self.bin_file.options.module.?; | ||
| 8482 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 8470 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 8483 | const extra = self.air.extraData(Air.TryPtr, ty_pl.payload); | 8471 | const extra = self.air.extraData(Air.TryPtr, ty_pl.payload); |
| 8484 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 8472 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 8485 | const err_union_ty = self.air.typeOf(extra.data.ptr).childType(); | 8473 | const err_union_ty = self.typeOf(extra.data.ptr).childType(mod); |
| 8486 | const result = try self.genTry(inst, extra.data.ptr, body, err_union_ty, true); | 8474 | const result = try self.genTry(inst, extra.data.ptr, body, err_union_ty, true); |
| 8487 | return self.finishAir(inst, result, .{ .none, .none, .none }); | 8475 | return self.finishAir(inst, result, .{ .none, .none, .none }); |
| 8488 | } | 8476 | } |
| ... | @@ -8546,8 +8534,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8546,8 +8534,9 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 8546 | } | 8534 | } |
| 8547 | 8535 | ||
| 8548 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { | 8536 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 8549 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 8537 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; |
| 8550 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | 8538 | const mod = self.bin_file.options.module.?; |
| 8539 | const function = mod.funcPtr(ty_fn.func); | ||
| 8551 | // TODO emit debug info for function change | 8540 | // TODO emit debug info for function change |
| 8552 | _ = function; | 8541 | _ = function; |
| 8553 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); | 8542 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); |
| ... | @@ -8561,7 +8550,7 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8561,7 +8550,7 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 8561 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | 8550 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 8562 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 8551 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8563 | const operand = pl_op.operand; | 8552 | const operand = pl_op.operand; |
| 8564 | const ty = self.air.typeOf(operand); | 8553 | const ty = self.typeOf(operand); |
| 8565 | const mcv = try self.resolveInst(operand); | 8554 | const mcv = try self.resolveInst(operand); |
| 8566 | 8555 | ||
| 8567 | const name = self.air.nullTerminatedString(pl_op.payload); | 8556 | const name = self.air.nullTerminatedString(pl_op.payload); |
| ... | @@ -8573,7 +8562,8 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8573,7 +8562,8 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 8573 | } | 8562 | } |
| 8574 | 8563 | ||
| 8575 | fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { | 8564 | fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { |
| 8576 | const abi_size = ty.abiSize(self.target.*); | 8565 | const mod = self.bin_file.options.module.?; |
| 8566 | const abi_size = ty.abiSize(mod); | ||
| 8577 | switch (mcv) { | 8567 | switch (mcv) { |
| 8578 | .eflags => |cc| { | 8568 | .eflags => |cc| { |
| 8579 | // Here we map the opposites since the jump is to the false branch. | 8569 | // Here we map the opposites since the jump is to the false branch. |
| ... | @@ -8602,7 +8592,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { | ... | @@ -8602,7 +8592,7 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 { |
| 8602 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | 8592 | fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 8603 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 8593 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8604 | const cond = try self.resolveInst(pl_op.operand); | 8594 | const cond = try self.resolveInst(pl_op.operand); |
| 8605 | const cond_ty = self.air.typeOf(pl_op.operand); | 8595 | const cond_ty = self.typeOf(pl_op.operand); |
| 8606 | const extra = self.air.extraData(Air.CondBr, pl_op.payload); | 8596 | const extra = self.air.extraData(Air.CondBr, pl_op.payload); |
| 8607 | const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len]; | 8597 | const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len]; |
| 8608 | const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; | 8598 | const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; |
| ... | @@ -8646,6 +8636,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8646,6 +8636,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 8646 | } | 8636 | } |
| 8647 | 8637 | ||
| 8648 | fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue { | 8638 | fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue { |
| 8639 | const mod = self.bin_file.options.module.?; | ||
| 8649 | switch (opt_mcv) { | 8640 | switch (opt_mcv) { |
| 8650 | .register_overflow => |ro| return .{ .eflags = ro.eflags.negate() }, | 8641 | .register_overflow => |ro| return .{ .eflags = ro.eflags.negate() }, |
| 8651 | else => {}, | 8642 | else => {}, |
| ... | @@ -8654,14 +8645,12 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC | ... | @@ -8654,14 +8645,12 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 8654 | try self.spillEflagsIfOccupied(); | 8645 | try self.spillEflagsIfOccupied(); |
| 8655 | self.eflags_inst = inst; | 8646 | self.eflags_inst = inst; |
| 8656 | 8647 | ||
| 8657 | var pl_buf: Type.Payload.ElemType = undefined; | 8648 | const pl_ty = opt_ty.optionalChild(mod); |
| 8658 | const pl_ty = opt_ty.optionalChild(&pl_buf); | ||
| 8659 | 8649 | ||
| 8660 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | 8650 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(mod)) |
| 8661 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload()) | 8651 | .{ .off = 0, .ty = if (pl_ty.isSlice(mod)) pl_ty.slicePtrFieldType(mod) else pl_ty } |
| 8662 | .{ .off = 0, .ty = if (pl_ty.isSlice()) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty } | ||
| 8663 | else | 8652 | else |
| 8664 | .{ .off = @intCast(i32, pl_ty.abiSize(self.target.*)), .ty = Type.bool }; | 8653 | .{ .off = @intCast(i32, pl_ty.abiSize(mod)), .ty = Type.bool }; |
| 8665 | 8654 | ||
| 8666 | switch (opt_mcv) { | 8655 | switch (opt_mcv) { |
| 8667 | .none, | 8656 | .none, |
| ... | @@ -8681,14 +8670,14 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC | ... | @@ -8681,14 +8670,14 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 8681 | 8670 | ||
| 8682 | .register => |opt_reg| { | 8671 | .register => |opt_reg| { |
| 8683 | if (some_info.off == 0) { | 8672 | if (some_info.off == 0) { |
| 8684 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); | 8673 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(mod)); |
| 8685 | const alias_reg = registerAlias(opt_reg, some_abi_size); | 8674 | const alias_reg = registerAlias(opt_reg, some_abi_size); |
| 8686 | assert(some_abi_size * 8 == alias_reg.bitSize()); | 8675 | assert(some_abi_size * 8 == alias_reg.bitSize()); |
| 8687 | try self.asmRegisterRegister(.{ ._, .@"test" }, alias_reg, alias_reg); | 8676 | try self.asmRegisterRegister(.{ ._, .@"test" }, alias_reg, alias_reg); |
| 8688 | return .{ .eflags = .z }; | 8677 | return .{ .eflags = .z }; |
| 8689 | } | 8678 | } |
| 8690 | assert(some_info.ty.tag() == .bool); | 8679 | assert(some_info.ty.ip_index == .bool_type); |
| 8691 | const opt_abi_size = @intCast(u32, opt_ty.abiSize(self.target.*)); | 8680 | const opt_abi_size = @intCast(u32, opt_ty.abiSize(mod)); |
| 8692 | try self.asmRegisterImmediate( | 8681 | try self.asmRegisterImmediate( |
| 8693 | .{ ._, .bt }, | 8682 | .{ ._, .bt }, |
| 8694 | registerAlias(opt_reg, opt_abi_size), | 8683 | registerAlias(opt_reg, opt_abi_size), |
| ... | @@ -8707,7 +8696,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC | ... | @@ -8707,7 +8696,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 8707 | defer self.register_manager.unlockReg(addr_reg_lock); | 8696 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 8708 | 8697 | ||
| 8709 | try self.genSetReg(addr_reg, Type.usize, opt_mcv.address()); | 8698 | try self.genSetReg(addr_reg, Type.usize, opt_mcv.address()); |
| 8710 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); | 8699 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(mod)); |
| 8711 | try self.asmMemoryImmediate( | 8700 | try self.asmMemoryImmediate( |
| 8712 | .{ ._, .cmp }, | 8701 | .{ ._, .cmp }, |
| 8713 | Memory.sib(Memory.PtrSize.fromSize(some_abi_size), .{ | 8702 | Memory.sib(Memory.PtrSize.fromSize(some_abi_size), .{ |
| ... | @@ -8720,7 +8709,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC | ... | @@ -8720,7 +8709,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 8720 | }, | 8709 | }, |
| 8721 | 8710 | ||
| 8722 | .indirect, .load_frame => { | 8711 | .indirect, .load_frame => { |
| 8723 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); | 8712 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(mod)); |
| 8724 | try self.asmMemoryImmediate( | 8713 | try self.asmMemoryImmediate( |
| 8725 | .{ ._, .cmp }, | 8714 | .{ ._, .cmp }, |
| 8726 | Memory.sib(Memory.PtrSize.fromSize(some_abi_size), switch (opt_mcv) { | 8715 | Memory.sib(Memory.PtrSize.fromSize(some_abi_size), switch (opt_mcv) { |
| ... | @@ -8742,18 +8731,17 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC | ... | @@ -8742,18 +8731,17 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 8742 | } | 8731 | } |
| 8743 | 8732 | ||
| 8744 | fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { | 8733 | fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue { |
| 8734 | const mod = self.bin_file.options.module.?; | ||
| 8745 | try self.spillEflagsIfOccupied(); | 8735 | try self.spillEflagsIfOccupied(); |
| 8746 | self.eflags_inst = inst; | 8736 | self.eflags_inst = inst; |
| 8747 | 8737 | ||
| 8748 | const opt_ty = ptr_ty.childType(); | 8738 | const opt_ty = ptr_ty.childType(mod); |
| 8749 | var pl_buf: Type.Payload.ElemType = undefined; | 8739 | const pl_ty = opt_ty.optionalChild(mod); |
| 8750 | const pl_ty = opt_ty.optionalChild(&pl_buf); | ||
| 8751 | 8740 | ||
| 8752 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | 8741 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(mod)) |
| 8753 | const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload()) | 8742 | .{ .off = 0, .ty = if (pl_ty.isSlice(mod)) pl_ty.slicePtrFieldType(mod) else pl_ty } |
| 8754 | .{ .off = 0, .ty = if (pl_ty.isSlice()) pl_ty.slicePtrFieldType(&ptr_buf) else pl_ty } | ||
| 8755 | else | 8743 | else |
| 8756 | .{ .off = @intCast(i32, pl_ty.abiSize(self.target.*)), .ty = Type.bool }; | 8744 | .{ .off = @intCast(i32, pl_ty.abiSize(mod)), .ty = Type.bool }; |
| 8757 | 8745 | ||
| 8758 | const ptr_reg = switch (ptr_mcv) { | 8746 | const ptr_reg = switch (ptr_mcv) { |
| 8759 | .register => |reg| reg, | 8747 | .register => |reg| reg, |
| ... | @@ -8762,7 +8750,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) | ... | @@ -8762,7 +8750,7 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) |
| 8762 | const ptr_lock = self.register_manager.lockReg(ptr_reg); | 8750 | const ptr_lock = self.register_manager.lockReg(ptr_reg); |
| 8763 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); | 8751 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 8764 | 8752 | ||
| 8765 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(self.target.*)); | 8753 | const some_abi_size = @intCast(u32, some_info.ty.abiSize(mod)); |
| 8766 | try self.asmMemoryImmediate( | 8754 | try self.asmMemoryImmediate( |
| 8767 | .{ ._, .cmp }, | 8755 | .{ ._, .cmp }, |
| 8768 | Memory.sib(Memory.PtrSize.fromSize(some_abi_size), .{ | 8756 | Memory.sib(Memory.PtrSize.fromSize(some_abi_size), .{ |
| ... | @@ -8775,9 +8763,10 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) | ... | @@ -8775,9 +8763,10 @@ fn isNullPtr(self: *Self, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) |
| 8775 | } | 8763 | } |
| 8776 | 8764 | ||
| 8777 | fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { | 8765 | fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { |
| 8778 | const err_type = ty.errorUnionSet(); | 8766 | const mod = self.bin_file.options.module.?; |
| 8767 | const err_type = ty.errorUnionSet(mod); | ||
| 8779 | 8768 | ||
| 8780 | if (err_type.errorSetIsEmpty()) { | 8769 | if (err_type.errorSetIsEmpty(mod)) { |
| 8781 | return MCValue{ .immediate = 0 }; // always false | 8770 | return MCValue{ .immediate = 0 }; // always false |
| 8782 | } | 8771 | } |
| 8783 | 8772 | ||
| ... | @@ -8786,7 +8775,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) ! | ... | @@ -8786,7 +8775,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) ! |
| 8786 | self.eflags_inst = inst; | 8775 | self.eflags_inst = inst; |
| 8787 | } | 8776 | } |
| 8788 | 8777 | ||
| 8789 | const err_off = errUnionErrorOffset(ty.errorUnionPayload(), self.target.*); | 8778 | const err_off = errUnionErrorOffset(ty.errorUnionPayload(mod), mod); |
| 8790 | switch (operand) { | 8779 | switch (operand) { |
| 8791 | .register => |reg| { | 8780 | .register => |reg| { |
| 8792 | const eu_lock = self.register_manager.lockReg(reg); | 8781 | const eu_lock = self.register_manager.lockReg(reg); |
| ... | @@ -8844,7 +8833,7 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCVa | ... | @@ -8844,7 +8833,7 @@ fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCVa |
| 8844 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | 8833 | fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 8845 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8834 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8846 | const operand = try self.resolveInst(un_op); | 8835 | const operand = try self.resolveInst(un_op); |
| 8847 | const ty = self.air.typeOf(un_op); | 8836 | const ty = self.typeOf(un_op); |
| 8848 | const result = try self.isNull(inst, ty, operand); | 8837 | const result = try self.isNull(inst, ty, operand); |
| 8849 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 8838 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8850 | } | 8839 | } |
| ... | @@ -8852,7 +8841,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8852,7 +8841,7 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index) !void { |
| 8852 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 8841 | fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8853 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8842 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8854 | const operand = try self.resolveInst(un_op); | 8843 | const operand = try self.resolveInst(un_op); |
| 8855 | const ty = self.air.typeOf(un_op); | 8844 | const ty = self.typeOf(un_op); |
| 8856 | const result = try self.isNullPtr(inst, ty, operand); | 8845 | const result = try self.isNullPtr(inst, ty, operand); |
| 8857 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 8846 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8858 | } | 8847 | } |
| ... | @@ -8860,7 +8849,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8860,7 +8849,7 @@ fn airIsNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8860 | fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | 8849 | fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 8861 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8850 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8862 | const operand = try self.resolveInst(un_op); | 8851 | const operand = try self.resolveInst(un_op); |
| 8863 | const ty = self.air.typeOf(un_op); | 8852 | const ty = self.typeOf(un_op); |
| 8864 | const result = switch (try self.isNull(inst, ty, operand)) { | 8853 | const result = switch (try self.isNull(inst, ty, operand)) { |
| 8865 | .eflags => |cc| .{ .eflags = cc.negate() }, | 8854 | .eflags => |cc| .{ .eflags = cc.negate() }, |
| 8866 | else => unreachable, | 8855 | else => unreachable, |
| ... | @@ -8871,7 +8860,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8871,7 +8860,7 @@ fn airIsNonNull(self: *Self, inst: Air.Inst.Index) !void { |
| 8871 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | 8860 | fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8872 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8861 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8873 | const operand = try self.resolveInst(un_op); | 8862 | const operand = try self.resolveInst(un_op); |
| 8874 | const ty = self.air.typeOf(un_op); | 8863 | const ty = self.typeOf(un_op); |
| 8875 | const result = switch (try self.isNullPtr(inst, ty, operand)) { | 8864 | const result = switch (try self.isNullPtr(inst, ty, operand)) { |
| 8876 | .eflags => |cc| .{ .eflags = cc.negate() }, | 8865 | .eflags => |cc| .{ .eflags = cc.negate() }, |
| 8877 | else => unreachable, | 8866 | else => unreachable, |
| ... | @@ -8882,12 +8871,13 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8882,12 +8871,13 @@ fn airIsNonNullPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8882 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { | 8871 | fn airIsErr(self: *Self, inst: Air.Inst.Index) !void { |
| 8883 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8872 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8884 | const operand = try self.resolveInst(un_op); | 8873 | const operand = try self.resolveInst(un_op); |
| 8885 | const ty = self.air.typeOf(un_op); | 8874 | const ty = self.typeOf(un_op); |
| 8886 | const result = try self.isErr(inst, ty, operand); | 8875 | const result = try self.isErr(inst, ty, operand); |
| 8887 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 8876 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8888 | } | 8877 | } |
| 8889 | 8878 | ||
| 8890 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 8879 | fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8880 | const mod = self.bin_file.options.module.?; | ||
| 8891 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8881 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8892 | 8882 | ||
| 8893 | const operand_ptr = try self.resolveInst(un_op); | 8883 | const operand_ptr = try self.resolveInst(un_op); |
| ... | @@ -8905,10 +8895,10 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8905,10 +8895,10 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8905 | break :blk try self.allocRegOrMem(inst, true); | 8895 | break :blk try self.allocRegOrMem(inst, true); |
| 8906 | } | 8896 | } |
| 8907 | }; | 8897 | }; |
| 8908 | const ptr_ty = self.air.typeOf(un_op); | 8898 | const ptr_ty = self.typeOf(un_op); |
| 8909 | try self.load(operand, ptr_ty, operand_ptr); | 8899 | try self.load(operand, ptr_ty, operand_ptr); |
| 8910 | 8900 | ||
| 8911 | const result = try self.isErr(inst, ptr_ty.childType(), operand); | 8901 | const result = try self.isErr(inst, ptr_ty.childType(mod), operand); |
| 8912 | 8902 | ||
| 8913 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 8903 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8914 | } | 8904 | } |
| ... | @@ -8916,12 +8906,13 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8916,12 +8906,13 @@ fn airIsErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8916 | fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { | 8906 | fn airIsNonErr(self: *Self, inst: Air.Inst.Index) !void { |
| 8917 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8907 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8918 | const operand = try self.resolveInst(un_op); | 8908 | const operand = try self.resolveInst(un_op); |
| 8919 | const ty = self.air.typeOf(un_op); | 8909 | const ty = self.typeOf(un_op); |
| 8920 | const result = try self.isNonErr(inst, ty, operand); | 8910 | const result = try self.isNonErr(inst, ty, operand); |
| 8921 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 8911 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8922 | } | 8912 | } |
| 8923 | 8913 | ||
| 8924 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { | 8914 | fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8915 | const mod = self.bin_file.options.module.?; | ||
| 8925 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8916 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8926 | 8917 | ||
| 8927 | const operand_ptr = try self.resolveInst(un_op); | 8918 | const operand_ptr = try self.resolveInst(un_op); |
| ... | @@ -8939,10 +8930,10 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8939,10 +8930,10 @@ fn airIsNonErrPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 8939 | break :blk try self.allocRegOrMem(inst, true); | 8930 | break :blk try self.allocRegOrMem(inst, true); |
| 8940 | } | 8931 | } |
| 8941 | }; | 8932 | }; |
| 8942 | const ptr_ty = self.air.typeOf(un_op); | 8933 | const ptr_ty = self.typeOf(un_op); |
| 8943 | try self.load(operand, ptr_ty, operand_ptr); | 8934 | try self.load(operand, ptr_ty, operand_ptr); |
| 8944 | 8935 | ||
| 8945 | const result = try self.isNonErr(inst, ptr_ty.childType(), operand); | 8936 | const result = try self.isNonErr(inst, ptr_ty.childType(mod), operand); |
| 8946 | 8937 | ||
| 8947 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 8938 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8948 | } | 8939 | } |
| ... | @@ -9005,7 +8996,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9005,7 +8996,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 9005 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { | 8996 | fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9006 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 8997 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 9007 | const condition = try self.resolveInst(pl_op.operand); | 8998 | const condition = try self.resolveInst(pl_op.operand); |
| 9008 | const condition_ty = self.air.typeOf(pl_op.operand); | 8999 | const condition_ty = self.typeOf(pl_op.operand); |
| 9009 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); | 9000 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 9010 | var extra_index: usize = switch_br.end; | 9001 | var extra_index: usize = switch_br.end; |
| 9011 | var case_i: u32 = 0; | 9002 | var case_i: u32 = 0; |
| ... | @@ -9088,12 +9079,13 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void { | ... | @@ -9088,12 +9079,13 @@ fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void { |
| 9088 | } | 9079 | } |
| 9089 | 9080 | ||
| 9090 | fn airBr(self: *Self, inst: Air.Inst.Index) !void { | 9081 | fn airBr(self: *Self, inst: Air.Inst.Index) !void { |
| 9082 | const mod = self.bin_file.options.module.?; | ||
| 9091 | const br = self.air.instructions.items(.data)[inst].br; | 9083 | const br = self.air.instructions.items(.data)[inst].br; |
| 9092 | const src_mcv = try self.resolveInst(br.operand); | 9084 | const src_mcv = try self.resolveInst(br.operand); |
| 9093 | 9085 | ||
| 9094 | const block_ty = self.air.typeOfIndex(br.block_inst); | 9086 | const block_ty = self.typeOfIndex(br.block_inst); |
| 9095 | const block_unused = | 9087 | const block_unused = |
| 9096 | !block_ty.hasRuntimeBitsIgnoreComptime() or self.liveness.isUnused(br.block_inst); | 9088 | !block_ty.hasRuntimeBitsIgnoreComptime(mod) or self.liveness.isUnused(br.block_inst); |
| 9097 | const block_tracking = self.inst_tracking.getPtr(br.block_inst).?; | 9089 | const block_tracking = self.inst_tracking.getPtr(br.block_inst).?; |
| 9098 | const block_data = self.blocks.getPtr(br.block_inst).?; | 9090 | const block_data = self.blocks.getPtr(br.block_inst).?; |
| 9099 | const first_br = block_data.relocs.items.len == 0; | 9091 | const first_br = block_data.relocs.items.len == 0; |
| ... | @@ -9216,7 +9208,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9216,7 +9208,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9216 | 9208 | ||
| 9217 | const arg_mcv = try self.resolveInst(input); | 9209 | const arg_mcv = try self.resolveInst(input); |
| 9218 | try self.register_manager.getReg(reg, null); | 9210 | try self.register_manager.getReg(reg, null); |
| 9219 | try self.genSetReg(reg, self.air.typeOf(input), arg_mcv); | 9211 | try self.genSetReg(reg, self.typeOf(input), arg_mcv); |
| 9220 | } | 9212 | } |
| 9221 | 9213 | ||
| 9222 | { | 9214 | { |
| ... | @@ -9402,7 +9394,8 @@ const MoveStrategy = union(enum) { | ... | @@ -9402,7 +9394,8 @@ const MoveStrategy = union(enum) { |
| 9402 | }; | 9394 | }; |
| 9403 | }; | 9395 | }; |
| 9404 | fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | 9396 | fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9405 | switch (ty.zigTypeTag()) { | 9397 | const mod = self.bin_file.options.module.?; |
| 9398 | switch (ty.zigTypeTag(mod)) { | ||
| 9406 | else => return .{ .move = .{ ._, .mov } }, | 9399 | else => return .{ .move = .{ ._, .mov } }, |
| 9407 | .Float => switch (ty.floatBits(self.target.*)) { | 9400 | .Float => switch (ty.floatBits(self.target.*)) { |
| 9408 | 16 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ | 9401 | 16 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| ... | @@ -9419,9 +9412,9 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | ... | @@ -9419,9 +9412,9 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9419 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, | 9412 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| 9420 | else => {}, | 9413 | else => {}, |
| 9421 | }, | 9414 | }, |
| 9422 | .Vector => switch (ty.childType().zigTypeTag()) { | 9415 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { |
| 9423 | .Int => switch (ty.childType().intInfo(self.target.*).bits) { | 9416 | .Int => switch (ty.childType(mod).intInfo(mod).bits) { |
| 9424 | 8 => switch (ty.vectorLen()) { | 9417 | 8 => switch (ty.vectorLen(mod)) { |
| 9425 | 1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{ | 9418 | 1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{ |
| 9426 | .insert = .{ .vp_b, .insr }, | 9419 | .insert = .{ .vp_b, .insr }, |
| 9427 | .extract = .{ .vp_b, .extr }, | 9420 | .extract = .{ .vp_b, .extr }, |
| ... | @@ -9451,7 +9444,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | ... | @@ -9451,7 +9444,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9451 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, | 9444 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9452 | else => {}, | 9445 | else => {}, |
| 9453 | }, | 9446 | }, |
| 9454 | 16 => switch (ty.vectorLen()) { | 9447 | 16 => switch (ty.vectorLen(mod)) { |
| 9455 | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ | 9448 | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 9456 | .insert = .{ .vp_w, .insr }, | 9449 | .insert = .{ .vp_w, .insr }, |
| 9457 | .extract = .{ .vp_w, .extr }, | 9450 | .extract = .{ .vp_w, .extr }, |
| ... | @@ -9474,7 +9467,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | ... | @@ -9474,7 +9467,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9474 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, | 9467 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9475 | else => {}, | 9468 | else => {}, |
| 9476 | }, | 9469 | }, |
| 9477 | 32 => switch (ty.vectorLen()) { | 9470 | 32 => switch (ty.vectorLen(mod)) { |
| 9478 | 1 => return .{ .move = if (self.hasFeature(.avx)) | 9471 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9479 | .{ .v_d, .mov } | 9472 | .{ .v_d, .mov } |
| 9480 | else | 9473 | else |
| ... | @@ -9490,7 +9483,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | ... | @@ -9490,7 +9483,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9490 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, | 9483 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9491 | else => {}, | 9484 | else => {}, |
| 9492 | }, | 9485 | }, |
| 9493 | 64 => switch (ty.vectorLen()) { | 9486 | 64 => switch (ty.vectorLen(mod)) { |
| 9494 | 1 => return .{ .move = if (self.hasFeature(.avx)) | 9487 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9495 | .{ .v_q, .mov } | 9488 | .{ .v_q, .mov } |
| 9496 | else | 9489 | else |
| ... | @@ -9502,7 +9495,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | ... | @@ -9502,7 +9495,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9502 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, | 9495 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9503 | else => {}, | 9496 | else => {}, |
| 9504 | }, | 9497 | }, |
| 9505 | 128 => switch (ty.vectorLen()) { | 9498 | 128 => switch (ty.vectorLen(mod)) { |
| 9506 | 1 => return .{ .move = if (self.hasFeature(.avx)) | 9499 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9507 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } | 9500 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 9508 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, | 9501 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| ... | @@ -9510,15 +9503,15 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | ... | @@ -9510,15 +9503,15 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9510 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, | 9503 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9511 | else => {}, | 9504 | else => {}, |
| 9512 | }, | 9505 | }, |
| 9513 | 256 => switch (ty.vectorLen()) { | 9506 | 256 => switch (ty.vectorLen(mod)) { |
| 9514 | 1 => if (self.hasFeature(.avx)) | 9507 | 1 => if (self.hasFeature(.avx)) |
| 9515 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, | 9508 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9516 | else => {}, | 9509 | else => {}, |
| 9517 | }, | 9510 | }, |
| 9518 | else => {}, | 9511 | else => {}, |
| 9519 | }, | 9512 | }, |
| 9520 | .Float => switch (ty.childType().floatBits(self.target.*)) { | 9513 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 9521 | 16 => switch (ty.vectorLen()) { | 9514 | 16 => switch (ty.vectorLen(mod)) { |
| 9522 | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ | 9515 | 1 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{ |
| 9523 | .insert = .{ .vp_w, .insr }, | 9516 | .insert = .{ .vp_w, .insr }, |
| 9524 | .extract = .{ .vp_w, .extr }, | 9517 | .extract = .{ .vp_w, .extr }, |
| ... | @@ -9541,7 +9534,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | ... | @@ -9541,7 +9534,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9541 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, | 9534 | return .{ .move = if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } }, |
| 9542 | else => {}, | 9535 | else => {}, |
| 9543 | }, | 9536 | }, |
| 9544 | 32 => switch (ty.vectorLen()) { | 9537 | 32 => switch (ty.vectorLen(mod)) { |
| 9545 | 1 => return .{ .move = if (self.hasFeature(.avx)) | 9538 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9546 | .{ .v_ss, .mov } | 9539 | .{ .v_ss, .mov } |
| 9547 | else | 9540 | else |
| ... | @@ -9557,7 +9550,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | ... | @@ -9557,7 +9550,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9557 | return .{ .move = if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } }, | 9550 | return .{ .move = if (aligned) .{ .v_ps, .mova } else .{ .v_ps, .movu } }, |
| 9558 | else => {}, | 9551 | else => {}, |
| 9559 | }, | 9552 | }, |
| 9560 | 64 => switch (ty.vectorLen()) { | 9553 | 64 => switch (ty.vectorLen(mod)) { |
| 9561 | 1 => return .{ .move = if (self.hasFeature(.avx)) | 9554 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9562 | .{ .v_sd, .mov } | 9555 | .{ .v_sd, .mov } |
| 9563 | else | 9556 | else |
| ... | @@ -9569,7 +9562,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { | ... | @@ -9569,7 +9562,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { |
| 9569 | return .{ .move = if (aligned) .{ .v_pd, .mova } else .{ .v_pd, .movu } }, | 9562 | return .{ .move = if (aligned) .{ .v_pd, .mova } else .{ .v_pd, .movu } }, |
| 9570 | else => {}, | 9563 | else => {}, |
| 9571 | }, | 9564 | }, |
| 9572 | 128 => switch (ty.vectorLen()) { | 9565 | 128 => switch (ty.vectorLen(mod)) { |
| 9573 | 1 => return .{ .move = if (self.hasFeature(.avx)) | 9566 | 1 => return .{ .move = if (self.hasFeature(.avx)) |
| 9574 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } | 9567 | if (aligned) .{ .v_, .movdqa } else .{ .v_, .movdqu } |
| 9575 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, | 9568 | else if (aligned) .{ ._, .movdqa } else .{ ._, .movdqu } }, |
| ... | @@ -9647,7 +9640,8 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError | ... | @@ -9647,7 +9640,8 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError |
| 9647 | } | 9640 | } |
| 9648 | 9641 | ||
| 9649 | fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerError!void { | 9642 | fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerError!void { |
| 9650 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 9643 | const mod = self.bin_file.options.module.?; |
| 9644 | const abi_size = @intCast(u32, ty.abiSize(mod)); | ||
| 9651 | if (abi_size * 8 > dst_reg.bitSize()) | 9645 | if (abi_size * 8 > dst_reg.bitSize()) |
| 9652 | return self.fail("genSetReg called with a value larger than dst_reg", .{}); | 9646 | return self.fail("genSetReg called with a value larger than dst_reg", .{}); |
| 9653 | switch (src_mcv) { | 9647 | switch (src_mcv) { |
| ... | @@ -9730,7 +9724,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9730,7 +9724,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9730 | .{ .register = try self.copyToTmpRegister(ty, src_mcv) }, | 9724 | .{ .register = try self.copyToTmpRegister(ty, src_mcv) }, |
| 9731 | ), | 9725 | ), |
| 9732 | .sse => try self.asmRegisterRegister( | 9726 | .sse => try self.asmRegisterRegister( |
| 9733 | if (@as(?Mir.Inst.FixedTag, switch (ty.scalarType().zigTypeTag()) { | 9727 | if (@as(?Mir.Inst.FixedTag, switch (ty.scalarType(mod).zigTypeTag(mod)) { |
| 9734 | else => switch (abi_size) { | 9728 | else => switch (abi_size) { |
| 9735 | 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, | 9729 | 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, |
| 9736 | 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, | 9730 | 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, |
| ... | @@ -9738,7 +9732,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9738,7 +9732,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9738 | 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null, | 9732 | 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null, |
| 9739 | else => null, | 9733 | else => null, |
| 9740 | }, | 9734 | }, |
| 9741 | .Float => switch (ty.scalarType().floatBits(self.target.*)) { | 9735 | .Float => switch (ty.scalarType(mod).floatBits(self.target.*)) { |
| 9742 | 16, 128 => switch (abi_size) { | 9736 | 16, 128 => switch (abi_size) { |
| 9743 | 2...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, | 9737 | 2...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, |
| 9744 | 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, | 9738 | 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, |
| ... | @@ -9789,7 +9783,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9789,7 +9783,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9789 | .indirect => try self.moveStrategy(ty, false), | 9783 | .indirect => try self.moveStrategy(ty, false), |
| 9790 | .load_frame => |frame_addr| try self.moveStrategy( | 9784 | .load_frame => |frame_addr| try self.moveStrategy( |
| 9791 | ty, | 9785 | ty, |
| 9792 | self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(self.target.*), | 9786 | self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(mod), |
| 9793 | ), | 9787 | ), |
| 9794 | .lea_frame => .{ .move = .{ ._, .lea } }, | 9788 | .lea_frame => .{ .move = .{ ._, .lea } }, |
| 9795 | else => unreachable, | 9789 | else => unreachable, |
| ... | @@ -9821,7 +9815,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9821,7 +9815,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9821 | switch (try self.moveStrategy(ty, mem.isAlignedGeneric( | 9815 | switch (try self.moveStrategy(ty, mem.isAlignedGeneric( |
| 9822 | u32, | 9816 | u32, |
| 9823 | @bitCast(u32, small_addr), | 9817 | @bitCast(u32, small_addr), |
| 9824 | ty.abiAlignment(self.target.*), | 9818 | ty.abiAlignment(mod), |
| 9825 | ))) { | 9819 | ))) { |
| 9826 | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), | 9820 | .move => |tag| try self.asmRegisterMemory(tag, dst_alias, src_mem), |
| 9827 | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( | 9821 | .insert_extract => |ie| try self.asmRegisterMemoryImmediate( |
| ... | @@ -9839,7 +9833,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9839,7 +9833,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9839 | ), | 9833 | ), |
| 9840 | } | 9834 | } |
| 9841 | }, | 9835 | }, |
| 9842 | .load_direct => |sym_index| switch (ty.zigTypeTag()) { | 9836 | .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) { |
| 9843 | else => { | 9837 | else => { |
| 9844 | const atom_index = try self.owner.getSymbolIndex(self); | 9838 | const atom_index = try self.owner.getSymbolIndex(self); |
| 9845 | _ = try self.addInst(.{ | 9839 | _ = try self.addInst(.{ |
| ... | @@ -9933,7 +9927,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -9933,7 +9927,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 9933 | } | 9927 | } |
| 9934 | 9928 | ||
| 9935 | fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCValue) InnerError!void { | 9929 | fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCValue) InnerError!void { |
| 9936 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 9930 | const mod = self.bin_file.options.module.?; |
| 9931 | const abi_size = @intCast(u32, ty.abiSize(mod)); | ||
| 9937 | const dst_ptr_mcv: MCValue = switch (base) { | 9932 | const dst_ptr_mcv: MCValue = switch (base) { |
| 9938 | .none => .{ .immediate = @bitCast(u64, @as(i64, disp)) }, | 9933 | .none => .{ .immediate = @bitCast(u64, @as(i64, disp)) }, |
| 9939 | .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } }, | 9934 | .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } }, |
| ... | @@ -9945,7 +9940,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -9945,7 +9940,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 9945 | try self.genInlineMemset(dst_ptr_mcv, .{ .immediate = 0xaa }, .{ .immediate = abi_size }), | 9940 | try self.genInlineMemset(dst_ptr_mcv, .{ .immediate = 0xaa }, .{ .immediate = abi_size }), |
| 9946 | .immediate => |imm| switch (abi_size) { | 9941 | .immediate => |imm| switch (abi_size) { |
| 9947 | 1, 2, 4 => { | 9942 | 1, 2, 4 => { |
| 9948 | const immediate = if (ty.isSignedInt()) | 9943 | const immediate = if (ty.isSignedInt(mod)) |
| 9949 | Immediate.s(@truncate(i32, @bitCast(i64, imm))) | 9944 | Immediate.s(@truncate(i32, @bitCast(i64, imm))) |
| 9950 | else | 9945 | else |
| 9951 | Immediate.u(@intCast(u32, imm)); | 9946 | Immediate.u(@intCast(u32, imm)); |
| ... | @@ -9967,7 +9962,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -9967,7 +9962,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 9967 | while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate( | 9962 | while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate( |
| 9968 | .{ ._, .mov }, | 9963 | .{ ._, .mov }, |
| 9969 | Memory.sib(.dword, .{ .base = base, .disp = disp + offset }), | 9964 | Memory.sib(.dword, .{ .base = base, .disp = disp + offset }), |
| 9970 | if (ty.isSignedInt()) | 9965 | if (ty.isSignedInt(mod)) |
| 9971 | Immediate.s(@truncate( | 9966 | Immediate.s(@truncate( |
| 9972 | i32, | 9967 | i32, |
| 9973 | @bitCast(i64, imm) >> (math.cast(u6, offset * 8) orelse 63), | 9968 | @bitCast(i64, imm) >> (math.cast(u6, offset * 8) orelse 63), |
| ... | @@ -9991,19 +9986,19 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -9991,19 +9986,19 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 9991 | .none => mem.isAlignedGeneric( | 9986 | .none => mem.isAlignedGeneric( |
| 9992 | u32, | 9987 | u32, |
| 9993 | @bitCast(u32, disp), | 9988 | @bitCast(u32, disp), |
| 9994 | ty.abiAlignment(self.target.*), | 9989 | ty.abiAlignment(mod), |
| 9995 | ), | 9990 | ), |
| 9996 | .reg => |reg| switch (reg) { | 9991 | .reg => |reg| switch (reg) { |
| 9997 | .es, .cs, .ss, .ds => mem.isAlignedGeneric( | 9992 | .es, .cs, .ss, .ds => mem.isAlignedGeneric( |
| 9998 | u32, | 9993 | u32, |
| 9999 | @bitCast(u32, disp), | 9994 | @bitCast(u32, disp), |
| 10000 | ty.abiAlignment(self.target.*), | 9995 | ty.abiAlignment(mod), |
| 10001 | ), | 9996 | ), |
| 10002 | else => false, | 9997 | else => false, |
| 10003 | }, | 9998 | }, |
| 10004 | .frame => |frame_index| self.getFrameAddrAlignment( | 9999 | .frame => |frame_index| self.getFrameAddrAlignment( |
| 10005 | .{ .index = frame_index, .off = disp }, | 10000 | .{ .index = frame_index, .off = disp }, |
| 10006 | ) >= ty.abiAlignment(self.target.*), | 10001 | ) >= ty.abiAlignment(mod), |
| 10007 | })) { | 10002 | })) { |
| 10008 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), | 10003 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), |
| 10009 | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( | 10004 | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( |
| ... | @@ -10017,14 +10012,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -10017,14 +10012,14 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 10017 | .register_overflow => |ro| { | 10012 | .register_overflow => |ro| { |
| 10018 | try self.genSetMem( | 10013 | try self.genSetMem( |
| 10019 | base, | 10014 | base, |
| 10020 | disp + @intCast(i32, ty.structFieldOffset(0, self.target.*)), | 10015 | disp + @intCast(i32, ty.structFieldOffset(0, mod)), |
| 10021 | ty.structFieldType(0), | 10016 | ty.structFieldType(0, mod), |
| 10022 | .{ .register = ro.reg }, | 10017 | .{ .register = ro.reg }, |
| 10023 | ); | 10018 | ); |
| 10024 | try self.genSetMem( | 10019 | try self.genSetMem( |
| 10025 | base, | 10020 | base, |
| 10026 | disp + @intCast(i32, ty.structFieldOffset(1, self.target.*)), | 10021 | disp + @intCast(i32, ty.structFieldOffset(1, mod)), |
| 10027 | ty.structFieldType(1), | 10022 | ty.structFieldType(1, mod), |
| 10028 | .{ .eflags = ro.eflags }, | 10023 | .{ .eflags = ro.eflags }, |
| 10029 | ); | 10024 | ); |
| 10030 | }, | 10025 | }, |
| ... | @@ -10138,7 +10133,7 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10138,7 +10133,7 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10138 | if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv; | 10133 | if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv; |
| 10139 | 10134 | ||
| 10140 | const dst_mcv = try self.allocRegOrMem(inst, true); | 10135 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| 10141 | const dst_ty = self.air.typeOfIndex(inst); | 10136 | const dst_ty = self.typeOfIndex(inst); |
| 10142 | try self.genCopy(dst_ty, dst_mcv, src_mcv); | 10137 | try self.genCopy(dst_ty, dst_mcv, src_mcv); |
| 10143 | break :result dst_mcv; | 10138 | break :result dst_mcv; |
| 10144 | }; | 10139 | }; |
| ... | @@ -10146,13 +10141,14 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10146,13 +10141,14 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10146 | } | 10141 | } |
| 10147 | 10142 | ||
| 10148 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | 10143 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 10144 | const mod = self.bin_file.options.module.?; | ||
| 10149 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 10145 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 10150 | const dst_ty = self.air.typeOfIndex(inst); | 10146 | const dst_ty = self.typeOfIndex(inst); |
| 10151 | const src_ty = self.air.typeOf(ty_op.operand); | 10147 | const src_ty = self.typeOf(ty_op.operand); |
| 10152 | 10148 | ||
| 10153 | const result = result: { | 10149 | const result = result: { |
| 10154 | const dst_rc = regClassForType(dst_ty); | 10150 | const dst_rc = regClassForType(dst_ty, mod); |
| 10155 | const src_rc = regClassForType(src_ty); | 10151 | const src_rc = regClassForType(src_ty, mod); |
| 10156 | const src_mcv = try self.resolveInst(ty_op.operand); | 10152 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 10157 | 10153 | ||
| 10158 | const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; | 10154 | const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| ... | @@ -10172,13 +10168,13 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10172,13 +10168,13 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 10172 | }; | 10168 | }; |
| 10173 | 10169 | ||
| 10174 | const dst_signedness = | 10170 | const dst_signedness = |
| 10175 | if (dst_ty.isAbiInt()) dst_ty.intInfo(self.target.*).signedness else .unsigned; | 10171 | if (dst_ty.isAbiInt(mod)) dst_ty.intInfo(mod).signedness else .unsigned; |
| 10176 | const src_signedness = | 10172 | const src_signedness = |
| 10177 | if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned; | 10173 | if (src_ty.isAbiInt(mod)) src_ty.intInfo(mod).signedness else .unsigned; |
| 10178 | if (dst_signedness == src_signedness) break :result dst_mcv; | 10174 | if (dst_signedness == src_signedness) break :result dst_mcv; |
| 10179 | 10175 | ||
| 10180 | const abi_size = @intCast(u16, dst_ty.abiSize(self.target.*)); | 10176 | const abi_size = @intCast(u16, dst_ty.abiSize(mod)); |
| 10181 | const bit_size = @intCast(u16, dst_ty.bitSize(self.target.*)); | 10177 | const bit_size = @intCast(u16, dst_ty.bitSize(mod)); |
| 10182 | if (abi_size * 8 <= bit_size) break :result dst_mcv; | 10178 | if (abi_size * 8 <= bit_size) break :result dst_mcv; |
| 10183 | 10179 | ||
| 10184 | const dst_limbs_len = math.divCeil(i32, bit_size, 64) catch unreachable; | 10180 | const dst_limbs_len = math.divCeil(i32, bit_size, 64) catch unreachable; |
| ... | @@ -10192,14 +10188,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10192,14 +10188,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 10192 | const high_lock = self.register_manager.lockReg(high_reg); | 10188 | const high_lock = self.register_manager.lockReg(high_reg); |
| 10193 | defer if (high_lock) |lock| self.register_manager.unlockReg(lock); | 10189 | defer if (high_lock) |lock| self.register_manager.unlockReg(lock); |
| 10194 | 10190 | ||
| 10195 | var high_pl = Type.Payload.Bits{ | 10191 | const high_ty = try mod.intType(dst_signedness, bit_size % 64); |
| 10196 | .base = .{ .tag = switch (dst_signedness) { | ||
| 10197 | .signed => .int_signed, | ||
| 10198 | .unsigned => .int_unsigned, | ||
| 10199 | } }, | ||
| 10200 | .data = bit_size % 64, | ||
| 10201 | }; | ||
| 10202 | const high_ty = Type.initPayload(&high_pl.base); | ||
| 10203 | 10192 | ||
| 10204 | try self.truncateRegister(high_ty, high_reg); | 10193 | try self.truncateRegister(high_ty, high_reg); |
| 10205 | if (!dst_mcv.isRegister()) try self.genCopy( | 10194 | if (!dst_mcv.isRegister()) try self.genCopy( |
| ... | @@ -10213,19 +10202,20 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10213,19 +10202,20 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 10213 | } | 10202 | } |
| 10214 | 10203 | ||
| 10215 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | 10204 | fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 10205 | const mod = self.bin_file.options.module.?; | ||
| 10216 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 10206 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 10217 | 10207 | ||
| 10218 | const slice_ty = self.air.typeOfIndex(inst); | 10208 | const slice_ty = self.typeOfIndex(inst); |
| 10219 | const ptr_ty = self.air.typeOf(ty_op.operand); | 10209 | const ptr_ty = self.typeOf(ty_op.operand); |
| 10220 | const ptr = try self.resolveInst(ty_op.operand); | 10210 | const ptr = try self.resolveInst(ty_op.operand); |
| 10221 | const array_ty = ptr_ty.childType(); | 10211 | const array_ty = ptr_ty.childType(mod); |
| 10222 | const array_len = array_ty.arrayLen(); | 10212 | const array_len = array_ty.arrayLen(mod); |
| 10223 | 10213 | ||
| 10224 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(slice_ty, self.target.*)); | 10214 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(slice_ty, mod)); |
| 10225 | try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, ptr); | 10215 | try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, ptr); |
| 10226 | try self.genSetMem( | 10216 | try self.genSetMem( |
| 10227 | .{ .frame = frame_index }, | 10217 | .{ .frame = frame_index }, |
| 10228 | @intCast(i32, ptr_ty.abiSize(self.target.*)), | 10218 | @intCast(i32, ptr_ty.abiSize(mod)), |
| 10229 | Type.usize, | 10219 | Type.usize, |
| 10230 | .{ .immediate = array_len }, | 10220 | .{ .immediate = array_len }, |
| 10231 | ); | 10221 | ); |
| ... | @@ -10235,20 +10225,21 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10235,20 +10225,21 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 10235 | } | 10225 | } |
| 10236 | 10226 | ||
| 10237 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { | 10227 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 10228 | const mod = self.bin_file.options.module.?; | ||
| 10238 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 10229 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 10239 | 10230 | ||
| 10240 | const src_ty = self.air.typeOf(ty_op.operand); | 10231 | const src_ty = self.typeOf(ty_op.operand); |
| 10241 | const src_bits = @intCast(u32, src_ty.bitSize(self.target.*)); | 10232 | const src_bits = @intCast(u32, src_ty.bitSize(mod)); |
| 10242 | const src_signedness = | 10233 | const src_signedness = |
| 10243 | if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned; | 10234 | if (src_ty.isAbiInt(mod)) src_ty.intInfo(mod).signedness else .unsigned; |
| 10244 | const dst_ty = self.air.typeOfIndex(inst); | 10235 | const dst_ty = self.typeOfIndex(inst); |
| 10245 | 10236 | ||
| 10246 | const src_size = math.divCeil(u32, @max(switch (src_signedness) { | 10237 | const src_size = math.divCeil(u32, @max(switch (src_signedness) { |
| 10247 | .signed => src_bits, | 10238 | .signed => src_bits, |
| 10248 | .unsigned => src_bits + 1, | 10239 | .unsigned => src_bits + 1, |
| 10249 | }, 32), 8) catch unreachable; | 10240 | }, 32), 8) catch unreachable; |
| 10250 | if (src_size > 8) return self.fail("TODO implement airIntToFloat from {} to {}", .{ | 10241 | if (src_size > 8) return self.fail("TODO implement airIntToFloat from {} to {}", .{ |
| 10251 | src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?), | 10242 | src_ty.fmt(mod), dst_ty.fmt(mod), |
| 10252 | }); | 10243 | }); |
| 10253 | 10244 | ||
| 10254 | const src_mcv = try self.resolveInst(ty_op.operand); | 10245 | const src_mcv = try self.resolveInst(ty_op.operand); |
| ... | @@ -10261,12 +10252,12 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10261,12 +10252,12 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 10261 | 10252 | ||
| 10262 | if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg); | 10253 | if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg); |
| 10263 | 10254 | ||
| 10264 | const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty)); | 10255 | const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod)); |
| 10265 | const dst_mcv = MCValue{ .register = dst_reg }; | 10256 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 10266 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 10257 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 10267 | defer self.register_manager.unlockReg(dst_lock); | 10258 | defer self.register_manager.unlockReg(dst_lock); |
| 10268 | 10259 | ||
| 10269 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (dst_ty.zigTypeTag()) { | 10260 | const mir_tag = if (@as(?Mir.Inst.FixedTag, switch (dst_ty.zigTypeTag(mod)) { |
| 10270 | .Float => switch (dst_ty.floatBits(self.target.*)) { | 10261 | .Float => switch (dst_ty.floatBits(self.target.*)) { |
| 10271 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .cvtsi2 } else .{ ._ss, .cvtsi2 }, | 10262 | 32 => if (self.hasFeature(.avx)) .{ .v_ss, .cvtsi2 } else .{ ._ss, .cvtsi2 }, |
| 10272 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .cvtsi2 } else .{ ._sd, .cvtsi2 }, | 10263 | 64 => if (self.hasFeature(.avx)) .{ .v_sd, .cvtsi2 } else .{ ._sd, .cvtsi2 }, |
| ... | @@ -10275,7 +10266,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10275,7 +10266,7 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 10275 | }, | 10266 | }, |
| 10276 | else => null, | 10267 | else => null, |
| 10277 | })) |tag| tag else return self.fail("TODO implement airIntToFloat from {} to {}", .{ | 10268 | })) |tag| tag else return self.fail("TODO implement airIntToFloat from {} to {}", .{ |
| 10278 | src_ty.fmt(self.bin_file.options.module.?), dst_ty.fmt(self.bin_file.options.module.?), | 10269 | src_ty.fmt(mod), dst_ty.fmt(mod), |
| 10279 | }); | 10270 | }); |
| 10280 | const dst_alias = dst_reg.to128(); | 10271 | const dst_alias = dst_reg.to128(); |
| 10281 | const src_alias = registerAlias(src_reg, src_size); | 10272 | const src_alias = registerAlias(src_reg, src_size); |
| ... | @@ -10288,13 +10279,14 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10288,13 +10279,14 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 10288 | } | 10279 | } |
| 10289 | 10280 | ||
| 10290 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { | 10281 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10282 | const mod = self.bin_file.options.module.?; | ||
| 10291 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 10283 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 10292 | 10284 | ||
| 10293 | const src_ty = self.air.typeOf(ty_op.operand); | 10285 | const src_ty = self.typeOf(ty_op.operand); |
| 10294 | const dst_ty = self.air.typeOfIndex(inst); | 10286 | const dst_ty = self.typeOfIndex(inst); |
| 10295 | const dst_bits = @intCast(u32, dst_ty.bitSize(self.target.*)); | 10287 | const dst_bits = @intCast(u32, dst_ty.bitSize(mod)); |
| 10296 | const dst_signedness = | 10288 | const dst_signedness = |
| 10297 | if (dst_ty.isAbiInt()) dst_ty.intInfo(self.target.*).signedness else .unsigned; | 10289 | if (dst_ty.isAbiInt(mod)) dst_ty.intInfo(mod).signedness else .unsigned; |
| 10298 | 10290 | ||
| 10299 | const dst_size = math.divCeil(u32, @max(switch (dst_signedness) { | 10291 | const dst_size = math.divCeil(u32, @max(switch (dst_signedness) { |
| 10300 | .signed => dst_bits, | 10292 | .signed => dst_bits, |
| ... | @@ -10312,13 +10304,13 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10312,13 +10304,13 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10312 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); | 10304 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 10313 | defer self.register_manager.unlockReg(src_lock); | 10305 | defer self.register_manager.unlockReg(src_lock); |
| 10314 | 10306 | ||
| 10315 | const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty)); | 10307 | const dst_reg = try self.register_manager.allocReg(inst, regClassForType(dst_ty, mod)); |
| 10316 | const dst_mcv = MCValue{ .register = dst_reg }; | 10308 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 10317 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); | 10309 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 10318 | defer self.register_manager.unlockReg(dst_lock); | 10310 | defer self.register_manager.unlockReg(dst_lock); |
| 10319 | 10311 | ||
| 10320 | try self.asmRegisterRegister( | 10312 | try self.asmRegisterRegister( |
| 10321 | if (@as(?Mir.Inst.FixedTag, switch (src_ty.zigTypeTag()) { | 10313 | if (@as(?Mir.Inst.FixedTag, switch (src_ty.zigTypeTag(mod)) { |
| 10322 | .Float => switch (src_ty.floatBits(self.target.*)) { | 10314 | .Float => switch (src_ty.floatBits(self.target.*)) { |
| 10323 | 32 => if (self.hasFeature(.avx)) .{ .v_, .cvttss2si } else .{ ._, .cvttss2si }, | 10315 | 32 => if (self.hasFeature(.avx)) .{ .v_, .cvttss2si } else .{ ._, .cvttss2si }, |
| 10324 | 64 => if (self.hasFeature(.avx)) .{ .v_, .cvttsd2si } else .{ ._, .cvttsd2si }, | 10316 | 64 => if (self.hasFeature(.avx)) .{ .v_, .cvttsd2si } else .{ ._, .cvttsd2si }, |
| ... | @@ -10339,12 +10331,13 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10339,12 +10331,13 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 10339 | } | 10331 | } |
| 10340 | 10332 | ||
| 10341 | fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { | 10333 | fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 10334 | const mod = self.bin_file.options.module.?; | ||
| 10342 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 10335 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 10343 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; | 10336 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 10344 | 10337 | ||
| 10345 | const ptr_ty = self.air.typeOf(extra.ptr); | 10338 | const ptr_ty = self.typeOf(extra.ptr); |
| 10346 | const val_ty = self.air.typeOf(extra.expected_value); | 10339 | const val_ty = self.typeOf(extra.expected_value); |
| 10347 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); | 10340 | const val_abi_size = @intCast(u32, val_ty.abiSize(mod)); |
| 10348 | 10341 | ||
| 10349 | try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx }); | 10342 | try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx }); |
| 10350 | const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx }); | 10343 | const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx }); |
| ... | @@ -10433,6 +10426,7 @@ fn atomicOp( | ... | @@ -10433,6 +10426,7 @@ fn atomicOp( |
| 10433 | rmw_op: ?std.builtin.AtomicRmwOp, | 10426 | rmw_op: ?std.builtin.AtomicRmwOp, |
| 10434 | order: std.builtin.AtomicOrder, | 10427 | order: std.builtin.AtomicOrder, |
| 10435 | ) InnerError!MCValue { | 10428 | ) InnerError!MCValue { |
| 10429 | const mod = self.bin_file.options.module.?; | ||
| 10436 | const ptr_lock = switch (ptr_mcv) { | 10430 | const ptr_lock = switch (ptr_mcv) { |
| 10437 | .register => |reg| self.register_manager.lockReg(reg), | 10431 | .register => |reg| self.register_manager.lockReg(reg), |
| 10438 | else => null, | 10432 | else => null, |
| ... | @@ -10445,7 +10439,7 @@ fn atomicOp( | ... | @@ -10445,7 +10439,7 @@ fn atomicOp( |
| 10445 | }; | 10439 | }; |
| 10446 | defer if (val_lock) |lock| self.register_manager.unlockReg(lock); | 10440 | defer if (val_lock) |lock| self.register_manager.unlockReg(lock); |
| 10447 | 10441 | ||
| 10448 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); | 10442 | const val_abi_size = @intCast(u32, val_ty.abiSize(mod)); |
| 10449 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); | 10443 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 10450 | const ptr_mem = switch (ptr_mcv) { | 10444 | const ptr_mem = switch (ptr_mcv) { |
| 10451 | .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size), | 10445 | .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size), |
| ... | @@ -10539,8 +10533,8 @@ fn atomicOp( | ... | @@ -10539,8 +10533,8 @@ fn atomicOp( |
| 10539 | .Or => try self.genBinOpMir(.{ ._, .@"or" }, val_ty, tmp_mcv, val_mcv), | 10533 | .Or => try self.genBinOpMir(.{ ._, .@"or" }, val_ty, tmp_mcv, val_mcv), |
| 10540 | .Xor => try self.genBinOpMir(.{ ._, .xor }, val_ty, tmp_mcv, val_mcv), | 10534 | .Xor => try self.genBinOpMir(.{ ._, .xor }, val_ty, tmp_mcv, val_mcv), |
| 10541 | .Min, .Max => { | 10535 | .Min, .Max => { |
| 10542 | const cc: Condition = switch (if (val_ty.isAbiInt()) | 10536 | const cc: Condition = switch (if (val_ty.isAbiInt(mod)) |
| 10543 | val_ty.intInfo(self.target.*).signedness | 10537 | val_ty.intInfo(mod).signedness |
| 10544 | else | 10538 | else |
| 10545 | .unsigned) { | 10539 | .unsigned) { |
| 10546 | .unsigned => switch (op) { | 10540 | .unsigned => switch (op) { |
| ... | @@ -10682,10 +10676,10 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10682,10 +10676,10 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { |
| 10682 | 10676 | ||
| 10683 | const unused = self.liveness.isUnused(inst); | 10677 | const unused = self.liveness.isUnused(inst); |
| 10684 | 10678 | ||
| 10685 | const ptr_ty = self.air.typeOf(pl_op.operand); | 10679 | const ptr_ty = self.typeOf(pl_op.operand); |
| 10686 | const ptr_mcv = try self.resolveInst(pl_op.operand); | 10680 | const ptr_mcv = try self.resolveInst(pl_op.operand); |
| 10687 | 10681 | ||
| 10688 | const val_ty = self.air.typeOf(extra.operand); | 10682 | const val_ty = self.typeOf(extra.operand); |
| 10689 | const val_mcv = try self.resolveInst(extra.operand); | 10683 | const val_mcv = try self.resolveInst(extra.operand); |
| 10690 | 10684 | ||
| 10691 | const result = | 10685 | const result = |
| ... | @@ -10696,7 +10690,7 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10696,7 +10690,7 @@ fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void { |
| 10696 | fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { | 10690 | fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 10697 | const atomic_load = self.air.instructions.items(.data)[inst].atomic_load; | 10691 | const atomic_load = self.air.instructions.items(.data)[inst].atomic_load; |
| 10698 | 10692 | ||
| 10699 | const ptr_ty = self.air.typeOf(atomic_load.ptr); | 10693 | const ptr_ty = self.typeOf(atomic_load.ptr); |
| 10700 | const ptr_mcv = try self.resolveInst(atomic_load.ptr); | 10694 | const ptr_mcv = try self.resolveInst(atomic_load.ptr); |
| 10701 | const ptr_lock = switch (ptr_mcv) { | 10695 | const ptr_lock = switch (ptr_mcv) { |
| 10702 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 10696 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| ... | @@ -10717,10 +10711,10 @@ fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10717,10 +10711,10 @@ fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 10717 | fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void { | 10711 | fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void { |
| 10718 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 10712 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 10719 | 10713 | ||
| 10720 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 10714 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 10721 | const ptr_mcv = try self.resolveInst(bin_op.lhs); | 10715 | const ptr_mcv = try self.resolveInst(bin_op.lhs); |
| 10722 | 10716 | ||
| 10723 | const val_ty = self.air.typeOf(bin_op.rhs); | 10717 | const val_ty = self.typeOf(bin_op.rhs); |
| 10724 | const val_mcv = try self.resolveInst(bin_op.rhs); | 10718 | const val_mcv = try self.resolveInst(bin_op.rhs); |
| 10725 | 10719 | ||
| 10726 | const result = try self.atomicOp(ptr_mcv, val_mcv, ptr_ty, val_ty, true, null, order); | 10720 | const result = try self.atomicOp(ptr_mcv, val_mcv, ptr_ty, val_ty, true, null, order); |
| ... | @@ -10728,6 +10722,7 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr | ... | @@ -10728,6 +10722,7 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr |
| 10728 | } | 10722 | } |
| 10729 | 10723 | ||
| 10730 | fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | 10724 | fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10725 | const mod = self.bin_file.options.module.?; | ||
| 10731 | if (safety) { | 10726 | if (safety) { |
| 10732 | // TODO if the value is undef, write 0xaa bytes to dest | 10727 | // TODO if the value is undef, write 0xaa bytes to dest |
| 10733 | } else { | 10728 | } else { |
| ... | @@ -10737,7 +10732,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -10737,7 +10732,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10737 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 10732 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 10738 | 10733 | ||
| 10739 | const dst_ptr = try self.resolveInst(bin_op.lhs); | 10734 | const dst_ptr = try self.resolveInst(bin_op.lhs); |
| 10740 | const dst_ptr_ty = self.air.typeOf(bin_op.lhs); | 10735 | const dst_ptr_ty = self.typeOf(bin_op.lhs); |
| 10741 | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { | 10736 | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { |
| 10742 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 10737 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 10743 | else => null, | 10738 | else => null, |
| ... | @@ -10745,26 +10740,26 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -10745,26 +10740,26 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10745 | defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock); | 10740 | defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 10746 | 10741 | ||
| 10747 | const src_val = try self.resolveInst(bin_op.rhs); | 10742 | const src_val = try self.resolveInst(bin_op.rhs); |
| 10748 | const elem_ty = self.air.typeOf(bin_op.rhs); | 10743 | const elem_ty = self.typeOf(bin_op.rhs); |
| 10749 | const src_val_lock: ?RegisterLock = switch (src_val) { | 10744 | const src_val_lock: ?RegisterLock = switch (src_val) { |
| 10750 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 10745 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 10751 | else => null, | 10746 | else => null, |
| 10752 | }; | 10747 | }; |
| 10753 | defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock); | 10748 | defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock); |
| 10754 | 10749 | ||
| 10755 | const elem_abi_size = @intCast(u31, elem_ty.abiSize(self.target.*)); | 10750 | const elem_abi_size = @intCast(u31, elem_ty.abiSize(mod)); |
| 10756 | 10751 | ||
| 10757 | if (elem_abi_size == 1) { | 10752 | if (elem_abi_size == 1) { |
| 10758 | const ptr: MCValue = switch (dst_ptr_ty.ptrSize()) { | 10753 | const ptr: MCValue = switch (dst_ptr_ty.ptrSize(mod)) { |
| 10759 | // TODO: this only handles slices stored in the stack | 10754 | // TODO: this only handles slices stored in the stack |
| 10760 | .Slice => dst_ptr, | 10755 | .Slice => dst_ptr, |
| 10761 | .One => dst_ptr, | 10756 | .One => dst_ptr, |
| 10762 | .C, .Many => unreachable, | 10757 | .C, .Many => unreachable, |
| 10763 | }; | 10758 | }; |
| 10764 | const len: MCValue = switch (dst_ptr_ty.ptrSize()) { | 10759 | const len: MCValue = switch (dst_ptr_ty.ptrSize(mod)) { |
| 10765 | // TODO: this only handles slices stored in the stack | 10760 | // TODO: this only handles slices stored in the stack |
| 10766 | .Slice => dst_ptr.address().offset(8).deref(), | 10761 | .Slice => dst_ptr.address().offset(8).deref(), |
| 10767 | .One => .{ .immediate = dst_ptr_ty.childType().arrayLen() }, | 10762 | .One => .{ .immediate = dst_ptr_ty.childType(mod).arrayLen(mod) }, |
| 10768 | .C, .Many => unreachable, | 10763 | .C, .Many => unreachable, |
| 10769 | }; | 10764 | }; |
| 10770 | const len_lock: ?RegisterLock = switch (len) { | 10765 | const len_lock: ?RegisterLock = switch (len) { |
| ... | @@ -10780,10 +10775,9 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -10780,10 +10775,9 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10780 | // Store the first element, and then rely on memcpy copying forwards. | 10775 | // Store the first element, and then rely on memcpy copying forwards. |
| 10781 | // Length zero requires a runtime check - so we handle arrays specially | 10776 | // Length zero requires a runtime check - so we handle arrays specially |
| 10782 | // here to elide it. | 10777 | // here to elide it. |
| 10783 | switch (dst_ptr_ty.ptrSize()) { | 10778 | switch (dst_ptr_ty.ptrSize(mod)) { |
| 10784 | .Slice => { | 10779 | .Slice => { |
| 10785 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 10780 | const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(mod); |
| 10786 | const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(&buf); | ||
| 10787 | 10781 | ||
| 10788 | // TODO: this only handles slices stored in the stack | 10782 | // TODO: this only handles slices stored in the stack |
| 10789 | const ptr = dst_ptr; | 10783 | const ptr = dst_ptr; |
| ... | @@ -10823,13 +10817,9 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -10823,13 +10817,9 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10823 | try self.performReloc(skip_reloc); | 10817 | try self.performReloc(skip_reloc); |
| 10824 | }, | 10818 | }, |
| 10825 | .One => { | 10819 | .One => { |
| 10826 | var elem_ptr_pl = Type.Payload.ElemType{ | 10820 | const elem_ptr_ty = try mod.singleMutPtrType(elem_ty); |
| 10827 | .base = .{ .tag = .single_mut_pointer }, | ||
| 10828 | .data = elem_ty, | ||
| 10829 | }; | ||
| 10830 | const elem_ptr_ty = Type.initPayload(&elem_ptr_pl.base); | ||
| 10831 | 10821 | ||
| 10832 | const len = dst_ptr_ty.childType().arrayLen(); | 10822 | const len = dst_ptr_ty.childType(mod).arrayLen(mod); |
| 10833 | 10823 | ||
| 10834 | assert(len != 0); // prevented by Sema | 10824 | assert(len != 0); // prevented by Sema |
| 10835 | try self.store(elem_ptr_ty, dst_ptr, src_val); | 10825 | try self.store(elem_ptr_ty, dst_ptr, src_val); |
| ... | @@ -10854,10 +10844,11 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -10854,10 +10844,11 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 10854 | } | 10844 | } |
| 10855 | 10845 | ||
| 10856 | fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | 10846 | fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 10847 | const mod = self.bin_file.options.module.?; | ||
| 10857 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 10848 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 10858 | 10849 | ||
| 10859 | const dst_ptr = try self.resolveInst(bin_op.lhs); | 10850 | const dst_ptr = try self.resolveInst(bin_op.lhs); |
| 10860 | const dst_ptr_ty = self.air.typeOf(bin_op.lhs); | 10851 | const dst_ptr_ty = self.typeOf(bin_op.lhs); |
| 10861 | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { | 10852 | const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) { |
| 10862 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 10853 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 10863 | else => null, | 10854 | else => null, |
| ... | @@ -10871,9 +10862,9 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10871,9 +10862,9 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 10871 | }; | 10862 | }; |
| 10872 | defer if (src_ptr_lock) |lock| self.register_manager.unlockReg(lock); | 10863 | defer if (src_ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 10873 | 10864 | ||
| 10874 | const len: MCValue = switch (dst_ptr_ty.ptrSize()) { | 10865 | const len: MCValue = switch (dst_ptr_ty.ptrSize(mod)) { |
| 10875 | .Slice => dst_ptr.address().offset(8).deref(), | 10866 | .Slice => dst_ptr.address().offset(8).deref(), |
| 10876 | .One => .{ .immediate = dst_ptr_ty.childType().arrayLen() }, | 10867 | .One => .{ .immediate = dst_ptr_ty.childType(mod).arrayLen(mod) }, |
| 10877 | .C, .Many => unreachable, | 10868 | .C, .Many => unreachable, |
| 10878 | }; | 10869 | }; |
| 10879 | const len_lock: ?RegisterLock = switch (len) { | 10870 | const len_lock: ?RegisterLock = switch (len) { |
| ... | @@ -10891,14 +10882,14 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10891,14 +10882,14 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 10891 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | 10882 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 10892 | const mod = self.bin_file.options.module.?; | 10883 | const mod = self.bin_file.options.module.?; |
| 10893 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 10884 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 10894 | const inst_ty = self.air.typeOfIndex(inst); | 10885 | const inst_ty = self.typeOfIndex(inst); |
| 10895 | const enum_ty = self.air.typeOf(un_op); | 10886 | const enum_ty = self.typeOf(un_op); |
| 10896 | 10887 | ||
| 10897 | // We need a properly aligned and sized call frame to be able to call this function. | 10888 | // We need a properly aligned and sized call frame to be able to call this function. |
| 10898 | { | 10889 | { |
| 10899 | const needed_call_frame = FrameAlloc.init(.{ | 10890 | const needed_call_frame = FrameAlloc.init(.{ |
| 10900 | .size = inst_ty.abiSize(self.target.*), | 10891 | .size = inst_ty.abiSize(mod), |
| 10901 | .alignment = inst_ty.abiAlignment(self.target.*), | 10892 | .alignment = inst_ty.abiAlignment(mod), |
| 10902 | }); | 10893 | }); |
| 10903 | const frame_allocs_slice = self.frame_allocs.slice(); | 10894 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 10904 | const stack_frame_size = | 10895 | const stack_frame_size = |
| ... | @@ -10923,7 +10914,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10923,7 +10914,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 10923 | try self.genLazySymbolRef( | 10914 | try self.genLazySymbolRef( |
| 10924 | .call, | 10915 | .call, |
| 10925 | .rax, | 10916 | .rax, |
| 10926 | link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod), | 10917 | link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(mod), mod), |
| 10927 | ); | 10918 | ); |
| 10928 | 10919 | ||
| 10929 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); | 10920 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| ... | @@ -10933,7 +10924,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -10933,7 +10924,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 10933 | const mod = self.bin_file.options.module.?; | 10924 | const mod = self.bin_file.options.module.?; |
| 10934 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 10925 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 10935 | 10926 | ||
| 10936 | const err_ty = self.air.typeOf(un_op); | 10927 | const err_ty = self.typeOf(un_op); |
| 10937 | const err_mcv = try self.resolveInst(un_op); | 10928 | const err_mcv = try self.resolveInst(un_op); |
| 10938 | const err_reg = try self.copyToTmpRegister(err_ty, err_mcv); | 10929 | const err_reg = try self.copyToTmpRegister(err_ty, err_mcv); |
| 10939 | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); | 10930 | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); |
| ... | @@ -11013,17 +11004,18 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11013,17 +11004,18 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 11013 | } | 11004 | } |
| 11014 | 11005 | ||
| 11015 | fn airSplat(self: *Self, inst: Air.Inst.Index) !void { | 11006 | fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 11007 | const mod = self.bin_file.options.module.?; | ||
| 11016 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 11008 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 11017 | const vector_ty = self.air.typeOfIndex(inst); | 11009 | const vector_ty = self.typeOfIndex(inst); |
| 11018 | const dst_rc = regClassForType(vector_ty); | 11010 | const dst_rc = regClassForType(vector_ty, mod); |
| 11019 | const scalar_ty = vector_ty.scalarType(); | 11011 | const scalar_ty = vector_ty.scalarType(mod); |
| 11020 | 11012 | ||
| 11021 | const src_mcv = try self.resolveInst(ty_op.operand); | 11013 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 11022 | const result: MCValue = result: { | 11014 | const result: MCValue = result: { |
| 11023 | switch (scalar_ty.zigTypeTag()) { | 11015 | switch (scalar_ty.zigTypeTag(mod)) { |
| 11024 | else => {}, | 11016 | else => {}, |
| 11025 | .Float => switch (scalar_ty.floatBits(self.target.*)) { | 11017 | .Float => switch (scalar_ty.floatBits(self.target.*)) { |
| 11026 | 32 => switch (vector_ty.vectorLen()) { | 11018 | 32 => switch (vector_ty.vectorLen(mod)) { |
| 11027 | 1 => { | 11019 | 1 => { |
| 11028 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; | 11020 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 11029 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); | 11021 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); |
| ... | @@ -11103,7 +11095,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11103,7 +11095,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 11103 | }, | 11095 | }, |
| 11104 | else => {}, | 11096 | else => {}, |
| 11105 | }, | 11097 | }, |
| 11106 | 64 => switch (vector_ty.vectorLen()) { | 11098 | 64 => switch (vector_ty.vectorLen(mod)) { |
| 11107 | 1 => { | 11099 | 1 => { |
| 11108 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; | 11100 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 11109 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); | 11101 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); |
| ... | @@ -11169,7 +11161,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11169,7 +11161,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) !void { |
| 11169 | }, | 11161 | }, |
| 11170 | else => {}, | 11162 | else => {}, |
| 11171 | }, | 11163 | }, |
| 11172 | 128 => switch (vector_ty.vectorLen()) { | 11164 | 128 => switch (vector_ty.vectorLen(mod)) { |
| 11173 | 1 => { | 11165 | 1 => { |
| 11174 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; | 11166 | if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv; |
| 11175 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); | 11167 | const dst_reg = try self.register_manager.allocReg(inst, dst_rc); |
| ... | @@ -11233,36 +11225,37 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11233,36 +11225,37 @@ fn airReduce(self: *Self, inst: Air.Inst.Index) !void { |
| 11233 | } | 11225 | } |
| 11234 | 11226 | ||
| 11235 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | 11227 | fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11236 | const result_ty = self.air.typeOfIndex(inst); | 11228 | const mod = self.bin_file.options.module.?; |
| 11237 | const len = @intCast(usize, result_ty.arrayLen()); | 11229 | const result_ty = self.typeOfIndex(inst); |
| 11230 | const len = @intCast(usize, result_ty.arrayLen(mod)); | ||
| 11238 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 11231 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 11239 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); | 11232 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 11240 | const result: MCValue = result: { | 11233 | const result: MCValue = result: { |
| 11241 | switch (result_ty.zigTypeTag()) { | 11234 | switch (result_ty.zigTypeTag(mod)) { |
| 11242 | .Struct => { | 11235 | .Struct => { |
| 11243 | const frame_index = | 11236 | const frame_index = |
| 11244 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, self.target.*)); | 11237 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, mod)); |
| 11245 | if (result_ty.containerLayout() == .Packed) { | 11238 | if (result_ty.containerLayout(mod) == .Packed) { |
| 11246 | const struct_obj = result_ty.castTag(.@"struct").?.data; | 11239 | const struct_obj = mod.typeToStruct(result_ty).?; |
| 11247 | try self.genInlineMemset( | 11240 | try self.genInlineMemset( |
| 11248 | .{ .lea_frame = .{ .index = frame_index } }, | 11241 | .{ .lea_frame = .{ .index = frame_index } }, |
| 11249 | .{ .immediate = 0 }, | 11242 | .{ .immediate = 0 }, |
| 11250 | .{ .immediate = result_ty.abiSize(self.target.*) }, | 11243 | .{ .immediate = result_ty.abiSize(mod) }, |
| 11251 | ); | 11244 | ); |
| 11252 | for (elements, 0..) |elem, elem_i| { | 11245 | for (elements, 0..) |elem, elem_i| { |
| 11253 | if (result_ty.structFieldValueComptime(elem_i) != null) continue; | 11246 | if ((try result_ty.structFieldValueComptime(mod, elem_i)) != null) continue; |
| 11254 | 11247 | ||
| 11255 | const elem_ty = result_ty.structFieldType(elem_i); | 11248 | const elem_ty = result_ty.structFieldType(elem_i, mod); |
| 11256 | const elem_bit_size = @intCast(u32, elem_ty.bitSize(self.target.*)); | 11249 | const elem_bit_size = @intCast(u32, elem_ty.bitSize(mod)); |
| 11257 | if (elem_bit_size > 64) { | 11250 | if (elem_bit_size > 64) { |
| 11258 | return self.fail( | 11251 | return self.fail( |
| 11259 | "TODO airAggregateInit implement packed structs with large fields", | 11252 | "TODO airAggregateInit implement packed structs with large fields", |
| 11260 | .{}, | 11253 | .{}, |
| 11261 | ); | 11254 | ); |
| 11262 | } | 11255 | } |
| 11263 | const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | 11256 | const elem_abi_size = @intCast(u32, elem_ty.abiSize(mod)); |
| 11264 | const elem_abi_bits = elem_abi_size * 8; | 11257 | const elem_abi_bits = elem_abi_size * 8; |
| 11265 | const elem_off = struct_obj.packedFieldBitOffset(self.target.*, elem_i); | 11258 | const elem_off = struct_obj.packedFieldBitOffset(mod, elem_i); |
| 11266 | const elem_byte_off = @intCast(i32, elem_off / elem_abi_bits * elem_abi_size); | 11259 | const elem_byte_off = @intCast(i32, elem_off / elem_abi_bits * elem_abi_size); |
| 11267 | const elem_bit_off = elem_off % elem_abi_bits; | 11260 | const elem_bit_off = elem_off % elem_abi_bits; |
| 11268 | const elem_mcv = try self.resolveInst(elem); | 11261 | const elem_mcv = try self.resolveInst(elem); |
| ... | @@ -11322,10 +11315,10 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11322,10 +11315,10 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11322 | } | 11315 | } |
| 11323 | } | 11316 | } |
| 11324 | } else for (elements, 0..) |elem, elem_i| { | 11317 | } else for (elements, 0..) |elem, elem_i| { |
| 11325 | if (result_ty.structFieldValueComptime(elem_i) != null) continue; | 11318 | if ((try result_ty.structFieldValueComptime(mod, elem_i)) != null) continue; |
| 11326 | 11319 | ||
| 11327 | const elem_ty = result_ty.structFieldType(elem_i); | 11320 | const elem_ty = result_ty.structFieldType(elem_i, mod); |
| 11328 | const elem_off = @intCast(i32, result_ty.structFieldOffset(elem_i, self.target.*)); | 11321 | const elem_off = @intCast(i32, result_ty.structFieldOffset(elem_i, mod)); |
| 11329 | const elem_mcv = try self.resolveInst(elem); | 11322 | const elem_mcv = try self.resolveInst(elem); |
| 11330 | const mat_elem_mcv = switch (elem_mcv) { | 11323 | const mat_elem_mcv = switch (elem_mcv) { |
| 11331 | .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, | 11324 | .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index }, |
| ... | @@ -11337,9 +11330,9 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11337,9 +11330,9 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11337 | }, | 11330 | }, |
| 11338 | .Array => { | 11331 | .Array => { |
| 11339 | const frame_index = | 11332 | const frame_index = |
| 11340 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, self.target.*)); | 11333 | try self.allocFrameIndex(FrameAlloc.initType(result_ty, mod)); |
| 11341 | const elem_ty = result_ty.childType(); | 11334 | const elem_ty = result_ty.childType(mod); |
| 11342 | const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*)); | 11335 | const elem_size = @intCast(u32, elem_ty.abiSize(mod)); |
| 11343 | 11336 | ||
| 11344 | for (elements, 0..) |elem, elem_i| { | 11337 | for (elements, 0..) |elem, elem_i| { |
| 11345 | const elem_mcv = try self.resolveInst(elem); | 11338 | const elem_mcv = try self.resolveInst(elem); |
| ... | @@ -11350,7 +11343,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11350,7 +11343,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11350 | const elem_off = @intCast(i32, elem_size * elem_i); | 11343 | const elem_off = @intCast(i32, elem_size * elem_i); |
| 11351 | try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv); | 11344 | try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv); |
| 11352 | } | 11345 | } |
| 11353 | if (result_ty.sentinel()) |sentinel| try self.genSetMem( | 11346 | if (result_ty.sentinel(mod)) |sentinel| try self.genSetMem( |
| 11354 | .{ .frame = frame_index }, | 11347 | .{ .frame = frame_index }, |
| 11355 | @intCast(i32, elem_size * elements.len), | 11348 | @intCast(i32, elem_size * elements.len), |
| 11356 | elem_ty, | 11349 | elem_ty, |
| ... | @@ -11374,13 +11367,14 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11374,13 +11367,14 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11374 | } | 11367 | } |
| 11375 | 11368 | ||
| 11376 | fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { | 11369 | fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11370 | const mod = self.bin_file.options.module.?; | ||
| 11377 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 11371 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 11378 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; | 11372 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 11379 | const result: MCValue = result: { | 11373 | const result: MCValue = result: { |
| 11380 | const union_ty = self.air.typeOfIndex(inst); | 11374 | const union_ty = self.typeOfIndex(inst); |
| 11381 | const layout = union_ty.unionGetLayout(self.target.*); | 11375 | const layout = union_ty.unionGetLayout(mod); |
| 11382 | 11376 | ||
| 11383 | const src_ty = self.air.typeOf(extra.init); | 11377 | const src_ty = self.typeOf(extra.init); |
| 11384 | const src_mcv = try self.resolveInst(extra.init); | 11378 | const src_mcv = try self.resolveInst(extra.init); |
| 11385 | if (layout.tag_size == 0) { | 11379 | if (layout.tag_size == 0) { |
| 11386 | if (self.reuseOperand(inst, extra.init, 0, src_mcv)) break :result src_mcv; | 11380 | if (self.reuseOperand(inst, extra.init, 0, src_mcv)) break :result src_mcv; |
| ... | @@ -11392,15 +11386,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11392,15 +11386,13 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { |
| 11392 | 11386 | ||
| 11393 | const dst_mcv = try self.allocRegOrMem(inst, false); | 11387 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 11394 | 11388 | ||
| 11395 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 11389 | const union_obj = mod.typeToUnion(union_ty).?; |
| 11396 | const field_name = union_obj.fields.keys()[extra.field_index]; | 11390 | const field_name = union_obj.fields.keys()[extra.field_index]; |
| 11397 | const tag_ty = union_ty.unionTagTypeSafety().?; | 11391 | const tag_ty = union_obj.tag_ty; |
| 11398 | const field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?); | 11392 | const field_index = tag_ty.enumFieldIndex(field_name, mod).?; |
| 11399 | var tag_pl = Value.Payload.U32{ .base = .{ .tag = .enum_field_index }, .data = field_index }; | 11393 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); |
| 11400 | const tag_val = Value.initPayload(&tag_pl.base); | 11394 | const tag_int_val = try tag_val.enumToInt(tag_ty, mod); |
| 11401 | var tag_int_pl: Value.Payload.U64 = undefined; | 11395 | const tag_int = tag_int_val.toUnsignedInt(mod); |
| 11402 | const tag_int_val = tag_val.enumToInt(tag_ty, &tag_int_pl); | ||
| 11403 | const tag_int = tag_int_val.toUnsignedInt(self.target.*); | ||
| 11404 | const tag_off = if (layout.tag_align < layout.payload_align) | 11396 | const tag_off = if (layout.tag_align < layout.payload_align) |
| 11405 | @intCast(i32, layout.payload_size) | 11397 | @intCast(i32, layout.payload_size) |
| 11406 | else | 11398 | else |
| ... | @@ -11424,9 +11416,10 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11424,9 +11416,10 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void { |
| 11424 | } | 11416 | } |
| 11425 | 11417 | ||
| 11426 | fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | 11418 | fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11419 | const mod = self.bin_file.options.module.?; | ||
| 11427 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 11420 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 11428 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; | 11421 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 11429 | const ty = self.air.typeOfIndex(inst); | 11422 | const ty = self.typeOfIndex(inst); |
| 11430 | 11423 | ||
| 11431 | if (!self.hasFeature(.fma)) return self.fail("TODO implement airMulAdd for {}", .{ | 11424 | if (!self.hasFeature(.fma)) return self.fail("TODO implement airMulAdd for {}", .{ |
| 11432 | ty.fmt(self.bin_file.options.module.?), | 11425 | ty.fmt(self.bin_file.options.module.?), |
| ... | @@ -11466,21 +11459,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11466,21 +11459,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11466 | const mir_tag = if (@as( | 11459 | const mir_tag = if (@as( |
| 11467 | ?Mir.Inst.FixedTag, | 11460 | ?Mir.Inst.FixedTag, |
| 11468 | if (mem.eql(u2, &order, &.{ 1, 3, 2 }) or mem.eql(u2, &order, &.{ 3, 1, 2 })) | 11461 | if (mem.eql(u2, &order, &.{ 1, 3, 2 }) or mem.eql(u2, &order, &.{ 3, 1, 2 })) |
| 11469 | switch (ty.zigTypeTag()) { | 11462 | switch (ty.zigTypeTag(mod)) { |
| 11470 | .Float => switch (ty.floatBits(self.target.*)) { | 11463 | .Float => switch (ty.floatBits(self.target.*)) { |
| 11471 | 32 => .{ .v_ss, .fmadd132 }, | 11464 | 32 => .{ .v_ss, .fmadd132 }, |
| 11472 | 64 => .{ .v_sd, .fmadd132 }, | 11465 | 64 => .{ .v_sd, .fmadd132 }, |
| 11473 | 16, 80, 128 => null, | 11466 | 16, 80, 128 => null, |
| 11474 | else => unreachable, | 11467 | else => unreachable, |
| 11475 | }, | 11468 | }, |
| 11476 | .Vector => switch (ty.childType().zigTypeTag()) { | 11469 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { |
| 11477 | .Float => switch (ty.childType().floatBits(self.target.*)) { | 11470 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 11478 | 32 => switch (ty.vectorLen()) { | 11471 | 32 => switch (ty.vectorLen(mod)) { |
| 11479 | 1 => .{ .v_ss, .fmadd132 }, | 11472 | 1 => .{ .v_ss, .fmadd132 }, |
| 11480 | 2...8 => .{ .v_ps, .fmadd132 }, | 11473 | 2...8 => .{ .v_ps, .fmadd132 }, |
| 11481 | else => null, | 11474 | else => null, |
| 11482 | }, | 11475 | }, |
| 11483 | 64 => switch (ty.vectorLen()) { | 11476 | 64 => switch (ty.vectorLen(mod)) { |
| 11484 | 1 => .{ .v_sd, .fmadd132 }, | 11477 | 1 => .{ .v_sd, .fmadd132 }, |
| 11485 | 2...4 => .{ .v_pd, .fmadd132 }, | 11478 | 2...4 => .{ .v_pd, .fmadd132 }, |
| 11486 | else => null, | 11479 | else => null, |
| ... | @@ -11493,21 +11486,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11493,21 +11486,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11493 | else => unreachable, | 11486 | else => unreachable, |
| 11494 | } | 11487 | } |
| 11495 | else if (mem.eql(u2, &order, &.{ 2, 1, 3 }) or mem.eql(u2, &order, &.{ 1, 2, 3 })) | 11488 | else if (mem.eql(u2, &order, &.{ 2, 1, 3 }) or mem.eql(u2, &order, &.{ 1, 2, 3 })) |
| 11496 | switch (ty.zigTypeTag()) { | 11489 | switch (ty.zigTypeTag(mod)) { |
| 11497 | .Float => switch (ty.floatBits(self.target.*)) { | 11490 | .Float => switch (ty.floatBits(self.target.*)) { |
| 11498 | 32 => .{ .v_ss, .fmadd213 }, | 11491 | 32 => .{ .v_ss, .fmadd213 }, |
| 11499 | 64 => .{ .v_sd, .fmadd213 }, | 11492 | 64 => .{ .v_sd, .fmadd213 }, |
| 11500 | 16, 80, 128 => null, | 11493 | 16, 80, 128 => null, |
| 11501 | else => unreachable, | 11494 | else => unreachable, |
| 11502 | }, | 11495 | }, |
| 11503 | .Vector => switch (ty.childType().zigTypeTag()) { | 11496 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { |
| 11504 | .Float => switch (ty.childType().floatBits(self.target.*)) { | 11497 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 11505 | 32 => switch (ty.vectorLen()) { | 11498 | 32 => switch (ty.vectorLen(mod)) { |
| 11506 | 1 => .{ .v_ss, .fmadd213 }, | 11499 | 1 => .{ .v_ss, .fmadd213 }, |
| 11507 | 2...8 => .{ .v_ps, .fmadd213 }, | 11500 | 2...8 => .{ .v_ps, .fmadd213 }, |
| 11508 | else => null, | 11501 | else => null, |
| 11509 | }, | 11502 | }, |
| 11510 | 64 => switch (ty.vectorLen()) { | 11503 | 64 => switch (ty.vectorLen(mod)) { |
| 11511 | 1 => .{ .v_sd, .fmadd213 }, | 11504 | 1 => .{ .v_sd, .fmadd213 }, |
| 11512 | 2...4 => .{ .v_pd, .fmadd213 }, | 11505 | 2...4 => .{ .v_pd, .fmadd213 }, |
| 11513 | else => null, | 11506 | else => null, |
| ... | @@ -11520,21 +11513,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11520,21 +11513,21 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11520 | else => unreachable, | 11513 | else => unreachable, |
| 11521 | } | 11514 | } |
| 11522 | else if (mem.eql(u2, &order, &.{ 2, 3, 1 }) or mem.eql(u2, &order, &.{ 3, 2, 1 })) | 11515 | else if (mem.eql(u2, &order, &.{ 2, 3, 1 }) or mem.eql(u2, &order, &.{ 3, 2, 1 })) |
| 11523 | switch (ty.zigTypeTag()) { | 11516 | switch (ty.zigTypeTag(mod)) { |
| 11524 | .Float => switch (ty.floatBits(self.target.*)) { | 11517 | .Float => switch (ty.floatBits(self.target.*)) { |
| 11525 | 32 => .{ .v_ss, .fmadd231 }, | 11518 | 32 => .{ .v_ss, .fmadd231 }, |
| 11526 | 64 => .{ .v_sd, .fmadd231 }, | 11519 | 64 => .{ .v_sd, .fmadd231 }, |
| 11527 | 16, 80, 128 => null, | 11520 | 16, 80, 128 => null, |
| 11528 | else => unreachable, | 11521 | else => unreachable, |
| 11529 | }, | 11522 | }, |
| 11530 | .Vector => switch (ty.childType().zigTypeTag()) { | 11523 | .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { |
| 11531 | .Float => switch (ty.childType().floatBits(self.target.*)) { | 11524 | .Float => switch (ty.childType(mod).floatBits(self.target.*)) { |
| 11532 | 32 => switch (ty.vectorLen()) { | 11525 | 32 => switch (ty.vectorLen(mod)) { |
| 11533 | 1 => .{ .v_ss, .fmadd231 }, | 11526 | 1 => .{ .v_ss, .fmadd231 }, |
| 11534 | 2...8 => .{ .v_ps, .fmadd231 }, | 11527 | 2...8 => .{ .v_ps, .fmadd231 }, |
| 11535 | else => null, | 11528 | else => null, |
| 11536 | }, | 11529 | }, |
| 11537 | 64 => switch (ty.vectorLen()) { | 11530 | 64 => switch (ty.vectorLen(mod)) { |
| 11538 | 1 => .{ .v_sd, .fmadd231 }, | 11531 | 1 => .{ .v_sd, .fmadd231 }, |
| 11539 | 2...4 => .{ .v_pd, .fmadd231 }, | 11532 | 2...4 => .{ .v_pd, .fmadd231 }, |
| 11540 | else => null, | 11533 | else => null, |
| ... | @@ -11555,7 +11548,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11555,7 +11548,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11555 | var mops: [3]MCValue = undefined; | 11548 | var mops: [3]MCValue = undefined; |
| 11556 | for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv; | 11549 | for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv; |
| 11557 | 11550 | ||
| 11558 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | 11551 | const abi_size = @intCast(u32, ty.abiSize(mod)); |
| 11559 | const mop1_reg = registerAlias(mops[0].getReg().?, abi_size); | 11552 | const mop1_reg = registerAlias(mops[0].getReg().?, abi_size); |
| 11560 | const mop2_reg = registerAlias(mops[1].getReg().?, abi_size); | 11553 | const mop2_reg = registerAlias(mops[1].getReg().?, abi_size); |
| 11561 | if (mops[2].isRegister()) try self.asmRegisterRegisterRegister( | 11554 | if (mops[2].isRegister()) try self.asmRegisterRegisterRegister( |
| ... | @@ -11573,22 +11566,22 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11573,22 +11566,22 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 11573 | } | 11566 | } |
| 11574 | 11567 | ||
| 11575 | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { | 11568 | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { |
| 11576 | const ty = self.air.typeOf(ref); | 11569 | const mod = self.bin_file.options.module.?; |
| 11570 | const ty = self.typeOf(ref); | ||
| 11577 | 11571 | ||
| 11578 | // If the type has no codegen bits, no need to store it. | 11572 | // If the type has no codegen bits, no need to store it. |
| 11579 | if (!ty.hasRuntimeBitsIgnoreComptime()) return .none; | 11573 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) return .none; |
| 11580 | 11574 | ||
| 11581 | if (Air.refToIndex(ref)) |inst| { | 11575 | if (Air.refToIndex(ref)) |inst| { |
| 11582 | const mcv = switch (self.air.instructions.items(.tag)[inst]) { | 11576 | const mcv = switch (self.air.instructions.items(.tag)[inst]) { |
| 11583 | .constant => tracking: { | 11577 | .interned => tracking: { |
| 11584 | const gop = try self.const_tracking.getOrPut(self.gpa, inst); | 11578 | const gop = try self.const_tracking.getOrPut(self.gpa, inst); |
| 11585 | if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(try self.genTypedValue(.{ | 11579 | if (!gop.found_existing) gop.value_ptr.* = InstTracking.init(try self.genTypedValue(.{ |
| 11586 | .ty = ty, | 11580 | .ty = ty, |
| 11587 | .val = self.air.value(ref).?, | 11581 | .val = self.air.instructions.items(.data)[inst].interned.toValue(), |
| 11588 | })); | 11582 | })); |
| 11589 | break :tracking gop.value_ptr; | 11583 | break :tracking gop.value_ptr; |
| 11590 | }, | 11584 | }, |
| 11591 | .const_ty => unreachable, | ||
| 11592 | else => self.inst_tracking.getPtr(inst).?, | 11585 | else => self.inst_tracking.getPtr(inst).?, |
| 11593 | }.short; | 11586 | }.short; |
| 11594 | switch (mcv) { | 11587 | switch (mcv) { |
| ... | @@ -11597,13 +11590,12 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { | ... | @@ -11597,13 +11590,12 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { |
| 11597 | } | 11590 | } |
| 11598 | } | 11591 | } |
| 11599 | 11592 | ||
| 11600 | return self.genTypedValue(.{ .ty = ty, .val = self.air.value(ref).? }); | 11593 | return self.genTypedValue(.{ .ty = ty, .val = (try self.air.value(ref, mod)).? }); |
| 11601 | } | 11594 | } |
| 11602 | 11595 | ||
| 11603 | fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) *InstTracking { | 11596 | fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) *InstTracking { |
| 11604 | const tracking = switch (self.air.instructions.items(.tag)[inst]) { | 11597 | const tracking = switch (self.air.instructions.items(.tag)[inst]) { |
| 11605 | .constant => &self.const_tracking, | 11598 | .interned => &self.const_tracking, |
| 11606 | .const_ty => unreachable, | ||
| 11607 | else => &self.inst_tracking, | 11599 | else => &self.inst_tracking, |
| 11608 | }.getPtr(inst).?; | 11600 | }.getPtr(inst).?; |
| 11609 | return switch (tracking.short) { | 11601 | return switch (tracking.short) { |
| ... | @@ -11634,7 +11626,8 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV | ... | @@ -11634,7 +11626,8 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV |
| 11634 | } | 11626 | } |
| 11635 | 11627 | ||
| 11636 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | 11628 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 11637 | return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl())) { | 11629 | const mod = self.bin_file.options.module.?; |
| 11630 | return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl(mod))) { | ||
| 11638 | .mcv => |mcv| switch (mcv) { | 11631 | .mcv => |mcv| switch (mcv) { |
| 11639 | .none => .none, | 11632 | .none => .none, |
| 11640 | .undef => .undef, | 11633 | .undef => .undef, |
| ... | @@ -11666,17 +11659,23 @@ const CallMCValues = struct { | ... | @@ -11666,17 +11659,23 @@ const CallMCValues = struct { |
| 11666 | /// Caller must call `CallMCValues.deinit`. | 11659 | /// Caller must call `CallMCValues.deinit`. |
| 11667 | fn resolveCallingConventionValues( | 11660 | fn resolveCallingConventionValues( |
| 11668 | self: *Self, | 11661 | self: *Self, |
| 11669 | fn_ty: Type, | 11662 | fn_info: InternPool.Key.FuncType, |
| 11670 | var_args: []const Air.Inst.Ref, | 11663 | var_args: []const Air.Inst.Ref, |
| 11671 | stack_frame_base: FrameIndex, | 11664 | stack_frame_base: FrameIndex, |
| 11672 | ) !CallMCValues { | 11665 | ) !CallMCValues { |
| 11673 | const cc = fn_ty.fnCallingConvention(); | 11666 | const mod = self.bin_file.options.module.?; |
| 11674 | const param_len = fn_ty.fnParamLen(); | 11667 | const cc = fn_info.cc; |
| 11675 | const param_types = try self.gpa.alloc(Type, param_len + var_args.len); | 11668 | const param_types = try self.gpa.alloc(Type, fn_info.param_types.len + var_args.len); |
| 11676 | defer self.gpa.free(param_types); | 11669 | defer self.gpa.free(param_types); |
| 11677 | fn_ty.fnParamTypes(param_types); | 11670 | |
| 11671 | for (param_types[0..fn_info.param_types.len], fn_info.param_types) |*dest, src| { | ||
| 11672 | dest.* = src.toType(); | ||
| 11673 | } | ||
| 11678 | // TODO: promote var arg types | 11674 | // TODO: promote var arg types |
| 11679 | for (param_types[param_len..], var_args) |*param_ty, arg| param_ty.* = self.air.typeOf(arg); | 11675 | for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg| { |
| 11676 | param_ty.* = self.typeOf(arg); | ||
| 11677 | } | ||
| 11678 | |||
| 11680 | var result: CallMCValues = .{ | 11679 | var result: CallMCValues = .{ |
| 11681 | .args = try self.gpa.alloc(MCValue, param_types.len), | 11680 | .args = try self.gpa.alloc(MCValue, param_types.len), |
| 11682 | // These undefined values must be populated before returning from this function. | 11681 | // These undefined values must be populated before returning from this function. |
| ... | @@ -11686,7 +11685,7 @@ fn resolveCallingConventionValues( | ... | @@ -11686,7 +11685,7 @@ fn resolveCallingConventionValues( |
| 11686 | }; | 11685 | }; |
| 11687 | errdefer self.gpa.free(result.args); | 11686 | errdefer self.gpa.free(result.args); |
| 11688 | 11687 | ||
| 11689 | const ret_ty = fn_ty.fnReturnType(); | 11688 | const ret_ty = fn_info.return_type.toType(); |
| 11690 | 11689 | ||
| 11691 | switch (cc) { | 11690 | switch (cc) { |
| 11692 | .Naked => { | 11691 | .Naked => { |
| ... | @@ -11702,21 +11701,21 @@ fn resolveCallingConventionValues( | ... | @@ -11702,21 +11701,21 @@ fn resolveCallingConventionValues( |
| 11702 | switch (self.target.os.tag) { | 11701 | switch (self.target.os.tag) { |
| 11703 | .windows => { | 11702 | .windows => { |
| 11704 | // Align the stack to 16bytes before allocating shadow stack space (if any). | 11703 | // Align the stack to 16bytes before allocating shadow stack space (if any). |
| 11705 | result.stack_byte_count += @intCast(u31, 4 * Type.usize.abiSize(self.target.*)); | 11704 | result.stack_byte_count += @intCast(u31, 4 * Type.usize.abiSize(mod)); |
| 11706 | }, | 11705 | }, |
| 11707 | else => {}, | 11706 | else => {}, |
| 11708 | } | 11707 | } |
| 11709 | 11708 | ||
| 11710 | // Return values | 11709 | // Return values |
| 11711 | if (ret_ty.zigTypeTag() == .NoReturn) { | 11710 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 11712 | result.return_value = InstTracking.init(.unreach); | 11711 | result.return_value = InstTracking.init(.unreach); |
| 11713 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | 11712 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 11714 | // TODO: is this even possible for C calling convention? | 11713 | // TODO: is this even possible for C calling convention? |
| 11715 | result.return_value = InstTracking.init(.none); | 11714 | result.return_value = InstTracking.init(.none); |
| 11716 | } else { | 11715 | } else { |
| 11717 | const classes = switch (self.target.os.tag) { | 11716 | const classes = switch (self.target.os.tag) { |
| 11718 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, self.target.*)}, | 11717 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, |
| 11719 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, self.target.*, .ret), .none), | 11718 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), |
| 11720 | }; | 11719 | }; |
| 11721 | if (classes.len > 1) { | 11720 | if (classes.len > 1) { |
| 11722 | return self.fail("TODO handle multiple classes per type", .{}); | 11721 | return self.fail("TODO handle multiple classes per type", .{}); |
| ... | @@ -11725,7 +11724,7 @@ fn resolveCallingConventionValues( | ... | @@ -11725,7 +11724,7 @@ fn resolveCallingConventionValues( |
| 11725 | result.return_value = switch (classes[0]) { | 11724 | result.return_value = switch (classes[0]) { |
| 11726 | .integer => InstTracking.init(.{ .register = registerAlias( | 11725 | .integer => InstTracking.init(.{ .register = registerAlias( |
| 11727 | ret_reg, | 11726 | ret_reg, |
| 11728 | @intCast(u32, ret_ty.abiSize(self.target.*)), | 11727 | @intCast(u32, ret_ty.abiSize(mod)), |
| 11729 | ) }), | 11728 | ) }), |
| 11730 | .float, .sse => InstTracking.init(.{ .register = .xmm0 }), | 11729 | .float, .sse => InstTracking.init(.{ .register = .xmm0 }), |
| 11731 | .memory => ret: { | 11730 | .memory => ret: { |
| ... | @@ -11744,11 +11743,11 @@ fn resolveCallingConventionValues( | ... | @@ -11744,11 +11743,11 @@ fn resolveCallingConventionValues( |
| 11744 | 11743 | ||
| 11745 | // Input params | 11744 | // Input params |
| 11746 | for (param_types, result.args) |ty, *arg| { | 11745 | for (param_types, result.args) |ty, *arg| { |
| 11747 | assert(ty.hasRuntimeBitsIgnoreComptime()); | 11746 | assert(ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 11748 | 11747 | ||
| 11749 | const classes = switch (self.target.os.tag) { | 11748 | const classes = switch (self.target.os.tag) { |
| 11750 | .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)}, | 11749 | .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)}, |
| 11751 | else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*, .arg), .none), | 11750 | else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none), |
| 11752 | }; | 11751 | }; |
| 11753 | if (classes.len > 1) { | 11752 | if (classes.len > 1) { |
| 11754 | return self.fail("TODO handle multiple classes per type", .{}); | 11753 | return self.fail("TODO handle multiple classes per type", .{}); |
| ... | @@ -11783,8 +11782,8 @@ fn resolveCallingConventionValues( | ... | @@ -11783,8 +11782,8 @@ fn resolveCallingConventionValues( |
| 11783 | }), | 11782 | }), |
| 11784 | } | 11783 | } |
| 11785 | 11784 | ||
| 11786 | const param_size = @intCast(u31, ty.abiSize(self.target.*)); | 11785 | const param_size = @intCast(u31, ty.abiSize(mod)); |
| 11787 | const param_align = @intCast(u31, ty.abiAlignment(self.target.*)); | 11786 | const param_align = @intCast(u31, ty.abiAlignment(mod)); |
| 11788 | result.stack_byte_count = | 11787 | result.stack_byte_count = |
| 11789 | mem.alignForwardGeneric(u31, result.stack_byte_count, param_align); | 11788 | mem.alignForwardGeneric(u31, result.stack_byte_count, param_align); |
| 11790 | arg.* = .{ .load_frame = .{ | 11789 | arg.* = .{ .load_frame = .{ |
| ... | @@ -11798,13 +11797,13 @@ fn resolveCallingConventionValues( | ... | @@ -11798,13 +11797,13 @@ fn resolveCallingConventionValues( |
| 11798 | result.stack_align = 16; | 11797 | result.stack_align = 16; |
| 11799 | 11798 | ||
| 11800 | // Return values | 11799 | // Return values |
| 11801 | if (ret_ty.zigTypeTag() == .NoReturn) { | 11800 | if (ret_ty.zigTypeTag(mod) == .NoReturn) { |
| 11802 | result.return_value = InstTracking.init(.unreach); | 11801 | result.return_value = InstTracking.init(.unreach); |
| 11803 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | 11802 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 11804 | result.return_value = InstTracking.init(.none); | 11803 | result.return_value = InstTracking.init(.none); |
| 11805 | } else { | 11804 | } else { |
| 11806 | const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; | 11805 | const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; |
| 11807 | const ret_ty_size = @intCast(u31, ret_ty.abiSize(self.target.*)); | 11806 | const ret_ty_size = @intCast(u31, ret_ty.abiSize(mod)); |
| 11808 | if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) { | 11807 | if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) { |
| 11809 | const aliased_reg = registerAlias(ret_reg, ret_ty_size); | 11808 | const aliased_reg = registerAlias(ret_reg, ret_ty_size); |
| 11810 | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; | 11809 | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; |
| ... | @@ -11819,12 +11818,12 @@ fn resolveCallingConventionValues( | ... | @@ -11819,12 +11818,12 @@ fn resolveCallingConventionValues( |
| 11819 | 11818 | ||
| 11820 | // Input params | 11819 | // Input params |
| 11821 | for (param_types, result.args) |ty, *arg| { | 11820 | for (param_types, result.args) |ty, *arg| { |
| 11822 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | 11821 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 11823 | arg.* = .none; | 11822 | arg.* = .none; |
| 11824 | continue; | 11823 | continue; |
| 11825 | } | 11824 | } |
| 11826 | const param_size = @intCast(u31, ty.abiSize(self.target.*)); | 11825 | const param_size = @intCast(u31, ty.abiSize(mod)); |
| 11827 | const param_align = @intCast(u31, ty.abiAlignment(self.target.*)); | 11826 | const param_align = @intCast(u31, ty.abiAlignment(mod)); |
| 11828 | result.stack_byte_count = | 11827 | result.stack_byte_count = |
| 11829 | mem.alignForwardGeneric(u31, result.stack_byte_count, param_align); | 11828 | mem.alignForwardGeneric(u31, result.stack_byte_count, param_align); |
| 11830 | arg.* = .{ .load_frame = .{ | 11829 | arg.* = .{ .load_frame = .{ |
| ... | @@ -11908,9 +11907,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { | ... | @@ -11908,9 +11907,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { |
| 11908 | /// Truncates the value in the register in place. | 11907 | /// Truncates the value in the register in place. |
| 11909 | /// Clobbers any remaining bits. | 11908 | /// Clobbers any remaining bits. |
| 11910 | fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { | 11909 | fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 11911 | const int_info = if (ty.isAbiInt()) ty.intInfo(self.target.*) else std.builtin.Type.Int{ | 11910 | const mod = self.bin_file.options.module.?; |
| 11911 | const int_info = if (ty.isAbiInt(mod)) ty.intInfo(mod) else std.builtin.Type.Int{ | ||
| 11912 | .signedness = .unsigned, | 11912 | .signedness = .unsigned, |
| 11913 | .bits = @intCast(u16, ty.bitSize(self.target.*)), | 11913 | .bits = @intCast(u16, ty.bitSize(mod)), |
| 11914 | }; | 11914 | }; |
| 11915 | const max_reg_bit_width = Register.rax.bitSize(); | 11915 | const max_reg_bit_width = Register.rax.bitSize(); |
| 11916 | switch (int_info.signedness) { | 11916 | switch (int_info.signedness) { |
| ... | @@ -11953,8 +11953,9 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { | ... | @@ -11953,8 +11953,9 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 11953 | } | 11953 | } |
| 11954 | 11954 | ||
| 11955 | fn regBitSize(self: *Self, ty: Type) u64 { | 11955 | fn regBitSize(self: *Self, ty: Type) u64 { |
| 11956 | const abi_size = ty.abiSize(self.target.*); | 11956 | const mod = self.bin_file.options.module.?; |
| 11957 | return switch (ty.zigTypeTag()) { | 11957 | const abi_size = ty.abiSize(mod); |
| 11958 | return switch (ty.zigTypeTag(mod)) { | ||
| 11958 | else => switch (abi_size) { | 11959 | else => switch (abi_size) { |
| 11959 | 1 => 8, | 11960 | 1 => 8, |
| 11960 | 2 => 16, | 11961 | 2 => 16, |
| ... | @@ -11971,7 +11972,8 @@ fn regBitSize(self: *Self, ty: Type) u64 { | ... | @@ -11971,7 +11972,8 @@ fn regBitSize(self: *Self, ty: Type) u64 { |
| 11971 | } | 11972 | } |
| 11972 | 11973 | ||
| 11973 | fn regExtraBits(self: *Self, ty: Type) u64 { | 11974 | fn regExtraBits(self: *Self, ty: Type) u64 { |
| 11974 | return self.regBitSize(ty) - ty.bitSize(self.target.*); | 11975 | const mod = self.bin_file.options.module.?; |
| 11976 | return self.regBitSize(ty) - ty.bitSize(mod); | ||
| 11975 | } | 11977 | } |
| 11976 | 11978 | ||
| 11977 | fn hasFeature(self: *Self, feature: Target.x86.Feature) bool { | 11979 | fn hasFeature(self: *Self, feature: Target.x86.Feature) bool { |
| ... | @@ -11983,3 +11985,13 @@ fn hasAnyFeatures(self: *Self, features: anytype) bool { | ... | @@ -11983,3 +11985,13 @@ fn hasAnyFeatures(self: *Self, features: anytype) bool { |
| 11983 | fn hasAllFeatures(self: *Self, features: anytype) bool { | 11985 | fn hasAllFeatures(self: *Self, features: anytype) bool { |
| 11984 | return Target.x86.featureSetHasAll(self.target.cpu.features, features); | 11986 | return Target.x86.featureSetHasAll(self.target.cpu.features, features); |
| 11985 | } | 11987 | } |
| 11988 | |||
| 11989 | fn typeOf(self: *Self, inst: Air.Inst.Ref) Type { | ||
| 11990 | const mod = self.bin_file.options.module.?; | ||
| 11991 | return self.air.typeOf(inst, &mod.intern_pool); | ||
| 11992 | } | ||
| 11993 | |||
| 11994 | fn typeOfIndex(self: *Self, inst: Air.Inst.Index) Type { | ||
| 11995 | const mod = self.bin_file.options.module.?; | ||
| 11996 | return self.air.typeOfIndex(inst, &mod.intern_pool); | ||
| 11997 | } |
src/arch/x86_64/abi.zig+33-63| ... | @@ -1,10 +1,3 @@ | ... | @@ -1,10 +1,3 @@ |
| 1 | const std = @import("std"); | ||
| 2 | const Type = @import("../../type.zig").Type; | ||
| 3 | const Target = std.Target; | ||
| 4 | const assert = std.debug.assert; | ||
| 5 | const Register = @import("bits.zig").Register; | ||
| 6 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | ||
| 7 | |||
| 8 | pub const Class = enum { | 1 | pub const Class = enum { |
| 9 | integer, | 2 | integer, |
| 10 | sse, | 3 | sse, |
| ... | @@ -19,7 +12,7 @@ pub const Class = enum { | ... | @@ -19,7 +12,7 @@ pub const Class = enum { |
| 19 | float_combine, | 12 | float_combine, |
| 20 | }; | 13 | }; |
| 21 | 14 | ||
| 22 | pub fn classifyWindows(ty: Type, target: Target) Class { | 15 | pub fn classifyWindows(ty: Type, mod: *Module) Class { |
| 23 | // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 | 16 | // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 |
| 24 | // "There's a strict one-to-one correspondence between a function call's arguments | 17 | // "There's a strict one-to-one correspondence between a function call's arguments |
| 25 | // and the registers used for those arguments. Any argument that doesn't fit in 8 | 18 | // and the registers used for those arguments. Any argument that doesn't fit in 8 |
| ... | @@ -28,7 +21,7 @@ pub fn classifyWindows(ty: Type, target: Target) Class { | ... | @@ -28,7 +21,7 @@ pub fn classifyWindows(ty: Type, target: Target) Class { |
| 28 | // "All floating point operations are done using the 16 XMM registers." | 21 | // "All floating point operations are done using the 16 XMM registers." |
| 29 | // "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed | 22 | // "Structs and unions of size 8, 16, 32, or 64 bits, and __m64 types, are passed |
| 30 | // as if they were integers of the same size." | 23 | // as if they were integers of the same size." |
| 31 | switch (ty.zigTypeTag()) { | 24 | switch (ty.zigTypeTag(mod)) { |
| 32 | .Pointer, | 25 | .Pointer, |
| 33 | .Int, | 26 | .Int, |
| 34 | .Bool, | 27 | .Bool, |
| ... | @@ -43,12 +36,12 @@ pub fn classifyWindows(ty: Type, target: Target) Class { | ... | @@ -43,12 +36,12 @@ pub fn classifyWindows(ty: Type, target: Target) Class { |
| 43 | .ErrorUnion, | 36 | .ErrorUnion, |
| 44 | .AnyFrame, | 37 | .AnyFrame, |
| 45 | .Frame, | 38 | .Frame, |
| 46 | => switch (ty.abiSize(target)) { | 39 | => switch (ty.abiSize(mod)) { |
| 47 | 0 => unreachable, | 40 | 0 => unreachable, |
| 48 | 1, 2, 4, 8 => return .integer, | 41 | 1, 2, 4, 8 => return .integer, |
| 49 | else => switch (ty.zigTypeTag()) { | 42 | else => switch (ty.zigTypeTag(mod)) { |
| 50 | .Int => return .win_i128, | 43 | .Int => return .win_i128, |
| 51 | .Struct, .Union => if (ty.containerLayout() == .Packed) { | 44 | .Struct, .Union => if (ty.containerLayout(mod) == .Packed) { |
| 52 | return .win_i128; | 45 | return .win_i128; |
| 53 | } else { | 46 | } else { |
| 54 | return .memory; | 47 | return .memory; |
| ... | @@ -75,14 +68,15 @@ pub const Context = enum { ret, arg, other }; | ... | @@ -75,14 +68,15 @@ pub const Context = enum { ret, arg, other }; |
| 75 | 68 | ||
| 76 | /// There are a maximum of 8 possible return slots. Returned values are in | 69 | /// There are a maximum of 8 possible return slots. Returned values are in |
| 77 | /// the beginning of the array; unused slots are filled with .none. | 70 | /// the beginning of the array; unused slots are filled with .none. |
| 78 | pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { | 71 | pub fn classifySystemV(ty: Type, mod: *Module, ctx: Context) [8]Class { |
| 72 | const target = mod.getTarget(); | ||
| 79 | const memory_class = [_]Class{ | 73 | const memory_class = [_]Class{ |
| 80 | .memory, .none, .none, .none, | 74 | .memory, .none, .none, .none, |
| 81 | .none, .none, .none, .none, | 75 | .none, .none, .none, .none, |
| 82 | }; | 76 | }; |
| 83 | var result = [1]Class{.none} ** 8; | 77 | var result = [1]Class{.none} ** 8; |
| 84 | switch (ty.zigTypeTag()) { | 78 | switch (ty.zigTypeTag(mod)) { |
| 85 | .Pointer => switch (ty.ptrSize()) { | 79 | .Pointer => switch (ty.ptrSize(mod)) { |
| 86 | .Slice => { | 80 | .Slice => { |
| 87 | result[0] = .integer; | 81 | result[0] = .integer; |
| 88 | result[1] = .integer; | 82 | result[1] = .integer; |
| ... | @@ -94,7 +88,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { | ... | @@ -94,7 +88,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 94 | }, | 88 | }, |
| 95 | }, | 89 | }, |
| 96 | .Int, .Enum, .ErrorSet => { | 90 | .Int, .Enum, .ErrorSet => { |
| 97 | const bits = ty.intInfo(target).bits; | 91 | const bits = ty.intInfo(mod).bits; |
| 98 | if (bits <= 64) { | 92 | if (bits <= 64) { |
| 99 | result[0] = .integer; | 93 | result[0] = .integer; |
| 100 | return result; | 94 | return result; |
| ... | @@ -164,8 +158,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { | ... | @@ -164,8 +158,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 164 | else => unreachable, | 158 | else => unreachable, |
| 165 | }, | 159 | }, |
| 166 | .Vector => { | 160 | .Vector => { |
| 167 | const elem_ty = ty.childType(); | 161 | const elem_ty = ty.childType(mod); |
| 168 | const bits = elem_ty.bitSize(target) * ty.arrayLen(); | 162 | const bits = elem_ty.bitSize(mod) * ty.arrayLen(mod); |
| 169 | if (bits <= 64) return .{ | 163 | if (bits <= 64) return .{ |
| 170 | .sse, .none, .none, .none, | 164 | .sse, .none, .none, .none, |
| 171 | .none, .none, .none, .none, | 165 | .none, .none, .none, .none, |
| ... | @@ -204,7 +198,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { | ... | @@ -204,7 +198,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 204 | return memory_class; | 198 | return memory_class; |
| 205 | }, | 199 | }, |
| 206 | .Optional => { | 200 | .Optional => { |
| 207 | if (ty.isPtrLikeOptional()) { | 201 | if (ty.isPtrLikeOptional(mod)) { |
| 208 | result[0] = .integer; | 202 | result[0] = .integer; |
| 209 | return result; | 203 | return result; |
| 210 | } | 204 | } |
| ... | @@ -215,8 +209,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { | ... | @@ -215,8 +209,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 215 | // it contains unaligned fields, it has class MEMORY" | 209 | // it contains unaligned fields, it has class MEMORY" |
| 216 | // "If the size of the aggregate exceeds a single eightbyte, each is classified | 210 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 217 | // separately.". | 211 | // separately.". |
| 218 | const ty_size = ty.abiSize(target); | 212 | const ty_size = ty.abiSize(mod); |
| 219 | if (ty.containerLayout() == .Packed) { | 213 | if (ty.containerLayout(mod) == .Packed) { |
| 220 | assert(ty_size <= 128); | 214 | assert(ty_size <= 128); |
| 221 | result[0] = .integer; | 215 | result[0] = .integer; |
| 222 | if (ty_size > 64) result[1] = .integer; | 216 | if (ty_size > 64) result[1] = .integer; |
| ... | @@ -227,15 +221,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { | ... | @@ -227,15 +221,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 227 | 221 | ||
| 228 | var result_i: usize = 0; // out of 8 | 222 | var result_i: usize = 0; // out of 8 |
| 229 | var byte_i: usize = 0; // out of 8 | 223 | var byte_i: usize = 0; // out of 8 |
| 230 | const fields = ty.structFields(); | 224 | const fields = ty.structFields(mod); |
| 231 | for (fields.values()) |field| { | 225 | for (fields.values()) |field| { |
| 232 | if (field.abi_align != 0) { | 226 | if (field.abi_align != 0) { |
| 233 | if (field.abi_align < field.ty.abiAlignment(target)) { | 227 | if (field.abi_align < field.ty.abiAlignment(mod)) { |
| 234 | return memory_class; | 228 | return memory_class; |
| 235 | } | 229 | } |
| 236 | } | 230 | } |
| 237 | const field_size = field.ty.abiSize(target); | 231 | const field_size = field.ty.abiSize(mod); |
| 238 | const field_class_array = classifySystemV(field.ty, target, .other); | 232 | const field_class_array = classifySystemV(field.ty, mod, .other); |
| 239 | const field_class = std.mem.sliceTo(&field_class_array, .none); | 233 | const field_class = std.mem.sliceTo(&field_class_array, .none); |
| 240 | if (byte_i + field_size <= 8) { | 234 | if (byte_i + field_size <= 8) { |
| 241 | // Combine this field with the previous one. | 235 | // Combine this field with the previous one. |
| ... | @@ -334,8 +328,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { | ... | @@ -334,8 +328,8 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 334 | // it contains unaligned fields, it has class MEMORY" | 328 | // it contains unaligned fields, it has class MEMORY" |
| 335 | // "If the size of the aggregate exceeds a single eightbyte, each is classified | 329 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 336 | // separately.". | 330 | // separately.". |
| 337 | const ty_size = ty.abiSize(target); | 331 | const ty_size = ty.abiSize(mod); |
| 338 | if (ty.containerLayout() == .Packed) { | 332 | if (ty.containerLayout(mod) == .Packed) { |
| 339 | assert(ty_size <= 128); | 333 | assert(ty_size <= 128); |
| 340 | result[0] = .integer; | 334 | result[0] = .integer; |
| 341 | if (ty_size > 64) result[1] = .integer; | 335 | if (ty_size > 64) result[1] = .integer; |
| ... | @@ -344,15 +338,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { | ... | @@ -344,15 +338,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 344 | if (ty_size > 64) | 338 | if (ty_size > 64) |
| 345 | return memory_class; | 339 | return memory_class; |
| 346 | 340 | ||
| 347 | const fields = ty.unionFields(); | 341 | const fields = ty.unionFields(mod); |
| 348 | for (fields.values()) |field| { | 342 | for (fields.values()) |field| { |
| 349 | if (field.abi_align != 0) { | 343 | if (field.abi_align != 0) { |
| 350 | if (field.abi_align < field.ty.abiAlignment(target)) { | 344 | if (field.abi_align < field.ty.abiAlignment(mod)) { |
| 351 | return memory_class; | 345 | return memory_class; |
| 352 | } | 346 | } |
| 353 | } | 347 | } |
| 354 | // Combine this field with the previous one. | 348 | // Combine this field with the previous one. |
| 355 | const field_class = classifySystemV(field.ty, target, .other); | 349 | const field_class = classifySystemV(field.ty, mod, .other); |
| 356 | for (&result, 0..) |*result_item, i| { | 350 | for (&result, 0..) |*result_item, i| { |
| 357 | const field_item = field_class[i]; | 351 | const field_item = field_class[i]; |
| 358 | // "If both classes are equal, this is the resulting class." | 352 | // "If both classes are equal, this is the resulting class." |
| ... | @@ -426,7 +420,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { | ... | @@ -426,7 +420,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 426 | return result; | 420 | return result; |
| 427 | }, | 421 | }, |
| 428 | .Array => { | 422 | .Array => { |
| 429 | const ty_size = ty.abiSize(target); | 423 | const ty_size = ty.abiSize(mod); |
| 430 | if (ty_size <= 64) { | 424 | if (ty_size <= 64) { |
| 431 | result[0] = .integer; | 425 | result[0] = .integer; |
| 432 | return result; | 426 | return result; |
| ... | @@ -527,10 +521,17 @@ pub const RegisterClass = struct { | ... | @@ -527,10 +521,17 @@ pub const RegisterClass = struct { |
| 527 | }; | 521 | }; |
| 528 | }; | 522 | }; |
| 529 | 523 | ||
| 524 | const builtin = @import("builtin"); | ||
| 525 | const std = @import("std"); | ||
| 526 | const Target = std.Target; | ||
| 527 | const assert = std.debug.assert; | ||
| 530 | const testing = std.testing; | 528 | const testing = std.testing; |
| 529 | |||
| 531 | const Module = @import("../../Module.zig"); | 530 | const Module = @import("../../Module.zig"); |
| 531 | const Register = @import("bits.zig").Register; | ||
| 532 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; | ||
| 533 | const Type = @import("../../type.zig").Type; | ||
| 532 | const Value = @import("../../value.zig").Value; | 534 | const Value = @import("../../value.zig").Value; |
| 533 | const builtin = @import("builtin"); | ||
| 534 | 535 | ||
| 535 | fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field { | 536 | fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field { |
| 536 | return .{ | 537 | return .{ |
| ... | @@ -541,34 +542,3 @@ fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field { | ... | @@ -541,34 +542,3 @@ fn _field(comptime tag: Type.Tag, offset: u32) Module.Struct.Field { |
| 541 | .is_comptime = false, | 542 | .is_comptime = false, |
| 542 | }; | 543 | }; |
| 543 | } | 544 | } |
| 544 | |||
| 545 | test "C_C_D" { | ||
| 546 | var fields = Module.Struct.Fields{}; | ||
| 547 | // const C_C_D = extern struct { v1: i8, v2: i8, v3: f64 }; | ||
| 548 | try fields.ensureTotalCapacity(testing.allocator, 3); | ||
| 549 | defer fields.deinit(testing.allocator); | ||
| 550 | fields.putAssumeCapacity("v1", _field(.i8, 0)); | ||
| 551 | fields.putAssumeCapacity("v2", _field(.i8, 1)); | ||
| 552 | fields.putAssumeCapacity("v3", _field(.f64, 4)); | ||
| 553 | |||
| 554 | var C_C_D_struct = Module.Struct{ | ||
| 555 | .fields = fields, | ||
| 556 | .namespace = undefined, | ||
| 557 | .owner_decl = undefined, | ||
| 558 | .zir_index = undefined, | ||
| 559 | .layout = .Extern, | ||
| 560 | .status = .fully_resolved, | ||
| 561 | .known_non_opv = true, | ||
| 562 | .is_tuple = false, | ||
| 563 | }; | ||
| 564 | var C_C_D = Type.Payload.Struct{ .data = &C_C_D_struct }; | ||
| 565 | |||
| 566 | try testing.expectEqual( | ||
| 567 | [_]Class{ .integer, .sse, .none, .none, .none, .none, .none, .none }, | ||
| 568 | classifySystemV(Type.initPayload(&C_C_D.base), builtin.target, .ret), | ||
| 569 | ); | ||
| 570 | try testing.expectEqual( | ||
| 571 | [_]Class{ .integer, .sse, .none, .none, .none, .none, .none, .none }, | ||
| 572 | classifySystemV(Type.initPayload(&C_C_D.base), builtin.target, .arg), | ||
| 573 | ); | ||
| 574 | } |
src/codegen.zig+499-792| ... | @@ -14,6 +14,7 @@ const Air = @import("Air.zig"); | ... | @@ -14,6 +14,7 @@ const Air = @import("Air.zig"); |
| 14 | const Allocator = mem.Allocator; | 14 | const Allocator = mem.Allocator; |
| 15 | const Compilation = @import("Compilation.zig"); | 15 | const Compilation = @import("Compilation.zig"); |
| 16 | const ErrorMsg = Module.ErrorMsg; | 16 | const ErrorMsg = Module.ErrorMsg; |
| 17 | const InternPool = @import("InternPool.zig"); | ||
| 17 | const Liveness = @import("Liveness.zig"); | 18 | const Liveness = @import("Liveness.zig"); |
| 18 | const Module = @import("Module.zig"); | 19 | const Module = @import("Module.zig"); |
| 19 | const Target = std.Target; | 20 | const Target = std.Target; |
| ... | @@ -66,7 +67,7 @@ pub const DebugInfoOutput = union(enum) { | ... | @@ -66,7 +67,7 @@ pub const DebugInfoOutput = union(enum) { |
| 66 | pub fn generateFunction( | 67 | pub fn generateFunction( |
| 67 | bin_file: *link.File, | 68 | bin_file: *link.File, |
| 68 | src_loc: Module.SrcLoc, | 69 | src_loc: Module.SrcLoc, |
| 69 | func: *Module.Fn, | 70 | func_index: Module.Fn.Index, |
| 70 | air: Air, | 71 | air: Air, |
| 71 | liveness: Liveness, | 72 | liveness: Liveness, |
| 72 | code: *std.ArrayList(u8), | 73 | code: *std.ArrayList(u8), |
| ... | @@ -75,17 +76,17 @@ pub fn generateFunction( | ... | @@ -75,17 +76,17 @@ pub fn generateFunction( |
| 75 | switch (bin_file.options.target.cpu.arch) { | 76 | switch (bin_file.options.target.cpu.arch) { |
| 76 | .arm, | 77 | .arm, |
| 77 | .armeb, | 78 | .armeb, |
| 78 | => return @import("arch/arm/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | 79 | => return @import("arch/arm/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), |
| 79 | .aarch64, | 80 | .aarch64, |
| 80 | .aarch64_be, | 81 | .aarch64_be, |
| 81 | .aarch64_32, | 82 | .aarch64_32, |
| 82 | => return @import("arch/aarch64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | 83 | => return @import("arch/aarch64/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), |
| 83 | .riscv64 => return @import("arch/riscv64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | 84 | .riscv64 => return @import("arch/riscv64/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), |
| 84 | .sparc64 => return @import("arch/sparc64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | 85 | .sparc64 => return @import("arch/sparc64/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), |
| 85 | .x86_64 => return @import("arch/x86_64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | 86 | .x86_64 => return @import("arch/x86_64/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), |
| 86 | .wasm32, | 87 | .wasm32, |
| 87 | .wasm64, | 88 | .wasm64, |
| 88 | => return @import("arch/wasm/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | 89 | => return @import("arch/wasm/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), |
| 89 | else => unreachable, | 90 | else => unreachable, |
| 90 | } | 91 | } |
| 91 | } | 92 | } |
| ... | @@ -139,13 +140,14 @@ pub fn generateLazySymbol( | ... | @@ -139,13 +140,14 @@ pub fn generateLazySymbol( |
| 139 | return generateLazyFunction(bin_file, src_loc, lazy_sym, code, debug_output); | 140 | return generateLazyFunction(bin_file, src_loc, lazy_sym, code, debug_output); |
| 140 | } | 141 | } |
| 141 | 142 | ||
| 142 | if (lazy_sym.ty.isAnyError()) { | 143 | if (lazy_sym.ty.isAnyError(mod)) { |
| 143 | alignment.* = 4; | 144 | alignment.* = 4; |
| 144 | const err_names = mod.error_name_list.items; | 145 | const err_names = mod.global_error_set.keys(); |
| 145 | mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian); | 146 | mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian); |
| 146 | var offset = code.items.len; | 147 | var offset = code.items.len; |
| 147 | try code.resize((1 + err_names.len + 1) * 4); | 148 | try code.resize((1 + err_names.len + 1) * 4); |
| 148 | for (err_names) |err_name| { | 149 | for (err_names) |err_name_nts| { |
| 150 | const err_name = mod.intern_pool.stringToSlice(err_name_nts); | ||
| 149 | mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); | 151 | mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); |
| 150 | offset += 4; | 152 | offset += 4; |
| 151 | try code.ensureUnusedCapacity(err_name.len + 1); | 153 | try code.ensureUnusedCapacity(err_name.len + 1); |
| ... | @@ -154,9 +156,10 @@ pub fn generateLazySymbol( | ... | @@ -154,9 +156,10 @@ pub fn generateLazySymbol( |
| 154 | } | 156 | } |
| 155 | mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); | 157 | mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); |
| 156 | return Result.ok; | 158 | return Result.ok; |
| 157 | } else if (lazy_sym.ty.zigTypeTag() == .Enum) { | 159 | } else if (lazy_sym.ty.zigTypeTag(mod) == .Enum) { |
| 158 | alignment.* = 1; | 160 | alignment.* = 1; |
| 159 | for (lazy_sym.ty.enumFields().keys()) |tag_name| { | 161 | for (lazy_sym.ty.enumFields(mod)) |tag_name_ip| { |
| 162 | const tag_name = mod.intern_pool.stringToSlice(tag_name_ip); | ||
| 160 | try code.ensureUnusedCapacity(tag_name.len + 1); | 163 | try code.ensureUnusedCapacity(tag_name.len + 1); |
| 161 | code.appendSliceAssumeCapacity(tag_name); | 164 | code.appendSliceAssumeCapacity(tag_name); |
| 162 | code.appendAssumeCapacity(0); | 165 | code.appendAssumeCapacity(0); |
| ... | @@ -181,749 +184,512 @@ pub fn generateSymbol( | ... | @@ -181,749 +184,512 @@ pub fn generateSymbol( |
| 181 | const tracy = trace(@src()); | 184 | const tracy = trace(@src()); |
| 182 | defer tracy.end(); | 185 | defer tracy.end(); |
| 183 | 186 | ||
| 187 | const mod = bin_file.options.module.?; | ||
| 184 | var typed_value = arg_tv; | 188 | var typed_value = arg_tv; |
| 185 | if (arg_tv.val.castTag(.runtime_value)) |rt| { | 189 | switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) { |
| 186 | typed_value.val = rt.data; | 190 | .runtime_value => |rt| typed_value.val = rt.val.toValue(), |
| 191 | else => {}, | ||
| 187 | } | 192 | } |
| 188 | 193 | ||
| 189 | const target = bin_file.options.target; | 194 | const target = mod.getTarget(); |
| 190 | const endian = target.cpu.arch.endian(); | 195 | const endian = target.cpu.arch.endian(); |
| 191 | 196 | ||
| 192 | const mod = bin_file.options.module.?; | ||
| 193 | log.debug("generateSymbol: ty = {}, val = {}", .{ | 197 | log.debug("generateSymbol: ty = {}, val = {}", .{ |
| 194 | typed_value.ty.fmt(mod), | 198 | typed_value.ty.fmt(mod), |
| 195 | typed_value.val.fmtValue(typed_value.ty, mod), | 199 | typed_value.val.fmtValue(typed_value.ty, mod), |
| 196 | }); | 200 | }); |
| 197 | 201 | ||
| 198 | if (typed_value.val.isUndefDeep()) { | 202 | if (typed_value.val.isUndefDeep(mod)) { |
| 199 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; | 203 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; |
| 200 | try code.appendNTimes(0xaa, abi_size); | 204 | try code.appendNTimes(0xaa, abi_size); |
| 201 | return Result.ok; | 205 | return .ok; |
| 202 | } | 206 | } |
| 203 | 207 | ||
| 204 | switch (typed_value.ty.zigTypeTag()) { | 208 | switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) { |
| 205 | .Fn => { | 209 | .int_type, |
| 206 | return Result{ | 210 | .ptr_type, |
| 207 | .fail = try ErrorMsg.create( | 211 | .array_type, |
| 208 | bin_file.allocator, | 212 | .vector_type, |
| 209 | src_loc, | 213 | .opt_type, |
| 210 | "TODO implement generateSymbol function pointers", | 214 | .anyframe_type, |
| 211 | .{}, | 215 | .error_union_type, |
| 212 | ), | 216 | .simple_type, |
| 213 | }; | 217 | .struct_type, |
| 214 | }, | 218 | .anon_struct_type, |
| 215 | .Float => { | 219 | .union_type, |
| 216 | switch (typed_value.ty.floatBits(target)) { | 220 | .opaque_type, |
| 217 | 16 => writeFloat(f16, typed_value.val.toFloat(f16), target, endian, try code.addManyAsArray(2)), | 221 | .enum_type, |
| 218 | 32 => writeFloat(f32, typed_value.val.toFloat(f32), target, endian, try code.addManyAsArray(4)), | 222 | .func_type, |
| 219 | 64 => writeFloat(f64, typed_value.val.toFloat(f64), target, endian, try code.addManyAsArray(8)), | 223 | .error_set_type, |
| 220 | 80 => { | 224 | .inferred_error_set_type, |
| 221 | writeFloat(f80, typed_value.val.toFloat(f80), target, endian, try code.addManyAsArray(10)); | 225 | => unreachable, // types, not values |
| 222 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; | 226 | |
| 223 | try code.appendNTimes(0, abi_size - 10); | 227 | .undef, .runtime_value => unreachable, // handled above |
| 224 | }, | 228 | .simple_value => |simple_value| switch (simple_value) { |
| 225 | 128 => writeFloat(f128, typed_value.val.toFloat(f128), target, endian, try code.addManyAsArray(16)), | 229 | .undefined, |
| 230 | .void, | ||
| 231 | .null, | ||
| 232 | .empty_struct, | ||
| 233 | .@"unreachable", | ||
| 234 | .generic_poison, | ||
| 235 | => unreachable, // non-runtime values | ||
| 236 | .false, .true => try code.append(switch (simple_value) { | ||
| 237 | .false => 0, | ||
| 238 | .true => 1, | ||
| 226 | else => unreachable, | 239 | else => unreachable, |
| 227 | } | 240 | }), |
| 228 | return Result.ok; | ||
| 229 | }, | 241 | }, |
| 230 | .Array => switch (typed_value.val.tag()) { | 242 | .variable, |
| 231 | .bytes => { | 243 | .extern_func, |
| 232 | const bytes = typed_value.val.castTag(.bytes).?.data; | 244 | .func, |
| 233 | const len = @intCast(usize, typed_value.ty.arrayLenIncludingSentinel()); | 245 | .enum_literal, |
| 234 | // The bytes payload already includes the sentinel, if any | 246 | .empty_enum_value, |
| 235 | try code.ensureUnusedCapacity(len); | 247 | => unreachable, // non-runtime values |
| 236 | code.appendSliceAssumeCapacity(bytes[0..len]); | 248 | .int => { |
| 237 | return Result.ok; | 249 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; |
| 238 | }, | 250 | var space: Value.BigIntSpace = undefined; |
| 239 | .str_lit => { | 251 | const val = typed_value.val.toBigInt(&space, mod); |
| 240 | const str_lit = typed_value.val.castTag(.str_lit).?.data; | 252 | val.writeTwosComplement(try code.addManyAsSlice(abi_size), endian); |
| 241 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | ||
| 242 | try code.ensureUnusedCapacity(bytes.len + 1); | ||
| 243 | code.appendSliceAssumeCapacity(bytes); | ||
| 244 | if (typed_value.ty.sentinel()) |sent_val| { | ||
| 245 | const byte = @intCast(u8, sent_val.toUnsignedInt(target)); | ||
| 246 | code.appendAssumeCapacity(byte); | ||
| 247 | } | ||
| 248 | return Result.ok; | ||
| 249 | }, | ||
| 250 | .aggregate => { | ||
| 251 | const elem_vals = typed_value.val.castTag(.aggregate).?.data; | ||
| 252 | const elem_ty = typed_value.ty.elemType(); | ||
| 253 | const len = @intCast(usize, typed_value.ty.arrayLenIncludingSentinel()); | ||
| 254 | for (elem_vals[0..len]) |elem_val| { | ||
| 255 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 256 | .ty = elem_ty, | ||
| 257 | .val = elem_val, | ||
| 258 | }, code, debug_output, reloc_info)) { | ||
| 259 | .ok => {}, | ||
| 260 | .fail => |em| return Result{ .fail = em }, | ||
| 261 | } | ||
| 262 | } | ||
| 263 | return Result.ok; | ||
| 264 | }, | ||
| 265 | .repeated => { | ||
| 266 | const array = typed_value.val.castTag(.repeated).?.data; | ||
| 267 | const elem_ty = typed_value.ty.childType(); | ||
| 268 | const sentinel = typed_value.ty.sentinel(); | ||
| 269 | const len = typed_value.ty.arrayLen(); | ||
| 270 | |||
| 271 | var index: u64 = 0; | ||
| 272 | while (index < len) : (index += 1) { | ||
| 273 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 274 | .ty = elem_ty, | ||
| 275 | .val = array, | ||
| 276 | }, code, debug_output, reloc_info)) { | ||
| 277 | .ok => {}, | ||
| 278 | .fail => |em| return Result{ .fail = em }, | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | if (sentinel) |sentinel_val| { | ||
| 283 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 284 | .ty = elem_ty, | ||
| 285 | .val = sentinel_val, | ||
| 286 | }, code, debug_output, reloc_info)) { | ||
| 287 | .ok => {}, | ||
| 288 | .fail => |em| return Result{ .fail = em }, | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | return Result.ok; | ||
| 293 | }, | ||
| 294 | .empty_array_sentinel => { | ||
| 295 | const elem_ty = typed_value.ty.childType(); | ||
| 296 | const sentinel_val = typed_value.ty.sentinel().?; | ||
| 297 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 298 | .ty = elem_ty, | ||
| 299 | .val = sentinel_val, | ||
| 300 | }, code, debug_output, reloc_info)) { | ||
| 301 | .ok => {}, | ||
| 302 | .fail => |em| return Result{ .fail = em }, | ||
| 303 | } | ||
| 304 | return Result.ok; | ||
| 305 | }, | ||
| 306 | else => return Result{ | ||
| 307 | .fail = try ErrorMsg.create( | ||
| 308 | bin_file.allocator, | ||
| 309 | src_loc, | ||
| 310 | "TODO implement generateSymbol for array type value: {s}", | ||
| 311 | .{@tagName(typed_value.val.tag())}, | ||
| 312 | ), | ||
| 313 | }, | ||
| 314 | }, | 253 | }, |
| 315 | .Pointer => switch (typed_value.val.tag()) { | 254 | .err => |err| { |
| 316 | .null_value => { | 255 | const int = try mod.getErrorValue(err.name); |
| 317 | switch (target.ptrBitWidth()) { | 256 | try code.writer().writeInt(u16, @intCast(u16, int), endian); |
| 318 | 32 => { | ||
| 319 | mem.writeInt(u32, try code.addManyAsArray(4), 0, endian); | ||
| 320 | if (typed_value.ty.isSlice()) try code.appendNTimes(0xaa, 4); | ||
| 321 | }, | ||
| 322 | 64 => { | ||
| 323 | mem.writeInt(u64, try code.addManyAsArray(8), 0, endian); | ||
| 324 | if (typed_value.ty.isSlice()) try code.appendNTimes(0xaa, 8); | ||
| 325 | }, | ||
| 326 | else => unreachable, | ||
| 327 | } | ||
| 328 | return Result.ok; | ||
| 329 | }, | ||
| 330 | .zero, .one, .int_u64, .int_big_positive => { | ||
| 331 | switch (target.ptrBitWidth()) { | ||
| 332 | 32 => { | ||
| 333 | const x = typed_value.val.toUnsignedInt(target); | ||
| 334 | mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, x), endian); | ||
| 335 | }, | ||
| 336 | 64 => { | ||
| 337 | const x = typed_value.val.toUnsignedInt(target); | ||
| 338 | mem.writeInt(u64, try code.addManyAsArray(8), x, endian); | ||
| 339 | }, | ||
| 340 | else => unreachable, | ||
| 341 | } | ||
| 342 | return Result.ok; | ||
| 343 | }, | ||
| 344 | .variable, .decl_ref, .decl_ref_mut => |tag| return lowerDeclRef( | ||
| 345 | bin_file, | ||
| 346 | src_loc, | ||
| 347 | typed_value, | ||
| 348 | switch (tag) { | ||
| 349 | .variable => typed_value.val.castTag(.variable).?.data.owner_decl, | ||
| 350 | .decl_ref => typed_value.val.castTag(.decl_ref).?.data, | ||
| 351 | .decl_ref_mut => typed_value.val.castTag(.decl_ref_mut).?.data.decl_index, | ||
| 352 | else => unreachable, | ||
| 353 | }, | ||
| 354 | code, | ||
| 355 | debug_output, | ||
| 356 | reloc_info, | ||
| 357 | ), | ||
| 358 | .slice => { | ||
| 359 | const slice = typed_value.val.castTag(.slice).?.data; | ||
| 360 | |||
| 361 | // generate ptr | ||
| 362 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 363 | const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf); | ||
| 364 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 365 | .ty = slice_ptr_field_type, | ||
| 366 | .val = slice.ptr, | ||
| 367 | }, code, debug_output, reloc_info)) { | ||
| 368 | .ok => {}, | ||
| 369 | .fail => |em| return Result{ .fail = em }, | ||
| 370 | } | ||
| 371 | |||
| 372 | // generate length | ||
| 373 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 374 | .ty = Type.initTag(.usize), | ||
| 375 | .val = slice.len, | ||
| 376 | }, code, debug_output, reloc_info)) { | ||
| 377 | .ok => {}, | ||
| 378 | .fail => |em| return Result{ .fail = em }, | ||
| 379 | } | ||
| 380 | |||
| 381 | return Result.ok; | ||
| 382 | }, | ||
| 383 | .field_ptr, .elem_ptr, .opt_payload_ptr => return lowerParentPtr( | ||
| 384 | bin_file, | ||
| 385 | src_loc, | ||
| 386 | typed_value, | ||
| 387 | typed_value.val, | ||
| 388 | code, | ||
| 389 | debug_output, | ||
| 390 | reloc_info, | ||
| 391 | ), | ||
| 392 | else => return Result{ | ||
| 393 | .fail = try ErrorMsg.create( | ||
| 394 | bin_file.allocator, | ||
| 395 | src_loc, | ||
| 396 | "TODO implement generateSymbol for pointer type value: '{s}'", | ||
| 397 | .{@tagName(typed_value.val.tag())}, | ||
| 398 | ), | ||
| 399 | }, | ||
| 400 | }, | 257 | }, |
| 401 | .Int => { | 258 | .error_union => |error_union| { |
| 402 | const info = typed_value.ty.intInfo(target); | 259 | const payload_ty = typed_value.ty.errorUnionPayload(mod); |
| 403 | if (info.bits <= 8) { | 260 | const err_val = switch (error_union.val) { |
| 404 | const x: u8 = switch (info.signedness) { | 261 | .err_name => |err_name| @intCast(u16, try mod.getErrorValue(err_name)), |
| 405 | .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(target)), | 262 | .payload => @as(u16, 0), |
| 406 | .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt(target))), | 263 | }; |
| 407 | }; | ||
| 408 | try code.append(x); | ||
| 409 | return Result.ok; | ||
| 410 | } | ||
| 411 | if (info.bits > 64) { | ||
| 412 | var bigint_buffer: Value.BigIntSpace = undefined; | ||
| 413 | const bigint = typed_value.val.toBigInt(&bigint_buffer, target); | ||
| 414 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; | ||
| 415 | const start = code.items.len; | ||
| 416 | try code.resize(start + abi_size); | ||
| 417 | bigint.writeTwosComplement(code.items[start..][0..abi_size], endian); | ||
| 418 | return Result.ok; | ||
| 419 | } | ||
| 420 | switch (info.signedness) { | ||
| 421 | .unsigned => { | ||
| 422 | if (info.bits <= 16) { | ||
| 423 | const x = @intCast(u16, typed_value.val.toUnsignedInt(target)); | ||
| 424 | mem.writeInt(u16, try code.addManyAsArray(2), x, endian); | ||
| 425 | } else if (info.bits <= 32) { | ||
| 426 | const x = @intCast(u32, typed_value.val.toUnsignedInt(target)); | ||
| 427 | mem.writeInt(u32, try code.addManyAsArray(4), x, endian); | ||
| 428 | } else { | ||
| 429 | const x = typed_value.val.toUnsignedInt(target); | ||
| 430 | mem.writeInt(u64, try code.addManyAsArray(8), x, endian); | ||
| 431 | } | ||
| 432 | }, | ||
| 433 | .signed => { | ||
| 434 | if (info.bits <= 16) { | ||
| 435 | const x = @intCast(i16, typed_value.val.toSignedInt(target)); | ||
| 436 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); | ||
| 437 | } else if (info.bits <= 32) { | ||
| 438 | const x = @intCast(i32, typed_value.val.toSignedInt(target)); | ||
| 439 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); | ||
| 440 | } else { | ||
| 441 | const x = typed_value.val.toSignedInt(target); | ||
| 442 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); | ||
| 443 | } | ||
| 444 | }, | ||
| 445 | } | ||
| 446 | return Result.ok; | ||
| 447 | }, | ||
| 448 | .Enum => { | ||
| 449 | var int_buffer: Value.Payload.U64 = undefined; | ||
| 450 | const int_val = typed_value.enumToInt(&int_buffer); | ||
| 451 | |||
| 452 | const info = typed_value.ty.intInfo(target); | ||
| 453 | if (info.bits <= 8) { | ||
| 454 | const x = @intCast(u8, int_val.toUnsignedInt(target)); | ||
| 455 | try code.append(x); | ||
| 456 | return Result.ok; | ||
| 457 | } | ||
| 458 | if (info.bits > 64) { | ||
| 459 | return Result{ | ||
| 460 | .fail = try ErrorMsg.create( | ||
| 461 | bin_file.allocator, | ||
| 462 | src_loc, | ||
| 463 | "TODO implement generateSymbol for big int enums ('{}')", | ||
| 464 | .{typed_value.ty.fmt(mod)}, | ||
| 465 | ), | ||
| 466 | }; | ||
| 467 | } | ||
| 468 | switch (info.signedness) { | ||
| 469 | .unsigned => { | ||
| 470 | if (info.bits <= 16) { | ||
| 471 | const x = @intCast(u16, int_val.toUnsignedInt(target)); | ||
| 472 | mem.writeInt(u16, try code.addManyAsArray(2), x, endian); | ||
| 473 | } else if (info.bits <= 32) { | ||
| 474 | const x = @intCast(u32, int_val.toUnsignedInt(target)); | ||
| 475 | mem.writeInt(u32, try code.addManyAsArray(4), x, endian); | ||
| 476 | } else { | ||
| 477 | const x = int_val.toUnsignedInt(target); | ||
| 478 | mem.writeInt(u64, try code.addManyAsArray(8), x, endian); | ||
| 479 | } | ||
| 480 | }, | ||
| 481 | .signed => { | ||
| 482 | if (info.bits <= 16) { | ||
| 483 | const x = @intCast(i16, int_val.toSignedInt(target)); | ||
| 484 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); | ||
| 485 | } else if (info.bits <= 32) { | ||
| 486 | const x = @intCast(i32, int_val.toSignedInt(target)); | ||
| 487 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); | ||
| 488 | } else { | ||
| 489 | const x = int_val.toSignedInt(target); | ||
| 490 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); | ||
| 491 | } | ||
| 492 | }, | ||
| 493 | } | ||
| 494 | return Result.ok; | ||
| 495 | }, | ||
| 496 | .Bool => { | ||
| 497 | const x: u8 = @boolToInt(typed_value.val.toBool()); | ||
| 498 | try code.append(x); | ||
| 499 | return Result.ok; | ||
| 500 | }, | ||
| 501 | .Struct => { | ||
| 502 | if (typed_value.ty.containerLayout() == .Packed) { | ||
| 503 | const struct_obj = typed_value.ty.castTag(.@"struct").?.data; | ||
| 504 | const fields = struct_obj.fields.values(); | ||
| 505 | const field_vals = typed_value.val.castTag(.aggregate).?.data; | ||
| 506 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; | ||
| 507 | const current_pos = code.items.len; | ||
| 508 | try code.resize(current_pos + abi_size); | ||
| 509 | var bits: u16 = 0; | ||
| 510 | |||
| 511 | for (field_vals, 0..) |field_val, index| { | ||
| 512 | const field_ty = fields[index].ty; | ||
| 513 | // pointer may point to a decl which must be marked used | ||
| 514 | // but can also result in a relocation. Therefore we handle those seperately. | ||
| 515 | if (field_ty.zigTypeTag() == .Pointer) { | ||
| 516 | const field_size = math.cast(usize, field_ty.abiSize(target)) orelse return error.Overflow; | ||
| 517 | var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size); | ||
| 518 | defer tmp_list.deinit(); | ||
| 519 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 520 | .ty = field_ty, | ||
| 521 | .val = field_val, | ||
| 522 | }, &tmp_list, debug_output, reloc_info)) { | ||
| 523 | .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items), | ||
| 524 | .fail => |em| return Result{ .fail = em }, | ||
| 525 | } | ||
| 526 | } else { | ||
| 527 | field_val.writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits) catch unreachable; | ||
| 528 | } | ||
| 529 | bits += @intCast(u16, field_ty.bitSize(target)); | ||
| 530 | } | ||
| 531 | 264 | ||
| 532 | return Result.ok; | 265 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 266 | try code.writer().writeInt(u16, err_val, endian); | ||
| 267 | return .ok; | ||
| 533 | } | 268 | } |
| 534 | 269 | ||
| 535 | const struct_begin = code.items.len; | 270 | const payload_align = payload_ty.abiAlignment(mod); |
| 536 | const field_vals = typed_value.val.castTag(.aggregate).?.data; | 271 | const error_align = Type.anyerror.abiAlignment(mod); |
| 537 | for (field_vals, 0..) |field_val, index| { | 272 | const abi_align = typed_value.ty.abiAlignment(mod); |
| 538 | const field_ty = typed_value.ty.structFieldType(index); | ||
| 539 | if (!field_ty.hasRuntimeBits()) continue; | ||
| 540 | 273 | ||
| 274 | // error value first when its type is larger than the error union's payload | ||
| 275 | if (error_align > payload_align) { | ||
| 276 | try code.writer().writeInt(u16, err_val, endian); | ||
| 277 | } | ||
| 278 | |||
| 279 | // emit payload part of the error union | ||
| 280 | { | ||
| 281 | const begin = code.items.len; | ||
| 541 | switch (try generateSymbol(bin_file, src_loc, .{ | 282 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 542 | .ty = field_ty, | 283 | .ty = payload_ty, |
| 543 | .val = field_val, | 284 | .val = switch (error_union.val) { |
| 285 | .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }), | ||
| 286 | .payload => |payload| payload, | ||
| 287 | }.toValue(), | ||
| 544 | }, code, debug_output, reloc_info)) { | 288 | }, code, debug_output, reloc_info)) { |
| 545 | .ok => {}, | 289 | .ok => {}, |
| 546 | .fail => |em| return Result{ .fail = em }, | 290 | .fail => |em| return .{ .fail = em }, |
| 547 | } | 291 | } |
| 548 | const unpadded_field_end = code.items.len - struct_begin; | 292 | const unpadded_end = code.items.len - begin; |
| 549 | 293 | const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); | |
| 550 | // Pad struct members if required | 294 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 551 | const padded_field_end = typed_value.ty.structFieldOffset(index + 1, target); | ||
| 552 | const padding = math.cast(usize, padded_field_end - unpadded_field_end) orelse return error.Overflow; | ||
| 553 | 295 | ||
| 554 | if (padding > 0) { | 296 | if (padding > 0) { |
| 555 | try code.writer().writeByteNTimes(0, padding); | 297 | try code.writer().writeByteNTimes(0, padding); |
| 556 | } | 298 | } |
| 557 | } | 299 | } |
| 558 | 300 | ||
| 559 | return Result.ok; | 301 | // Payload size is larger than error set, so emit our error set last |
| 560 | }, | 302 | if (error_align <= payload_align) { |
| 561 | .Union => { | 303 | const begin = code.items.len; |
| 562 | const union_obj = typed_value.val.castTag(.@"union").?.data; | 304 | try code.writer().writeInt(u16, err_val, endian); |
| 563 | const layout = typed_value.ty.unionGetLayout(target); | 305 | const unpadded_end = code.items.len - begin; |
| 564 | 306 | const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); | |
| 565 | if (layout.payload_size == 0) { | 307 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 566 | return generateSymbol(bin_file, src_loc, .{ | ||
| 567 | .ty = typed_value.ty.unionTagType().?, | ||
| 568 | .val = union_obj.tag, | ||
| 569 | }, code, debug_output, reloc_info); | ||
| 570 | } | ||
| 571 | |||
| 572 | // Check if we should store the tag first. | ||
| 573 | if (layout.tag_align >= layout.payload_align) { | ||
| 574 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 575 | .ty = typed_value.ty.unionTagType().?, | ||
| 576 | .val = union_obj.tag, | ||
| 577 | }, code, debug_output, reloc_info)) { | ||
| 578 | .ok => {}, | ||
| 579 | .fail => |em| return Result{ .fail = em }, | ||
| 580 | } | ||
| 581 | } | ||
| 582 | |||
| 583 | const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data; | ||
| 584 | const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?; | ||
| 585 | assert(union_ty.haveFieldTypes()); | ||
| 586 | const field_ty = union_ty.fields.values()[field_index].ty; | ||
| 587 | if (!field_ty.hasRuntimeBits()) { | ||
| 588 | try code.writer().writeByteNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); | ||
| 589 | } else { | ||
| 590 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 591 | .ty = field_ty, | ||
| 592 | .val = union_obj.val, | ||
| 593 | }, code, debug_output, reloc_info)) { | ||
| 594 | .ok => {}, | ||
| 595 | .fail => |em| return Result{ .fail = em }, | ||
| 596 | } | ||
| 597 | 308 | ||
| 598 | const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(target)) orelse return error.Overflow; | ||
| 599 | if (padding > 0) { | 309 | if (padding > 0) { |
| 600 | try code.writer().writeByteNTimes(0, padding); | 310 | try code.writer().writeByteNTimes(0, padding); |
| 601 | } | 311 | } |
| 602 | } | 312 | } |
| 603 | 313 | }, | |
| 604 | if (layout.tag_size > 0) { | 314 | .enum_tag => |enum_tag| { |
| 315 | const int_tag_ty = typed_value.ty.intTagType(mod); | ||
| 316 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 317 | .ty = int_tag_ty, | ||
| 318 | .val = try mod.getCoerced(enum_tag.int.toValue(), int_tag_ty), | ||
| 319 | }, code, debug_output, reloc_info)) { | ||
| 320 | .ok => {}, | ||
| 321 | .fail => |em| return .{ .fail = em }, | ||
| 322 | } | ||
| 323 | }, | ||
| 324 | .float => |float| switch (float.storage) { | ||
| 325 | .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(2)), | ||
| 326 | .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(4)), | ||
| 327 | .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(8)), | ||
| 328 | .f80 => |f80_val| { | ||
| 329 | writeFloat(f80, f80_val, target, endian, try code.addManyAsArray(10)); | ||
| 330 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; | ||
| 331 | try code.appendNTimes(0, abi_size - 10); | ||
| 332 | }, | ||
| 333 | .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(16)), | ||
| 334 | }, | ||
| 335 | .ptr => |ptr| { | ||
| 336 | // generate ptr | ||
| 337 | switch (try lowerParentPtr(bin_file, src_loc, switch (ptr.len) { | ||
| 338 | .none => typed_value.val, | ||
| 339 | else => typed_value.val.slicePtr(mod), | ||
| 340 | }.toIntern(), code, debug_output, reloc_info)) { | ||
| 341 | .ok => {}, | ||
| 342 | .fail => |em| return .{ .fail = em }, | ||
| 343 | } | ||
| 344 | if (ptr.len != .none) { | ||
| 345 | // generate len | ||
| 605 | switch (try generateSymbol(bin_file, src_loc, .{ | 346 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 606 | .ty = union_ty.tag_ty, | 347 | .ty = Type.usize, |
| 607 | .val = union_obj.tag, | 348 | .val = ptr.len.toValue(), |
| 608 | }, code, debug_output, reloc_info)) { | 349 | }, code, debug_output, reloc_info)) { |
| 609 | .ok => {}, | 350 | .ok => {}, |
| 610 | .fail => |em| return Result{ .fail = em }, | 351 | .fail => |em| return Result{ .fail = em }, |
| 611 | } | 352 | } |
| 612 | } | 353 | } |
| 613 | |||
| 614 | if (layout.padding > 0) { | ||
| 615 | try code.writer().writeByteNTimes(0, layout.padding); | ||
| 616 | } | ||
| 617 | |||
| 618 | return Result.ok; | ||
| 619 | }, | 354 | }, |
| 620 | .Optional => { | 355 | .opt => { |
| 621 | var opt_buf: Type.Payload.ElemType = undefined; | 356 | const payload_type = typed_value.ty.optionalChild(mod); |
| 622 | const payload_type = typed_value.ty.optionalChild(&opt_buf); | 357 | const payload_val = typed_value.val.optionalValue(mod); |
| 623 | const is_pl = !typed_value.val.isNull(); | 358 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; |
| 624 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; | ||
| 625 | |||
| 626 | if (!payload_type.hasRuntimeBits()) { | ||
| 627 | try code.writer().writeByteNTimes(@boolToInt(is_pl), abi_size); | ||
| 628 | return Result.ok; | ||
| 629 | } | ||
| 630 | 359 | ||
| 631 | if (typed_value.ty.optionalReprIsPayload()) { | 360 | if (typed_value.ty.optionalReprIsPayload(mod)) { |
| 632 | if (typed_value.val.castTag(.opt_payload)) |payload| { | 361 | if (payload_val) |value| { |
| 633 | switch (try generateSymbol(bin_file, src_loc, .{ | 362 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 634 | .ty = payload_type, | 363 | .ty = payload_type, |
| 635 | .val = payload.data, | 364 | .val = value, |
| 636 | }, code, debug_output, reloc_info)) { | 365 | }, code, debug_output, reloc_info)) { |
| 637 | .ok => {}, | 366 | .ok => {}, |
| 638 | .fail => |em| return Result{ .fail = em }, | 367 | .fail => |em| return Result{ .fail = em }, |
| 639 | } | 368 | } |
| 640 | } else if (!typed_value.val.isNull()) { | 369 | } else { |
| 370 | try code.writer().writeByteNTimes(0, abi_size); | ||
| 371 | } | ||
| 372 | } else { | ||
| 373 | const padding = abi_size - (math.cast(usize, payload_type.abiSize(mod)) orelse return error.Overflow) - 1; | ||
| 374 | if (payload_type.hasRuntimeBits(mod)) { | ||
| 375 | const value = payload_val orelse (try mod.intern(.{ .undef = payload_type.toIntern() })).toValue(); | ||
| 641 | switch (try generateSymbol(bin_file, src_loc, .{ | 376 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 642 | .ty = payload_type, | 377 | .ty = payload_type, |
| 643 | .val = typed_value.val, | 378 | .val = value, |
| 644 | }, code, debug_output, reloc_info)) { | 379 | }, code, debug_output, reloc_info)) { |
| 645 | .ok => {}, | 380 | .ok => {}, |
| 646 | .fail => |em| return Result{ .fail = em }, | 381 | .fail => |em| return Result{ .fail = em }, |
| 647 | } | 382 | } |
| 648 | } else { | ||
| 649 | try code.writer().writeByteNTimes(0, abi_size); | ||
| 650 | } | 383 | } |
| 651 | 384 | try code.writer().writeByte(@boolToInt(payload_val != null)); | |
| 652 | return Result.ok; | 385 | try code.writer().writeByteNTimes(0, padding); |
| 653 | } | 386 | } |
| 387 | }, | ||
| 388 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(typed_value.ty.toIntern())) { | ||
| 389 | .array_type => |array_type| switch (aggregate.storage) { | ||
| 390 | .bytes => |bytes| try code.appendSlice(bytes), | ||
| 391 | .elems, .repeated_elem => { | ||
| 392 | var index: u64 = 0; | ||
| 393 | var len_including_sentinel = | ||
| 394 | array_type.len + @boolToInt(array_type.sentinel != .none); | ||
| 395 | while (index < len_including_sentinel) : (index += 1) { | ||
| 396 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 397 | .ty = array_type.child.toType(), | ||
| 398 | .val = switch (aggregate.storage) { | ||
| 399 | .bytes => unreachable, | ||
| 400 | .elems => |elems| elems[@intCast(usize, index)], | ||
| 401 | .repeated_elem => |elem| elem, | ||
| 402 | }.toValue(), | ||
| 403 | }, code, debug_output, reloc_info)) { | ||
| 404 | .ok => {}, | ||
| 405 | .fail => |em| return .{ .fail = em }, | ||
| 406 | } | ||
| 407 | } | ||
| 408 | }, | ||
| 409 | }, | ||
| 410 | .vector_type => |vector_type| { | ||
| 411 | switch (aggregate.storage) { | ||
| 412 | .bytes => |bytes| try code.appendSlice(bytes), | ||
| 413 | .elems, .repeated_elem => { | ||
| 414 | var index: u64 = 0; | ||
| 415 | while (index < vector_type.len) : (index += 1) { | ||
| 416 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 417 | .ty = vector_type.child.toType(), | ||
| 418 | .val = switch (aggregate.storage) { | ||
| 419 | .bytes => unreachable, | ||
| 420 | .elems => |elems| elems[@intCast(usize, index)], | ||
| 421 | .repeated_elem => |elem| elem, | ||
| 422 | }.toValue(), | ||
| 423 | }, code, debug_output, reloc_info)) { | ||
| 424 | .ok => {}, | ||
| 425 | .fail => |em| return .{ .fail = em }, | ||
| 426 | } | ||
| 427 | } | ||
| 428 | }, | ||
| 429 | } | ||
| 654 | 430 | ||
| 655 | const padding = abi_size - (math.cast(usize, payload_type.abiSize(target)) orelse return error.Overflow) - 1; | 431 | const padding = math.cast(usize, typed_value.ty.abiSize(mod) - |
| 656 | const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.initTag(.undef); | 432 | (math.divCeil(u64, vector_type.child.toType().bitSize(mod) * vector_type.len, 8) catch |err| switch (err) { |
| 657 | switch (try generateSymbol(bin_file, src_loc, .{ | 433 | error.DivisionByZero => unreachable, |
| 658 | .ty = payload_type, | 434 | else => |e| return e, |
| 659 | .val = value, | 435 | })) orelse return error.Overflow; |
| 660 | }, code, debug_output, reloc_info)) { | 436 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); |
| 661 | .ok => {}, | 437 | }, |
| 662 | .fail => |em| return Result{ .fail = em }, | 438 | .anon_struct_type => |tuple| { |
| 663 | } | 439 | const struct_begin = code.items.len; |
| 664 | try code.writer().writeByte(@boolToInt(is_pl)); | 440 | for (tuple.types, tuple.values, 0..) |field_ty, comptime_val, index| { |
| 665 | try code.writer().writeByteNTimes(0, padding); | 441 | if (comptime_val != .none) continue; |
| 442 | if (!field_ty.toType().hasRuntimeBits(mod)) continue; | ||
| 443 | |||
| 444 | const field_val = switch (aggregate.storage) { | ||
| 445 | .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{ | ||
| 446 | .ty = field_ty, | ||
| 447 | .storage = .{ .u64 = bytes[index] }, | ||
| 448 | } }), | ||
| 449 | .elems => |elems| elems[index], | ||
| 450 | .repeated_elem => |elem| elem, | ||
| 451 | }; | ||
| 452 | |||
| 453 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 454 | .ty = field_ty.toType(), | ||
| 455 | .val = field_val.toValue(), | ||
| 456 | }, code, debug_output, reloc_info)) { | ||
| 457 | .ok => {}, | ||
| 458 | .fail => |em| return Result{ .fail = em }, | ||
| 459 | } | ||
| 460 | const unpadded_field_end = code.items.len - struct_begin; | ||
| 461 | |||
| 462 | // Pad struct members if required | ||
| 463 | const padded_field_end = typed_value.ty.structFieldOffset(index + 1, mod); | ||
| 464 | const padding = math.cast(usize, padded_field_end - unpadded_field_end) orelse | ||
| 465 | return error.Overflow; | ||
| 666 | 466 | ||
| 667 | return Result.ok; | 467 | if (padding > 0) { |
| 468 | try code.writer().writeByteNTimes(0, padding); | ||
| 469 | } | ||
| 470 | } | ||
| 471 | }, | ||
| 472 | .struct_type => |struct_type| { | ||
| 473 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 474 | |||
| 475 | if (struct_obj.layout == .Packed) { | ||
| 476 | const fields = struct_obj.fields.values(); | ||
| 477 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse | ||
| 478 | return error.Overflow; | ||
| 479 | const current_pos = code.items.len; | ||
| 480 | try code.resize(current_pos + abi_size); | ||
| 481 | var bits: u16 = 0; | ||
| 482 | |||
| 483 | for (fields, 0..) |field, index| { | ||
| 484 | const field_ty = field.ty; | ||
| 485 | |||
| 486 | const field_val = switch (aggregate.storage) { | ||
| 487 | .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{ | ||
| 488 | .ty = field_ty.toIntern(), | ||
| 489 | .storage = .{ .u64 = bytes[index] }, | ||
| 490 | } }), | ||
| 491 | .elems => |elems| elems[index], | ||
| 492 | .repeated_elem => |elem| elem, | ||
| 493 | }; | ||
| 494 | |||
| 495 | // pointer may point to a decl which must be marked used | ||
| 496 | // but can also result in a relocation. Therefore we handle those separately. | ||
| 497 | if (field_ty.zigTypeTag(mod) == .Pointer) { | ||
| 498 | const field_size = math.cast(usize, field_ty.abiSize(mod)) orelse | ||
| 499 | return error.Overflow; | ||
| 500 | var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size); | ||
| 501 | defer tmp_list.deinit(); | ||
| 502 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 503 | .ty = field_ty, | ||
| 504 | .val = field_val.toValue(), | ||
| 505 | }, &tmp_list, debug_output, reloc_info)) { | ||
| 506 | .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items), | ||
| 507 | .fail => |em| return Result{ .fail = em }, | ||
| 508 | } | ||
| 509 | } else { | ||
| 510 | field_val.toValue().writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits) catch unreachable; | ||
| 511 | } | ||
| 512 | bits += @intCast(u16, field_ty.bitSize(mod)); | ||
| 513 | } | ||
| 514 | } else { | ||
| 515 | const struct_begin = code.items.len; | ||
| 516 | for (struct_obj.fields.values(), 0..) |field, index| { | ||
| 517 | const field_ty = field.ty; | ||
| 518 | if (!field_ty.hasRuntimeBits(mod)) continue; | ||
| 519 | |||
| 520 | const field_val = switch (mod.intern_pool.indexToKey(typed_value.val.toIntern()).aggregate.storage) { | ||
| 521 | .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{ | ||
| 522 | .ty = field_ty.toIntern(), | ||
| 523 | .storage = .{ .u64 = bytes[index] }, | ||
| 524 | } }), | ||
| 525 | .elems => |elems| elems[index], | ||
| 526 | .repeated_elem => |elem| elem, | ||
| 527 | }; | ||
| 528 | |||
| 529 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 530 | .ty = field_ty, | ||
| 531 | .val = field_val.toValue(), | ||
| 532 | }, code, debug_output, reloc_info)) { | ||
| 533 | .ok => {}, | ||
| 534 | .fail => |em| return Result{ .fail = em }, | ||
| 535 | } | ||
| 536 | const unpadded_field_end = code.items.len - struct_begin; | ||
| 537 | |||
| 538 | // Pad struct members if required | ||
| 539 | const padded_field_end = typed_value.ty.structFieldOffset(index + 1, mod); | ||
| 540 | const padding = math.cast(usize, padded_field_end - unpadded_field_end) orelse return error.Overflow; | ||
| 541 | |||
| 542 | if (padding > 0) { | ||
| 543 | try code.writer().writeByteNTimes(0, padding); | ||
| 544 | } | ||
| 545 | } | ||
| 546 | } | ||
| 547 | }, | ||
| 548 | else => unreachable, | ||
| 668 | }, | 549 | }, |
| 669 | .ErrorUnion => { | 550 | .un => |un| { |
| 670 | const error_ty = typed_value.ty.errorUnionSet(); | 551 | const layout = typed_value.ty.unionGetLayout(mod); |
| 671 | const payload_ty = typed_value.ty.errorUnionPayload(); | ||
| 672 | const is_payload = typed_value.val.errorUnionIsPayload(); | ||
| 673 | 552 | ||
| 674 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 553 | if (layout.payload_size == 0) { |
| 675 | const err_val = if (is_payload) Value.initTag(.zero) else typed_value.val; | ||
| 676 | return generateSymbol(bin_file, src_loc, .{ | 554 | return generateSymbol(bin_file, src_loc, .{ |
| 677 | .ty = error_ty, | 555 | .ty = typed_value.ty.unionTagType(mod).?, |
| 678 | .val = err_val, | 556 | .val = un.tag.toValue(), |
| 679 | }, code, debug_output, reloc_info); | 557 | }, code, debug_output, reloc_info); |
| 680 | } | 558 | } |
| 681 | 559 | ||
| 682 | const payload_align = payload_ty.abiAlignment(target); | 560 | // Check if we should store the tag first. |
| 683 | const error_align = Type.anyerror.abiAlignment(target); | 561 | if (layout.tag_align >= layout.payload_align) { |
| 684 | const abi_align = typed_value.ty.abiAlignment(target); | ||
| 685 | |||
| 686 | // error value first when its type is larger than the error union's payload | ||
| 687 | if (error_align > payload_align) { | ||
| 688 | switch (try generateSymbol(bin_file, src_loc, .{ | 562 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 689 | .ty = error_ty, | 563 | .ty = typed_value.ty.unionTagType(mod).?, |
| 690 | .val = if (is_payload) Value.initTag(.zero) else typed_value.val, | 564 | .val = un.tag.toValue(), |
| 691 | }, code, debug_output, reloc_info)) { | 565 | }, code, debug_output, reloc_info)) { |
| 692 | .ok => {}, | 566 | .ok => {}, |
| 693 | .fail => |em| return Result{ .fail = em }, | 567 | .fail => |em| return Result{ .fail = em }, |
| 694 | } | 568 | } |
| 695 | } | 569 | } |
| 696 | 570 | ||
| 697 | // emit payload part of the error union | 571 | const union_ty = mod.typeToUnion(typed_value.ty).?; |
| 698 | { | 572 | const field_index = typed_value.ty.unionTagFieldIndex(un.tag.toValue(), mod).?; |
| 699 | const begin = code.items.len; | 573 | assert(union_ty.haveFieldTypes()); |
| 700 | const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.initTag(.undef); | 574 | const field_ty = union_ty.fields.values()[field_index].ty; |
| 575 | if (!field_ty.hasRuntimeBits(mod)) { | ||
| 576 | try code.writer().writeByteNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); | ||
| 577 | } else { | ||
| 701 | switch (try generateSymbol(bin_file, src_loc, .{ | 578 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 702 | .ty = payload_ty, | 579 | .ty = field_ty, |
| 703 | .val = payload_val, | 580 | .val = un.val.toValue(), |
| 704 | }, code, debug_output, reloc_info)) { | 581 | }, code, debug_output, reloc_info)) { |
| 705 | .ok => {}, | 582 | .ok => {}, |
| 706 | .fail => |em| return Result{ .fail = em }, | 583 | .fail => |em| return Result{ .fail = em }, |
| 707 | } | 584 | } |
| 708 | const unpadded_end = code.items.len - begin; | ||
| 709 | const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); | ||
| 710 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | ||
| 711 | 585 | ||
| 586 | const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(mod)) orelse return error.Overflow; | ||
| 712 | if (padding > 0) { | 587 | if (padding > 0) { |
| 713 | try code.writer().writeByteNTimes(0, padding); | 588 | try code.writer().writeByteNTimes(0, padding); |
| 714 | } | 589 | } |
| 715 | } | 590 | } |
| 716 | 591 | ||
| 717 | // Payload size is larger than error set, so emit our error set last | 592 | if (layout.tag_size > 0) { |
| 718 | if (error_align <= payload_align) { | ||
| 719 | const begin = code.items.len; | ||
| 720 | switch (try generateSymbol(bin_file, src_loc, .{ | 593 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 721 | .ty = error_ty, | 594 | .ty = union_ty.tag_ty, |
| 722 | .val = if (is_payload) Value.initTag(.zero) else typed_value.val, | 595 | .val = un.tag.toValue(), |
| 723 | }, code, debug_output, reloc_info)) { | 596 | }, code, debug_output, reloc_info)) { |
| 724 | .ok => {}, | 597 | .ok => {}, |
| 725 | .fail => |em| return Result{ .fail = em }, | 598 | .fail => |em| return Result{ .fail = em }, |
| 726 | } | 599 | } |
| 727 | const unpadded_end = code.items.len - begin; | ||
| 728 | const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); | ||
| 729 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | ||
| 730 | |||
| 731 | if (padding > 0) { | ||
| 732 | try code.writer().writeByteNTimes(0, padding); | ||
| 733 | } | ||
| 734 | } | ||
| 735 | |||
| 736 | return Result.ok; | ||
| 737 | }, | ||
| 738 | .ErrorSet => { | ||
| 739 | switch (typed_value.val.tag()) { | ||
| 740 | .@"error" => { | ||
| 741 | const name = typed_value.val.getError().?; | ||
| 742 | const kv = try bin_file.options.module.?.getErrorValue(name); | ||
| 743 | try code.writer().writeInt(u32, kv.value, endian); | ||
| 744 | }, | ||
| 745 | else => { | ||
| 746 | try code.writer().writeByteNTimes(0, @intCast(usize, Type.anyerror.abiSize(target))); | ||
| 747 | }, | ||
| 748 | } | 600 | } |
| 749 | return Result.ok; | ||
| 750 | }, | 601 | }, |
| 751 | .Vector => switch (typed_value.val.tag()) { | 602 | .memoized_call => unreachable, |
| 752 | .bytes => { | ||
| 753 | const bytes = typed_value.val.castTag(.bytes).?.data; | ||
| 754 | const len = math.cast(usize, typed_value.ty.arrayLen()) orelse return error.Overflow; | ||
| 755 | const padding = math.cast(usize, typed_value.ty.abiSize(target) - len) orelse | ||
| 756 | return error.Overflow; | ||
| 757 | try code.ensureUnusedCapacity(len + padding); | ||
| 758 | code.appendSliceAssumeCapacity(bytes[0..len]); | ||
| 759 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | ||
| 760 | return Result.ok; | ||
| 761 | }, | ||
| 762 | .aggregate => { | ||
| 763 | const elem_vals = typed_value.val.castTag(.aggregate).?.data; | ||
| 764 | const elem_ty = typed_value.ty.elemType(); | ||
| 765 | const len = math.cast(usize, typed_value.ty.arrayLen()) orelse return error.Overflow; | ||
| 766 | const padding = math.cast(usize, typed_value.ty.abiSize(target) - | ||
| 767 | (math.divCeil(u64, elem_ty.bitSize(target) * len, 8) catch |err| switch (err) { | ||
| 768 | error.DivisionByZero => unreachable, | ||
| 769 | else => |e| return e, | ||
| 770 | })) orelse return error.Overflow; | ||
| 771 | for (elem_vals[0..len]) |elem_val| { | ||
| 772 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 773 | .ty = elem_ty, | ||
| 774 | .val = elem_val, | ||
| 775 | }, code, debug_output, reloc_info)) { | ||
| 776 | .ok => {}, | ||
| 777 | .fail => |em| return Result{ .fail = em }, | ||
| 778 | } | ||
| 779 | } | ||
| 780 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | ||
| 781 | return Result.ok; | ||
| 782 | }, | ||
| 783 | .repeated => { | ||
| 784 | const array = typed_value.val.castTag(.repeated).?.data; | ||
| 785 | const elem_ty = typed_value.ty.childType(); | ||
| 786 | const len = typed_value.ty.arrayLen(); | ||
| 787 | const padding = math.cast(usize, typed_value.ty.abiSize(target) - | ||
| 788 | (math.divCeil(u64, elem_ty.bitSize(target) * len, 8) catch |err| switch (err) { | ||
| 789 | error.DivisionByZero => unreachable, | ||
| 790 | else => |e| return e, | ||
| 791 | })) orelse return error.Overflow; | ||
| 792 | var index: u64 = 0; | ||
| 793 | while (index < len) : (index += 1) { | ||
| 794 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 795 | .ty = elem_ty, | ||
| 796 | .val = array, | ||
| 797 | }, code, debug_output, reloc_info)) { | ||
| 798 | .ok => {}, | ||
| 799 | .fail => |em| return Result{ .fail = em }, | ||
| 800 | } | ||
| 801 | } | ||
| 802 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | ||
| 803 | return Result.ok; | ||
| 804 | }, | ||
| 805 | .str_lit => { | ||
| 806 | const str_lit = typed_value.val.castTag(.str_lit).?.data; | ||
| 807 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | ||
| 808 | const padding = math.cast(usize, typed_value.ty.abiSize(target) - str_lit.len) orelse | ||
| 809 | return error.Overflow; | ||
| 810 | try code.ensureUnusedCapacity(str_lit.len + padding); | ||
| 811 | code.appendSliceAssumeCapacity(bytes); | ||
| 812 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | ||
| 813 | return Result.ok; | ||
| 814 | }, | ||
| 815 | else => unreachable, | ||
| 816 | }, | ||
| 817 | else => |tag| return Result{ .fail = try ErrorMsg.create( | ||
| 818 | bin_file.allocator, | ||
| 819 | src_loc, | ||
| 820 | "TODO implement generateSymbol for type '{s}'", | ||
| 821 | .{@tagName(tag)}, | ||
| 822 | ) }, | ||
| 823 | } | 603 | } |
| 604 | return .ok; | ||
| 824 | } | 605 | } |
| 825 | 606 | ||
| 826 | fn lowerParentPtr( | 607 | fn lowerParentPtr( |
| 827 | bin_file: *link.File, | 608 | bin_file: *link.File, |
| 828 | src_loc: Module.SrcLoc, | 609 | src_loc: Module.SrcLoc, |
| 829 | typed_value: TypedValue, | 610 | parent_ptr: InternPool.Index, |
| 830 | parent_ptr: Value, | ||
| 831 | code: *std.ArrayList(u8), | 611 | code: *std.ArrayList(u8), |
| 832 | debug_output: DebugInfoOutput, | 612 | debug_output: DebugInfoOutput, |
| 833 | reloc_info: RelocInfo, | 613 | reloc_info: RelocInfo, |
| 834 | ) CodeGenError!Result { | 614 | ) CodeGenError!Result { |
| 835 | const target = bin_file.options.target; | 615 | const mod = bin_file.options.module.?; |
| 836 | switch (parent_ptr.tag()) { | 616 | const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr; |
| 837 | .field_ptr => { | 617 | assert(ptr.len == .none); |
| 838 | const field_ptr = parent_ptr.castTag(.field_ptr).?.data; | 618 | return switch (ptr.addr) { |
| 619 | .decl, .mut_decl => try lowerDeclRef( | ||
| 620 | bin_file, | ||
| 621 | src_loc, | ||
| 622 | switch (ptr.addr) { | ||
| 623 | .decl => |decl| decl, | ||
| 624 | .mut_decl => |mut_decl| mut_decl.decl, | ||
| 625 | else => unreachable, | ||
| 626 | }, | ||
| 627 | code, | ||
| 628 | debug_output, | ||
| 629 | reloc_info, | ||
| 630 | ), | ||
| 631 | .int => |int| try generateSymbol(bin_file, src_loc, .{ | ||
| 632 | .ty = Type.usize, | ||
| 633 | .val = int.toValue(), | ||
| 634 | }, code, debug_output, reloc_info), | ||
| 635 | .eu_payload => |eu_payload| try lowerParentPtr( | ||
| 636 | bin_file, | ||
| 637 | src_loc, | ||
| 638 | eu_payload, | ||
| 639 | code, | ||
| 640 | debug_output, | ||
| 641 | reloc_info.offset(@intCast(u32, errUnionPayloadOffset( | ||
| 642 | mod.intern_pool.typeOf(eu_payload).toType(), | ||
| 643 | mod, | ||
| 644 | ))), | ||
| 645 | ), | ||
| 646 | .opt_payload => |opt_payload| try lowerParentPtr( | ||
| 647 | bin_file, | ||
| 648 | src_loc, | ||
| 649 | opt_payload, | ||
| 650 | code, | ||
| 651 | debug_output, | ||
| 652 | reloc_info, | ||
| 653 | ), | ||
| 654 | .elem => |elem| try lowerParentPtr( | ||
| 655 | bin_file, | ||
| 656 | src_loc, | ||
| 657 | elem.base, | ||
| 658 | code, | ||
| 659 | debug_output, | ||
| 660 | reloc_info.offset(@intCast(u32, elem.index * | ||
| 661 | mod.intern_pool.typeOf(elem.base).toType().elemType2(mod).abiSize(mod))), | ||
| 662 | ), | ||
| 663 | .field => |field| { | ||
| 664 | const base_type = mod.intern_pool.indexToKey(mod.intern_pool.typeOf(field.base)).ptr_type.child; | ||
| 839 | return lowerParentPtr( | 665 | return lowerParentPtr( |
| 840 | bin_file, | 666 | bin_file, |
| 841 | src_loc, | 667 | src_loc, |
| 842 | typed_value, | 668 | field.base, |
| 843 | field_ptr.container_ptr, | ||
| 844 | code, | 669 | code, |
| 845 | debug_output, | 670 | debug_output, |
| 846 | reloc_info.offset(@intCast(u32, switch (field_ptr.container_ty.zigTypeTag()) { | 671 | reloc_info.offset(switch (mod.intern_pool.indexToKey(base_type)) { |
| 847 | .Pointer => offset: { | 672 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 848 | assert(field_ptr.container_ty.isSlice()); | 673 | .One, .Many, .C => unreachable, |
| 849 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 674 | .Slice => switch (field.index) { |
| 850 | break :offset switch (field_ptr.field_index) { | ||
| 851 | 0 => 0, | 675 | 0 => 0, |
| 852 | 1 => field_ptr.container_ty.slicePtrFieldType(&buf).abiSize(target), | 676 | 1 => @divExact(mod.getTarget().ptrBitWidth(), 8), |
| 853 | else => unreachable, | 677 | else => unreachable, |
| 854 | }; | 678 | }, |
| 855 | }, | 679 | }, |
| 856 | .Struct, .Union => field_ptr.container_ty.structFieldOffset( | 680 | .struct_type, |
| 857 | field_ptr.field_index, | 681 | .anon_struct_type, |
| 858 | target, | 682 | .union_type, |
| 859 | ), | 683 | => @intCast(u32, base_type.toType().structFieldOffset( |
| 860 | else => return Result{ .fail = try ErrorMsg.create( | 684 | @intCast(u32, field.index), |
| 861 | bin_file.allocator, | 685 | mod, |
| 862 | src_loc, | 686 | )), |
| 863 | "TODO implement lowerParentPtr for field_ptr with a container of type {}", | 687 | else => unreachable, |
| 864 | .{field_ptr.container_ty.fmt(bin_file.options.module.?)}, | 688 | }), |
| 865 | ) }, | ||
| 866 | })), | ||
| 867 | ); | ||
| 868 | }, | ||
| 869 | .elem_ptr => { | ||
| 870 | const elem_ptr = parent_ptr.castTag(.elem_ptr).?.data; | ||
| 871 | return lowerParentPtr( | ||
| 872 | bin_file, | ||
| 873 | src_loc, | ||
| 874 | typed_value, | ||
| 875 | elem_ptr.array_ptr, | ||
| 876 | code, | ||
| 877 | debug_output, | ||
| 878 | reloc_info.offset(@intCast(u32, elem_ptr.index * elem_ptr.elem_ty.abiSize(target))), | ||
| 879 | ); | ||
| 880 | }, | ||
| 881 | .opt_payload_ptr => { | ||
| 882 | const opt_payload_ptr = parent_ptr.castTag(.opt_payload_ptr).?.data; | ||
| 883 | return lowerParentPtr( | ||
| 884 | bin_file, | ||
| 885 | src_loc, | ||
| 886 | typed_value, | ||
| 887 | opt_payload_ptr.container_ptr, | ||
| 888 | code, | ||
| 889 | debug_output, | ||
| 890 | reloc_info, | ||
| 891 | ); | ||
| 892 | }, | ||
| 893 | .eu_payload_ptr => { | ||
| 894 | const eu_payload_ptr = parent_ptr.castTag(.eu_payload_ptr).?.data; | ||
| 895 | const pl_ty = eu_payload_ptr.container_ty.errorUnionPayload(); | ||
| 896 | return lowerParentPtr( | ||
| 897 | bin_file, | ||
| 898 | src_loc, | ||
| 899 | typed_value, | ||
| 900 | eu_payload_ptr.container_ptr, | ||
| 901 | code, | ||
| 902 | debug_output, | ||
| 903 | reloc_info.offset(@intCast(u32, errUnionPayloadOffset(pl_ty, target))), | ||
| 904 | ); | 689 | ); |
| 905 | }, | 690 | }, |
| 906 | .variable, .decl_ref, .decl_ref_mut => |tag| return lowerDeclRef( | 691 | .comptime_field => unreachable, |
| 907 | bin_file, | 692 | }; |
| 908 | src_loc, | ||
| 909 | typed_value, | ||
| 910 | switch (tag) { | ||
| 911 | .variable => parent_ptr.castTag(.variable).?.data.owner_decl, | ||
| 912 | .decl_ref => parent_ptr.castTag(.decl_ref).?.data, | ||
| 913 | .decl_ref_mut => parent_ptr.castTag(.decl_ref_mut).?.data.decl_index, | ||
| 914 | else => unreachable, | ||
| 915 | }, | ||
| 916 | code, | ||
| 917 | debug_output, | ||
| 918 | reloc_info, | ||
| 919 | ), | ||
| 920 | else => |tag| return Result{ .fail = try ErrorMsg.create( | ||
| 921 | bin_file.allocator, | ||
| 922 | src_loc, | ||
| 923 | "TODO implement lowerParentPtr for type '{s}'", | ||
| 924 | .{@tagName(tag)}, | ||
| 925 | ) }, | ||
| 926 | } | ||
| 927 | } | 693 | } |
| 928 | 694 | ||
| 929 | const RelocInfo = struct { | 695 | const RelocInfo = struct { |
| ... | @@ -938,51 +704,25 @@ const RelocInfo = struct { | ... | @@ -938,51 +704,25 @@ const RelocInfo = struct { |
| 938 | fn lowerDeclRef( | 704 | fn lowerDeclRef( |
| 939 | bin_file: *link.File, | 705 | bin_file: *link.File, |
| 940 | src_loc: Module.SrcLoc, | 706 | src_loc: Module.SrcLoc, |
| 941 | typed_value: TypedValue, | ||
| 942 | decl_index: Module.Decl.Index, | 707 | decl_index: Module.Decl.Index, |
| 943 | code: *std.ArrayList(u8), | 708 | code: *std.ArrayList(u8), |
| 944 | debug_output: DebugInfoOutput, | 709 | debug_output: DebugInfoOutput, |
| 945 | reloc_info: RelocInfo, | 710 | reloc_info: RelocInfo, |
| 946 | ) CodeGenError!Result { | 711 | ) CodeGenError!Result { |
| 712 | _ = src_loc; | ||
| 713 | _ = debug_output; | ||
| 947 | const target = bin_file.options.target; | 714 | const target = bin_file.options.target; |
| 948 | const module = bin_file.options.module.?; | 715 | const mod = bin_file.options.module.?; |
| 949 | if (typed_value.ty.isSlice()) { | ||
| 950 | // generate ptr | ||
| 951 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 952 | const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf); | ||
| 953 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 954 | .ty = slice_ptr_field_type, | ||
| 955 | .val = typed_value.val, | ||
| 956 | }, code, debug_output, reloc_info)) { | ||
| 957 | .ok => {}, | ||
| 958 | .fail => |em| return Result{ .fail = em }, | ||
| 959 | } | ||
| 960 | |||
| 961 | // generate length | ||
| 962 | var slice_len: Value.Payload.U64 = .{ | ||
| 963 | .base = .{ .tag = .int_u64 }, | ||
| 964 | .data = typed_value.val.sliceLen(module), | ||
| 965 | }; | ||
| 966 | switch (try generateSymbol(bin_file, src_loc, .{ | ||
| 967 | .ty = Type.usize, | ||
| 968 | .val = Value.initPayload(&slice_len.base), | ||
| 969 | }, code, debug_output, reloc_info)) { | ||
| 970 | .ok => {}, | ||
| 971 | .fail => |em| return Result{ .fail = em }, | ||
| 972 | } | ||
| 973 | |||
| 974 | return Result.ok; | ||
| 975 | } | ||
| 976 | 716 | ||
| 977 | const ptr_width = target.ptrBitWidth(); | 717 | const ptr_width = target.ptrBitWidth(); |
| 978 | const decl = module.declPtr(decl_index); | 718 | const decl = mod.declPtr(decl_index); |
| 979 | const is_fn_body = decl.ty.zigTypeTag() == .Fn; | 719 | const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn; |
| 980 | if (!is_fn_body and !decl.ty.hasRuntimeBits()) { | 720 | if (!is_fn_body and !decl.ty.hasRuntimeBits(mod)) { |
| 981 | try code.writer().writeByteNTimes(0xaa, @divExact(ptr_width, 8)); | 721 | try code.writer().writeByteNTimes(0xaa, @divExact(ptr_width, 8)); |
| 982 | return Result.ok; | 722 | return Result.ok; |
| 983 | } | 723 | } |
| 984 | 724 | ||
| 985 | module.markDeclAlive(decl); | 725 | try mod.markDeclAlive(decl); |
| 986 | 726 | ||
| 987 | const vaddr = try bin_file.getDeclVAddr(decl_index, .{ | 727 | const vaddr = try bin_file.getDeclVAddr(decl_index, .{ |
| 988 | .parent_atom_index = reloc_info.parent_atom_index, | 728 | .parent_atom_index = reloc_info.parent_atom_index, |
| ... | @@ -1059,16 +799,16 @@ fn genDeclRef( | ... | @@ -1059,16 +799,16 @@ fn genDeclRef( |
| 1059 | tv: TypedValue, | 799 | tv: TypedValue, |
| 1060 | decl_index: Module.Decl.Index, | 800 | decl_index: Module.Decl.Index, |
| 1061 | ) CodeGenError!GenResult { | 801 | ) CodeGenError!GenResult { |
| 1062 | const module = bin_file.options.module.?; | 802 | const mod = bin_file.options.module.?; |
| 1063 | log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmt(module), tv.val.fmtValue(tv.ty, module) }); | 803 | log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmt(mod), tv.val.fmtValue(tv.ty, mod) }); |
| 1064 | 804 | ||
| 1065 | const target = bin_file.options.target; | 805 | const target = bin_file.options.target; |
| 1066 | const ptr_bits = target.ptrBitWidth(); | 806 | const ptr_bits = target.ptrBitWidth(); |
| 1067 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 807 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 1068 | 808 | ||
| 1069 | const decl = module.declPtr(decl_index); | 809 | const decl = mod.declPtr(decl_index); |
| 1070 | 810 | ||
| 1071 | if (!decl.ty.isFnOrHasRuntimeBitsIgnoreComptime()) { | 811 | if (!decl.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { |
| 1072 | const imm: u64 = switch (ptr_bytes) { | 812 | const imm: u64 = switch (ptr_bytes) { |
| 1073 | 1 => 0xaa, | 813 | 1 => 0xaa, |
| 1074 | 2 => 0xaaaa, | 814 | 2 => 0xaaaa, |
| ... | @@ -1080,20 +820,20 @@ fn genDeclRef( | ... | @@ -1080,20 +820,20 @@ fn genDeclRef( |
| 1080 | } | 820 | } |
| 1081 | 821 | ||
| 1082 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? | 822 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? |
| 1083 | if (tv.ty.castPtrToFn()) |fn_ty| { | 823 | if (tv.ty.castPtrToFn(mod)) |fn_ty| { |
| 1084 | if (fn_ty.fnInfo().is_generic) { | 824 | if (mod.typeToFunc(fn_ty).?.is_generic) { |
| 1085 | return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(target) }); | 825 | return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(mod) }); |
| 1086 | } | 826 | } |
| 1087 | } else if (tv.ty.zigTypeTag() == .Pointer) { | 827 | } else if (tv.ty.zigTypeTag(mod) == .Pointer) { |
| 1088 | const elem_ty = tv.ty.elemType2(); | 828 | const elem_ty = tv.ty.elemType2(mod); |
| 1089 | if (!elem_ty.hasRuntimeBits()) { | 829 | if (!elem_ty.hasRuntimeBits(mod)) { |
| 1090 | return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(target) }); | 830 | return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(mod) }); |
| 1091 | } | 831 | } |
| 1092 | } | 832 | } |
| 1093 | 833 | ||
| 1094 | module.markDeclAlive(decl); | 834 | try mod.markDeclAlive(decl); |
| 1095 | 835 | ||
| 1096 | const is_threadlocal = tv.val.isPtrToThreadLocal(module) and !bin_file.options.single_threaded; | 836 | const is_threadlocal = tv.val.isPtrToThreadLocal(mod) and !bin_file.options.single_threaded; |
| 1097 | 837 | ||
| 1098 | if (bin_file.cast(link.File.Elf)) |elf_file| { | 838 | if (bin_file.cast(link.File.Elf)) |elf_file| { |
| 1099 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | 839 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); |
| ... | @@ -1157,57 +897,56 @@ pub fn genTypedValue( | ... | @@ -1157,57 +897,56 @@ pub fn genTypedValue( |
| 1157 | arg_tv: TypedValue, | 897 | arg_tv: TypedValue, |
| 1158 | owner_decl_index: Module.Decl.Index, | 898 | owner_decl_index: Module.Decl.Index, |
| 1159 | ) CodeGenError!GenResult { | 899 | ) CodeGenError!GenResult { |
| 900 | const mod = bin_file.options.module.?; | ||
| 1160 | var typed_value = arg_tv; | 901 | var typed_value = arg_tv; |
| 1161 | if (typed_value.val.castTag(.runtime_value)) |rt| { | 902 | switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) { |
| 1162 | typed_value.val = rt.data; | 903 | .runtime_value => |rt| typed_value.val = rt.val.toValue(), |
| 904 | else => {}, | ||
| 1163 | } | 905 | } |
| 1164 | 906 | ||
| 1165 | const mod = bin_file.options.module.?; | ||
| 1166 | log.debug("genTypedValue: ty = {}, val = {}", .{ | 907 | log.debug("genTypedValue: ty = {}, val = {}", .{ |
| 1167 | typed_value.ty.fmt(mod), | 908 | typed_value.ty.fmt(mod), |
| 1168 | typed_value.val.fmtValue(typed_value.ty, mod), | 909 | typed_value.val.fmtValue(typed_value.ty, mod), |
| 1169 | }); | 910 | }); |
| 1170 | 911 | ||
| 1171 | if (typed_value.val.isUndef()) | 912 | if (typed_value.val.isUndef(mod)) |
| 1172 | return GenResult.mcv(.undef); | 913 | return GenResult.mcv(.undef); |
| 1173 | 914 | ||
| 1174 | const target = bin_file.options.target; | 915 | const target = bin_file.options.target; |
| 1175 | const ptr_bits = target.ptrBitWidth(); | 916 | const ptr_bits = target.ptrBitWidth(); |
| 1176 | 917 | ||
| 1177 | if (!typed_value.ty.isSlice()) { | 918 | if (!typed_value.ty.isSlice(mod)) switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) { |
| 1178 | if (typed_value.val.castTag(.variable)) |payload| { | 919 | .ptr => |ptr| switch (ptr.addr) { |
| 1179 | return genDeclRef(bin_file, src_loc, typed_value, payload.data.owner_decl); | 920 | .decl => |decl| return genDeclRef(bin_file, src_loc, typed_value, decl), |
| 1180 | } | 921 | .mut_decl => |mut_decl| return genDeclRef(bin_file, src_loc, typed_value, mut_decl.decl), |
| 1181 | if (typed_value.val.castTag(.decl_ref)) |payload| { | 922 | else => {}, |
| 1182 | return genDeclRef(bin_file, src_loc, typed_value, payload.data); | 923 | }, |
| 1183 | } | 924 | else => {}, |
| 1184 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | 925 | }; |
| 1185 | return genDeclRef(bin_file, src_loc, typed_value, payload.data.decl_index); | ||
| 1186 | } | ||
| 1187 | } | ||
| 1188 | 926 | ||
| 1189 | switch (typed_value.ty.zigTypeTag()) { | 927 | switch (typed_value.ty.zigTypeTag(mod)) { |
| 1190 | .Void => return GenResult.mcv(.none), | 928 | .Void => return GenResult.mcv(.none), |
| 1191 | .Pointer => switch (typed_value.ty.ptrSize()) { | 929 | .Pointer => switch (typed_value.ty.ptrSize(mod)) { |
| 1192 | .Slice => {}, | 930 | .Slice => {}, |
| 1193 | else => { | 931 | else => switch (typed_value.val.toIntern()) { |
| 1194 | switch (typed_value.val.tag()) { | 932 | .null_value => { |
| 1195 | .null_value => { | 933 | return GenResult.mcv(.{ .immediate = 0 }); |
| 1196 | return GenResult.mcv(.{ .immediate = 0 }); | 934 | }, |
| 1197 | }, | 935 | .none => {}, |
| 1198 | .int_u64 => { | 936 | else => switch (mod.intern_pool.indexToKey(typed_value.val.toIntern())) { |
| 1199 | return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); | 937 | .int => { |
| 938 | return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(mod) }); | ||
| 1200 | }, | 939 | }, |
| 1201 | else => {}, | 940 | else => {}, |
| 1202 | } | 941 | }, |
| 1203 | }, | 942 | }, |
| 1204 | }, | 943 | }, |
| 1205 | .Int => { | 944 | .Int => { |
| 1206 | const info = typed_value.ty.intInfo(target); | 945 | const info = typed_value.ty.intInfo(mod); |
| 1207 | if (info.bits <= ptr_bits) { | 946 | if (info.bits <= ptr_bits) { |
| 1208 | const unsigned = switch (info.signedness) { | 947 | const unsigned = switch (info.signedness) { |
| 1209 | .signed => @bitCast(u64, typed_value.val.toSignedInt(target)), | 948 | .signed => @bitCast(u64, typed_value.val.toSignedInt(mod)), |
| 1210 | .unsigned => typed_value.val.toUnsignedInt(target), | 949 | .unsigned => typed_value.val.toUnsignedInt(mod), |
| 1211 | }; | 950 | }; |
| 1212 | return GenResult.mcv(.{ .immediate = unsigned }); | 951 | return GenResult.mcv(.{ .immediate = unsigned }); |
| 1213 | } | 952 | } |
| ... | @@ -1216,78 +955,46 @@ pub fn genTypedValue( | ... | @@ -1216,78 +955,46 @@ pub fn genTypedValue( |
| 1216 | return GenResult.mcv(.{ .immediate = @boolToInt(typed_value.val.toBool()) }); | 955 | return GenResult.mcv(.{ .immediate = @boolToInt(typed_value.val.toBool()) }); |
| 1217 | }, | 956 | }, |
| 1218 | .Optional => { | 957 | .Optional => { |
| 1219 | if (typed_value.ty.isPtrLikeOptional()) { | 958 | if (typed_value.ty.isPtrLikeOptional(mod)) { |
| 1220 | if (typed_value.val.tag() == .null_value) return GenResult.mcv(.{ .immediate = 0 }); | ||
| 1221 | |||
| 1222 | var buf: Type.Payload.ElemType = undefined; | ||
| 1223 | return genTypedValue(bin_file, src_loc, .{ | 959 | return genTypedValue(bin_file, src_loc, .{ |
| 1224 | .ty = typed_value.ty.optionalChild(&buf), | 960 | .ty = typed_value.ty.optionalChild(mod), |
| 1225 | .val = if (typed_value.val.castTag(.opt_payload)) |pl| pl.data else typed_value.val, | 961 | .val = typed_value.val.optionalValue(mod) orelse return GenResult.mcv(.{ .immediate = 0 }), |
| 1226 | }, owner_decl_index); | 962 | }, owner_decl_index); |
| 1227 | } else if (typed_value.ty.abiSize(target) == 1) { | 963 | } else if (typed_value.ty.abiSize(mod) == 1) { |
| 1228 | return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull()) }); | 964 | return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull(mod)) }); |
| 1229 | } | 965 | } |
| 1230 | }, | 966 | }, |
| 1231 | .Enum => { | 967 | .Enum => { |
| 1232 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | 968 | const enum_tag = mod.intern_pool.indexToKey(typed_value.val.toIntern()).enum_tag; |
| 1233 | switch (typed_value.ty.tag()) { | 969 | const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int); |
| 1234 | .enum_simple => { | 970 | return genTypedValue(bin_file, src_loc, .{ |
| 1235 | return GenResult.mcv(.{ .immediate = field_index.data }); | 971 | .ty = int_tag_ty.toType(), |
| 1236 | }, | 972 | .val = enum_tag.int.toValue(), |
| 1237 | .enum_numbered, .enum_full, .enum_nonexhaustive => { | 973 | }, owner_decl_index); |
| 1238 | const enum_values = if (typed_value.ty.castTag(.enum_numbered)) |pl| | ||
| 1239 | pl.data.values | ||
| 1240 | else | ||
| 1241 | typed_value.ty.cast(Type.Payload.EnumFull).?.data.values; | ||
| 1242 | if (enum_values.count() != 0) { | ||
| 1243 | const tag_val = enum_values.keys()[field_index.data]; | ||
| 1244 | var buf: Type.Payload.Bits = undefined; | ||
| 1245 | return genTypedValue(bin_file, src_loc, .{ | ||
| 1246 | .ty = typed_value.ty.intTagType(&buf), | ||
| 1247 | .val = tag_val, | ||
| 1248 | }, owner_decl_index); | ||
| 1249 | } else { | ||
| 1250 | return GenResult.mcv(.{ .immediate = field_index.data }); | ||
| 1251 | } | ||
| 1252 | }, | ||
| 1253 | else => unreachable, | ||
| 1254 | } | ||
| 1255 | } else { | ||
| 1256 | var int_tag_buffer: Type.Payload.Bits = undefined; | ||
| 1257 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | ||
| 1258 | return genTypedValue(bin_file, src_loc, .{ | ||
| 1259 | .ty = int_tag_ty, | ||
| 1260 | .val = typed_value.val, | ||
| 1261 | }, owner_decl_index); | ||
| 1262 | } | ||
| 1263 | }, | 974 | }, |
| 1264 | .ErrorSet => { | 975 | .ErrorSet => { |
| 1265 | switch (typed_value.val.tag()) { | 976 | const err_name = mod.intern_pool.indexToKey(typed_value.val.toIntern()).err.name; |
| 1266 | .@"error" => { | 977 | const error_index = mod.global_error_set.getIndex(err_name).?; |
| 1267 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | 978 | return GenResult.mcv(.{ .immediate = error_index }); |
| 1268 | const module = bin_file.options.module.?; | ||
| 1269 | const global_error_set = module.global_error_set; | ||
| 1270 | const error_index = global_error_set.get(err_name).?; | ||
| 1271 | return GenResult.mcv(.{ .immediate = error_index }); | ||
| 1272 | }, | ||
| 1273 | else => { | ||
| 1274 | // In this case we are rendering an error union which has a 0 bits payload. | ||
| 1275 | return GenResult.mcv(.{ .immediate = 0 }); | ||
| 1276 | }, | ||
| 1277 | } | ||
| 1278 | }, | 979 | }, |
| 1279 | .ErrorUnion => { | 980 | .ErrorUnion => { |
| 1280 | const error_type = typed_value.ty.errorUnionSet(); | 981 | const err_type = typed_value.ty.errorUnionSet(mod); |
| 1281 | const payload_type = typed_value.ty.errorUnionPayload(); | 982 | const payload_type = typed_value.ty.errorUnionPayload(mod); |
| 1282 | const is_pl = typed_value.val.errorUnionIsPayload(); | 983 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1283 | |||
| 1284 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | ||
| 1285 | // We use the error type directly as the type. | 984 | // We use the error type directly as the type. |
| 1286 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); | 985 | switch (mod.intern_pool.indexToKey(typed_value.val.toIntern()).error_union.val) { |
| 1287 | return genTypedValue(bin_file, src_loc, .{ | 986 | .err_name => |err_name| return genTypedValue(bin_file, src_loc, .{ |
| 1288 | .ty = error_type, | 987 | .ty = err_type, |
| 1289 | .val = err_val, | 988 | .val = (try mod.intern(.{ .err = .{ |
| 1290 | }, owner_decl_index); | 989 | .ty = err_type.toIntern(), |
| 990 | .name = err_name, | ||
| 991 | } })).toValue(), | ||
| 992 | }, owner_decl_index), | ||
| 993 | .payload => return genTypedValue(bin_file, src_loc, .{ | ||
| 994 | .ty = Type.err_int, | ||
| 995 | .val = try mod.intValue(Type.err_int, 0), | ||
| 996 | }, owner_decl_index), | ||
| 997 | } | ||
| 1291 | } | 998 | } |
| 1292 | }, | 999 | }, |
| 1293 | 1000 | ||
| ... | @@ -1306,23 +1013,23 @@ pub fn genTypedValue( | ... | @@ -1306,23 +1013,23 @@ pub fn genTypedValue( |
| 1306 | return genUnnamedConst(bin_file, src_loc, typed_value, owner_decl_index); | 1013 | return genUnnamedConst(bin_file, src_loc, typed_value, owner_decl_index); |
| 1307 | } | 1014 | } |
| 1308 | 1015 | ||
| 1309 | pub fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u64 { | 1016 | pub fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u64 { |
| 1310 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return 0; | 1017 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; |
| 1311 | const payload_align = payload_ty.abiAlignment(target); | 1018 | const payload_align = payload_ty.abiAlignment(mod); |
| 1312 | const error_align = Type.anyerror.abiAlignment(target); | 1019 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1313 | if (payload_align >= error_align or !payload_ty.hasRuntimeBitsIgnoreComptime()) { | 1020 | if (payload_align >= error_align or !payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1314 | return 0; | 1021 | return 0; |
| 1315 | } else { | 1022 | } else { |
| 1316 | return mem.alignForwardGeneric(u64, Type.anyerror.abiSize(target), payload_align); | 1023 | return mem.alignForwardGeneric(u64, Type.anyerror.abiSize(mod), payload_align); |
| 1317 | } | 1024 | } |
| 1318 | } | 1025 | } |
| 1319 | 1026 | ||
| 1320 | pub fn errUnionErrorOffset(payload_ty: Type, target: std.Target) u64 { | 1027 | pub fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u64 { |
| 1321 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return 0; | 1028 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return 0; |
| 1322 | const payload_align = payload_ty.abiAlignment(target); | 1029 | const payload_align = payload_ty.abiAlignment(mod); |
| 1323 | const error_align = Type.anyerror.abiAlignment(target); | 1030 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1324 | if (payload_align >= error_align and payload_ty.hasRuntimeBitsIgnoreComptime()) { | 1031 | if (payload_align >= error_align and payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1325 | return mem.alignForwardGeneric(u64, payload_ty.abiSize(target), error_align); | 1032 | return mem.alignForwardGeneric(u64, payload_ty.abiSize(mod), error_align); |
| 1326 | } else { | 1033 | } else { |
| 1327 | return 0; | 1034 | return 0; |
| 1328 | } | 1035 | } |
src/codegen/c.zig+1341-1369| ... | @@ -16,6 +16,7 @@ const trace = @import("../tracy.zig").trace; | ... | @@ -16,6 +16,7 @@ const trace = @import("../tracy.zig").trace; |
| 16 | const LazySrcLoc = Module.LazySrcLoc; | 16 | const LazySrcLoc = Module.LazySrcLoc; |
| 17 | const Air = @import("../Air.zig"); | 17 | const Air = @import("../Air.zig"); |
| 18 | const Liveness = @import("../Liveness.zig"); | 18 | const Liveness = @import("../Liveness.zig"); |
| 19 | const InternPool = @import("../InternPool.zig"); | ||
| 19 | 20 | ||
| 20 | const BigIntLimb = std.math.big.Limb; | 21 | const BigIntLimb = std.math.big.Limb; |
| 21 | const BigInt = std.math.big.int; | 22 | const BigInt = std.math.big.int; |
| ... | @@ -256,7 +257,7 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) { | ... | @@ -256,7 +257,7 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) { |
| 256 | return .{ .data = ident }; | 257 | return .{ .data = ident }; |
| 257 | } | 258 | } |
| 258 | 259 | ||
| 259 | /// This data is available when outputting .c code for a `*Module.Fn`. | 260 | /// This data is available when outputting .c code for a `Module.Fn.Index`. |
| 260 | /// It is not available when generating .h file. | 261 | /// It is not available when generating .h file. |
| 261 | pub const Function = struct { | 262 | pub const Function = struct { |
| 262 | air: Air, | 263 | air: Air, |
| ... | @@ -267,7 +268,7 @@ pub const Function = struct { | ... | @@ -267,7 +268,7 @@ pub const Function = struct { |
| 267 | next_block_index: usize = 0, | 268 | next_block_index: usize = 0, |
| 268 | object: Object, | 269 | object: Object, |
| 269 | lazy_fns: LazyFnMap, | 270 | lazy_fns: LazyFnMap, |
| 270 | func: *Module.Fn, | 271 | func_index: Module.Fn.Index, |
| 271 | /// All the locals, to be emitted at the top of the function. | 272 | /// All the locals, to be emitted at the top of the function. |
| 272 | locals: std.ArrayListUnmanaged(Local) = .{}, | 273 | locals: std.ArrayListUnmanaged(Local) = .{}, |
| 273 | /// Which locals are available for reuse, based on Type. | 274 | /// Which locals are available for reuse, based on Type. |
| ... | @@ -285,10 +286,11 @@ pub const Function = struct { | ... | @@ -285,10 +286,11 @@ pub const Function = struct { |
| 285 | const gop = try f.value_map.getOrPut(inst); | 286 | const gop = try f.value_map.getOrPut(inst); |
| 286 | if (gop.found_existing) return gop.value_ptr.*; | 287 | if (gop.found_existing) return gop.value_ptr.*; |
| 287 | 288 | ||
| 288 | const val = f.air.value(ref).?; | 289 | const mod = f.object.dg.module; |
| 289 | const ty = f.air.typeOf(ref); | 290 | const val = (try f.air.value(ref, mod)).?; |
| 291 | const ty = f.typeOf(ref); | ||
| 290 | 292 | ||
| 291 | const result: CValue = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: { | 293 | const result: CValue = if (lowersToArray(ty, mod)) result: { |
| 292 | const writer = f.object.code_header.writer(); | 294 | const writer = f.object.code_header.writer(); |
| 293 | const alignment = 0; | 295 | const alignment = 0; |
| 294 | const decl_c_value = try f.allocLocalValue(ty, alignment); | 296 | const decl_c_value = try f.allocLocalValue(ty, alignment); |
| ... | @@ -318,11 +320,11 @@ pub const Function = struct { | ... | @@ -318,11 +320,11 @@ pub const Function = struct { |
| 318 | /// those which go into `allocs`. This function does not add the resulting local into `allocs`; | 320 | /// those which go into `allocs`. This function does not add the resulting local into `allocs`; |
| 319 | /// that responsibility lies with the caller. | 321 | /// that responsibility lies with the caller. |
| 320 | fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue { | 322 | fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue { |
| 323 | const mod = f.object.dg.module; | ||
| 321 | const gpa = f.object.dg.gpa; | 324 | const gpa = f.object.dg.gpa; |
| 322 | const target = f.object.dg.module.getTarget(); | ||
| 323 | try f.locals.append(gpa, .{ | 325 | try f.locals.append(gpa, .{ |
| 324 | .cty_idx = try f.typeToIndex(ty, .complete), | 326 | .cty_idx = try f.typeToIndex(ty, .complete), |
| 325 | .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target)), | 327 | .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)), |
| 326 | }); | 328 | }); |
| 327 | return .{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) }; | 329 | return .{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) }; |
| 328 | } | 330 | } |
| ... | @@ -336,10 +338,10 @@ pub const Function = struct { | ... | @@ -336,10 +338,10 @@ pub const Function = struct { |
| 336 | /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should | 338 | /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should |
| 337 | /// not be used for persistent locals (i.e. those in `allocs`). | 339 | /// not be used for persistent locals (i.e. those in `allocs`). |
| 338 | fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue { | 340 | fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue { |
| 339 | const target = f.object.dg.module.getTarget(); | 341 | const mod = f.object.dg.module; |
| 340 | if (f.free_locals_map.getPtr(.{ | 342 | if (f.free_locals_map.getPtr(.{ |
| 341 | .cty_idx = try f.typeToIndex(ty, .complete), | 343 | .cty_idx = try f.typeToIndex(ty, .complete), |
| 342 | .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target)), | 344 | .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)), |
| 343 | })) |locals_list| { | 345 | })) |locals_list| { |
| 344 | if (locals_list.popOrNull()) |local_entry| { | 346 | if (locals_list.popOrNull()) |local_entry| { |
| 345 | return .{ .new_local = local_entry.key }; | 347 | return .{ .new_local = local_entry.key }; |
| ... | @@ -352,8 +354,9 @@ pub const Function = struct { | ... | @@ -352,8 +354,9 @@ pub const Function = struct { |
| 352 | fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void { | 354 | fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void { |
| 353 | switch (c_value) { | 355 | switch (c_value) { |
| 354 | .constant => |inst| { | 356 | .constant => |inst| { |
| 355 | const ty = f.air.typeOf(inst); | 357 | const mod = f.object.dg.module; |
| 356 | const val = f.air.value(inst).?; | 358 | const ty = f.typeOf(inst); |
| 359 | const val = (try f.air.value(inst, mod)).?; | ||
| 357 | return f.object.dg.renderValue(w, ty, val, location); | 360 | return f.object.dg.renderValue(w, ty, val, location); |
| 358 | }, | 361 | }, |
| 359 | .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location), | 362 | .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location), |
| ... | @@ -364,8 +367,9 @@ pub const Function = struct { | ... | @@ -364,8 +367,9 @@ pub const Function = struct { |
| 364 | fn writeCValueDeref(f: *Function, w: anytype, c_value: CValue) !void { | 367 | fn writeCValueDeref(f: *Function, w: anytype, c_value: CValue) !void { |
| 365 | switch (c_value) { | 368 | switch (c_value) { |
| 366 | .constant => |inst| { | 369 | .constant => |inst| { |
| 367 | const ty = f.air.typeOf(inst); | 370 | const mod = f.object.dg.module; |
| 368 | const val = f.air.value(inst).?; | 371 | const ty = f.typeOf(inst); |
| 372 | const val = (try f.air.value(inst, mod)).?; | ||
| 369 | try w.writeAll("(*"); | 373 | try w.writeAll("(*"); |
| 370 | try f.object.dg.renderValue(w, ty, val, .Other); | 374 | try f.object.dg.renderValue(w, ty, val, .Other); |
| 371 | return w.writeByte(')'); | 375 | return w.writeByte(')'); |
| ... | @@ -377,8 +381,9 @@ pub const Function = struct { | ... | @@ -377,8 +381,9 @@ pub const Function = struct { |
| 377 | fn writeCValueMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { | 381 | fn writeCValueMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { |
| 378 | switch (c_value) { | 382 | switch (c_value) { |
| 379 | .constant => |inst| { | 383 | .constant => |inst| { |
| 380 | const ty = f.air.typeOf(inst); | 384 | const mod = f.object.dg.module; |
| 381 | const val = f.air.value(inst).?; | 385 | const ty = f.typeOf(inst); |
| 386 | const val = (try f.air.value(inst, mod)).?; | ||
| 382 | try f.object.dg.renderValue(w, ty, val, .Other); | 387 | try f.object.dg.renderValue(w, ty, val, .Other); |
| 383 | try w.writeByte('.'); | 388 | try w.writeByte('.'); |
| 384 | return f.writeCValue(w, member, .Other); | 389 | return f.writeCValue(w, member, .Other); |
| ... | @@ -390,8 +395,9 @@ pub const Function = struct { | ... | @@ -390,8 +395,9 @@ pub const Function = struct { |
| 390 | fn writeCValueDerefMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { | 395 | fn writeCValueDerefMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { |
| 391 | switch (c_value) { | 396 | switch (c_value) { |
| 392 | .constant => |inst| { | 397 | .constant => |inst| { |
| 393 | const ty = f.air.typeOf(inst); | 398 | const mod = f.object.dg.module; |
| 394 | const val = f.air.value(inst).?; | 399 | const ty = f.typeOf(inst); |
| 400 | const val = (try f.air.value(inst, mod)).?; | ||
| 395 | try w.writeByte('('); | 401 | try w.writeByte('('); |
| 396 | try f.object.dg.renderValue(w, ty, val, .Other); | 402 | try f.object.dg.renderValue(w, ty, val, .Other); |
| 397 | try w.writeAll(")->"); | 403 | try w.writeAll(")->"); |
| ... | @@ -446,6 +452,7 @@ pub const Function = struct { | ... | @@ -446,6 +452,7 @@ pub const Function = struct { |
| 446 | var promoted = f.object.dg.ctypes.promote(gpa); | 452 | var promoted = f.object.dg.ctypes.promote(gpa); |
| 447 | defer f.object.dg.ctypes.demote(promoted); | 453 | defer f.object.dg.ctypes.demote(promoted); |
| 448 | const arena = promoted.arena.allocator(); | 454 | const arena = promoted.arena.allocator(); |
| 455 | const mod = f.object.dg.module; | ||
| 449 | 456 | ||
| 450 | gop.value_ptr.* = .{ | 457 | gop.value_ptr.* = .{ |
| 451 | .fn_name = switch (key) { | 458 | .fn_name = switch (key) { |
| ... | @@ -454,12 +461,12 @@ pub const Function = struct { | ... | @@ -454,12 +461,12 @@ pub const Function = struct { |
| 454 | .never_inline, | 461 | .never_inline, |
| 455 | => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{ | 462 | => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{ |
| 456 | @tagName(key), | 463 | @tagName(key), |
| 457 | fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)), | 464 | fmtIdent(mod.intern_pool.stringToSlice(mod.declPtr(owner_decl).name)), |
| 458 | @enumToInt(owner_decl), | 465 | @enumToInt(owner_decl), |
| 459 | }), | 466 | }), |
| 460 | }, | 467 | }, |
| 461 | .data = switch (key) { | 468 | .data = switch (key) { |
| 462 | .tag_name => .{ .tag_name = try data.tag_name.copy(arena) }, | 469 | .tag_name => .{ .tag_name = data.tag_name }, |
| 463 | .never_tail => .{ .never_tail = data.never_tail }, | 470 | .never_tail => .{ .never_tail = data.never_tail }, |
| 464 | .never_inline => .{ .never_inline = data.never_inline }, | 471 | .never_inline => .{ .never_inline = data.never_inline }, |
| 465 | }, | 472 | }, |
| ... | @@ -480,6 +487,16 @@ pub const Function = struct { | ... | @@ -480,6 +487,16 @@ pub const Function = struct { |
| 480 | f.object.dg.ctypes.deinit(gpa); | 487 | f.object.dg.ctypes.deinit(gpa); |
| 481 | f.object.dg.fwd_decl.deinit(); | 488 | f.object.dg.fwd_decl.deinit(); |
| 482 | } | 489 | } |
| 490 | |||
| 491 | fn typeOf(f: *Function, inst: Air.Inst.Ref) Type { | ||
| 492 | const mod = f.object.dg.module; | ||
| 493 | return f.air.typeOf(inst, &mod.intern_pool); | ||
| 494 | } | ||
| 495 | |||
| 496 | fn typeOfIndex(f: *Function, inst: Air.Inst.Index) Type { | ||
| 497 | const mod = f.object.dg.module; | ||
| 498 | return f.air.typeOfIndex(inst, &mod.intern_pool); | ||
| 499 | } | ||
| 483 | }; | 500 | }; |
| 484 | 501 | ||
| 485 | /// This data is available when outputting .c code for a `Module`. | 502 | /// This data is available when outputting .c code for a `Module`. |
| ... | @@ -508,8 +525,9 @@ pub const DeclGen = struct { | ... | @@ -508,8 +525,9 @@ pub const DeclGen = struct { |
| 508 | 525 | ||
| 509 | fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { | 526 | fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { |
| 510 | @setCold(true); | 527 | @setCold(true); |
| 528 | const mod = dg.module; | ||
| 511 | const src = LazySrcLoc.nodeOffset(0); | 529 | const src = LazySrcLoc.nodeOffset(0); |
| 512 | const src_loc = src.toSrcLoc(dg.decl.?); | 530 | const src_loc = src.toSrcLoc(dg.decl.?, mod); |
| 513 | dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args); | 531 | dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args); |
| 514 | return error.AnalysisFail; | 532 | return error.AnalysisFail; |
| 515 | } | 533 | } |
| ... | @@ -522,53 +540,28 @@ pub const DeclGen = struct { | ... | @@ -522,53 +540,28 @@ pub const DeclGen = struct { |
| 522 | decl_index: Decl.Index, | 540 | decl_index: Decl.Index, |
| 523 | location: ValueRenderLocation, | 541 | location: ValueRenderLocation, |
| 524 | ) error{ OutOfMemory, AnalysisFail }!void { | 542 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 525 | const decl = dg.module.declPtr(decl_index); | 543 | const mod = dg.module; |
| 544 | const decl = mod.declPtr(decl_index); | ||
| 526 | assert(decl.has_tv); | 545 | assert(decl.has_tv); |
| 527 | 546 | ||
| 528 | // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. | 547 | // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. |
| 529 | if (ty.isPtrAtRuntime() and !decl.ty.isFnOrHasRuntimeBits()) { | 548 | if (ty.isPtrAtRuntime(mod) and !decl.ty.isFnOrHasRuntimeBits(mod)) { |
| 530 | return dg.writeCValue(writer, .{ .undef = ty }); | 549 | return dg.writeCValue(writer, .{ .undef = ty }); |
| 531 | } | 550 | } |
| 532 | 551 | ||
| 533 | // Chase function values in order to be able to reference the original function. | 552 | // Chase function values in order to be able to reference the original function. |
| 534 | inline for (.{ .function, .extern_fn }) |tag| | 553 | if (decl.val.getFunction(mod)) |func| if (func.owner_decl != decl_index) |
| 535 | if (decl.val.castTag(tag)) |func| | 554 | return dg.renderDeclValue(writer, ty, val, func.owner_decl, location); |
| 536 | if (func.data.owner_decl != decl_index) | 555 | if (decl.val.getExternFunc(mod)) |extern_func| if (extern_func.decl != decl_index) |
| 537 | return dg.renderDeclValue(writer, ty, val, func.data.owner_decl, location); | 556 | return dg.renderDeclValue(writer, ty, val, extern_func.decl, location); |
| 538 | 557 | ||
| 539 | if (decl.val.castTag(.variable)) |var_payload| | 558 | if (decl.val.getVariable(mod)) |variable| try dg.renderFwdDecl(decl_index, variable); |
| 540 | try dg.renderFwdDecl(decl_index, var_payload.data); | ||
| 541 | |||
| 542 | if (ty.isSlice()) { | ||
| 543 | if (location == .StaticInitializer) { | ||
| 544 | try writer.writeByte('{'); | ||
| 545 | } else { | ||
| 546 | try writer.writeByte('('); | ||
| 547 | try dg.renderType(writer, ty); | ||
| 548 | try writer.writeAll("){ .ptr = "); | ||
| 549 | } | ||
| 550 | |||
| 551 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 552 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer); | ||
| 553 | |||
| 554 | var len_pl: Value.Payload.U64 = .{ | ||
| 555 | .base = .{ .tag = .int_u64 }, | ||
| 556 | .data = val.sliceLen(dg.module), | ||
| 557 | }; | ||
| 558 | const len_val = Value.initPayload(&len_pl.base); | ||
| 559 | |||
| 560 | if (location == .StaticInitializer) { | ||
| 561 | return writer.print(", {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val, .Other)}); | ||
| 562 | } else { | ||
| 563 | return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val, .Other)}); | ||
| 564 | } | ||
| 565 | } | ||
| 566 | 559 | ||
| 567 | // We shouldn't cast C function pointers as this is UB (when you call | 560 | // We shouldn't cast C function pointers as this is UB (when you call |
| 568 | // them). The analysis until now should ensure that the C function | 561 | // them). The analysis until now should ensure that the C function |
| 569 | // pointers are compatible. If they are not, then there is a bug | 562 | // pointers are compatible. If they are not, then there is a bug |
| 570 | // somewhere and we should let the C compiler tell us about it. | 563 | // somewhere and we should let the C compiler tell us about it. |
| 571 | const need_typecast = if (ty.castPtrToFn()) |_| false else !ty.eql(decl.ty, dg.module); | 564 | const need_typecast = if (ty.castPtrToFn(mod)) |_| false else !ty.childType(mod).eql(decl.ty, mod); |
| 572 | if (need_typecast) { | 565 | if (need_typecast) { |
| 573 | try writer.writeAll("(("); | 566 | try writer.writeAll("(("); |
| 574 | try dg.renderType(writer, ty); | 567 | try dg.renderType(writer, ty); |
| ... | @@ -579,127 +572,124 @@ pub const DeclGen = struct { | ... | @@ -579,127 +572,124 @@ pub const DeclGen = struct { |
| 579 | if (need_typecast) try writer.writeByte(')'); | 572 | if (need_typecast) try writer.writeByte(')'); |
| 580 | } | 573 | } |
| 581 | 574 | ||
| 582 | // Renders a "parent" pointer by recursing to the root decl/variable | 575 | /// Renders a "parent" pointer by recursing to the root decl/variable |
| 583 | // that its contents are defined with respect to. | 576 | /// that its contents are defined with respect to. |
| 584 | // | 577 | fn renderParentPtr( |
| 585 | // Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr | 578 | dg: *DeclGen, |
| 586 | fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void { | 579 | writer: anytype, |
| 587 | if (!ptr_ty.isSlice()) { | 580 | ptr_val: InternPool.Index, |
| 588 | try writer.writeByte('('); | 581 | location: ValueRenderLocation, |
| 589 | try dg.renderType(writer, ptr_ty); | 582 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 590 | try writer.writeByte(')'); | 583 | const mod = dg.module; |
| 591 | } | 584 | const ptr_ty = mod.intern_pool.typeOf(ptr_val).toType(); |
| 592 | switch (ptr_val.tag()) { | 585 | const ptr_cty = try dg.typeToIndex(ptr_ty, .complete); |
| 593 | .int_u64, .one => try writer.print("{x}", .{try dg.fmtIntLiteral(Type.usize, ptr_val, .Other)}), | 586 | const ptr = mod.intern_pool.indexToKey(ptr_val).ptr; |
| 594 | .decl_ref_mut, .decl_ref, .variable => { | 587 | switch (ptr.addr) { |
| 595 | const decl_index = switch (ptr_val.tag()) { | 588 | .decl, .mut_decl => try dg.renderDeclValue( |
| 596 | .decl_ref => ptr_val.castTag(.decl_ref).?.data, | 589 | writer, |
| 597 | .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index, | 590 | ptr_ty, |
| 598 | .variable => ptr_val.castTag(.variable).?.data.owner_decl, | 591 | ptr_val.toValue(), |
| 592 | switch (ptr.addr) { | ||
| 593 | .decl => |decl| decl, | ||
| 594 | .mut_decl => |mut_decl| mut_decl.decl, | ||
| 595 | else => unreachable, | ||
| 596 | }, | ||
| 597 | location, | ||
| 598 | ), | ||
| 599 | .int => |int| try writer.print("{x}", .{ | ||
| 600 | try dg.fmtIntLiteral(Type.usize, int.toValue(), .Other), | ||
| 601 | }), | ||
| 602 | .eu_payload, .opt_payload => |base| { | ||
| 603 | const ptr_base_ty = mod.intern_pool.typeOf(base).toType(); | ||
| 604 | const base_ty = ptr_base_ty.childType(mod); | ||
| 605 | // Ensure complete type definition is visible before accessing fields. | ||
| 606 | _ = try dg.typeToIndex(base_ty, .complete); | ||
| 607 | const payload_ty = switch (ptr.addr) { | ||
| 608 | .eu_payload => base_ty.errorUnionPayload(mod), | ||
| 609 | .opt_payload => base_ty.optionalChild(mod), | ||
| 599 | else => unreachable, | 610 | else => unreachable, |
| 600 | }; | 611 | }; |
| 601 | try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location); | 612 | const ptr_payload_ty = try mod.adjustPtrTypeChild(ptr_base_ty, payload_ty); |
| 613 | const ptr_payload_cty = try dg.typeToIndex(ptr_payload_ty, .complete); | ||
| 614 | if (ptr_cty != ptr_payload_cty) { | ||
| 615 | try writer.writeByte('('); | ||
| 616 | try dg.renderCType(writer, ptr_cty); | ||
| 617 | try writer.writeByte(')'); | ||
| 618 | } | ||
| 619 | try writer.writeAll("&("); | ||
| 620 | try dg.renderParentPtr(writer, base, location); | ||
| 621 | try writer.writeAll(")->payload"); | ||
| 602 | }, | 622 | }, |
| 603 | .field_ptr => { | 623 | .elem => |elem| { |
| 604 | const target = dg.module.getTarget(); | 624 | const ptr_base_ty = mod.intern_pool.typeOf(elem.base).toType(); |
| 605 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | 625 | const elem_ty = ptr_base_ty.elemType2(mod); |
| 606 | 626 | const ptr_elem_ty = try mod.adjustPtrTypeChild(ptr_base_ty, elem_ty); | |
| 627 | const ptr_elem_cty = try dg.typeToIndex(ptr_elem_ty, .complete); | ||
| 628 | if (ptr_cty != ptr_elem_cty) { | ||
| 629 | try writer.writeByte('('); | ||
| 630 | try dg.renderCType(writer, ptr_cty); | ||
| 631 | try writer.writeByte(')'); | ||
| 632 | } | ||
| 633 | try writer.writeAll("&("); | ||
| 634 | if (mod.intern_pool.indexToKey(ptr_base_ty.toIntern()).ptr_type.flags.size == .One) | ||
| 635 | try writer.writeByte('*'); | ||
| 636 | try dg.renderParentPtr(writer, elem.base, location); | ||
| 637 | try writer.print(")[{d}]", .{elem.index}); | ||
| 638 | }, | ||
| 639 | .field => |field| { | ||
| 640 | const ptr_base_ty = mod.intern_pool.typeOf(field.base).toType(); | ||
| 641 | const base_ty = ptr_base_ty.childType(mod); | ||
| 607 | // Ensure complete type definition is visible before accessing fields. | 642 | // Ensure complete type definition is visible before accessing fields. |
| 608 | _ = try dg.typeToIndex(field_ptr.container_ty, .complete); | 643 | _ = try dg.typeToIndex(base_ty, .complete); |
| 609 | 644 | const field_ty = switch (mod.intern_pool.indexToKey(base_ty.toIntern())) { | |
| 610 | var container_ptr_pl = ptr_ty.ptrInfo(); | 645 | .anon_struct_type, .struct_type, .union_type => base_ty.structFieldType(@intCast(usize, field.index), mod), |
| 611 | container_ptr_pl.data.pointee_type = field_ptr.container_ty; | 646 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 612 | const container_ptr_ty = Type.initPayload(&container_ptr_pl.base); | 647 | .One, .Many, .C => unreachable, |
| 613 | 648 | .Slice => switch (field.index) { | |
| 614 | switch (fieldLocation( | 649 | Value.slice_ptr_index => base_ty.slicePtrFieldType(mod), |
| 615 | field_ptr.container_ty, | 650 | Value.slice_len_index => Type.usize, |
| 616 | ptr_ty, | 651 | else => unreachable, |
| 617 | @intCast(u32, field_ptr.field_index), | 652 | }, |
| 618 | target, | 653 | }, |
| 619 | )) { | 654 | else => unreachable, |
| 620 | .begin => try dg.renderParentPtr( | 655 | }; |
| 621 | writer, | 656 | const ptr_field_ty = try mod.adjustPtrTypeChild(ptr_base_ty, field_ty); |
| 622 | field_ptr.container_ptr, | 657 | const ptr_field_cty = try dg.typeToIndex(ptr_field_ty, .complete); |
| 623 | container_ptr_ty, | 658 | if (ptr_cty != ptr_field_cty) { |
| 624 | location, | 659 | try writer.writeByte('('); |
| 625 | ), | 660 | try dg.renderCType(writer, ptr_cty); |
| 626 | .field => |field| { | 661 | try writer.writeByte(')'); |
| 662 | } | ||
| 663 | switch (fieldLocation(base_ty, ptr_ty, @intCast(u32, field.index), mod)) { | ||
| 664 | .begin => try dg.renderParentPtr(writer, field.base, location), | ||
| 665 | .field => |name| { | ||
| 627 | try writer.writeAll("&("); | 666 | try writer.writeAll("&("); |
| 628 | try dg.renderParentPtr( | 667 | try dg.renderParentPtr(writer, field.base, location); |
| 629 | writer, | ||
| 630 | field_ptr.container_ptr, | ||
| 631 | container_ptr_ty, | ||
| 632 | location, | ||
| 633 | ); | ||
| 634 | try writer.writeAll(")->"); | 668 | try writer.writeAll(")->"); |
| 635 | try dg.writeCValue(writer, field); | 669 | try dg.writeCValue(writer, name); |
| 636 | }, | 670 | }, |
| 637 | .byte_offset => |byte_offset| { | 671 | .byte_offset => |byte_offset| { |
| 638 | var u8_ptr_pl = ptr_ty.ptrInfo(); | 672 | const u8_ptr_ty = try mod.adjustPtrTypeChild(ptr_ty, Type.u8); |
| 639 | u8_ptr_pl.data.pointee_type = Type.u8; | 673 | const byte_offset_val = try mod.intValue(Type.usize, byte_offset); |
| 640 | const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); | ||
| 641 | |||
| 642 | var byte_offset_pl = Value.Payload.U64{ | ||
| 643 | .base = .{ .tag = .int_u64 }, | ||
| 644 | .data = byte_offset, | ||
| 645 | }; | ||
| 646 | const byte_offset_val = Value.initPayload(&byte_offset_pl.base); | ||
| 647 | 674 | ||
| 648 | try writer.writeAll("(("); | 675 | try writer.writeAll("(("); |
| 649 | try dg.renderType(writer, u8_ptr_ty); | 676 | try dg.renderType(writer, u8_ptr_ty); |
| 650 | try writer.writeByte(')'); | 677 | try writer.writeByte(')'); |
| 651 | try dg.renderParentPtr( | 678 | try dg.renderParentPtr(writer, field.base, location); |
| 652 | writer, | ||
| 653 | field_ptr.container_ptr, | ||
| 654 | container_ptr_ty, | ||
| 655 | location, | ||
| 656 | ); | ||
| 657 | try writer.print(" + {})", .{ | 679 | try writer.print(" + {})", .{ |
| 658 | try dg.fmtIntLiteral(Type.usize, byte_offset_val, .Other), | 680 | try dg.fmtIntLiteral(Type.usize, byte_offset_val, .Other), |
| 659 | }); | 681 | }); |
| 660 | }, | 682 | }, |
| 661 | .end => { | 683 | .end => { |
| 662 | try writer.writeAll("(("); | 684 | try writer.writeAll("(("); |
| 663 | try dg.renderParentPtr( | 685 | try dg.renderParentPtr(writer, field.base, location); |
| 664 | writer, | ||
| 665 | field_ptr.container_ptr, | ||
| 666 | container_ptr_ty, | ||
| 667 | location, | ||
| 668 | ); | ||
| 669 | try writer.print(") + {})", .{ | 686 | try writer.print(") + {})", .{ |
| 670 | try dg.fmtIntLiteral(Type.usize, Value.one, .Other), | 687 | try dg.fmtIntLiteral(Type.usize, try mod.intValue(Type.usize, 1), .Other), |
| 671 | }); | 688 | }); |
| 672 | }, | 689 | }, |
| 673 | } | 690 | } |
| 674 | }, | 691 | }, |
| 675 | .elem_ptr => { | 692 | .comptime_field => unreachable, |
| 676 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | ||
| 677 | var elem_ptr_ty_pl: Type.Payload.ElemType = .{ | ||
| 678 | .base = .{ .tag = .c_mut_pointer }, | ||
| 679 | .data = elem_ptr.elem_ty, | ||
| 680 | }; | ||
| 681 | const elem_ptr_ty = Type.initPayload(&elem_ptr_ty_pl.base); | ||
| 682 | |||
| 683 | try writer.writeAll("&("); | ||
| 684 | try dg.renderParentPtr(writer, elem_ptr.array_ptr, elem_ptr_ty, location); | ||
| 685 | try writer.print(")[{d}]", .{elem_ptr.index}); | ||
| 686 | }, | ||
| 687 | .opt_payload_ptr, .eu_payload_ptr => { | ||
| 688 | const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data; | ||
| 689 | var container_ptr_ty_pl: Type.Payload.ElemType = .{ | ||
| 690 | .base = .{ .tag = .c_mut_pointer }, | ||
| 691 | .data = payload_ptr.container_ty, | ||
| 692 | }; | ||
| 693 | const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base); | ||
| 694 | |||
| 695 | // Ensure complete type definition is visible before accessing fields. | ||
| 696 | _ = try dg.typeToIndex(payload_ptr.container_ty, .complete); | ||
| 697 | |||
| 698 | try writer.writeAll("&("); | ||
| 699 | try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location); | ||
| 700 | try writer.writeAll(")->payload"); | ||
| 701 | }, | ||
| 702 | else => unreachable, | ||
| 703 | } | 693 | } |
| 704 | } | 694 | } |
| 705 | 695 | ||
| ... | @@ -710,23 +700,25 @@ pub const DeclGen = struct { | ... | @@ -710,23 +700,25 @@ pub const DeclGen = struct { |
| 710 | arg_val: Value, | 700 | arg_val: Value, |
| 711 | location: ValueRenderLocation, | 701 | location: ValueRenderLocation, |
| 712 | ) error{ OutOfMemory, AnalysisFail }!void { | 702 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 703 | const mod = dg.module; | ||
| 713 | var val = arg_val; | 704 | var val = arg_val; |
| 714 | if (val.castTag(.runtime_value)) |rt| { | 705 | switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 715 | val = rt.data; | 706 | .runtime_value => |rt| val = rt.val.toValue(), |
| 707 | else => {}, | ||
| 716 | } | 708 | } |
| 717 | const target = dg.module.getTarget(); | 709 | const target = mod.getTarget(); |
| 718 | const initializer_type: ValueRenderLocation = switch (location) { | 710 | const initializer_type: ValueRenderLocation = switch (location) { |
| 719 | .StaticInitializer => .StaticInitializer, | 711 | .StaticInitializer => .StaticInitializer, |
| 720 | else => .Initializer, | 712 | else => .Initializer, |
| 721 | }; | 713 | }; |
| 722 | 714 | ||
| 723 | const safety_on = switch (dg.module.optimizeMode()) { | 715 | const safety_on = switch (mod.optimizeMode()) { |
| 724 | .Debug, .ReleaseSafe => true, | 716 | .Debug, .ReleaseSafe => true, |
| 725 | .ReleaseFast, .ReleaseSmall => false, | 717 | .ReleaseFast, .ReleaseSmall => false, |
| 726 | }; | 718 | }; |
| 727 | 719 | ||
| 728 | if (val.isUndefDeep()) { | 720 | if (val.isUndefDeep(mod)) { |
| 729 | switch (ty.zigTypeTag()) { | 721 | switch (ty.zigTypeTag(mod)) { |
| 730 | .Bool => { | 722 | .Bool => { |
| 731 | if (safety_on) { | 723 | if (safety_on) { |
| 732 | return writer.writeAll("0xaa"); | 724 | return writer.writeAll("0xaa"); |
| ... | @@ -737,8 +729,8 @@ pub const DeclGen = struct { | ... | @@ -737,8 +729,8 @@ pub const DeclGen = struct { |
| 737 | .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val, location)}), | 729 | .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val, location)}), |
| 738 | .Float => { | 730 | .Float => { |
| 739 | const bits = ty.floatBits(target); | 731 | const bits = ty.floatBits(target); |
| 740 | var repr_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = bits }; | 732 | // All unsigned ints matching float types are pre-allocated. |
| 741 | const repr_ty = Type.initPayload(&repr_pl.base); | 733 | const repr_ty = mod.intType(.unsigned, bits) catch unreachable; |
| 742 | 734 | ||
| 743 | try writer.writeAll("zig_cast_"); | 735 | try writer.writeAll("zig_cast_"); |
| 744 | try dg.renderTypeForBuiltinFnName(writer, ty); | 736 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| ... | @@ -757,7 +749,7 @@ pub const DeclGen = struct { | ... | @@ -757,7 +749,7 @@ pub const DeclGen = struct { |
| 757 | try dg.renderValue(writer, repr_ty, Value.undef, .FunctionArgument); | 749 | try dg.renderValue(writer, repr_ty, Value.undef, .FunctionArgument); |
| 758 | return writer.writeByte(')'); | 750 | return writer.writeByte(')'); |
| 759 | }, | 751 | }, |
| 760 | .Pointer => if (ty.isSlice()) { | 752 | .Pointer => if (ty.isSlice(mod)) { |
| 761 | if (!location.isInitializer()) { | 753 | if (!location.isInitializer()) { |
| 762 | try writer.writeByte('('); | 754 | try writer.writeByte('('); |
| 763 | try dg.renderType(writer, ty); | 755 | try dg.renderType(writer, ty); |
| ... | @@ -765,8 +757,7 @@ pub const DeclGen = struct { | ... | @@ -765,8 +757,7 @@ pub const DeclGen = struct { |
| 765 | } | 757 | } |
| 766 | 758 | ||
| 767 | try writer.writeAll("{("); | 759 | try writer.writeAll("{("); |
| 768 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 760 | const ptr_ty = ty.slicePtrFieldType(mod); |
| 769 | const ptr_ty = ty.slicePtrFieldType(&buf); | ||
| 770 | try dg.renderType(writer, ptr_ty); | 761 | try dg.renderType(writer, ptr_ty); |
| 771 | return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); | 762 | return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); |
| 772 | } else { | 763 | } else { |
| ... | @@ -775,14 +766,13 @@ pub const DeclGen = struct { | ... | @@ -775,14 +766,13 @@ pub const DeclGen = struct { |
| 775 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); | 766 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); |
| 776 | }, | 767 | }, |
| 777 | .Optional => { | 768 | .Optional => { |
| 778 | var opt_buf: Type.Payload.ElemType = undefined; | 769 | const payload_ty = ty.optionalChild(mod); |
| 779 | const payload_ty = ty.optionalChild(&opt_buf); | ||
| 780 | 770 | ||
| 781 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 771 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 782 | return dg.renderValue(writer, Type.bool, val, location); | 772 | return dg.renderValue(writer, Type.bool, val, location); |
| 783 | } | 773 | } |
| 784 | 774 | ||
| 785 | if (ty.optionalReprIsPayload()) { | 775 | if (ty.optionalReprIsPayload(mod)) { |
| 786 | return dg.renderValue(writer, payload_ty, val, location); | 776 | return dg.renderValue(writer, payload_ty, val, location); |
| 787 | } | 777 | } |
| 788 | 778 | ||
| ... | @@ -798,7 +788,7 @@ pub const DeclGen = struct { | ... | @@ -798,7 +788,7 @@ pub const DeclGen = struct { |
| 798 | try dg.renderValue(writer, Type.bool, val, initializer_type); | 788 | try dg.renderValue(writer, Type.bool, val, initializer_type); |
| 799 | return writer.writeAll(" }"); | 789 | return writer.writeAll(" }"); |
| 800 | }, | 790 | }, |
| 801 | .Struct => switch (ty.containerLayout()) { | 791 | .Struct => switch (ty.containerLayout(mod)) { |
| 802 | .Auto, .Extern => { | 792 | .Auto, .Extern => { |
| 803 | if (!location.isInitializer()) { | 793 | if (!location.isInitializer()) { |
| 804 | try writer.writeByte('('); | 794 | try writer.writeByte('('); |
| ... | @@ -808,10 +798,10 @@ pub const DeclGen = struct { | ... | @@ -808,10 +798,10 @@ pub const DeclGen = struct { |
| 808 | 798 | ||
| 809 | try writer.writeByte('{'); | 799 | try writer.writeByte('{'); |
| 810 | var empty = true; | 800 | var empty = true; |
| 811 | for (0..ty.structFieldCount()) |field_i| { | 801 | for (0..ty.structFieldCount(mod)) |field_i| { |
| 812 | if (ty.structFieldIsComptime(field_i)) continue; | 802 | if (ty.structFieldIsComptime(field_i, mod)) continue; |
| 813 | const field_ty = ty.structFieldType(field_i); | 803 | const field_ty = ty.structFieldType(field_i, mod); |
| 814 | if (!field_ty.hasRuntimeBits()) continue; | 804 | if (!field_ty.hasRuntimeBits(mod)) continue; |
| 815 | 805 | ||
| 816 | if (!empty) try writer.writeByte(','); | 806 | if (!empty) try writer.writeByte(','); |
| 817 | try dg.renderValue(writer, field_ty, val, initializer_type); | 807 | try dg.renderValue(writer, field_ty, val, initializer_type); |
| ... | @@ -831,29 +821,29 @@ pub const DeclGen = struct { | ... | @@ -831,29 +821,29 @@ pub const DeclGen = struct { |
| 831 | } | 821 | } |
| 832 | 822 | ||
| 833 | try writer.writeByte('{'); | 823 | try writer.writeByte('{'); |
| 834 | if (ty.unionTagTypeSafety()) |tag_ty| { | 824 | if (ty.unionTagTypeSafety(mod)) |tag_ty| { |
| 835 | const layout = ty.unionGetLayout(target); | 825 | const layout = ty.unionGetLayout(mod); |
| 836 | if (layout.tag_size != 0) { | 826 | if (layout.tag_size != 0) { |
| 837 | try writer.writeAll(" .tag = "); | 827 | try writer.writeAll(" .tag = "); |
| 838 | try dg.renderValue(writer, tag_ty, val, initializer_type); | 828 | try dg.renderValue(writer, tag_ty, val, initializer_type); |
| 839 | } | 829 | } |
| 840 | if (ty.unionHasAllZeroBitFieldTypes()) return try writer.writeByte('}'); | 830 | if (ty.unionHasAllZeroBitFieldTypes(mod)) return try writer.writeByte('}'); |
| 841 | if (layout.tag_size != 0) try writer.writeByte(','); | 831 | if (layout.tag_size != 0) try writer.writeByte(','); |
| 842 | try writer.writeAll(" .payload = {"); | 832 | try writer.writeAll(" .payload = {"); |
| 843 | } | 833 | } |
| 844 | for (ty.unionFields().values()) |field| { | 834 | for (ty.unionFields(mod).values()) |field| { |
| 845 | if (!field.ty.hasRuntimeBits()) continue; | 835 | if (!field.ty.hasRuntimeBits(mod)) continue; |
| 846 | try dg.renderValue(writer, field.ty, val, initializer_type); | 836 | try dg.renderValue(writer, field.ty, val, initializer_type); |
| 847 | break; | 837 | break; |
| 848 | } | 838 | } |
| 849 | if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); | 839 | if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}'); |
| 850 | return writer.writeByte('}'); | 840 | return writer.writeByte('}'); |
| 851 | }, | 841 | }, |
| 852 | .ErrorUnion => { | 842 | .ErrorUnion => { |
| 853 | const payload_ty = ty.errorUnionPayload(); | 843 | const payload_ty = ty.errorUnionPayload(mod); |
| 854 | const error_ty = ty.errorUnionSet(); | 844 | const error_ty = ty.errorUnionSet(mod); |
| 855 | 845 | ||
| 856 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 846 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 857 | return dg.renderValue(writer, error_ty, val, location); | 847 | return dg.renderValue(writer, error_ty, val, location); |
| 858 | } | 848 | } |
| 859 | 849 | ||
| ... | @@ -870,11 +860,11 @@ pub const DeclGen = struct { | ... | @@ -870,11 +860,11 @@ pub const DeclGen = struct { |
| 870 | return writer.writeAll(" }"); | 860 | return writer.writeAll(" }"); |
| 871 | }, | 861 | }, |
| 872 | .Array, .Vector => { | 862 | .Array, .Vector => { |
| 873 | const ai = ty.arrayInfo(); | 863 | const ai = ty.arrayInfo(mod); |
| 874 | if (ai.elem_type.eql(Type.u8, dg.module)) { | 864 | if (ai.elem_type.eql(Type.u8, mod)) { |
| 875 | var literal = stringLiteral(writer); | 865 | var literal = stringLiteral(writer); |
| 876 | try literal.start(); | 866 | try literal.start(); |
| 877 | const c_len = ty.arrayLenIncludingSentinel(); | 867 | const c_len = ty.arrayLenIncludingSentinel(mod); |
| 878 | var index: u64 = 0; | 868 | var index: u64 = 0; |
| 879 | while (index < c_len) : (index += 1) | 869 | while (index < c_len) : (index += 1) |
| 880 | try literal.writeChar(0xaa); | 870 | try literal.writeChar(0xaa); |
| ... | @@ -887,11 +877,11 @@ pub const DeclGen = struct { | ... | @@ -887,11 +877,11 @@ pub const DeclGen = struct { |
| 887 | } | 877 | } |
| 888 | 878 | ||
| 889 | try writer.writeByte('{'); | 879 | try writer.writeByte('{'); |
| 890 | const c_len = ty.arrayLenIncludingSentinel(); | 880 | const c_len = ty.arrayLenIncludingSentinel(mod); |
| 891 | var index: u64 = 0; | 881 | var index: u64 = 0; |
| 892 | while (index < c_len) : (index += 1) { | 882 | while (index < c_len) : (index += 1) { |
| 893 | if (index > 0) try writer.writeAll(", "); | 883 | if (index > 0) try writer.writeAll(", "); |
| 894 | try dg.renderValue(writer, ty.childType(), val, initializer_type); | 884 | try dg.renderValue(writer, ty.childType(mod), val, initializer_type); |
| 895 | } | 885 | } |
| 896 | return writer.writeByte('}'); | 886 | return writer.writeByte('}'); |
| 897 | } | 887 | } |
| ... | @@ -916,23 +906,129 @@ pub const DeclGen = struct { | ... | @@ -916,23 +906,129 @@ pub const DeclGen = struct { |
| 916 | } | 906 | } |
| 917 | unreachable; | 907 | unreachable; |
| 918 | } | 908 | } |
| 919 | switch (ty.zigTypeTag()) { | 909 | |
| 920 | .Int => switch (val.tag()) { | 910 | switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 921 | .field_ptr, | 911 | // types, not values |
| 922 | .elem_ptr, | 912 | .int_type, |
| 923 | .opt_payload_ptr, | 913 | .ptr_type, |
| 924 | .eu_payload_ptr, | 914 | .array_type, |
| 925 | .decl_ref_mut, | 915 | .vector_type, |
| 926 | .decl_ref, | 916 | .opt_type, |
| 927 | => try dg.renderParentPtr(writer, val, ty, location), | 917 | .anyframe_type, |
| 928 | else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, location)}), | 918 | .error_union_type, |
| 919 | .simple_type, | ||
| 920 | .struct_type, | ||
| 921 | .anon_struct_type, | ||
| 922 | .union_type, | ||
| 923 | .opaque_type, | ||
| 924 | .enum_type, | ||
| 925 | .func_type, | ||
| 926 | .error_set_type, | ||
| 927 | .inferred_error_set_type, | ||
| 928 | // memoization, not values | ||
| 929 | .memoized_call, | ||
| 930 | => unreachable, | ||
| 931 | |||
| 932 | .undef, .runtime_value => unreachable, // handled above | ||
| 933 | .simple_value => |simple_value| switch (simple_value) { | ||
| 934 | // non-runtime values | ||
| 935 | .undefined => unreachable, | ||
| 936 | .void => unreachable, | ||
| 937 | .null => unreachable, | ||
| 938 | .empty_struct => unreachable, | ||
| 939 | .@"unreachable" => unreachable, | ||
| 940 | .generic_poison => unreachable, | ||
| 941 | |||
| 942 | .false => try writer.writeAll("false"), | ||
| 943 | .true => try writer.writeAll("true"), | ||
| 929 | }, | 944 | }, |
| 930 | .Float => { | 945 | .variable, |
| 946 | .extern_func, | ||
| 947 | .func, | ||
| 948 | .enum_literal, | ||
| 949 | .empty_enum_value, | ||
| 950 | => unreachable, // non-runtime values | ||
| 951 | .int => |int| switch (int.storage) { | ||
| 952 | .u64, .i64, .big_int => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, location)}), | ||
| 953 | .lazy_align, .lazy_size => { | ||
| 954 | try writer.writeAll("(("); | ||
| 955 | try dg.renderType(writer, ty); | ||
| 956 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); | ||
| 957 | }, | ||
| 958 | }, | ||
| 959 | .err => |err| try writer.print("zig_error_{}", .{ | ||
| 960 | fmtIdent(mod.intern_pool.stringToSlice(err.name)), | ||
| 961 | }), | ||
| 962 | .error_union => |error_union| { | ||
| 963 | const payload_ty = ty.errorUnionPayload(mod); | ||
| 964 | const error_ty = ty.errorUnionSet(mod); | ||
| 965 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | ||
| 966 | switch (error_union.val) { | ||
| 967 | .err_name => |err_name| return dg.renderValue( | ||
| 968 | writer, | ||
| 969 | error_ty, | ||
| 970 | (try mod.intern(.{ .err = .{ | ||
| 971 | .ty = error_ty.toIntern(), | ||
| 972 | .name = err_name, | ||
| 973 | } })).toValue(), | ||
| 974 | location, | ||
| 975 | ), | ||
| 976 | .payload => return dg.renderValue( | ||
| 977 | writer, | ||
| 978 | Type.err_int, | ||
| 979 | try mod.intValue(Type.err_int, 0), | ||
| 980 | location, | ||
| 981 | ), | ||
| 982 | } | ||
| 983 | } | ||
| 984 | |||
| 985 | if (!location.isInitializer()) { | ||
| 986 | try writer.writeByte('('); | ||
| 987 | try dg.renderType(writer, ty); | ||
| 988 | try writer.writeByte(')'); | ||
| 989 | } | ||
| 990 | |||
| 991 | try writer.writeAll("{ .payload = "); | ||
| 992 | try dg.renderValue( | ||
| 993 | writer, | ||
| 994 | payload_ty, | ||
| 995 | switch (error_union.val) { | ||
| 996 | .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }), | ||
| 997 | .payload => |payload| payload, | ||
| 998 | }.toValue(), | ||
| 999 | initializer_type, | ||
| 1000 | ); | ||
| 1001 | try writer.writeAll(", .error = "); | ||
| 1002 | switch (error_union.val) { | ||
| 1003 | .err_name => |err_name| try dg.renderValue( | ||
| 1004 | writer, | ||
| 1005 | error_ty, | ||
| 1006 | (try mod.intern(.{ .err = .{ | ||
| 1007 | .ty = error_ty.toIntern(), | ||
| 1008 | .name = err_name, | ||
| 1009 | } })).toValue(), | ||
| 1010 | location, | ||
| 1011 | ), | ||
| 1012 | .payload => try dg.renderValue( | ||
| 1013 | writer, | ||
| 1014 | Type.err_int, | ||
| 1015 | try mod.intValue(Type.err_int, 0), | ||
| 1016 | location, | ||
| 1017 | ), | ||
| 1018 | } | ||
| 1019 | try writer.writeAll(" }"); | ||
| 1020 | }, | ||
| 1021 | .enum_tag => { | ||
| 1022 | const enum_tag = mod.intern_pool.indexToKey(val.ip_index).enum_tag; | ||
| 1023 | const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int); | ||
| 1024 | try dg.renderValue(writer, int_tag_ty.toType(), enum_tag.int.toValue(), location); | ||
| 1025 | }, | ||
| 1026 | .float => { | ||
| 931 | const bits = ty.floatBits(target); | 1027 | const bits = ty.floatBits(target); |
| 932 | const f128_val = val.toFloat(f128); | 1028 | const f128_val = val.toFloat(f128, mod); |
| 933 | 1029 | ||
| 934 | var repr_ty_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = bits }; | 1030 | // All unsigned ints matching float types are pre-allocated. |
| 935 | const repr_ty = Type.initPayload(&repr_ty_pl.base); | 1031 | const repr_ty = mod.intType(.unsigned, bits) catch unreachable; |
| 936 | 1032 | ||
| 937 | assert(bits <= 128); | 1033 | assert(bits <= 128); |
| 938 | var repr_val_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined; | 1034 | var repr_val_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined; |
| ... | @@ -943,21 +1039,15 @@ pub const DeclGen = struct { | ... | @@ -943,21 +1039,15 @@ pub const DeclGen = struct { |
| 943 | }; | 1039 | }; |
| 944 | 1040 | ||
| 945 | switch (bits) { | 1041 | switch (bits) { |
| 946 | 16 => repr_val_big.set(@bitCast(u16, val.toFloat(f16))), | 1042 | 16 => repr_val_big.set(@bitCast(u16, val.toFloat(f16, mod))), |
| 947 | 32 => repr_val_big.set(@bitCast(u32, val.toFloat(f32))), | 1043 | 32 => repr_val_big.set(@bitCast(u32, val.toFloat(f32, mod))), |
| 948 | 64 => repr_val_big.set(@bitCast(u64, val.toFloat(f64))), | 1044 | 64 => repr_val_big.set(@bitCast(u64, val.toFloat(f64, mod))), |
| 949 | 80 => repr_val_big.set(@bitCast(u80, val.toFloat(f80))), | 1045 | 80 => repr_val_big.set(@bitCast(u80, val.toFloat(f80, mod))), |
| 950 | 128 => repr_val_big.set(@bitCast(u128, f128_val)), | 1046 | 128 => repr_val_big.set(@bitCast(u128, f128_val)), |
| 951 | else => unreachable, | 1047 | else => unreachable, |
| 952 | } | 1048 | } |
| 953 | 1049 | ||
| 954 | var repr_val_pl = Value.Payload.BigInt{ | 1050 | const repr_val = try mod.intValue_big(repr_ty, repr_val_big.toConst()); |
| 955 | .base = .{ | ||
| 956 | .tag = if (repr_val_big.positive) .int_big_positive else .int_big_negative, | ||
| 957 | }, | ||
| 958 | .data = repr_val_big.limbs[0..repr_val_big.len], | ||
| 959 | }; | ||
| 960 | const repr_val = Value.initPayload(&repr_val_pl.base); | ||
| 961 | 1051 | ||
| 962 | try writer.writeAll("zig_cast_"); | 1052 | try writer.writeAll("zig_cast_"); |
| 963 | try dg.renderTypeForBuiltinFnName(writer, ty); | 1053 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| ... | @@ -968,10 +1058,10 @@ pub const DeclGen = struct { | ... | @@ -968,10 +1058,10 @@ pub const DeclGen = struct { |
| 968 | try dg.renderTypeForBuiltinFnName(writer, ty); | 1058 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 969 | try writer.writeByte('('); | 1059 | try writer.writeByte('('); |
| 970 | switch (bits) { | 1060 | switch (bits) { |
| 971 | 16 => try writer.print("{x}", .{val.toFloat(f16)}), | 1061 | 16 => try writer.print("{x}", .{val.toFloat(f16, mod)}), |
| 972 | 32 => try writer.print("{x}", .{val.toFloat(f32)}), | 1062 | 32 => try writer.print("{x}", .{val.toFloat(f32, mod)}), |
| 973 | 64 => try writer.print("{x}", .{val.toFloat(f64)}), | 1063 | 64 => try writer.print("{x}", .{val.toFloat(f64, mod)}), |
| 974 | 80 => try writer.print("{x}", .{val.toFloat(f80)}), | 1064 | 80 => try writer.print("{x}", .{val.toFloat(f80, mod)}), |
| 975 | 128 => try writer.print("{x}", .{f128_val}), | 1065 | 128 => try writer.print("{x}", .{f128_val}), |
| 976 | else => unreachable, | 1066 | else => unreachable, |
| 977 | } | 1067 | } |
| ... | @@ -1011,10 +1101,10 @@ pub const DeclGen = struct { | ... | @@ -1011,10 +1101,10 @@ pub const DeclGen = struct { |
| 1011 | if (std.math.isNan(f128_val)) switch (bits) { | 1101 | if (std.math.isNan(f128_val)) switch (bits) { |
| 1012 | // We only actually need to pass the significand, but it will get | 1102 | // We only actually need to pass the significand, but it will get |
| 1013 | // properly masked anyway, so just pass the whole value. | 1103 | // properly masked anyway, so just pass the whole value. |
| 1014 | 16 => try writer.print("\"0x{x}\"", .{@bitCast(u16, val.toFloat(f16))}), | 1104 | 16 => try writer.print("\"0x{x}\"", .{@bitCast(u16, val.toFloat(f16, mod))}), |
| 1015 | 32 => try writer.print("\"0x{x}\"", .{@bitCast(u32, val.toFloat(f32))}), | 1105 | 32 => try writer.print("\"0x{x}\"", .{@bitCast(u32, val.toFloat(f32, mod))}), |
| 1016 | 64 => try writer.print("\"0x{x}\"", .{@bitCast(u64, val.toFloat(f64))}), | 1106 | 64 => try writer.print("\"0x{x}\"", .{@bitCast(u64, val.toFloat(f64, mod))}), |
| 1017 | 80 => try writer.print("\"0x{x}\"", .{@bitCast(u80, val.toFloat(f80))}), | 1107 | 80 => try writer.print("\"0x{x}\"", .{@bitCast(u80, val.toFloat(f80, mod))}), |
| 1018 | 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}), | 1108 | 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}), |
| 1019 | else => unreachable, | 1109 | else => unreachable, |
| 1020 | }; | 1110 | }; |
| ... | @@ -1023,173 +1113,80 @@ pub const DeclGen = struct { | ... | @@ -1023,173 +1113,80 @@ pub const DeclGen = struct { |
| 1023 | } | 1113 | } |
| 1024 | try writer.print("{x}", .{try dg.fmtIntLiteral(repr_ty, repr_val, location)}); | 1114 | try writer.print("{x}", .{try dg.fmtIntLiteral(repr_ty, repr_val, location)}); |
| 1025 | if (!empty) try writer.writeByte(')'); | 1115 | if (!empty) try writer.writeByte(')'); |
| 1026 | return; | ||
| 1027 | }, | 1116 | }, |
| 1028 | .Pointer => switch (val.tag()) { | 1117 | .ptr => |ptr| { |
| 1029 | .null_value, .zero => if (ty.isSlice()) { | 1118 | if (ptr.len != .none) { |
| 1030 | var slice_pl = Value.Payload.Slice{ | ||
| 1031 | .base = .{ .tag = .slice }, | ||
| 1032 | .data = .{ .ptr = val, .len = Value.undef }, | ||
| 1033 | }; | ||
| 1034 | const slice_val = Value.initPayload(&slice_pl.base); | ||
| 1035 | |||
| 1036 | return dg.renderValue(writer, ty, slice_val, location); | ||
| 1037 | } else { | ||
| 1038 | try writer.writeAll("(("); | ||
| 1039 | try dg.renderType(writer, ty); | ||
| 1040 | try writer.writeAll(")NULL)"); | ||
| 1041 | }, | ||
| 1042 | .variable => { | ||
| 1043 | const decl = val.castTag(.variable).?.data.owner_decl; | ||
| 1044 | return dg.renderDeclValue(writer, ty, val, decl, location); | ||
| 1045 | }, | ||
| 1046 | .slice => { | ||
| 1047 | if (!location.isInitializer()) { | 1119 | if (!location.isInitializer()) { |
| 1048 | try writer.writeByte('('); | 1120 | try writer.writeByte('('); |
| 1049 | try dg.renderType(writer, ty); | 1121 | try dg.renderType(writer, ty); |
| 1050 | try writer.writeByte(')'); | 1122 | try writer.writeByte(')'); |
| 1051 | } | 1123 | } |
| 1052 | |||
| 1053 | const slice = val.castTag(.slice).?.data; | ||
| 1054 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 1055 | |||
| 1056 | try writer.writeByte('{'); | 1124 | try writer.writeByte('{'); |
| 1057 | try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, initializer_type); | ||
| 1058 | try writer.writeAll(", "); | ||
| 1059 | try dg.renderValue(writer, Type.usize, slice.len, initializer_type); | ||
| 1060 | try writer.writeByte('}'); | ||
| 1061 | }, | ||
| 1062 | .function => { | ||
| 1063 | const func = val.castTag(.function).?.data; | ||
| 1064 | try dg.renderDeclName(writer, func.owner_decl, 0); | ||
| 1065 | }, | ||
| 1066 | .extern_fn => { | ||
| 1067 | const extern_fn = val.castTag(.extern_fn).?.data; | ||
| 1068 | try dg.renderDeclName(writer, extern_fn.owner_decl, 0); | ||
| 1069 | }, | ||
| 1070 | .int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => { | ||
| 1071 | try writer.writeAll("(("); | ||
| 1072 | try dg.renderType(writer, ty); | ||
| 1073 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); | ||
| 1074 | }, | ||
| 1075 | .field_ptr, | ||
| 1076 | .elem_ptr, | ||
| 1077 | .opt_payload_ptr, | ||
| 1078 | .eu_payload_ptr, | ||
| 1079 | .decl_ref_mut, | ||
| 1080 | .decl_ref, | ||
| 1081 | => try dg.renderParentPtr(writer, val, ty, location), | ||
| 1082 | else => unreachable, | ||
| 1083 | }, | ||
| 1084 | .Array, .Vector => { | ||
| 1085 | if (location == .FunctionArgument) { | ||
| 1086 | try writer.writeByte('('); | ||
| 1087 | try dg.renderType(writer, ty); | ||
| 1088 | try writer.writeByte(')'); | ||
| 1089 | } | 1125 | } |
| 1090 | 1126 | const ptr_location = switch (ptr.len) { | |
| 1091 | // First try specific tag representations for more efficiency. | 1127 | .none => location, |
| 1092 | switch (val.tag()) { | 1128 | else => initializer_type, |
| 1093 | .undef, .empty_struct_value, .empty_array => { | 1129 | }; |
| 1094 | const ai = ty.arrayInfo(); | 1130 | const ptr_ty = switch (ptr.len) { |
| 1095 | try writer.writeByte('{'); | 1131 | .none => ty, |
| 1096 | if (ai.sentinel) |s| { | 1132 | else => ty.slicePtrFieldType(mod), |
| 1097 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | 1133 | }; |
| 1098 | } else { | 1134 | const ptr_val = switch (ptr.len) { |
| 1099 | try writer.writeByte('0'); | 1135 | .none => val, |
| 1100 | } | 1136 | else => val.slicePtr(mod), |
| 1101 | try writer.writeByte('}'); | 1137 | }; |
| 1102 | }, | 1138 | switch (ptr.addr) { |
| 1103 | .bytes, .str_lit => |t| { | 1139 | .decl, .mut_decl => try dg.renderDeclValue( |
| 1104 | const bytes = switch (t) { | 1140 | writer, |
| 1105 | .bytes => val.castTag(.bytes).?.data, | 1141 | ptr_ty, |
| 1106 | .str_lit => bytes: { | 1142 | ptr_val, |
| 1107 | const str_lit = val.castTag(.str_lit).?.data; | 1143 | switch (ptr.addr) { |
| 1108 | break :bytes dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | 1144 | .decl => |decl| decl, |
| 1109 | }, | 1145 | .mut_decl => |mut_decl| mut_decl.decl, |
| 1110 | else => unreachable, | 1146 | else => unreachable, |
| 1111 | }; | 1147 | }, |
| 1112 | const sentinel = if (ty.sentinel()) |sentinel| @intCast(u8, sentinel.toUnsignedInt(target)) else null; | 1148 | ptr_location, |
| 1113 | try writer.print("{s}", .{ | 1149 | ), |
| 1114 | fmtStringLiteral(bytes[0..@intCast(usize, ty.arrayLen())], sentinel), | 1150 | .int => |int| { |
| 1151 | try writer.writeAll("(("); | ||
| 1152 | try dg.renderType(writer, ptr_ty); | ||
| 1153 | try writer.print("){x})", .{ | ||
| 1154 | try dg.fmtIntLiteral(Type.usize, int.toValue(), ptr_location), | ||
| 1115 | }); | 1155 | }); |
| 1116 | }, | 1156 | }, |
| 1117 | else => { | 1157 | .eu_payload, |
| 1118 | // Fall back to generic implementation. | 1158 | .opt_payload, |
| 1119 | var arena = std.heap.ArenaAllocator.init(dg.gpa); | 1159 | .elem, |
| 1120 | defer arena.deinit(); | 1160 | .field, |
| 1121 | const arena_allocator = arena.allocator(); | 1161 | => try dg.renderParentPtr(writer, ptr_val.ip_index, ptr_location), |
| 1122 | 1162 | .comptime_field => unreachable, | |
| 1123 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal | ||
| 1124 | const max_string_initializer_len = 65535; | ||
| 1125 | |||
| 1126 | const ai = ty.arrayInfo(); | ||
| 1127 | if (ai.elem_type.eql(Type.u8, dg.module)) { | ||
| 1128 | if (ai.len <= max_string_initializer_len) { | ||
| 1129 | var literal = stringLiteral(writer); | ||
| 1130 | try literal.start(); | ||
| 1131 | var index: usize = 0; | ||
| 1132 | while (index < ai.len) : (index += 1) { | ||
| 1133 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | ||
| 1134 | const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(target)); | ||
| 1135 | try literal.writeChar(elem_val_u8); | ||
| 1136 | } | ||
| 1137 | if (ai.sentinel) |s| { | ||
| 1138 | const s_u8 = @intCast(u8, s.toUnsignedInt(target)); | ||
| 1139 | if (s_u8 != 0) try literal.writeChar(s_u8); | ||
| 1140 | } | ||
| 1141 | try literal.end(); | ||
| 1142 | } else { | ||
| 1143 | try writer.writeByte('{'); | ||
| 1144 | var index: usize = 0; | ||
| 1145 | while (index < ai.len) : (index += 1) { | ||
| 1146 | if (index != 0) try writer.writeByte(','); | ||
| 1147 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | ||
| 1148 | const elem_val_u8 = if (elem_val.isUndef()) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(target)); | ||
| 1149 | try writer.print("'\\x{x}'", .{elem_val_u8}); | ||
| 1150 | } | ||
| 1151 | if (ai.sentinel) |s| { | ||
| 1152 | if (index != 0) try writer.writeByte(','); | ||
| 1153 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | ||
| 1154 | } | ||
| 1155 | try writer.writeByte('}'); | ||
| 1156 | } | ||
| 1157 | } else { | ||
| 1158 | try writer.writeByte('{'); | ||
| 1159 | var index: usize = 0; | ||
| 1160 | while (index < ai.len) : (index += 1) { | ||
| 1161 | if (index != 0) try writer.writeByte(','); | ||
| 1162 | const elem_val = try val.elemValue(dg.module, arena_allocator, index); | ||
| 1163 | try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type); | ||
| 1164 | } | ||
| 1165 | if (ai.sentinel) |s| { | ||
| 1166 | if (index != 0) try writer.writeByte(','); | ||
| 1167 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | ||
| 1168 | } | ||
| 1169 | try writer.writeByte('}'); | ||
| 1170 | } | ||
| 1171 | }, | ||
| 1172 | } | 1163 | } |
| 1173 | }, | 1164 | if (ptr.len != .none) { |
| 1174 | .Bool => { | 1165 | try writer.writeAll(", "); |
| 1175 | if (val.toBool()) { | 1166 | try dg.renderValue(writer, Type.usize, ptr.len.toValue(), initializer_type); |
| 1176 | return writer.writeAll("true"); | 1167 | try writer.writeByte('}'); |
| 1177 | } else { | ||
| 1178 | return writer.writeAll("false"); | ||
| 1179 | } | 1168 | } |
| 1180 | }, | 1169 | }, |
| 1181 | .Optional => { | 1170 | .opt => |opt| { |
| 1182 | var opt_buf: Type.Payload.ElemType = undefined; | 1171 | const payload_ty = ty.optionalChild(mod); |
| 1183 | const payload_ty = ty.optionalChild(&opt_buf); | ||
| 1184 | 1172 | ||
| 1185 | const is_null_val = Value.makeBool(val.tag() == .null_value); | 1173 | const is_null_val = Value.makeBool(opt.val == .none); |
| 1186 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) | 1174 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 1187 | return dg.renderValue(writer, Type.bool, is_null_val, location); | 1175 | return dg.renderValue(writer, Type.bool, is_null_val, location); |
| 1188 | 1176 | ||
| 1189 | if (ty.optionalReprIsPayload()) { | 1177 | if (ty.optionalReprIsPayload(mod)) return dg.renderValue( |
| 1190 | const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else val; | 1178 | writer, |
| 1191 | return dg.renderValue(writer, payload_ty, payload_val, location); | 1179 | payload_ty, |
| 1192 | } | 1180 | switch (opt.val) { |
| 1181 | .none => switch (payload_ty.zigTypeTag(mod)) { | ||
| 1182 | .ErrorSet => try mod.intValue(Type.err_int, 0), | ||
| 1183 | .Pointer => try mod.getCoerced(val, payload_ty), | ||
| 1184 | else => unreachable, | ||
| 1185 | }, | ||
| 1186 | else => |payload| payload.toValue(), | ||
| 1187 | }, | ||
| 1188 | location, | ||
| 1189 | ); | ||
| 1193 | 1190 | ||
| 1194 | if (!location.isInitializer()) { | 1191 | if (!location.isInitializer()) { |
| 1195 | try writer.writeByte('('); | 1192 | try writer.writeByte('('); |
| ... | @@ -1197,93 +1194,74 @@ pub const DeclGen = struct { | ... | @@ -1197,93 +1194,74 @@ pub const DeclGen = struct { |
| 1197 | try writer.writeByte(')'); | 1194 | try writer.writeByte(')'); |
| 1198 | } | 1195 | } |
| 1199 | 1196 | ||
| 1200 | const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else Value.undef; | ||
| 1201 | |||
| 1202 | try writer.writeAll("{ .payload = "); | 1197 | try writer.writeAll("{ .payload = "); |
| 1203 | try dg.renderValue(writer, payload_ty, payload_val, initializer_type); | 1198 | try dg.renderValue(writer, payload_ty, switch (opt.val) { |
| 1199 | .none => try mod.intern(.{ .undef = payload_ty.ip_index }), | ||
| 1200 | else => |payload| payload, | ||
| 1201 | }.toValue(), initializer_type); | ||
| 1204 | try writer.writeAll(", .is_null = "); | 1202 | try writer.writeAll(", .is_null = "); |
| 1205 | try dg.renderValue(writer, Type.bool, is_null_val, initializer_type); | 1203 | try dg.renderValue(writer, Type.bool, is_null_val, initializer_type); |
| 1206 | try writer.writeAll(" }"); | 1204 | try writer.writeAll(" }"); |
| 1207 | }, | 1205 | }, |
| 1208 | .ErrorSet => { | 1206 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 1209 | if (val.castTag(.@"error")) |error_pl| { | 1207 | .array_type, .vector_type => { |
| 1210 | // Error values are already defined by genErrDecls. | 1208 | if (location == .FunctionArgument) { |
| 1211 | try writer.print("zig_error_{}", .{fmtIdent(error_pl.data.name)}); | 1209 | try writer.writeByte('('); |
| 1212 | } else { | 1210 | try dg.renderType(writer, ty); |
| 1213 | try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, .Other)}); | 1211 | try writer.writeByte(')'); |
| 1214 | } | 1212 | } |
| 1215 | }, | 1213 | // Fall back to generic implementation. |
| 1216 | .ErrorUnion => { | ||
| 1217 | const payload_ty = ty.errorUnionPayload(); | ||
| 1218 | const error_ty = ty.errorUnionSet(); | ||
| 1219 | const error_val = if (val.errorUnionIsPayload()) Value.zero else val; | ||
| 1220 | 1214 | ||
| 1221 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 1215 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal |
| 1222 | return dg.renderValue(writer, error_ty, error_val, location); | 1216 | const max_string_initializer_len = 65535; |
| 1223 | } | ||
| 1224 | 1217 | ||
| 1225 | if (!location.isInitializer()) { | 1218 | const ai = ty.arrayInfo(mod); |
| 1226 | try writer.writeByte('('); | 1219 | if (ai.elem_type.eql(Type.u8, mod)) { |
| 1227 | try dg.renderType(writer, ty); | 1220 | if (ai.len <= max_string_initializer_len) { |
| 1228 | try writer.writeByte(')'); | 1221 | var literal = stringLiteral(writer); |
| 1229 | } | 1222 | try literal.start(); |
| 1230 | 1223 | var index: usize = 0; | |
| 1231 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef; | 1224 | while (index < ai.len) : (index += 1) { |
| 1232 | try writer.writeAll("{ .payload = "); | 1225 | const elem_val = try val.elemValue(mod, index); |
| 1233 | try dg.renderValue(writer, payload_ty, payload_val, initializer_type); | 1226 | const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod)); |
| 1234 | try writer.writeAll(", .error = "); | 1227 | try literal.writeChar(elem_val_u8); |
| 1235 | try dg.renderValue(writer, error_ty, error_val, initializer_type); | 1228 | } |
| 1236 | try writer.writeAll(" }"); | 1229 | if (ai.sentinel) |s| { |
| 1237 | }, | 1230 | const s_u8 = @intCast(u8, s.toUnsignedInt(mod)); |
| 1238 | .Enum => { | 1231 | if (s_u8 != 0) try literal.writeChar(s_u8); |
| 1239 | switch (val.tag()) { | 1232 | } |
| 1240 | .enum_field_index => { | 1233 | try literal.end(); |
| 1241 | const field_index = val.castTag(.enum_field_index).?.data; | 1234 | } else { |
| 1242 | switch (ty.tag()) { | 1235 | try writer.writeByte('{'); |
| 1243 | .enum_simple => return writer.print("{d}", .{field_index}), | 1236 | var index: usize = 0; |
| 1244 | .enum_full, .enum_nonexhaustive => { | 1237 | while (index < ai.len) : (index += 1) { |
| 1245 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | 1238 | if (index != 0) try writer.writeByte(','); |
| 1246 | if (enum_full.values.count() != 0) { | 1239 | const elem_val = try val.elemValue(mod, index); |
| 1247 | const tag_val = enum_full.values.keys()[field_index]; | 1240 | const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod)); |
| 1248 | return dg.renderValue(writer, enum_full.tag_ty, tag_val, location); | 1241 | try writer.print("'\\x{x}'", .{elem_val_u8}); |
| 1249 | } else { | 1242 | } |
| 1250 | return writer.print("{d}", .{field_index}); | 1243 | if (ai.sentinel) |s| { |
| 1251 | } | 1244 | if (index != 0) try writer.writeByte(','); |
| 1252 | }, | 1245 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); |
| 1253 | .enum_numbered => { | 1246 | } |
| 1254 | const enum_obj = ty.castTag(.enum_numbered).?.data; | 1247 | try writer.writeByte('}'); |
| 1255 | if (enum_obj.values.count() != 0) { | ||
| 1256 | const tag_val = enum_obj.values.keys()[field_index]; | ||
| 1257 | return dg.renderValue(writer, enum_obj.tag_ty, tag_val, location); | ||
| 1258 | } else { | ||
| 1259 | return writer.print("{d}", .{field_index}); | ||
| 1260 | } | ||
| 1261 | }, | ||
| 1262 | else => unreachable, | ||
| 1263 | } | 1248 | } |
| 1264 | }, | 1249 | } else { |
| 1265 | else => { | 1250 | try writer.writeByte('{'); |
| 1266 | var int_tag_ty_buffer: Type.Payload.Bits = undefined; | 1251 | var index: usize = 0; |
| 1267 | const int_tag_ty = ty.intTagType(&int_tag_ty_buffer); | 1252 | while (index < ai.len) : (index += 1) { |
| 1268 | return dg.renderValue(writer, int_tag_ty, val, location); | 1253 | if (index != 0) try writer.writeByte(','); |
| 1269 | }, | 1254 | const elem_val = try val.elemValue(mod, index); |
| 1270 | } | 1255 | try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type); |
| 1271 | }, | 1256 | } |
| 1272 | .Fn => switch (val.tag()) { | 1257 | if (ai.sentinel) |s| { |
| 1273 | .function => { | 1258 | if (index != 0) try writer.writeByte(','); |
| 1274 | const decl = val.castTag(.function).?.data.owner_decl; | 1259 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); |
| 1275 | return dg.renderDeclValue(writer, ty, val, decl, location); | 1260 | } |
| 1276 | }, | 1261 | try writer.writeByte('}'); |
| 1277 | .extern_fn => { | 1262 | } |
| 1278 | const decl = val.castTag(.extern_fn).?.data.owner_decl; | ||
| 1279 | return dg.renderDeclValue(writer, ty, val, decl, location); | ||
| 1280 | }, | 1263 | }, |
| 1281 | else => unreachable, | 1264 | .anon_struct_type => |tuple| { |
| 1282 | }, | ||
| 1283 | .Struct => switch (ty.containerLayout()) { | ||
| 1284 | .Auto, .Extern => { | ||
| 1285 | const field_vals = val.castTag(.aggregate).?.data; | ||
| 1286 | |||
| 1287 | if (!location.isInitializer()) { | 1265 | if (!location.isInitializer()) { |
| 1288 | try writer.writeByte('('); | 1266 | try writer.writeByte('('); |
| 1289 | try dg.renderType(writer, ty); | 1267 | try dg.renderType(writer, ty); |
| ... | @@ -1292,133 +1270,184 @@ pub const DeclGen = struct { | ... | @@ -1292,133 +1270,184 @@ pub const DeclGen = struct { |
| 1292 | 1270 | ||
| 1293 | try writer.writeByte('{'); | 1271 | try writer.writeByte('{'); |
| 1294 | var empty = true; | 1272 | var empty = true; |
| 1295 | for (field_vals, 0..) |field_val, field_i| { | 1273 | for (tuple.types, tuple.values, 0..) |field_ty, comptime_ty, field_i| { |
| 1296 | if (ty.structFieldIsComptime(field_i)) continue; | 1274 | if (comptime_ty != .none) continue; |
| 1297 | const field_ty = ty.structFieldType(field_i); | 1275 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 1298 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | ||
| 1299 | 1276 | ||
| 1300 | if (!empty) try writer.writeByte(','); | 1277 | if (!empty) try writer.writeByte(','); |
| 1301 | try dg.renderValue(writer, field_ty, field_val, initializer_type); | 1278 | |
| 1279 | const field_val = switch (aggregate.storage) { | ||
| 1280 | .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{ | ||
| 1281 | .ty = field_ty, | ||
| 1282 | .storage = .{ .u64 = bytes[field_i] }, | ||
| 1283 | } }), | ||
| 1284 | .elems => |elems| elems[field_i], | ||
| 1285 | .repeated_elem => |elem| elem, | ||
| 1286 | }; | ||
| 1287 | try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), initializer_type); | ||
| 1302 | 1288 | ||
| 1303 | empty = false; | 1289 | empty = false; |
| 1304 | } | 1290 | } |
| 1305 | try writer.writeByte('}'); | 1291 | try writer.writeByte('}'); |
| 1306 | }, | 1292 | }, |
| 1307 | .Packed => { | 1293 | .struct_type => |struct_type| { |
| 1308 | const field_vals = val.castTag(.aggregate).?.data; | 1294 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 1309 | const int_info = ty.intInfo(target); | 1295 | switch (struct_obj.layout) { |
| 1296 | .Auto, .Extern => { | ||
| 1297 | if (!location.isInitializer()) { | ||
| 1298 | try writer.writeByte('('); | ||
| 1299 | try dg.renderType(writer, ty); | ||
| 1300 | try writer.writeByte(')'); | ||
| 1301 | } | ||
| 1310 | 1302 | ||
| 1311 | var bit_offset_ty_pl = Type.Payload.Bits{ | 1303 | try writer.writeByte('{'); |
| 1312 | .base = .{ .tag = .int_unsigned }, | 1304 | var empty = true; |
| 1313 | .data = Type.smallestUnsignedBits(int_info.bits - 1), | 1305 | for (struct_obj.fields.values(), 0..) |field, field_i| { |
| 1314 | }; | 1306 | if (field.is_comptime) continue; |
| 1315 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); | 1307 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 1308 | |||
| 1309 | if (!empty) try writer.writeByte(','); | ||
| 1310 | const field_val = switch (aggregate.storage) { | ||
| 1311 | .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{ | ||
| 1312 | .ty = field.ty.toIntern(), | ||
| 1313 | .storage = .{ .u64 = bytes[field_i] }, | ||
| 1314 | } }), | ||
| 1315 | .elems => |elems| elems[field_i], | ||
| 1316 | .repeated_elem => |elem| elem, | ||
| 1317 | }; | ||
| 1318 | try dg.renderValue(writer, field.ty, field_val.toValue(), initializer_type); | ||
| 1319 | |||
| 1320 | empty = false; | ||
| 1321 | } | ||
| 1322 | try writer.writeByte('}'); | ||
| 1323 | }, | ||
| 1324 | .Packed => { | ||
| 1325 | const int_info = ty.intInfo(mod); | ||
| 1316 | 1326 | ||
| 1317 | var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; | 1327 | const bits = Type.smallestUnsignedBits(int_info.bits - 1); |
| 1318 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); | 1328 | const bit_offset_ty = try mod.intType(.unsigned, bits); |
| 1319 | 1329 | ||
| 1320 | var eff_num_fields: usize = 0; | 1330 | var bit_offset: u64 = 0; |
| 1321 | for (0..field_vals.len) |field_i| { | 1331 | var eff_num_fields: usize = 0; |
| 1322 | if (ty.structFieldIsComptime(field_i)) continue; | ||
| 1323 | const field_ty = ty.structFieldType(field_i); | ||
| 1324 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | ||
| 1325 | 1332 | ||
| 1326 | eff_num_fields += 1; | 1333 | for (struct_obj.fields.values()) |field| { |
| 1327 | } | 1334 | if (field.is_comptime) continue; |
| 1335 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1328 | 1336 | ||
| 1329 | if (eff_num_fields == 0) { | 1337 | eff_num_fields += 1; |
| 1330 | try writer.writeByte('('); | 1338 | } |
| 1331 | try dg.renderValue(writer, ty, Value.undef, initializer_type); | ||
| 1332 | try writer.writeByte(')'); | ||
| 1333 | } else if (ty.bitSize(target) > 64) { | ||
| 1334 | // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) | ||
| 1335 | var num_or = eff_num_fields - 1; | ||
| 1336 | while (num_or > 0) : (num_or -= 1) { | ||
| 1337 | try writer.writeAll("zig_or_"); | ||
| 1338 | try dg.renderTypeForBuiltinFnName(writer, ty); | ||
| 1339 | try writer.writeByte('('); | ||
| 1340 | } | ||
| 1341 | 1339 | ||
| 1342 | var eff_index: usize = 0; | 1340 | if (eff_num_fields == 0) { |
| 1343 | var needs_closing_paren = false; | ||
| 1344 | for (field_vals, 0..) |field_val, field_i| { | ||
| 1345 | if (ty.structFieldIsComptime(field_i)) continue; | ||
| 1346 | const field_ty = ty.structFieldType(field_i); | ||
| 1347 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | ||
| 1348 | |||
| 1349 | const cast_context = IntCastContext{ .value = .{ .value = field_val } }; | ||
| 1350 | if (bit_offset_val_pl.data != 0) { | ||
| 1351 | try writer.writeAll("zig_shl_"); | ||
| 1352 | try dg.renderTypeForBuiltinFnName(writer, ty); | ||
| 1353 | try writer.writeByte('('); | 1341 | try writer.writeByte('('); |
| 1354 | try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); | 1342 | try dg.renderValue(writer, ty, Value.undef, initializer_type); |
| 1355 | try writer.writeAll(", "); | ||
| 1356 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | ||
| 1357 | try writer.writeByte(')'); | 1343 | try writer.writeByte(')'); |
| 1358 | } else { | 1344 | } else if (ty.bitSize(mod) > 64) { |
| 1359 | try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); | 1345 | // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) |
| 1360 | } | 1346 | var num_or = eff_num_fields - 1; |
| 1361 | 1347 | while (num_or > 0) : (num_or -= 1) { | |
| 1362 | if (needs_closing_paren) try writer.writeByte(')'); | 1348 | try writer.writeAll("zig_or_"); |
| 1363 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); | 1349 | try dg.renderTypeForBuiltinFnName(writer, ty); |
| 1364 | 1350 | try writer.writeByte('('); | |
| 1365 | bit_offset_val_pl.data += field_ty.bitSize(target); | 1351 | } |
| 1366 | needs_closing_paren = true; | ||
| 1367 | eff_index += 1; | ||
| 1368 | } | ||
| 1369 | } else { | ||
| 1370 | try writer.writeByte('('); | ||
| 1371 | // a << a_off | b << b_off | c << c_off | ||
| 1372 | var empty = true; | ||
| 1373 | for (field_vals, 0..) |field_val, field_i| { | ||
| 1374 | if (ty.structFieldIsComptime(field_i)) continue; | ||
| 1375 | const field_ty = ty.structFieldType(field_i); | ||
| 1376 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | ||
| 1377 | |||
| 1378 | if (!empty) try writer.writeAll(" | "); | ||
| 1379 | try writer.writeByte('('); | ||
| 1380 | try dg.renderType(writer, ty); | ||
| 1381 | try writer.writeByte(')'); | ||
| 1382 | 1352 | ||
| 1383 | if (bit_offset_val_pl.data != 0) { | 1353 | var eff_index: usize = 0; |
| 1384 | try dg.renderValue(writer, field_ty, field_val, .Other); | 1354 | var needs_closing_paren = false; |
| 1385 | try writer.writeAll(" << "); | 1355 | for (struct_obj.fields.values(), 0..) |field, field_i| { |
| 1386 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | 1356 | if (field.is_comptime) continue; |
| 1357 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1358 | |||
| 1359 | const field_val = switch (aggregate.storage) { | ||
| 1360 | .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{ | ||
| 1361 | .ty = field.ty.toIntern(), | ||
| 1362 | .storage = .{ .u64 = bytes[field_i] }, | ||
| 1363 | } }), | ||
| 1364 | .elems => |elems| elems[field_i], | ||
| 1365 | .repeated_elem => |elem| elem, | ||
| 1366 | }; | ||
| 1367 | const cast_context = IntCastContext{ .value = .{ .value = field_val.toValue() } }; | ||
| 1368 | if (bit_offset != 0) { | ||
| 1369 | try writer.writeAll("zig_shl_"); | ||
| 1370 | try dg.renderTypeForBuiltinFnName(writer, ty); | ||
| 1371 | try writer.writeByte('('); | ||
| 1372 | try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument); | ||
| 1373 | try writer.writeAll(", "); | ||
| 1374 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | ||
| 1375 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | ||
| 1376 | try writer.writeByte(')'); | ||
| 1377 | } else { | ||
| 1378 | try dg.renderIntCast(writer, ty, cast_context, field.ty, .FunctionArgument); | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | if (needs_closing_paren) try writer.writeByte(')'); | ||
| 1382 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); | ||
| 1383 | |||
| 1384 | bit_offset += field.ty.bitSize(mod); | ||
| 1385 | needs_closing_paren = true; | ||
| 1386 | eff_index += 1; | ||
| 1387 | } | ||
| 1387 | } else { | 1388 | } else { |
| 1388 | try dg.renderValue(writer, field_ty, field_val, .Other); | 1389 | try writer.writeByte('('); |
| 1390 | // a << a_off | b << b_off | c << c_off | ||
| 1391 | var empty = true; | ||
| 1392 | for (struct_obj.fields.values(), 0..) |field, field_i| { | ||
| 1393 | if (field.is_comptime) continue; | ||
| 1394 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 1395 | |||
| 1396 | if (!empty) try writer.writeAll(" | "); | ||
| 1397 | try writer.writeByte('('); | ||
| 1398 | try dg.renderType(writer, ty); | ||
| 1399 | try writer.writeByte(')'); | ||
| 1400 | |||
| 1401 | const field_val = switch (aggregate.storage) { | ||
| 1402 | .bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{ | ||
| 1403 | .ty = field.ty.toIntern(), | ||
| 1404 | .storage = .{ .u64 = bytes[field_i] }, | ||
| 1405 | } }), | ||
| 1406 | .elems => |elems| elems[field_i], | ||
| 1407 | .repeated_elem => |elem| elem, | ||
| 1408 | }; | ||
| 1409 | |||
| 1410 | if (bit_offset != 0) { | ||
| 1411 | try dg.renderValue(writer, field.ty, field_val.toValue(), .Other); | ||
| 1412 | try writer.writeAll(" << "); | ||
| 1413 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | ||
| 1414 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | ||
| 1415 | } else { | ||
| 1416 | try dg.renderValue(writer, field.ty, field_val.toValue(), .Other); | ||
| 1417 | } | ||
| 1418 | |||
| 1419 | bit_offset += field.ty.bitSize(mod); | ||
| 1420 | empty = false; | ||
| 1421 | } | ||
| 1422 | try writer.writeByte(')'); | ||
| 1389 | } | 1423 | } |
| 1390 | 1424 | }, | |
| 1391 | bit_offset_val_pl.data += field_ty.bitSize(target); | ||
| 1392 | empty = false; | ||
| 1393 | } | ||
| 1394 | try writer.writeByte(')'); | ||
| 1395 | } | 1425 | } |
| 1396 | }, | 1426 | }, |
| 1427 | else => unreachable, | ||
| 1397 | }, | 1428 | }, |
| 1398 | .Union => { | 1429 | .un => |un| { |
| 1399 | const union_obj = val.castTag(.@"union").?.data; | ||
| 1400 | |||
| 1401 | if (!location.isInitializer()) { | 1430 | if (!location.isInitializer()) { |
| 1402 | try writer.writeByte('('); | 1431 | try writer.writeByte('('); |
| 1403 | try dg.renderType(writer, ty); | 1432 | try dg.renderType(writer, ty); |
| 1404 | try writer.writeByte(')'); | 1433 | try writer.writeByte(')'); |
| 1405 | } | 1434 | } |
| 1406 | 1435 | ||
| 1407 | const field_i = ty.unionTagFieldIndex(union_obj.tag, dg.module).?; | 1436 | const field_i = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; |
| 1408 | const field_ty = ty.unionFields().values()[field_i].ty; | 1437 | const field_ty = ty.unionFields(mod).values()[field_i].ty; |
| 1409 | const field_name = ty.unionFields().keys()[field_i]; | 1438 | const field_name = ty.unionFields(mod).keys()[field_i]; |
| 1410 | if (ty.containerLayout() == .Packed) { | 1439 | if (ty.containerLayout(mod) == .Packed) { |
| 1411 | if (field_ty.hasRuntimeBits()) { | 1440 | if (field_ty.hasRuntimeBits(mod)) { |
| 1412 | if (field_ty.isPtrAtRuntime()) { | 1441 | if (field_ty.isPtrAtRuntime(mod)) { |
| 1413 | try writer.writeByte('('); | 1442 | try writer.writeByte('('); |
| 1414 | try dg.renderType(writer, ty); | 1443 | try dg.renderType(writer, ty); |
| 1415 | try writer.writeByte(')'); | 1444 | try writer.writeByte(')'); |
| 1416 | } else if (field_ty.zigTypeTag() == .Float) { | 1445 | } else if (field_ty.zigTypeTag(mod) == .Float) { |
| 1417 | try writer.writeByte('('); | 1446 | try writer.writeByte('('); |
| 1418 | try dg.renderType(writer, ty); | 1447 | try dg.renderType(writer, ty); |
| 1419 | try writer.writeByte(')'); | 1448 | try writer.writeByte(')'); |
| 1420 | } | 1449 | } |
| 1421 | try dg.renderValue(writer, field_ty, union_obj.val, initializer_type); | 1450 | try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type); |
| 1422 | } else { | 1451 | } else { |
| 1423 | try writer.writeAll("0"); | 1452 | try writer.writeAll("0"); |
| 1424 | } | 1453 | } |
| ... | @@ -1426,44 +1455,28 @@ pub const DeclGen = struct { | ... | @@ -1426,44 +1455,28 @@ pub const DeclGen = struct { |
| 1426 | } | 1455 | } |
| 1427 | 1456 | ||
| 1428 | try writer.writeByte('{'); | 1457 | try writer.writeByte('{'); |
| 1429 | if (ty.unionTagTypeSafety()) |tag_ty| { | 1458 | if (ty.unionTagTypeSafety(mod)) |tag_ty| { |
| 1430 | const layout = ty.unionGetLayout(target); | 1459 | const layout = ty.unionGetLayout(mod); |
| 1431 | if (layout.tag_size != 0) { | 1460 | if (layout.tag_size != 0) { |
| 1432 | try writer.writeAll(" .tag = "); | 1461 | try writer.writeAll(" .tag = "); |
| 1433 | try dg.renderValue(writer, tag_ty, union_obj.tag, initializer_type); | 1462 | try dg.renderValue(writer, tag_ty, un.tag.toValue(), initializer_type); |
| 1434 | } | 1463 | } |
| 1435 | if (ty.unionHasAllZeroBitFieldTypes()) return try writer.writeByte('}'); | 1464 | if (ty.unionHasAllZeroBitFieldTypes(mod)) return try writer.writeByte('}'); |
| 1436 | if (layout.tag_size != 0) try writer.writeByte(','); | 1465 | if (layout.tag_size != 0) try writer.writeByte(','); |
| 1437 | try writer.writeAll(" .payload = {"); | 1466 | try writer.writeAll(" .payload = {"); |
| 1438 | } | 1467 | } |
| 1439 | if (field_ty.hasRuntimeBits()) { | 1468 | if (field_ty.hasRuntimeBits(mod)) { |
| 1440 | try writer.print(" .{ } = ", .{fmtIdent(field_name)}); | 1469 | try writer.print(" .{ } = ", .{fmtIdent(mod.intern_pool.stringToSlice(field_name))}); |
| 1441 | try dg.renderValue(writer, field_ty, union_obj.val, initializer_type); | 1470 | try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type); |
| 1442 | try writer.writeByte(' '); | 1471 | try writer.writeByte(' '); |
| 1443 | } else for (ty.unionFields().values()) |field| { | 1472 | } else for (ty.unionFields(mod).values()) |field| { |
| 1444 | if (!field.ty.hasRuntimeBits()) continue; | 1473 | if (!field.ty.hasRuntimeBits(mod)) continue; |
| 1445 | try dg.renderValue(writer, field.ty, Value.undef, initializer_type); | 1474 | try dg.renderValue(writer, field.ty, Value.undef, initializer_type); |
| 1446 | break; | 1475 | break; |
| 1447 | } | 1476 | } |
| 1448 | if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); | 1477 | if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}'); |
| 1449 | try writer.writeByte('}'); | 1478 | try writer.writeByte('}'); |
| 1450 | }, | 1479 | }, |
| 1451 | |||
| 1452 | .ComptimeInt => unreachable, | ||
| 1453 | .ComptimeFloat => unreachable, | ||
| 1454 | .Type => unreachable, | ||
| 1455 | .EnumLiteral => unreachable, | ||
| 1456 | .Void => unreachable, | ||
| 1457 | .NoReturn => unreachable, | ||
| 1458 | .Undefined => unreachable, | ||
| 1459 | .Null => unreachable, | ||
| 1460 | .Opaque => unreachable, | ||
| 1461 | |||
| 1462 | .Frame, | ||
| 1463 | .AnyFrame, | ||
| 1464 | => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{ | ||
| 1465 | @tagName(tag), | ||
| 1466 | }), | ||
| 1467 | } | 1480 | } |
| 1468 | } | 1481 | } |
| 1469 | 1482 | ||
| ... | @@ -1478,12 +1491,12 @@ pub const DeclGen = struct { | ... | @@ -1478,12 +1491,12 @@ pub const DeclGen = struct { |
| 1478 | }, | 1491 | }, |
| 1479 | ) !void { | 1492 | ) !void { |
| 1480 | const store = &dg.ctypes.set; | 1493 | const store = &dg.ctypes.set; |
| 1481 | const module = dg.module; | 1494 | const mod = dg.module; |
| 1482 | 1495 | ||
| 1483 | const fn_decl = module.declPtr(fn_decl_index); | 1496 | const fn_decl = mod.declPtr(fn_decl_index); |
| 1484 | const fn_cty_idx = try dg.typeToIndex(fn_decl.ty, kind); | 1497 | const fn_cty_idx = try dg.typeToIndex(fn_decl.ty, kind); |
| 1485 | 1498 | ||
| 1486 | const fn_info = fn_decl.ty.fnInfo(); | 1499 | const fn_info = mod.typeToFunc(fn_decl.ty).?; |
| 1487 | if (fn_info.cc == .Naked) { | 1500 | if (fn_info.cc == .Naked) { |
| 1488 | switch (kind) { | 1501 | switch (kind) { |
| 1489 | .forward => try w.writeAll("zig_naked_decl "), | 1502 | .forward => try w.writeAll("zig_naked_decl "), |
| ... | @@ -1491,14 +1504,13 @@ pub const DeclGen = struct { | ... | @@ -1491,14 +1504,13 @@ pub const DeclGen = struct { |
| 1491 | else => unreachable, | 1504 | else => unreachable, |
| 1492 | } | 1505 | } |
| 1493 | } | 1506 | } |
| 1494 | if (fn_decl.val.castTag(.function)) |func_payload| | 1507 | if (fn_decl.val.getFunction(mod)) |func| if (func.is_cold) try w.writeAll("zig_cold "); |
| 1495 | if (func_payload.data.is_cold) try w.writeAll("zig_cold "); | 1508 | if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn "); |
| 1496 | if (fn_info.return_type.tag() == .noreturn) try w.writeAll("zig_noreturn "); | ||
| 1497 | 1509 | ||
| 1498 | const trailing = try renderTypePrefix( | 1510 | const trailing = try renderTypePrefix( |
| 1499 | dg.decl_index, | 1511 | dg.decl_index, |
| 1500 | store.*, | 1512 | store.*, |
| 1501 | module, | 1513 | mod, |
| 1502 | w, | 1514 | w, |
| 1503 | fn_cty_idx, | 1515 | fn_cty_idx, |
| 1504 | .suffix, | 1516 | .suffix, |
| ... | @@ -1512,8 +1524,8 @@ pub const DeclGen = struct { | ... | @@ -1512,8 +1524,8 @@ pub const DeclGen = struct { |
| 1512 | 1524 | ||
| 1513 | switch (kind) { | 1525 | switch (kind) { |
| 1514 | .forward => {}, | 1526 | .forward => {}, |
| 1515 | .complete => if (fn_info.alignment > 0) | 1527 | .complete => if (fn_info.alignment.toByteUnitsOptional()) |a| |
| 1516 | try w.print(" zig_align_fn({})", .{fn_info.alignment}), | 1528 | try w.print(" zig_align_fn({})", .{a}), |
| 1517 | else => unreachable, | 1529 | else => unreachable, |
| 1518 | } | 1530 | } |
| 1519 | 1531 | ||
| ... | @@ -1525,7 +1537,7 @@ pub const DeclGen = struct { | ... | @@ -1525,7 +1537,7 @@ pub const DeclGen = struct { |
| 1525 | try renderTypeSuffix( | 1537 | try renderTypeSuffix( |
| 1526 | dg.decl_index, | 1538 | dg.decl_index, |
| 1527 | store.*, | 1539 | store.*, |
| 1528 | module, | 1540 | mod, |
| 1529 | w, | 1541 | w, |
| 1530 | fn_cty_idx, | 1542 | fn_cty_idx, |
| 1531 | .suffix, | 1543 | .suffix, |
| ... | @@ -1537,8 +1549,8 @@ pub const DeclGen = struct { | ... | @@ -1537,8 +1549,8 @@ pub const DeclGen = struct { |
| 1537 | ); | 1549 | ); |
| 1538 | 1550 | ||
| 1539 | switch (kind) { | 1551 | switch (kind) { |
| 1540 | .forward => if (fn_info.alignment > 0) | 1552 | .forward => if (fn_info.alignment.toByteUnitsOptional()) |a| |
| 1541 | try w.print(" zig_align_fn({})", .{fn_info.alignment}), | 1553 | try w.print(" zig_align_fn({})", .{a}), |
| 1542 | .complete => {}, | 1554 | .complete => {}, |
| 1543 | else => unreachable, | 1555 | else => unreachable, |
| 1544 | } | 1556 | } |
| ... | @@ -1577,9 +1589,9 @@ pub const DeclGen = struct { | ... | @@ -1577,9 +1589,9 @@ pub const DeclGen = struct { |
| 1577 | 1589 | ||
| 1578 | fn renderCType(dg: *DeclGen, w: anytype, idx: CType.Index) error{ OutOfMemory, AnalysisFail }!void { | 1590 | fn renderCType(dg: *DeclGen, w: anytype, idx: CType.Index) error{ OutOfMemory, AnalysisFail }!void { |
| 1579 | const store = &dg.ctypes.set; | 1591 | const store = &dg.ctypes.set; |
| 1580 | const module = dg.module; | 1592 | const mod = dg.module; |
| 1581 | _ = try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, .{}); | 1593 | _ = try renderTypePrefix(dg.decl_index, store.*, mod, w, idx, .suffix, .{}); |
| 1582 | try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{}); | 1594 | try renderTypeSuffix(dg.decl_index, store.*, mod, w, idx, .suffix, .{}); |
| 1583 | } | 1595 | } |
| 1584 | 1596 | ||
| 1585 | const IntCastContext = union(enum) { | 1597 | const IntCastContext = union(enum) { |
| ... | @@ -1619,18 +1631,18 @@ pub const DeclGen = struct { | ... | @@ -1619,18 +1631,18 @@ pub const DeclGen = struct { |
| 1619 | /// | > 64 bit integer | < 64 bit integer | zig_make_<dest_ty>(0, src) | 1631 | /// | > 64 bit integer | < 64 bit integer | zig_make_<dest_ty>(0, src) |
| 1620 | /// | > 64 bit integer | > 64 bit integer | zig_make_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src)) | 1632 | /// | > 64 bit integer | > 64 bit integer | zig_make_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src)) |
| 1621 | fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void { | 1633 | fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void { |
| 1622 | const target = dg.module.getTarget(); | 1634 | const mod = dg.module; |
| 1623 | const dest_bits = dest_ty.bitSize(target); | 1635 | const dest_bits = dest_ty.bitSize(mod); |
| 1624 | const dest_int_info = dest_ty.intInfo(target); | 1636 | const dest_int_info = dest_ty.intInfo(mod); |
| 1625 | 1637 | ||
| 1626 | const src_is_ptr = src_ty.isPtrAtRuntime(); | 1638 | const src_is_ptr = src_ty.isPtrAtRuntime(mod); |
| 1627 | const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) { | 1639 | const src_eff_ty: Type = if (src_is_ptr) switch (dest_int_info.signedness) { |
| 1628 | .unsigned => Type.usize, | 1640 | .unsigned => Type.usize, |
| 1629 | .signed => Type.isize, | 1641 | .signed => Type.isize, |
| 1630 | } else src_ty; | 1642 | } else src_ty; |
| 1631 | 1643 | ||
| 1632 | const src_bits = src_eff_ty.bitSize(target); | 1644 | const src_bits = src_eff_ty.bitSize(mod); |
| 1633 | const src_int_info = if (src_eff_ty.isAbiInt()) src_eff_ty.intInfo(target) else null; | 1645 | const src_int_info = if (src_eff_ty.isAbiInt(mod)) src_eff_ty.intInfo(mod) else null; |
| 1634 | if (dest_bits <= 64 and src_bits <= 64) { | 1646 | if (dest_bits <= 64 and src_bits <= 64) { |
| 1635 | const needs_cast = src_int_info == null or | 1647 | const needs_cast = src_int_info == null or |
| 1636 | (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or | 1648 | (toCIntBits(dest_int_info.bits) != toCIntBits(src_int_info.?.bits) or |
| ... | @@ -1703,8 +1715,8 @@ pub const DeclGen = struct { | ... | @@ -1703,8 +1715,8 @@ pub const DeclGen = struct { |
| 1703 | alignment: u32, | 1715 | alignment: u32, |
| 1704 | kind: CType.Kind, | 1716 | kind: CType.Kind, |
| 1705 | ) error{ OutOfMemory, AnalysisFail }!void { | 1717 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1706 | const target = dg.module.getTarget(); | 1718 | const mod = dg.module; |
| 1707 | const alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target)); | 1719 | const alignas = CType.AlignAs.init(alignment, ty.abiAlignment(mod)); |
| 1708 | try dg.renderCTypeAndName(w, try dg.typeToIndex(ty, kind), name, qualifiers, alignas); | 1720 | try dg.renderCTypeAndName(w, try dg.typeToIndex(ty, kind), name, qualifiers, alignas); |
| 1709 | } | 1721 | } |
| 1710 | 1722 | ||
| ... | @@ -1717,7 +1729,7 @@ pub const DeclGen = struct { | ... | @@ -1717,7 +1729,7 @@ pub const DeclGen = struct { |
| 1717 | alignas: CType.AlignAs, | 1729 | alignas: CType.AlignAs, |
| 1718 | ) error{ OutOfMemory, AnalysisFail }!void { | 1730 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 1719 | const store = &dg.ctypes.set; | 1731 | const store = &dg.ctypes.set; |
| 1720 | const module = dg.module; | 1732 | const mod = dg.module; |
| 1721 | 1733 | ||
| 1722 | switch (std.math.order(alignas.@"align", alignas.abi)) { | 1734 | switch (std.math.order(alignas.@"align", alignas.abi)) { |
| 1723 | .lt => try w.print("zig_under_align({}) ", .{alignas.getAlign()}), | 1735 | .lt => try w.print("zig_under_align({}) ", .{alignas.getAlign()}), |
| ... | @@ -1726,25 +1738,20 @@ pub const DeclGen = struct { | ... | @@ -1726,25 +1738,20 @@ pub const DeclGen = struct { |
| 1726 | } | 1738 | } |
| 1727 | 1739 | ||
| 1728 | const trailing = | 1740 | const trailing = |
| 1729 | try renderTypePrefix(dg.decl_index, store.*, module, w, cty_idx, .suffix, qualifiers); | 1741 | try renderTypePrefix(dg.decl_index, store.*, mod, w, cty_idx, .suffix, qualifiers); |
| 1730 | try w.print("{}", .{trailing}); | 1742 | try w.print("{}", .{trailing}); |
| 1731 | try dg.writeCValue(w, name); | 1743 | try dg.writeCValue(w, name); |
| 1732 | try renderTypeSuffix(dg.decl_index, store.*, module, w, cty_idx, .suffix, .{}); | 1744 | try renderTypeSuffix(dg.decl_index, store.*, mod, w, cty_idx, .suffix, .{}); |
| 1733 | } | 1745 | } |
| 1734 | 1746 | ||
| 1735 | fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool { | 1747 | fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool { |
| 1736 | switch (tv.val.tag()) { | 1748 | const mod = dg.module; |
| 1737 | .extern_fn => return true, | 1749 | return switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { |
| 1738 | .function => { | 1750 | .variable => |variable| mod.decl_exports.contains(variable.decl), |
| 1739 | const func = tv.val.castTag(.function).?.data; | 1751 | .extern_func => true, |
| 1740 | return dg.module.decl_exports.contains(func.owner_decl); | 1752 | .func => |func| mod.decl_exports.contains(mod.funcPtr(func.index).owner_decl), |
| 1741 | }, | ||
| 1742 | .variable => { | ||
| 1743 | const variable = tv.val.castTag(.variable).?.data; | ||
| 1744 | return dg.module.decl_exports.contains(variable.owner_decl); | ||
| 1745 | }, | ||
| 1746 | else => unreachable, | 1753 | else => unreachable, |
| 1747 | } | 1754 | }; |
| 1748 | } | 1755 | } |
| 1749 | 1756 | ||
| 1750 | fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { | 1757 | fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { |
| ... | @@ -1819,7 +1826,7 @@ pub const DeclGen = struct { | ... | @@ -1819,7 +1826,7 @@ pub const DeclGen = struct { |
| 1819 | try dg.writeCValue(writer, member); | 1826 | try dg.writeCValue(writer, member); |
| 1820 | } | 1827 | } |
| 1821 | 1828 | ||
| 1822 | fn renderFwdDecl(dg: *DeclGen, decl_index: Decl.Index, variable: *Module.Var) !void { | 1829 | fn renderFwdDecl(dg: *DeclGen, decl_index: Decl.Index, variable: InternPool.Key.Variable) !void { |
| 1823 | const decl = dg.module.declPtr(decl_index); | 1830 | const decl = dg.module.declPtr(decl_index); |
| 1824 | const fwd_decl_writer = dg.fwd_decl.writer(); | 1831 | const fwd_decl_writer = dg.fwd_decl.writer(); |
| 1825 | const is_global = dg.declIsGlobal(.{ .ty = decl.ty, .val = decl.val }) or variable.is_extern; | 1832 | const is_global = dg.declIsGlobal(.{ .ty = decl.ty, .val = decl.val }) or variable.is_extern; |
| ... | @@ -1830,7 +1837,7 @@ pub const DeclGen = struct { | ... | @@ -1830,7 +1837,7 @@ pub const DeclGen = struct { |
| 1830 | fwd_decl_writer, | 1837 | fwd_decl_writer, |
| 1831 | decl.ty, | 1838 | decl.ty, |
| 1832 | .{ .decl = decl_index }, | 1839 | .{ .decl = decl_index }, |
| 1833 | CQualifiers.init(.{ .@"const" = !variable.is_mutable }), | 1840 | CQualifiers.init(.{ .@"const" = variable.is_const }), |
| 1834 | decl.@"align", | 1841 | decl.@"align", |
| 1835 | .complete, | 1842 | .complete, |
| 1836 | ); | 1843 | ); |
| ... | @@ -1838,19 +1845,20 @@ pub const DeclGen = struct { | ... | @@ -1838,19 +1845,20 @@ pub const DeclGen = struct { |
| 1838 | } | 1845 | } |
| 1839 | 1846 | ||
| 1840 | fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void { | 1847 | fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index, export_index: u32) !void { |
| 1841 | const decl = dg.module.declPtr(decl_index); | 1848 | const mod = dg.module; |
| 1842 | dg.module.markDeclAlive(decl); | 1849 | const decl = mod.declPtr(decl_index); |
| 1843 | 1850 | try mod.markDeclAlive(decl); | |
| 1844 | if (dg.module.decl_exports.get(decl_index)) |exports| { | 1851 | |
| 1845 | try writer.writeAll(exports.items[export_index].options.name); | 1852 | if (mod.decl_exports.get(decl_index)) |exports| { |
| 1846 | } else if (decl.isExtern()) { | 1853 | try writer.print("{}", .{exports.items[export_index].opts.name.fmt(&mod.intern_pool)}); |
| 1847 | try writer.writeAll(mem.span(decl.name)); | 1854 | } else if (decl.isExtern(mod)) { |
| 1855 | try writer.print("{}", .{decl.name.fmt(&mod.intern_pool)}); | ||
| 1848 | } else { | 1856 | } else { |
| 1849 | // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), | 1857 | // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), |
| 1850 | // expand to 3x the length of its input, but let's cut it off at a much shorter limit. | 1858 | // expand to 3x the length of its input, but let's cut it off at a much shorter limit. |
| 1851 | var name: [100]u8 = undefined; | 1859 | var name: [100]u8 = undefined; |
| 1852 | var name_stream = std.io.fixedBufferStream(&name); | 1860 | var name_stream = std.io.fixedBufferStream(&name); |
| 1853 | decl.renderFullyQualifiedName(dg.module, name_stream.writer()) catch |err| switch (err) { | 1861 | decl.renderFullyQualifiedName(mod, name_stream.writer()) catch |err| switch (err) { |
| 1854 | error.NoSpaceLeft => {}, | 1862 | error.NoSpaceLeft => {}, |
| 1855 | }; | 1863 | }; |
| 1856 | try writer.print("{}__{d}", .{ | 1864 | try writer.print("{}__{d}", .{ |
| ... | @@ -1894,18 +1902,18 @@ pub const DeclGen = struct { | ... | @@ -1894,18 +1902,18 @@ pub const DeclGen = struct { |
| 1894 | .bits => {}, | 1902 | .bits => {}, |
| 1895 | } | 1903 | } |
| 1896 | 1904 | ||
| 1897 | const target = dg.module.getTarget(); | 1905 | const mod = dg.module; |
| 1898 | const int_info = if (ty.isAbiInt()) ty.intInfo(target) else std.builtin.Type.Int{ | 1906 | const int_info = if (ty.isAbiInt(mod)) ty.intInfo(mod) else std.builtin.Type.Int{ |
| 1899 | .signedness = .unsigned, | 1907 | .signedness = .unsigned, |
| 1900 | .bits = @intCast(u16, ty.bitSize(target)), | 1908 | .bits = @intCast(u16, ty.bitSize(mod)), |
| 1901 | }; | 1909 | }; |
| 1902 | 1910 | ||
| 1903 | if (is_big) try writer.print(", {}", .{int_info.signedness == .signed}); | 1911 | if (is_big) try writer.print(", {}", .{int_info.signedness == .signed}); |
| 1904 | 1912 | ||
| 1905 | var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = int_info.bits }; | 1913 | const bits_ty = if (is_big) Type.u16 else Type.u8; |
| 1906 | try writer.print(", {}", .{try dg.fmtIntLiteral( | 1914 | try writer.print(", {}", .{try dg.fmtIntLiteral( |
| 1907 | if (is_big) Type.u16 else Type.u8, | 1915 | bits_ty, |
| 1908 | Value.initPayload(&bits_pl.base), | 1916 | try mod.intValue(bits_ty, int_info.bits), |
| 1909 | .FunctionArgument, | 1917 | .FunctionArgument, |
| 1910 | )}); | 1918 | )}); |
| 1911 | } | 1919 | } |
| ... | @@ -1916,6 +1924,7 @@ pub const DeclGen = struct { | ... | @@ -1916,6 +1924,7 @@ pub const DeclGen = struct { |
| 1916 | val: Value, | 1924 | val: Value, |
| 1917 | loc: ValueRenderLocation, | 1925 | loc: ValueRenderLocation, |
| 1918 | ) !std.fmt.Formatter(formatIntLiteral) { | 1926 | ) !std.fmt.Formatter(formatIntLiteral) { |
| 1927 | const mod = dg.module; | ||
| 1919 | const kind: CType.Kind = switch (loc) { | 1928 | const kind: CType.Kind = switch (loc) { |
| 1920 | .FunctionArgument => .parameter, | 1929 | .FunctionArgument => .parameter, |
| 1921 | .Initializer, .Other => .complete, | 1930 | .Initializer, .Other => .complete, |
| ... | @@ -1923,7 +1932,7 @@ pub const DeclGen = struct { | ... | @@ -1923,7 +1932,7 @@ pub const DeclGen = struct { |
| 1923 | }; | 1932 | }; |
| 1924 | return std.fmt.Formatter(formatIntLiteral){ .data = .{ | 1933 | return std.fmt.Formatter(formatIntLiteral){ .data = .{ |
| 1925 | .dg = dg, | 1934 | .dg = dg, |
| 1926 | .int_info = ty.intInfo(dg.module.getTarget()), | 1935 | .int_info = ty.intInfo(mod), |
| 1927 | .kind = kind, | 1936 | .kind = kind, |
| 1928 | .cty = try dg.typeToCType(ty, kind), | 1937 | .cty = try dg.typeToCType(ty, kind), |
| 1929 | .val = val, | 1938 | .val = val, |
| ... | @@ -1979,7 +1988,7 @@ fn renderTypeName( | ... | @@ -1979,7 +1988,7 @@ fn renderTypeName( |
| 1979 | try w.print("{s} {s}{}__{d}", .{ | 1988 | try w.print("{s} {s}{}__{d}", .{ |
| 1980 | @tagName(tag)["fwd_".len..], | 1989 | @tagName(tag)["fwd_".len..], |
| 1981 | attributes, | 1990 | attributes, |
| 1982 | fmtIdent(mem.span(mod.declPtr(owner_decl).name)), | 1991 | fmtIdent(mod.intern_pool.stringToSlice(mod.declPtr(owner_decl).name)), |
| 1983 | @enumToInt(owner_decl), | 1992 | @enumToInt(owner_decl), |
| 1984 | }); | 1993 | }); |
| 1985 | }, | 1994 | }, |
| ... | @@ -2392,15 +2401,20 @@ pub fn genGlobalAsm(mod: *Module, writer: anytype) !void { | ... | @@ -2392,15 +2401,20 @@ pub fn genGlobalAsm(mod: *Module, writer: anytype) !void { |
| 2392 | } | 2401 | } |
| 2393 | 2402 | ||
| 2394 | pub fn genErrDecls(o: *Object) !void { | 2403 | pub fn genErrDecls(o: *Object) !void { |
| 2404 | const mod = o.dg.module; | ||
| 2395 | const writer = o.writer(); | 2405 | const writer = o.writer(); |
| 2396 | 2406 | ||
| 2397 | try writer.writeAll("enum {\n"); | 2407 | try writer.writeAll("enum {\n"); |
| 2398 | o.indent_writer.pushIndent(); | 2408 | o.indent_writer.pushIndent(); |
| 2399 | var max_name_len: usize = 0; | 2409 | var max_name_len: usize = 0; |
| 2400 | for (o.dg.module.error_name_list.items, 0..) |name, value| { | 2410 | for (mod.global_error_set.keys()[1..], 1..) |name_nts, value| { |
| 2401 | max_name_len = std.math.max(name.len, max_name_len); | 2411 | const name = mod.intern_pool.stringToSlice(name_nts); |
| 2402 | var err_pl = Value.Payload.Error{ .data = .{ .name = name } }; | 2412 | max_name_len = @max(name.len, max_name_len); |
| 2403 | try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_pl.base), .Other); | 2413 | const err_val = try mod.intern(.{ .err = .{ |
| 2414 | .ty = .anyerror_type, | ||
| 2415 | .name = name_nts, | ||
| 2416 | } }); | ||
| 2417 | try o.dg.renderValue(writer, Type.anyerror, err_val.toValue(), .Other); | ||
| 2404 | try writer.print(" = {d}u,\n", .{value}); | 2418 | try writer.print(" = {d}u,\n", .{value}); |
| 2405 | } | 2419 | } |
| 2406 | o.indent_writer.popIndent(); | 2420 | o.indent_writer.popIndent(); |
| ... | @@ -2412,40 +2426,44 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -2412,40 +2426,44 @@ pub fn genErrDecls(o: *Object) !void { |
| 2412 | defer o.dg.gpa.free(name_buf); | 2426 | defer o.dg.gpa.free(name_buf); |
| 2413 | 2427 | ||
| 2414 | @memcpy(name_buf[0..name_prefix.len], name_prefix); | 2428 | @memcpy(name_buf[0..name_prefix.len], name_prefix); |
| 2415 | for (o.dg.module.error_name_list.items) |name| { | 2429 | for (mod.global_error_set.keys()) |name_nts| { |
| 2430 | const name = mod.intern_pool.stringToSlice(name_nts); | ||
| 2416 | @memcpy(name_buf[name_prefix.len..][0..name.len], name); | 2431 | @memcpy(name_buf[name_prefix.len..][0..name.len], name); |
| 2417 | const identifier = name_buf[0 .. name_prefix.len + name.len]; | 2432 | const identifier = name_buf[0 .. name_prefix.len + name.len]; |
| 2418 | 2433 | ||
| 2419 | var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len }; | 2434 | const name_ty = try mod.arrayType(.{ |
| 2420 | const name_ty = Type.initPayload(&name_ty_pl.base); | 2435 | .len = name.len, |
| 2421 | 2436 | .child = .u8_type, | |
| 2422 | var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name }; | 2437 | .sentinel = .zero_u8, |
| 2423 | const name_val = Value.initPayload(&name_pl.base); | 2438 | }); |
| 2439 | const name_val = try mod.intern(.{ .aggregate = .{ | ||
| 2440 | .ty = name_ty.toIntern(), | ||
| 2441 | .storage = .{ .bytes = name }, | ||
| 2442 | } }); | ||
| 2424 | 2443 | ||
| 2425 | try writer.writeAll("static "); | 2444 | try writer.writeAll("static "); |
| 2426 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, 0, .complete); | 2445 | try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, 0, .complete); |
| 2427 | try writer.writeAll(" = "); | 2446 | try writer.writeAll(" = "); |
| 2428 | try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer); | 2447 | try o.dg.renderValue(writer, name_ty, name_val.toValue(), .StaticInitializer); |
| 2429 | try writer.writeAll(";\n"); | 2448 | try writer.writeAll(";\n"); |
| 2430 | } | 2449 | } |
| 2431 | 2450 | ||
| 2432 | var name_array_ty_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{ | 2451 | const name_array_ty = try mod.arrayType(.{ |
| 2433 | .len = o.dg.module.error_name_list.items.len, | 2452 | .len = mod.global_error_set.count(), |
| 2434 | .elem_type = Type.initTag(.const_slice_u8_sentinel_0), | 2453 | .child = .slice_const_u8_sentinel_0_type, |
| 2435 | } }; | 2454 | }); |
| 2436 | const name_array_ty = Type.initPayload(&name_array_ty_pl.base); | ||
| 2437 | 2455 | ||
| 2438 | try writer.writeAll("static "); | 2456 | try writer.writeAll("static "); |
| 2439 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, 0, .complete); | 2457 | try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, 0, .complete); |
| 2440 | try writer.writeAll(" = {"); | 2458 | try writer.writeAll(" = {"); |
| 2441 | for (o.dg.module.error_name_list.items, 0..) |name, value| { | 2459 | for (mod.global_error_set.keys(), 0..) |name_nts, value| { |
| 2460 | const name = mod.intern_pool.stringToSlice(name_nts); | ||
| 2442 | if (value != 0) try writer.writeByte(','); | 2461 | if (value != 0) try writer.writeByte(','); |
| 2443 | 2462 | ||
| 2444 | var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len }; | 2463 | const len_val = try mod.intValue(Type.usize, name.len); |
| 2445 | const len_val = Value.initPayload(&len_pl.base); | ||
| 2446 | 2464 | ||
| 2447 | try writer.print("{{" ++ name_prefix ++ "{}, {}}}", .{ | 2465 | try writer.print("{{" ++ name_prefix ++ "{}, {}}}", .{ |
| 2448 | fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val, .Other), | 2466 | fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val, .StaticInitializer), |
| 2449 | }); | 2467 | }); |
| 2450 | } | 2468 | } |
| 2451 | try writer.writeAll("};\n"); | 2469 | try writer.writeAll("};\n"); |
| ... | @@ -2455,20 +2473,23 @@ fn genExports(o: *Object) !void { | ... | @@ -2455,20 +2473,23 @@ fn genExports(o: *Object) !void { |
| 2455 | const tracy = trace(@src()); | 2473 | const tracy = trace(@src()); |
| 2456 | defer tracy.end(); | 2474 | defer tracy.end(); |
| 2457 | 2475 | ||
| 2476 | const mod = o.dg.module; | ||
| 2477 | const ip = &mod.intern_pool; | ||
| 2458 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2478 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2459 | if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| { | 2479 | if (mod.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| { |
| 2460 | for (exports.items[1..], 1..) |@"export", i| { | 2480 | for (exports.items[1..], 1..) |@"export", i| { |
| 2461 | try fwd_decl_writer.writeAll("zig_export("); | 2481 | try fwd_decl_writer.writeAll("zig_export("); |
| 2462 | try o.dg.renderFunctionSignature(fwd_decl_writer, o.dg.decl_index.unwrap().?, .forward, .{ .export_index = @intCast(u32, i) }); | 2482 | try o.dg.renderFunctionSignature(fwd_decl_writer, o.dg.decl_index.unwrap().?, .forward, .{ .export_index = @intCast(u32, i) }); |
| 2463 | try fwd_decl_writer.print(", {s}, {s});\n", .{ | 2483 | try fwd_decl_writer.print(", {s}, {s});\n", .{ |
| 2464 | fmtStringLiteral(exports.items[0].options.name, null), | 2484 | fmtStringLiteral(ip.stringToSlice(exports.items[0].opts.name), null), |
| 2465 | fmtStringLiteral(@"export".options.name, null), | 2485 | fmtStringLiteral(ip.stringToSlice(@"export".opts.name), null), |
| 2466 | }); | 2486 | }); |
| 2467 | } | 2487 | } |
| 2468 | } | 2488 | } |
| 2469 | } | 2489 | } |
| 2470 | 2490 | ||
| 2471 | pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { | 2491 | pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2492 | const mod = o.dg.module; | ||
| 2472 | const w = o.writer(); | 2493 | const w = o.writer(); |
| 2473 | const key = lazy_fn.key_ptr.*; | 2494 | const key = lazy_fn.key_ptr.*; |
| 2474 | const val = lazy_fn.value_ptr; | 2495 | const val = lazy_fn.value_ptr; |
| ... | @@ -2477,7 +2498,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { | ... | @@ -2477,7 +2498,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2477 | .tag_name => { | 2498 | .tag_name => { |
| 2478 | const enum_ty = val.data.tag_name; | 2499 | const enum_ty = val.data.tag_name; |
| 2479 | 2500 | ||
| 2480 | const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | 2501 | const name_slice_ty = Type.slice_const_u8_sentinel_0; |
| 2481 | 2502 | ||
| 2482 | try w.writeAll("static "); | 2503 | try w.writeAll("static "); |
| 2483 | try o.dg.renderType(w, name_slice_ty); | 2504 | try o.dg.renderType(w, name_slice_ty); |
| ... | @@ -2486,34 +2507,30 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { | ... | @@ -2486,34 +2507,30 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2486 | try w.writeByte('('); | 2507 | try w.writeByte('('); |
| 2487 | try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete); | 2508 | try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete); |
| 2488 | try w.writeAll(") {\n switch (tag) {\n"); | 2509 | try w.writeAll(") {\n switch (tag) {\n"); |
| 2489 | for (enum_ty.enumFields().keys(), 0..) |name, index| { | 2510 | for (enum_ty.enumFields(mod), 0..) |name_ip, index_usize| { |
| 2490 | var tag_pl: Value.Payload.U32 = .{ | 2511 | const index = @intCast(u32, index_usize); |
| 2491 | .base = .{ .tag = .enum_field_index }, | 2512 | const name = mod.intern_pool.stringToSlice(name_ip); |
| 2492 | .data = @intCast(u32, index), | 2513 | const tag_val = try mod.enumValueFieldIndex(enum_ty, index); |
| 2493 | }; | ||
| 2494 | const tag_val = Value.initPayload(&tag_pl.base); | ||
| 2495 | 2514 | ||
| 2496 | var int_pl: Value.Payload.U64 = undefined; | 2515 | const int_val = try tag_val.enumToInt(enum_ty, mod); |
| 2497 | const int_val = tag_val.enumToInt(enum_ty, &int_pl); | ||
| 2498 | 2516 | ||
| 2499 | var name_ty_pl = Type.Payload.Len{ | 2517 | const name_ty = try mod.arrayType(.{ |
| 2500 | .base = .{ .tag = .array_u8_sentinel_0 }, | 2518 | .len = name.len, |
| 2501 | .data = name.len, | 2519 | .child = .u8_type, |
| 2502 | }; | 2520 | .sentinel = .zero_u8, |
| 2503 | const name_ty = Type.initPayload(&name_ty_pl.base); | 2521 | }); |
| 2504 | 2522 | const name_val = try mod.intern(.{ .aggregate = .{ | |
| 2505 | var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name }; | 2523 | .ty = name_ty.toIntern(), |
| 2506 | const name_val = Value.initPayload(&name_pl.base); | 2524 | .storage = .{ .bytes = name }, |
| 2507 | 2525 | } }); | |
| 2508 | var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len }; | 2526 | const len_val = try mod.intValue(Type.usize, name.len); |
| 2509 | const len_val = Value.initPayload(&len_pl.base); | ||
| 2510 | 2527 | ||
| 2511 | try w.print(" case {}: {{\n static ", .{ | 2528 | try w.print(" case {}: {{\n static ", .{ |
| 2512 | try o.dg.fmtIntLiteral(enum_ty, int_val, .Other), | 2529 | try o.dg.fmtIntLiteral(enum_ty, int_val, .Other), |
| 2513 | }); | 2530 | }); |
| 2514 | try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete); | 2531 | try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete); |
| 2515 | try w.writeAll(" = "); | 2532 | try w.writeAll(" = "); |
| 2516 | try o.dg.renderValue(w, name_ty, name_val, .Initializer); | 2533 | try o.dg.renderValue(w, name_ty, name_val.toValue(), .Initializer); |
| 2517 | try w.writeAll(";\n return ("); | 2534 | try w.writeAll(";\n return ("); |
| 2518 | try o.dg.renderType(w, name_slice_ty); | 2535 | try o.dg.renderType(w, name_slice_ty); |
| 2519 | try w.print("){{{}, {}}};\n", .{ | 2536 | try w.print("){{{}, {}}};\n", .{ |
| ... | @@ -2529,7 +2546,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { | ... | @@ -2529,7 +2546,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2529 | try w.writeAll("}\n"); | 2546 | try w.writeAll("}\n"); |
| 2530 | }, | 2547 | }, |
| 2531 | .never_tail, .never_inline => |fn_decl_index| { | 2548 | .never_tail, .never_inline => |fn_decl_index| { |
| 2532 | const fn_decl = o.dg.module.declPtr(fn_decl_index); | 2549 | const fn_decl = mod.declPtr(fn_decl_index); |
| 2533 | const fn_cty = try o.dg.typeToCType(fn_decl.ty, .complete); | 2550 | const fn_cty = try o.dg.typeToCType(fn_decl.ty, .complete); |
| 2534 | const fn_info = fn_cty.cast(CType.Payload.Function).?.data; | 2551 | const fn_info = fn_cty.cast(CType.Payload.Function).?.data; |
| 2535 | 2552 | ||
| ... | @@ -2646,19 +2663,19 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2646,19 +2663,19 @@ pub fn genDecl(o: *Object) !void { |
| 2646 | const tracy = trace(@src()); | 2663 | const tracy = trace(@src()); |
| 2647 | defer tracy.end(); | 2664 | defer tracy.end(); |
| 2648 | 2665 | ||
| 2666 | const mod = o.dg.module; | ||
| 2649 | const decl = o.dg.decl.?; | 2667 | const decl = o.dg.decl.?; |
| 2650 | const decl_c_value = .{ .decl = o.dg.decl_index.unwrap().? }; | 2668 | const decl_c_value = .{ .decl = o.dg.decl_index.unwrap().? }; |
| 2651 | const tv: TypedValue = .{ .ty = decl.ty, .val = decl.val }; | 2669 | const tv: TypedValue = .{ .ty = decl.ty, .val = (try decl.internValue(mod)).toValue() }; |
| 2652 | 2670 | ||
| 2653 | if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime()) return; | 2671 | if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return; |
| 2654 | if (tv.val.tag() == .extern_fn) { | 2672 | if (tv.val.getExternFunc(mod)) |_| { |
| 2655 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2673 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2656 | try fwd_decl_writer.writeAll("zig_extern "); | 2674 | try fwd_decl_writer.writeAll("zig_extern "); |
| 2657 | try o.dg.renderFunctionSignature(fwd_decl_writer, decl_c_value.decl, .forward, .{ .export_index = 0 }); | 2675 | try o.dg.renderFunctionSignature(fwd_decl_writer, decl_c_value.decl, .forward, .{ .export_index = 0 }); |
| 2658 | try fwd_decl_writer.writeAll(";\n"); | 2676 | try fwd_decl_writer.writeAll(";\n"); |
| 2659 | try genExports(o); | 2677 | try genExports(o); |
| 2660 | } else if (tv.val.castTag(.variable)) |var_payload| { | 2678 | } else if (tv.val.getVariable(mod)) |variable| { |
| 2661 | const variable: *Module.Var = var_payload.data; | ||
| 2662 | try o.dg.renderFwdDecl(decl_c_value.decl, variable); | 2679 | try o.dg.renderFwdDecl(decl_c_value.decl, variable); |
| 2663 | try genExports(o); | 2680 | try genExports(o); |
| 2664 | 2681 | ||
| ... | @@ -2669,11 +2686,12 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2669,11 +2686,12 @@ pub fn genDecl(o: *Object) !void { |
| 2669 | if (!is_global) try w.writeAll("static "); | 2686 | if (!is_global) try w.writeAll("static "); |
| 2670 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); | 2687 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); |
| 2671 | if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); | 2688 | if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); |
| 2672 | if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section}); | 2689 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| |
| 2690 | try w.print("zig_linksection(\"{s}\", ", .{s}); | ||
| 2673 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.@"align", .complete); | 2691 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.@"align", .complete); |
| 2674 | if (decl.@"linksection" != null) try w.writeAll(", read, write)"); | 2692 | if (decl.@"linksection" != .none) try w.writeAll(", read, write)"); |
| 2675 | try w.writeAll(" = "); | 2693 | try w.writeAll(" = "); |
| 2676 | try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer); | 2694 | try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer); |
| 2677 | try w.writeByte(';'); | 2695 | try w.writeByte(';'); |
| 2678 | try o.indent_writer.insertNewline(); | 2696 | try o.indent_writer.insertNewline(); |
| 2679 | } else { | 2697 | } else { |
| ... | @@ -2686,9 +2704,10 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2686,9 +2704,10 @@ pub fn genDecl(o: *Object) !void { |
| 2686 | 2704 | ||
| 2687 | const w = o.writer(); | 2705 | const w = o.writer(); |
| 2688 | if (!is_global) try w.writeAll("static "); | 2706 | if (!is_global) try w.writeAll("static "); |
| 2689 | if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section}); | 2707 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| |
| 2708 | try w.print("zig_linksection(\"{s}\", ", .{s}); | ||
| 2690 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.@"align", .complete); | 2709 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.@"align", .complete); |
| 2691 | if (decl.@"linksection" != null) try w.writeAll(", read)"); | 2710 | if (decl.@"linksection" != .none) try w.writeAll(", read)"); |
| 2692 | try w.writeAll(" = "); | 2711 | try w.writeAll(" = "); |
| 2693 | try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); | 2712 | try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); |
| 2694 | try w.writeAll(";\n"); | 2713 | try w.writeAll(";\n"); |
| ... | @@ -2704,8 +2723,9 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { | ... | @@ -2704,8 +2723,9 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { |
| 2704 | .val = dg.decl.?.val, | 2723 | .val = dg.decl.?.val, |
| 2705 | }; | 2724 | }; |
| 2706 | const writer = dg.fwd_decl.writer(); | 2725 | const writer = dg.fwd_decl.writer(); |
| 2726 | const mod = dg.module; | ||
| 2707 | 2727 | ||
| 2708 | switch (tv.ty.zigTypeTag()) { | 2728 | switch (tv.ty.zigTypeTag(mod)) { |
| 2709 | .Fn => { | 2729 | .Fn => { |
| 2710 | const is_global = dg.declIsGlobal(tv); | 2730 | const is_global = dg.declIsGlobal(tv); |
| 2711 | if (is_global) { | 2731 | if (is_global) { |
| ... | @@ -2791,17 +2811,18 @@ fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []con | ... | @@ -2791,17 +2811,18 @@ fn genBodyResolveState(f: *Function, inst: Air.Inst.Index, leading_deaths: []con |
| 2791 | } | 2811 | } |
| 2792 | 2812 | ||
| 2793 | fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void { | 2813 | fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void { |
| 2814 | const mod = f.object.dg.module; | ||
| 2815 | const ip = &mod.intern_pool; | ||
| 2794 | const air_tags = f.air.instructions.items(.tag); | 2816 | const air_tags = f.air.instructions.items(.tag); |
| 2795 | 2817 | ||
| 2796 | for (body) |inst| { | 2818 | for (body) |inst| { |
| 2797 | if (f.liveness.isUnused(inst) and !f.air.mustLower(inst)) { | 2819 | if (f.liveness.isUnused(inst) and !f.air.mustLower(inst, ip)) |
| 2798 | continue; | 2820 | continue; |
| 2799 | } | ||
| 2800 | 2821 | ||
| 2801 | const result_value = switch (air_tags[inst]) { | 2822 | const result_value = switch (air_tags[inst]) { |
| 2802 | // zig fmt: off | 2823 | // zig fmt: off |
| 2803 | .constant => unreachable, // excluded from function bodies | 2824 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, |
| 2804 | .const_ty => unreachable, // excluded from function bodies | 2825 | |
| 2805 | .arg => try airArg(f, inst), | 2826 | .arg => try airArg(f, inst), |
| 2806 | 2827 | ||
| 2807 | .trap => try airTrap(f.object.writer()), | 2828 | .trap => try airTrap(f.object.writer()), |
| ... | @@ -2826,10 +2847,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, | ... | @@ -2826,10 +2847,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2826 | .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .none), | 2847 | .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .none), |
| 2827 | .rem => blk: { | 2848 | .rem => blk: { |
| 2828 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2849 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2829 | const lhs_scalar_ty = f.air.typeOf(bin_op.lhs).scalarType(); | 2850 | const lhs_scalar_ty = f.typeOf(bin_op.lhs).scalarType(mod); |
| 2830 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), | 2851 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), |
| 2831 | // so we only check one. | 2852 | // so we only check one. |
| 2832 | break :blk if (lhs_scalar_ty.isInt()) | 2853 | break :blk if (lhs_scalar_ty.isInt(mod)) |
| 2833 | try airBinOp(f, inst, "%", "rem", .none) | 2854 | try airBinOp(f, inst, "%", "rem", .none) |
| 2834 | else | 2855 | else |
| 2835 | try airBinFloatOp(f, inst, "fmod"); | 2856 | try airBinFloatOp(f, inst, "fmod"); |
| ... | @@ -3077,7 +3098,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, | ... | @@ -3077,7 +3098,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 3077 | fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue { | 3098 | fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue { |
| 3078 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3099 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3079 | 3100 | ||
| 3080 | const inst_ty = f.air.typeOfIndex(inst); | 3101 | const inst_ty = f.typeOfIndex(inst); |
| 3081 | const operand = try f.resolveInst(ty_op.operand); | 3102 | const operand = try f.resolveInst(ty_op.operand); |
| 3082 | try reap(f, inst, &.{ty_op.operand}); | 3103 | try reap(f, inst, &.{ty_op.operand}); |
| 3083 | 3104 | ||
| ... | @@ -3095,9 +3116,10 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [ | ... | @@ -3095,9 +3116,10 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [ |
| 3095 | } | 3116 | } |
| 3096 | 3117 | ||
| 3097 | fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { | 3118 | fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3098 | const inst_ty = f.air.typeOfIndex(inst); | 3119 | const mod = f.object.dg.module; |
| 3120 | const inst_ty = f.typeOfIndex(inst); | ||
| 3099 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3121 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3100 | if (!inst_ty.hasRuntimeBitsIgnoreComptime()) { | 3122 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3101 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 3123 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3102 | return .none; | 3124 | return .none; |
| 3103 | } | 3125 | } |
| ... | @@ -3120,13 +3142,14 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3120,13 +3142,14 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3120 | } | 3142 | } |
| 3121 | 3143 | ||
| 3122 | fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | 3144 | fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3145 | const mod = f.object.dg.module; | ||
| 3123 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 3146 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3124 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; | 3147 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3125 | 3148 | ||
| 3126 | const inst_ty = f.air.typeOfIndex(inst); | 3149 | const inst_ty = f.typeOfIndex(inst); |
| 3127 | const ptr_ty = f.air.typeOf(bin_op.lhs); | 3150 | const ptr_ty = f.typeOf(bin_op.lhs); |
| 3128 | const elem_ty = ptr_ty.childType(); | 3151 | const elem_ty = ptr_ty.childType(mod); |
| 3129 | const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(); | 3152 | const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(mod); |
| 3130 | 3153 | ||
| 3131 | const ptr = try f.resolveInst(bin_op.lhs); | 3154 | const ptr = try f.resolveInst(bin_op.lhs); |
| 3132 | const index = try f.resolveInst(bin_op.rhs); | 3155 | const index = try f.resolveInst(bin_op.rhs); |
| ... | @@ -3141,7 +3164,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3141,7 +3164,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3141 | try f.renderType(writer, inst_ty); | 3164 | try f.renderType(writer, inst_ty); |
| 3142 | try writer.writeByte(')'); | 3165 | try writer.writeByte(')'); |
| 3143 | if (elem_has_bits) try writer.writeByte('&'); | 3166 | if (elem_has_bits) try writer.writeByte('&'); |
| 3144 | if (elem_has_bits and ptr_ty.ptrSize() == .One) { | 3167 | if (elem_has_bits and ptr_ty.ptrSize(mod) == .One) { |
| 3145 | // It's a pointer to an array, so we need to de-reference. | 3168 | // It's a pointer to an array, so we need to de-reference. |
| 3146 | try f.writeCValueDeref(writer, ptr); | 3169 | try f.writeCValueDeref(writer, ptr); |
| 3147 | } else try f.writeCValue(writer, ptr, .Other); | 3170 | } else try f.writeCValue(writer, ptr, .Other); |
| ... | @@ -3155,9 +3178,10 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3155,9 +3178,10 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3155 | } | 3178 | } |
| 3156 | 3179 | ||
| 3157 | fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { | 3180 | fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3158 | const inst_ty = f.air.typeOfIndex(inst); | 3181 | const mod = f.object.dg.module; |
| 3182 | const inst_ty = f.typeOfIndex(inst); | ||
| 3159 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3183 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3160 | if (!inst_ty.hasRuntimeBitsIgnoreComptime()) { | 3184 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3161 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 3185 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3162 | return .none; | 3186 | return .none; |
| 3163 | } | 3187 | } |
| ... | @@ -3180,13 +3204,14 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3180,13 +3204,14 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3180 | } | 3204 | } |
| 3181 | 3205 | ||
| 3182 | fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | 3206 | fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3207 | const mod = f.object.dg.module; | ||
| 3183 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 3208 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3184 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; | 3209 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3185 | 3210 | ||
| 3186 | const inst_ty = f.air.typeOfIndex(inst); | 3211 | const inst_ty = f.typeOfIndex(inst); |
| 3187 | const slice_ty = f.air.typeOf(bin_op.lhs); | 3212 | const slice_ty = f.typeOf(bin_op.lhs); |
| 3188 | const elem_ty = slice_ty.elemType2(); | 3213 | const elem_ty = slice_ty.elemType2(mod); |
| 3189 | const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(); | 3214 | const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(mod); |
| 3190 | 3215 | ||
| 3191 | const slice = try f.resolveInst(bin_op.lhs); | 3216 | const slice = try f.resolveInst(bin_op.lhs); |
| 3192 | const index = try f.resolveInst(bin_op.rhs); | 3217 | const index = try f.resolveInst(bin_op.rhs); |
| ... | @@ -3209,9 +3234,10 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3209,9 +3234,10 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3209 | } | 3234 | } |
| 3210 | 3235 | ||
| 3211 | fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { | 3236 | fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3237 | const mod = f.object.dg.module; | ||
| 3212 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3238 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3213 | const inst_ty = f.air.typeOfIndex(inst); | 3239 | const inst_ty = f.typeOfIndex(inst); |
| 3214 | if (!inst_ty.hasRuntimeBitsIgnoreComptime()) { | 3240 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3215 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 3241 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3216 | return .none; | 3242 | return .none; |
| 3217 | } | 3243 | } |
| ... | @@ -3234,14 +3260,14 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3234,14 +3260,14 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3234 | } | 3260 | } |
| 3235 | 3261 | ||
| 3236 | fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { | 3262 | fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3237 | const inst_ty = f.air.typeOfIndex(inst); | 3263 | const mod = f.object.dg.module; |
| 3238 | const elem_type = inst_ty.elemType(); | 3264 | const inst_ty = f.typeOfIndex(inst); |
| 3239 | if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty }; | 3265 | const elem_type = inst_ty.childType(mod); |
| 3266 | if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return .{ .undef = inst_ty }; | ||
| 3240 | 3267 | ||
| 3241 | const target = f.object.dg.module.getTarget(); | ||
| 3242 | const local = try f.allocLocalValue( | 3268 | const local = try f.allocLocalValue( |
| 3243 | elem_type, | 3269 | elem_type, |
| 3244 | inst_ty.ptrAlignment(target), | 3270 | inst_ty.ptrAlignment(mod), |
| 3245 | ); | 3271 | ); |
| 3246 | log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local }); | 3272 | log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local }); |
| 3247 | const gpa = f.object.dg.module.gpa; | 3273 | const gpa = f.object.dg.module.gpa; |
| ... | @@ -3250,14 +3276,14 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3250,14 +3276,14 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3250 | } | 3276 | } |
| 3251 | 3277 | ||
| 3252 | fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { | 3278 | fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3253 | const inst_ty = f.air.typeOfIndex(inst); | 3279 | const mod = f.object.dg.module; |
| 3254 | const elem_ty = inst_ty.elemType(); | 3280 | const inst_ty = f.typeOfIndex(inst); |
| 3255 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return .{ .undef = inst_ty }; | 3281 | const elem_ty = inst_ty.childType(mod); |
| 3282 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return .{ .undef = inst_ty }; | ||
| 3256 | 3283 | ||
| 3257 | const target = f.object.dg.module.getTarget(); | ||
| 3258 | const local = try f.allocLocalValue( | 3284 | const local = try f.allocLocalValue( |
| 3259 | elem_ty, | 3285 | elem_ty, |
| 3260 | inst_ty.ptrAlignment(target), | 3286 | inst_ty.ptrAlignment(mod), |
| 3261 | ); | 3287 | ); |
| 3262 | log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local }); | 3288 | log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local }); |
| 3263 | const gpa = f.object.dg.module.gpa; | 3289 | const gpa = f.object.dg.module.gpa; |
| ... | @@ -3266,7 +3292,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3266,7 +3292,7 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3266 | } | 3292 | } |
| 3267 | 3293 | ||
| 3268 | fn airArg(f: *Function, inst: Air.Inst.Index) !CValue { | 3294 | fn airArg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3269 | const inst_ty = f.air.typeOfIndex(inst); | 3295 | const inst_ty = f.typeOfIndex(inst); |
| 3270 | const inst_cty = try f.typeToIndex(inst_ty, .parameter); | 3296 | const inst_cty = try f.typeToIndex(inst_ty, .parameter); |
| 3271 | 3297 | ||
| 3272 | const i = f.next_arg_index; | 3298 | const i = f.next_arg_index; |
| ... | @@ -3290,14 +3316,15 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3290,14 +3316,15 @@ fn airArg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3290 | } | 3316 | } |
| 3291 | 3317 | ||
| 3292 | fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | 3318 | fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3319 | const mod = f.object.dg.module; | ||
| 3293 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3320 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3294 | 3321 | ||
| 3295 | const ptr_ty = f.air.typeOf(ty_op.operand); | 3322 | const ptr_ty = f.typeOf(ty_op.operand); |
| 3296 | const ptr_scalar_ty = ptr_ty.scalarType(); | 3323 | const ptr_scalar_ty = ptr_ty.scalarType(mod); |
| 3297 | const ptr_info = ptr_scalar_ty.ptrInfo().data; | 3324 | const ptr_info = ptr_scalar_ty.ptrInfo(mod); |
| 3298 | const src_ty = ptr_info.pointee_type; | 3325 | const src_ty = ptr_info.pointee_type; |
| 3299 | 3326 | ||
| 3300 | if (!src_ty.hasRuntimeBitsIgnoreComptime()) { | 3327 | if (!src_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3301 | try reap(f, inst, &.{ty_op.operand}); | 3328 | try reap(f, inst, &.{ty_op.operand}); |
| 3302 | return .none; | 3329 | return .none; |
| 3303 | } | 3330 | } |
| ... | @@ -3306,9 +3333,8 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3306,9 +3333,8 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3306 | 3333 | ||
| 3307 | try reap(f, inst, &.{ty_op.operand}); | 3334 | try reap(f, inst, &.{ty_op.operand}); |
| 3308 | 3335 | ||
| 3309 | const target = f.object.dg.module.getTarget(); | 3336 | const is_aligned = ptr_info.@"align" == 0 or ptr_info.@"align" >= src_ty.abiAlignment(mod); |
| 3310 | const is_aligned = ptr_info.@"align" == 0 or ptr_info.@"align" >= src_ty.abiAlignment(target); | 3337 | const is_array = lowersToArray(src_ty, mod); |
| 3311 | const is_array = lowersToArray(src_ty, target); | ||
| 3312 | const need_memcpy = !is_aligned or is_array; | 3338 | const need_memcpy = !is_aligned or is_array; |
| 3313 | 3339 | ||
| 3314 | const writer = f.object.writer(); | 3340 | const writer = f.object.writer(); |
| ... | @@ -3327,29 +3353,13 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3327,29 +3353,13 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3327 | try f.renderType(writer, src_ty); | 3353 | try f.renderType(writer, src_ty); |
| 3328 | try writer.writeAll("))"); | 3354 | try writer.writeAll("))"); |
| 3329 | } else if (ptr_info.host_size > 0 and ptr_info.vector_index == .none) { | 3355 | } else if (ptr_info.host_size > 0 and ptr_info.vector_index == .none) { |
| 3330 | var host_pl = Type.Payload.Bits{ | 3356 | const host_bits: u16 = ptr_info.host_size * 8; |
| 3331 | .base = .{ .tag = .int_unsigned }, | 3357 | const host_ty = try mod.intType(.unsigned, host_bits); |
| 3332 | .data = ptr_info.host_size * 8, | ||
| 3333 | }; | ||
| 3334 | const host_ty = Type.initPayload(&host_pl.base); | ||
| 3335 | 3358 | ||
| 3336 | var bit_offset_ty_pl = Type.Payload.Bits{ | 3359 | const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(host_bits - 1)); |
| 3337 | .base = .{ .tag = .int_unsigned }, | 3360 | const bit_offset_val = try mod.intValue(bit_offset_ty, ptr_info.bit_offset); |
| 3338 | .data = Type.smallestUnsignedBits(host_pl.data - 1), | ||
| 3339 | }; | ||
| 3340 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); | ||
| 3341 | 3361 | ||
| 3342 | var bit_offset_val_pl: Value.Payload.U64 = .{ | 3362 | const field_ty = try mod.intType(.unsigned, @intCast(u16, src_ty.bitSize(mod))); |
| 3343 | .base = .{ .tag = .int_u64 }, | ||
| 3344 | .data = ptr_info.bit_offset, | ||
| 3345 | }; | ||
| 3346 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); | ||
| 3347 | |||
| 3348 | var field_pl = Type.Payload.Bits{ | ||
| 3349 | .base = .{ .tag = .int_unsigned }, | ||
| 3350 | .data = @intCast(u16, src_ty.bitSize(target)), | ||
| 3351 | }; | ||
| 3352 | const field_ty = Type.initPayload(&field_pl.base); | ||
| 3353 | 3363 | ||
| 3354 | try f.writeCValue(writer, local, .Other); | 3364 | try f.writeCValue(writer, local, .Other); |
| 3355 | try v.elem(f, writer); | 3365 | try v.elem(f, writer); |
| ... | @@ -3360,9 +3370,9 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3360,9 +3370,9 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3360 | try writer.writeAll("(("); | 3370 | try writer.writeAll("(("); |
| 3361 | try f.renderType(writer, field_ty); | 3371 | try f.renderType(writer, field_ty); |
| 3362 | try writer.writeByte(')'); | 3372 | try writer.writeByte(')'); |
| 3363 | const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64; | 3373 | const cant_cast = host_ty.isInt(mod) and host_ty.bitSize(mod) > 64; |
| 3364 | if (cant_cast) { | 3374 | if (cant_cast) { |
| 3365 | if (field_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); | 3375 | if (field_ty.bitSize(mod) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); |
| 3366 | try writer.writeAll("zig_lo_"); | 3376 | try writer.writeAll("zig_lo_"); |
| 3367 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); | 3377 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3368 | try writer.writeByte('('); | 3378 | try writer.writeByte('('); |
| ... | @@ -3390,23 +3400,22 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3390,23 +3400,22 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3390 | } | 3400 | } |
| 3391 | 3401 | ||
| 3392 | fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { | 3402 | fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 3403 | const mod = f.object.dg.module; | ||
| 3393 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 3404 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 3394 | const writer = f.object.writer(); | 3405 | const writer = f.object.writer(); |
| 3395 | const target = f.object.dg.module.getTarget(); | ||
| 3396 | const op_inst = Air.refToIndex(un_op); | 3406 | const op_inst = Air.refToIndex(un_op); |
| 3397 | const op_ty = f.air.typeOf(un_op); | 3407 | const op_ty = f.typeOf(un_op); |
| 3398 | const ret_ty = if (is_ptr) op_ty.childType() else op_ty; | 3408 | const ret_ty = if (is_ptr) op_ty.childType(mod) else op_ty; |
| 3399 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; | 3409 | const lowered_ret_ty = try lowerFnRetTy(ret_ty, mod); |
| 3400 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); | ||
| 3401 | 3410 | ||
| 3402 | if (op_inst != null and f.air.instructions.items(.tag)[op_inst.?] == .call_always_tail) { | 3411 | if (op_inst != null and f.air.instructions.items(.tag)[op_inst.?] == .call_always_tail) { |
| 3403 | try reap(f, inst, &.{un_op}); | 3412 | try reap(f, inst, &.{un_op}); |
| 3404 | _ = try airCall(f, op_inst.?, .always_tail); | 3413 | _ = try airCall(f, op_inst.?, .always_tail); |
| 3405 | } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) { | 3414 | } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3406 | const operand = try f.resolveInst(un_op); | 3415 | const operand = try f.resolveInst(un_op); |
| 3407 | try reap(f, inst, &.{un_op}); | 3416 | try reap(f, inst, &.{un_op}); |
| 3408 | var deref = is_ptr; | 3417 | var deref = is_ptr; |
| 3409 | const is_array = lowersToArray(ret_ty, target); | 3418 | const is_array = lowersToArray(ret_ty, mod); |
| 3410 | const ret_val = if (is_array) ret_val: { | 3419 | const ret_val = if (is_array) ret_val: { |
| 3411 | const array_local = try f.allocLocal(inst, lowered_ret_ty); | 3420 | const array_local = try f.allocLocal(inst, lowered_ret_ty); |
| 3412 | try writer.writeAll("memcpy("); | 3421 | try writer.writeAll("memcpy("); |
| ... | @@ -3435,22 +3444,23 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { | ... | @@ -3435,22 +3444,23 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 3435 | } else { | 3444 | } else { |
| 3436 | try reap(f, inst, &.{un_op}); | 3445 | try reap(f, inst, &.{un_op}); |
| 3437 | // Not even allowed to return void in a naked function. | 3446 | // Not even allowed to return void in a naked function. |
| 3438 | if (if (f.object.dg.decl) |decl| decl.ty.fnCallingConvention() != .Naked else true) | 3447 | if (if (f.object.dg.decl) |decl| decl.ty.fnCallingConvention(mod) != .Naked else true) |
| 3439 | try writer.writeAll("return;\n"); | 3448 | try writer.writeAll("return;\n"); |
| 3440 | } | 3449 | } |
| 3441 | return .none; | 3450 | return .none; |
| 3442 | } | 3451 | } |
| 3443 | 3452 | ||
| 3444 | fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { | 3453 | fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3454 | const mod = f.object.dg.module; | ||
| 3445 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3455 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3446 | 3456 | ||
| 3447 | const operand = try f.resolveInst(ty_op.operand); | 3457 | const operand = try f.resolveInst(ty_op.operand); |
| 3448 | try reap(f, inst, &.{ty_op.operand}); | 3458 | try reap(f, inst, &.{ty_op.operand}); |
| 3449 | 3459 | ||
| 3450 | const inst_ty = f.air.typeOfIndex(inst); | 3460 | const inst_ty = f.typeOfIndex(inst); |
| 3451 | const inst_scalar_ty = inst_ty.scalarType(); | 3461 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 3452 | const operand_ty = f.air.typeOf(ty_op.operand); | 3462 | const operand_ty = f.typeOf(ty_op.operand); |
| 3453 | const scalar_ty = operand_ty.scalarType(); | 3463 | const scalar_ty = operand_ty.scalarType(mod); |
| 3454 | 3464 | ||
| 3455 | const writer = f.object.writer(); | 3465 | const writer = f.object.writer(); |
| 3456 | const local = try f.allocLocal(inst, inst_ty); | 3466 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -3467,20 +3477,20 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3467,20 +3477,20 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3467 | } | 3477 | } |
| 3468 | 3478 | ||
| 3469 | fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { | 3479 | fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3480 | const mod = f.object.dg.module; | ||
| 3470 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3481 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3471 | 3482 | ||
| 3472 | const operand = try f.resolveInst(ty_op.operand); | 3483 | const operand = try f.resolveInst(ty_op.operand); |
| 3473 | try reap(f, inst, &.{ty_op.operand}); | 3484 | try reap(f, inst, &.{ty_op.operand}); |
| 3474 | const inst_ty = f.air.typeOfIndex(inst); | 3485 | const inst_ty = f.typeOfIndex(inst); |
| 3475 | const inst_scalar_ty = inst_ty.scalarType(); | 3486 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 3476 | const target = f.object.dg.module.getTarget(); | 3487 | const dest_int_info = inst_scalar_ty.intInfo(mod); |
| 3477 | const dest_int_info = inst_scalar_ty.intInfo(target); | ||
| 3478 | const dest_bits = dest_int_info.bits; | 3488 | const dest_bits = dest_int_info.bits; |
| 3479 | const dest_c_bits = toCIntBits(dest_int_info.bits) orelse | 3489 | const dest_c_bits = toCIntBits(dest_int_info.bits) orelse |
| 3480 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); | 3490 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| 3481 | const operand_ty = f.air.typeOf(ty_op.operand); | 3491 | const operand_ty = f.typeOf(ty_op.operand); |
| 3482 | const scalar_ty = operand_ty.scalarType(); | 3492 | const scalar_ty = operand_ty.scalarType(mod); |
| 3483 | const scalar_int_info = scalar_ty.intInfo(target); | 3493 | const scalar_int_info = scalar_ty.intInfo(mod); |
| 3484 | 3494 | ||
| 3485 | const writer = f.object.writer(); | 3495 | const writer = f.object.writer(); |
| 3486 | const local = try f.allocLocal(inst, inst_ty); | 3496 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -3508,14 +3518,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3508,14 +3518,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3508 | try v.elem(f, writer); | 3518 | try v.elem(f, writer); |
| 3509 | } else switch (dest_int_info.signedness) { | 3519 | } else switch (dest_int_info.signedness) { |
| 3510 | .unsigned => { | 3520 | .unsigned => { |
| 3511 | var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa); | 3521 | const mask_val = try inst_scalar_ty.maxIntScalar(mod, scalar_ty); |
| 3512 | defer arena.deinit(); | ||
| 3513 | |||
| 3514 | const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; | ||
| 3515 | var stack align(@alignOf(ExpectedContents)) = | ||
| 3516 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); | ||
| 3517 | |||
| 3518 | const mask_val = try inst_scalar_ty.maxInt(stack.get(), target); | ||
| 3519 | try writer.writeAll("zig_and_"); | 3522 | try writer.writeAll("zig_and_"); |
| 3520 | try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); | 3523 | try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); |
| 3521 | try writer.writeByte('('); | 3524 | try writer.writeByte('('); |
| ... | @@ -3526,11 +3529,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3526,11 +3529,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3526 | .signed => { | 3529 | .signed => { |
| 3527 | const c_bits = toCIntBits(scalar_int_info.bits) orelse | 3530 | const c_bits = toCIntBits(scalar_int_info.bits) orelse |
| 3528 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); | 3531 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| 3529 | var shift_pl = Value.Payload.U64{ | 3532 | const shift_val = try mod.intValue(Type.u8, c_bits - dest_bits); |
| 3530 | .base = .{ .tag = .int_u64 }, | ||
| 3531 | .data = c_bits - dest_bits, | ||
| 3532 | }; | ||
| 3533 | const shift_val = Value.initPayload(&shift_pl.base); | ||
| 3534 | 3533 | ||
| 3535 | try writer.writeAll("zig_shr_"); | 3534 | try writer.writeAll("zig_shr_"); |
| 3536 | try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); | 3535 | try f.object.dg.renderTypeForBuiltinFnName(writer, scalar_ty); |
| ... | @@ -3566,7 +3565,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3566,7 +3565,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3566 | const operand = try f.resolveInst(un_op); | 3565 | const operand = try f.resolveInst(un_op); |
| 3567 | try reap(f, inst, &.{un_op}); | 3566 | try reap(f, inst, &.{un_op}); |
| 3568 | const writer = f.object.writer(); | 3567 | const writer = f.object.writer(); |
| 3569 | const inst_ty = f.air.typeOfIndex(inst); | 3568 | const inst_ty = f.typeOfIndex(inst); |
| 3570 | const local = try f.allocLocal(inst, inst_ty); | 3569 | const local = try f.allocLocal(inst, inst_ty); |
| 3571 | const a = try Assignment.start(f, writer, inst_ty); | 3570 | const a = try Assignment.start(f, writer, inst_ty); |
| 3572 | try f.writeCValue(writer, local, .Other); | 3571 | try f.writeCValue(writer, local, .Other); |
| ... | @@ -3577,17 +3576,18 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3577,17 +3576,18 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3577 | } | 3576 | } |
| 3578 | 3577 | ||
| 3579 | fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | 3578 | fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3579 | const mod = f.object.dg.module; | ||
| 3580 | // *a = b; | 3580 | // *a = b; |
| 3581 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3581 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3582 | 3582 | ||
| 3583 | const ptr_ty = f.air.typeOf(bin_op.lhs); | 3583 | const ptr_ty = f.typeOf(bin_op.lhs); |
| 3584 | const ptr_scalar_ty = ptr_ty.scalarType(); | 3584 | const ptr_scalar_ty = ptr_ty.scalarType(mod); |
| 3585 | const ptr_info = ptr_scalar_ty.ptrInfo().data; | 3585 | const ptr_info = ptr_scalar_ty.ptrInfo(mod); |
| 3586 | 3586 | ||
| 3587 | const ptr_val = try f.resolveInst(bin_op.lhs); | 3587 | const ptr_val = try f.resolveInst(bin_op.lhs); |
| 3588 | const src_ty = f.air.typeOf(bin_op.rhs); | 3588 | const src_ty = f.typeOf(bin_op.rhs); |
| 3589 | 3589 | ||
| 3590 | const val_is_undef = if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; | 3590 | const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |v| v.isUndefDeep(mod) else false; |
| 3591 | 3591 | ||
| 3592 | if (val_is_undef) { | 3592 | if (val_is_undef) { |
| 3593 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 3593 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| ... | @@ -3602,10 +3602,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -3602,10 +3602,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3602 | return .none; | 3602 | return .none; |
| 3603 | } | 3603 | } |
| 3604 | 3604 | ||
| 3605 | const target = f.object.dg.module.getTarget(); | ||
| 3606 | const is_aligned = ptr_info.@"align" == 0 or | 3605 | const is_aligned = ptr_info.@"align" == 0 or |
| 3607 | ptr_info.@"align" >= ptr_info.pointee_type.abiAlignment(target); | 3606 | ptr_info.@"align" >= ptr_info.pointee_type.abiAlignment(mod); |
| 3608 | const is_array = lowersToArray(ptr_info.pointee_type, target); | 3607 | const is_array = lowersToArray(ptr_info.pointee_type, mod); |
| 3609 | const need_memcpy = !is_aligned or is_array; | 3608 | const need_memcpy = !is_aligned or is_array; |
| 3610 | 3609 | ||
| 3611 | const src_val = try f.resolveInst(bin_op.rhs); | 3610 | const src_val = try f.resolveInst(bin_op.rhs); |
| ... | @@ -3647,22 +3646,12 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -3647,22 +3646,12 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3647 | } | 3646 | } |
| 3648 | } else if (ptr_info.host_size > 0 and ptr_info.vector_index == .none) { | 3647 | } else if (ptr_info.host_size > 0 and ptr_info.vector_index == .none) { |
| 3649 | const host_bits = ptr_info.host_size * 8; | 3648 | const host_bits = ptr_info.host_size * 8; |
| 3650 | var host_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = host_bits }; | 3649 | const host_ty = try mod.intType(.unsigned, host_bits); |
| 3651 | const host_ty = Type.initPayload(&host_pl.base); | ||
| 3652 | 3650 | ||
| 3653 | var bit_offset_ty_pl = Type.Payload.Bits{ | 3651 | const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(host_bits - 1)); |
| 3654 | .base = .{ .tag = .int_unsigned }, | 3652 | const bit_offset_val = try mod.intValue(bit_offset_ty, ptr_info.bit_offset); |
| 3655 | .data = Type.smallestUnsignedBits(host_bits - 1), | ||
| 3656 | }; | ||
| 3657 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); | ||
| 3658 | |||
| 3659 | var bit_offset_val_pl: Value.Payload.U64 = .{ | ||
| 3660 | .base = .{ .tag = .int_u64 }, | ||
| 3661 | .data = ptr_info.bit_offset, | ||
| 3662 | }; | ||
| 3663 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); | ||
| 3664 | 3653 | ||
| 3665 | const src_bits = src_ty.bitSize(target); | 3654 | const src_bits = src_ty.bitSize(mod); |
| 3666 | 3655 | ||
| 3667 | const ExpectedContents = [BigInt.Managed.default_capacity]BigIntLimb; | 3656 | const ExpectedContents = [BigInt.Managed.default_capacity]BigIntLimb; |
| 3668 | var stack align(@alignOf(ExpectedContents)) = | 3657 | var stack align(@alignOf(ExpectedContents)) = |
| ... | @@ -3675,11 +3664,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -3675,11 +3664,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3675 | try mask.shiftLeft(&mask, ptr_info.bit_offset); | 3664 | try mask.shiftLeft(&mask, ptr_info.bit_offset); |
| 3676 | try mask.bitNotWrap(&mask, .unsigned, host_bits); | 3665 | try mask.bitNotWrap(&mask, .unsigned, host_bits); |
| 3677 | 3666 | ||
| 3678 | var mask_pl = Value.Payload.BigInt{ | 3667 | const mask_val = try mod.intValue_big(host_ty, mask.toConst()); |
| 3679 | .base = .{ .tag = .int_big_positive }, | ||
| 3680 | .data = mask.limbs[0..mask.len()], | ||
| 3681 | }; | ||
| 3682 | const mask_val = Value.initPayload(&mask_pl.base); | ||
| 3683 | 3668 | ||
| 3684 | try f.writeCValueDeref(writer, ptr_val); | 3669 | try f.writeCValueDeref(writer, ptr_val); |
| 3685 | try v.elem(f, writer); | 3670 | try v.elem(f, writer); |
| ... | @@ -3693,9 +3678,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -3693,9 +3678,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3693 | try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)}); | 3678 | try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)}); |
| 3694 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); | 3679 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3695 | try writer.writeByte('('); | 3680 | try writer.writeByte('('); |
| 3696 | const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64; | 3681 | const cant_cast = host_ty.isInt(mod) and host_ty.bitSize(mod) > 64; |
| 3697 | if (cant_cast) { | 3682 | if (cant_cast) { |
| 3698 | if (src_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); | 3683 | if (src_ty.bitSize(mod) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); |
| 3699 | try writer.writeAll("zig_make_"); | 3684 | try writer.writeAll("zig_make_"); |
| 3700 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); | 3685 | try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); |
| 3701 | try writer.writeAll("(0, "); | 3686 | try writer.writeAll("(0, "); |
| ... | @@ -3705,7 +3690,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -3705,7 +3690,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3705 | try writer.writeByte(')'); | 3690 | try writer.writeByte(')'); |
| 3706 | } | 3691 | } |
| 3707 | 3692 | ||
| 3708 | if (src_ty.isPtrAtRuntime()) { | 3693 | if (src_ty.isPtrAtRuntime(mod)) { |
| 3709 | try writer.writeByte('('); | 3694 | try writer.writeByte('('); |
| 3710 | try f.renderType(writer, Type.usize); | 3695 | try f.renderType(writer, Type.usize); |
| 3711 | try writer.writeByte(')'); | 3696 | try writer.writeByte(')'); |
| ... | @@ -3728,6 +3713,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -3728,6 +3713,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 3728 | } | 3713 | } |
| 3729 | 3714 | ||
| 3730 | fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue { | 3715 | fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue { |
| 3716 | const mod = f.object.dg.module; | ||
| 3731 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 3717 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3732 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; | 3718 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3733 | 3719 | ||
| ... | @@ -3735,9 +3721,9 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: | ... | @@ -3735,9 +3721,9 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3735 | const rhs = try f.resolveInst(bin_op.rhs); | 3721 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3736 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 3722 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3737 | 3723 | ||
| 3738 | const inst_ty = f.air.typeOfIndex(inst); | 3724 | const inst_ty = f.typeOfIndex(inst); |
| 3739 | const operand_ty = f.air.typeOf(bin_op.lhs); | 3725 | const operand_ty = f.typeOf(bin_op.lhs); |
| 3740 | const scalar_ty = operand_ty.scalarType(); | 3726 | const scalar_ty = operand_ty.scalarType(mod); |
| 3741 | 3727 | ||
| 3742 | const w = f.object.writer(); | 3728 | const w = f.object.writer(); |
| 3743 | const local = try f.allocLocal(inst, inst_ty); | 3729 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -3765,15 +3751,16 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: | ... | @@ -3765,15 +3751,16 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3765 | } | 3751 | } |
| 3766 | 3752 | ||
| 3767 | fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { | 3753 | fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3754 | const mod = f.object.dg.module; | ||
| 3768 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3755 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3769 | const operand_ty = f.air.typeOf(ty_op.operand); | 3756 | const operand_ty = f.typeOf(ty_op.operand); |
| 3770 | const scalar_ty = operand_ty.scalarType(); | 3757 | const scalar_ty = operand_ty.scalarType(mod); |
| 3771 | if (scalar_ty.tag() != .bool) return try airUnBuiltinCall(f, inst, "not", .bits); | 3758 | if (scalar_ty.ip_index != .bool_type) return try airUnBuiltinCall(f, inst, "not", .bits); |
| 3772 | 3759 | ||
| 3773 | const op = try f.resolveInst(ty_op.operand); | 3760 | const op = try f.resolveInst(ty_op.operand); |
| 3774 | try reap(f, inst, &.{ty_op.operand}); | 3761 | try reap(f, inst, &.{ty_op.operand}); |
| 3775 | 3762 | ||
| 3776 | const inst_ty = f.air.typeOfIndex(inst); | 3763 | const inst_ty = f.typeOfIndex(inst); |
| 3777 | 3764 | ||
| 3778 | const writer = f.object.writer(); | 3765 | const writer = f.object.writer(); |
| 3779 | const local = try f.allocLocal(inst, inst_ty); | 3766 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -3797,18 +3784,18 @@ fn airBinOp( | ... | @@ -3797,18 +3784,18 @@ fn airBinOp( |
| 3797 | operation: []const u8, | 3784 | operation: []const u8, |
| 3798 | info: BuiltinInfo, | 3785 | info: BuiltinInfo, |
| 3799 | ) !CValue { | 3786 | ) !CValue { |
| 3787 | const mod = f.object.dg.module; | ||
| 3800 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3788 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3801 | const operand_ty = f.air.typeOf(bin_op.lhs); | 3789 | const operand_ty = f.typeOf(bin_op.lhs); |
| 3802 | const scalar_ty = operand_ty.scalarType(); | 3790 | const scalar_ty = operand_ty.scalarType(mod); |
| 3803 | const target = f.object.dg.module.getTarget(); | 3791 | if ((scalar_ty.isInt(mod) and scalar_ty.bitSize(mod) > 64) or scalar_ty.isRuntimeFloat()) |
| 3804 | if ((scalar_ty.isInt() and scalar_ty.bitSize(target) > 64) or scalar_ty.isRuntimeFloat()) | ||
| 3805 | return try airBinBuiltinCall(f, inst, operation, info); | 3792 | return try airBinBuiltinCall(f, inst, operation, info); |
| 3806 | 3793 | ||
| 3807 | const lhs = try f.resolveInst(bin_op.lhs); | 3794 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3808 | const rhs = try f.resolveInst(bin_op.rhs); | 3795 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3809 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 3796 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3810 | 3797 | ||
| 3811 | const inst_ty = f.air.typeOfIndex(inst); | 3798 | const inst_ty = f.typeOfIndex(inst); |
| 3812 | 3799 | ||
| 3813 | const writer = f.object.writer(); | 3800 | const writer = f.object.writer(); |
| 3814 | const local = try f.allocLocal(inst, inst_ty); | 3801 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -3835,12 +3822,12 @@ fn airCmpOp( | ... | @@ -3835,12 +3822,12 @@ fn airCmpOp( |
| 3835 | data: anytype, | 3822 | data: anytype, |
| 3836 | operator: std.math.CompareOperator, | 3823 | operator: std.math.CompareOperator, |
| 3837 | ) !CValue { | 3824 | ) !CValue { |
| 3838 | const lhs_ty = f.air.typeOf(data.lhs); | 3825 | const mod = f.object.dg.module; |
| 3839 | const scalar_ty = lhs_ty.scalarType(); | 3826 | const lhs_ty = f.typeOf(data.lhs); |
| 3827 | const scalar_ty = lhs_ty.scalarType(mod); | ||
| 3840 | 3828 | ||
| 3841 | const target = f.object.dg.module.getTarget(); | 3829 | const scalar_bits = scalar_ty.bitSize(mod); |
| 3842 | const scalar_bits = scalar_ty.bitSize(target); | 3830 | if (scalar_ty.isInt(mod) and scalar_bits > 64) |
| 3843 | if (scalar_ty.isInt() and scalar_bits > 64) | ||
| 3844 | return airCmpBuiltinCall( | 3831 | return airCmpBuiltinCall( |
| 3845 | f, | 3832 | f, |
| 3846 | inst, | 3833 | inst, |
| ... | @@ -3852,13 +3839,13 @@ fn airCmpOp( | ... | @@ -3852,13 +3839,13 @@ fn airCmpOp( |
| 3852 | if (scalar_ty.isRuntimeFloat()) | 3839 | if (scalar_ty.isRuntimeFloat()) |
| 3853 | return airCmpBuiltinCall(f, inst, data, operator, .operator, .none); | 3840 | return airCmpBuiltinCall(f, inst, data, operator, .operator, .none); |
| 3854 | 3841 | ||
| 3855 | const inst_ty = f.air.typeOfIndex(inst); | 3842 | const inst_ty = f.typeOfIndex(inst); |
| 3856 | const lhs = try f.resolveInst(data.lhs); | 3843 | const lhs = try f.resolveInst(data.lhs); |
| 3857 | const rhs = try f.resolveInst(data.rhs); | 3844 | const rhs = try f.resolveInst(data.rhs); |
| 3858 | try reap(f, inst, &.{ data.lhs, data.rhs }); | 3845 | try reap(f, inst, &.{ data.lhs, data.rhs }); |
| 3859 | 3846 | ||
| 3860 | const rhs_ty = f.air.typeOf(data.rhs); | 3847 | const rhs_ty = f.typeOf(data.rhs); |
| 3861 | const need_cast = lhs_ty.isSinglePointer() or rhs_ty.isSinglePointer(); | 3848 | const need_cast = lhs_ty.isSinglePointer(mod) or rhs_ty.isSinglePointer(mod); |
| 3862 | const writer = f.object.writer(); | 3849 | const writer = f.object.writer(); |
| 3863 | const local = try f.allocLocal(inst, inst_ty); | 3850 | const local = try f.allocLocal(inst, inst_ty); |
| 3864 | const v = try Vectorize.start(f, inst, writer, lhs_ty); | 3851 | const v = try Vectorize.start(f, inst, writer, lhs_ty); |
| ... | @@ -3885,12 +3872,12 @@ fn airEquality( | ... | @@ -3885,12 +3872,12 @@ fn airEquality( |
| 3885 | inst: Air.Inst.Index, | 3872 | inst: Air.Inst.Index, |
| 3886 | operator: std.math.CompareOperator, | 3873 | operator: std.math.CompareOperator, |
| 3887 | ) !CValue { | 3874 | ) !CValue { |
| 3875 | const mod = f.object.dg.module; | ||
| 3888 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3876 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3889 | 3877 | ||
| 3890 | const operand_ty = f.air.typeOf(bin_op.lhs); | 3878 | const operand_ty = f.typeOf(bin_op.lhs); |
| 3891 | const target = f.object.dg.module.getTarget(); | 3879 | const operand_bits = operand_ty.bitSize(mod); |
| 3892 | const operand_bits = operand_ty.bitSize(target); | 3880 | if (operand_ty.isInt(mod) and operand_bits > 64) |
| 3893 | if (operand_ty.isInt() and operand_bits > 64) | ||
| 3894 | return airCmpBuiltinCall( | 3881 | return airCmpBuiltinCall( |
| 3895 | f, | 3882 | f, |
| 3896 | inst, | 3883 | inst, |
| ... | @@ -3907,12 +3894,12 @@ fn airEquality( | ... | @@ -3907,12 +3894,12 @@ fn airEquality( |
| 3907 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 3894 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3908 | 3895 | ||
| 3909 | const writer = f.object.writer(); | 3896 | const writer = f.object.writer(); |
| 3910 | const inst_ty = f.air.typeOfIndex(inst); | 3897 | const inst_ty = f.typeOfIndex(inst); |
| 3911 | const local = try f.allocLocal(inst, inst_ty); | 3898 | const local = try f.allocLocal(inst, inst_ty); |
| 3912 | try f.writeCValue(writer, local, .Other); | 3899 | try f.writeCValue(writer, local, .Other); |
| 3913 | try writer.writeAll(" = "); | 3900 | try writer.writeAll(" = "); |
| 3914 | 3901 | ||
| 3915 | if (operand_ty.zigTypeTag() == .Optional and !operand_ty.optionalReprIsPayload()) { | 3902 | if (operand_ty.zigTypeTag(mod) == .Optional and !operand_ty.optionalReprIsPayload(mod)) { |
| 3916 | // (A && B) || (C && (A == B)) | 3903 | // (A && B) || (C && (A == B)) |
| 3917 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload | 3904 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload |
| 3918 | 3905 | ||
| ... | @@ -3951,7 +3938,7 @@ fn airEquality( | ... | @@ -3951,7 +3938,7 @@ fn airEquality( |
| 3951 | fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { | 3938 | fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3952 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 3939 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 3953 | 3940 | ||
| 3954 | const inst_ty = f.air.typeOfIndex(inst); | 3941 | const inst_ty = f.typeOfIndex(inst); |
| 3955 | const operand = try f.resolveInst(un_op); | 3942 | const operand = try f.resolveInst(un_op); |
| 3956 | try reap(f, inst, &.{un_op}); | 3943 | try reap(f, inst, &.{un_op}); |
| 3957 | 3944 | ||
| ... | @@ -3965,6 +3952,7 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3965,6 +3952,7 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3965 | } | 3952 | } |
| 3966 | 3953 | ||
| 3967 | fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { | 3954 | fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 3955 | const mod = f.object.dg.module; | ||
| 3968 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 3956 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3969 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; | 3957 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3970 | 3958 | ||
| ... | @@ -3972,9 +3960,9 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { | ... | @@ -3972,9 +3960,9 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 3972 | const rhs = try f.resolveInst(bin_op.rhs); | 3960 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3973 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 3961 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 3974 | 3962 | ||
| 3975 | const inst_ty = f.air.typeOfIndex(inst); | 3963 | const inst_ty = f.typeOfIndex(inst); |
| 3976 | const inst_scalar_ty = inst_ty.scalarType(); | 3964 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 3977 | const elem_ty = inst_scalar_ty.elemType2(); | 3965 | const elem_ty = inst_scalar_ty.elemType2(mod); |
| 3978 | 3966 | ||
| 3979 | const local = try f.allocLocal(inst, inst_ty); | 3967 | const local = try f.allocLocal(inst, inst_ty); |
| 3980 | const writer = f.object.writer(); | 3968 | const writer = f.object.writer(); |
| ... | @@ -3983,7 +3971,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { | ... | @@ -3983,7 +3971,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 3983 | try v.elem(f, writer); | 3971 | try v.elem(f, writer); |
| 3984 | try writer.writeAll(" = "); | 3972 | try writer.writeAll(" = "); |
| 3985 | 3973 | ||
| 3986 | if (elem_ty.hasRuntimeBitsIgnoreComptime()) { | 3974 | if (elem_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3987 | // We must convert to and from integer types to prevent UB if the operation | 3975 | // We must convert to and from integer types to prevent UB if the operation |
| 3988 | // results in a NULL pointer, or if LHS is NULL. The operation is only UB | 3976 | // results in a NULL pointer, or if LHS is NULL. The operation is only UB |
| 3989 | // if the result is NULL and then dereferenced. | 3977 | // if the result is NULL and then dereferenced. |
| ... | @@ -4012,13 +4000,13 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { | ... | @@ -4012,13 +4000,13 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 4012 | } | 4000 | } |
| 4013 | 4001 | ||
| 4014 | fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue { | 4002 | fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue { |
| 4003 | const mod = f.object.dg.module; | ||
| 4015 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 4004 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 4016 | 4005 | ||
| 4017 | const inst_ty = f.air.typeOfIndex(inst); | 4006 | const inst_ty = f.typeOfIndex(inst); |
| 4018 | const inst_scalar_ty = inst_ty.scalarType(); | 4007 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 4019 | 4008 | ||
| 4020 | const target = f.object.dg.module.getTarget(); | 4009 | if (inst_scalar_ty.isInt(mod) and inst_scalar_ty.bitSize(mod) > 64) |
| 4021 | if (inst_scalar_ty.isInt() and inst_scalar_ty.bitSize(target) > 64) | ||
| 4022 | return try airBinBuiltinCall(f, inst, operation[1..], .none); | 4010 | return try airBinBuiltinCall(f, inst, operation[1..], .none); |
| 4023 | if (inst_scalar_ty.isRuntimeFloat()) | 4011 | if (inst_scalar_ty.isRuntimeFloat()) |
| 4024 | return try airBinFloatOp(f, inst, operation); | 4012 | return try airBinFloatOp(f, inst, operation); |
| ... | @@ -4054,6 +4042,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons | ... | @@ -4054,6 +4042,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons |
| 4054 | } | 4042 | } |
| 4055 | 4043 | ||
| 4056 | fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { | 4044 | fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4045 | const mod = f.object.dg.module; | ||
| 4057 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 4046 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4058 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; | 4047 | const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data; |
| 4059 | 4048 | ||
| ... | @@ -4061,9 +4050,8 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4061,9 +4050,8 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4061 | const len = try f.resolveInst(bin_op.rhs); | 4050 | const len = try f.resolveInst(bin_op.rhs); |
| 4062 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 4051 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 4063 | 4052 | ||
| 4064 | const inst_ty = f.air.typeOfIndex(inst); | 4053 | const inst_ty = f.typeOfIndex(inst); |
| 4065 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 4054 | const ptr_ty = inst_ty.slicePtrFieldType(mod); |
| 4066 | const ptr_ty = inst_ty.slicePtrFieldType(&buf); | ||
| 4067 | 4055 | ||
| 4068 | const writer = f.object.writer(); | 4056 | const writer = f.object.writer(); |
| 4069 | const local = try f.allocLocal(inst, inst_ty); | 4057 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -4092,12 +4080,11 @@ fn airCall( | ... | @@ -4092,12 +4080,11 @@ fn airCall( |
| 4092 | inst: Air.Inst.Index, | 4080 | inst: Air.Inst.Index, |
| 4093 | modifier: std.builtin.CallModifier, | 4081 | modifier: std.builtin.CallModifier, |
| 4094 | ) !CValue { | 4082 | ) !CValue { |
| 4083 | const mod = f.object.dg.module; | ||
| 4095 | // Not even allowed to call panic in a naked function. | 4084 | // Not even allowed to call panic in a naked function. |
| 4096 | if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none; | 4085 | if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention(mod) == .Naked) return .none; |
| 4097 | 4086 | ||
| 4098 | const gpa = f.object.dg.gpa; | 4087 | const gpa = f.object.dg.gpa; |
| 4099 | const module = f.object.dg.module; | ||
| 4100 | const target = module.getTarget(); | ||
| 4101 | const writer = f.object.writer(); | 4088 | const writer = f.object.writer(); |
| 4102 | 4089 | ||
| 4103 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 4090 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| ... | @@ -4107,7 +4094,7 @@ fn airCall( | ... | @@ -4107,7 +4094,7 @@ fn airCall( |
| 4107 | const resolved_args = try gpa.alloc(CValue, args.len); | 4094 | const resolved_args = try gpa.alloc(CValue, args.len); |
| 4108 | defer gpa.free(resolved_args); | 4095 | defer gpa.free(resolved_args); |
| 4109 | for (resolved_args, args) |*resolved_arg, arg| { | 4096 | for (resolved_args, args) |*resolved_arg, arg| { |
| 4110 | const arg_ty = f.air.typeOf(arg); | 4097 | const arg_ty = f.typeOf(arg); |
| 4111 | const arg_cty = try f.typeToIndex(arg_ty, .parameter); | 4098 | const arg_cty = try f.typeToIndex(arg_ty, .parameter); |
| 4112 | if (f.indexToCType(arg_cty).tag() == .void) { | 4099 | if (f.indexToCType(arg_cty).tag() == .void) { |
| 4113 | resolved_arg.* = .none; | 4100 | resolved_arg.* = .none; |
| ... | @@ -4115,8 +4102,7 @@ fn airCall( | ... | @@ -4115,8 +4102,7 @@ fn airCall( |
| 4115 | } | 4102 | } |
| 4116 | resolved_arg.* = try f.resolveInst(arg); | 4103 | resolved_arg.* = try f.resolveInst(arg); |
| 4117 | if (arg_cty != try f.typeToIndex(arg_ty, .complete)) { | 4104 | if (arg_cty != try f.typeToIndex(arg_ty, .complete)) { |
| 4118 | var lowered_arg_buf: LowerFnRetTyBuffer = undefined; | 4105 | const lowered_arg_ty = try lowerFnRetTy(arg_ty, mod); |
| 4119 | const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target); | ||
| 4120 | 4106 | ||
| 4121 | const array_local = try f.allocLocal(inst, lowered_arg_ty); | 4107 | const array_local = try f.allocLocal(inst, lowered_arg_ty); |
| 4122 | try writer.writeAll("memcpy("); | 4108 | try writer.writeAll("memcpy("); |
| ... | @@ -4138,22 +4124,21 @@ fn airCall( | ... | @@ -4138,22 +4124,21 @@ fn airCall( |
| 4138 | for (args) |arg| try bt.feed(arg); | 4124 | for (args) |arg| try bt.feed(arg); |
| 4139 | } | 4125 | } |
| 4140 | 4126 | ||
| 4141 | const callee_ty = f.air.typeOf(pl_op.operand); | 4127 | const callee_ty = f.typeOf(pl_op.operand); |
| 4142 | const fn_ty = switch (callee_ty.zigTypeTag()) { | 4128 | const fn_ty = switch (callee_ty.zigTypeTag(mod)) { |
| 4143 | .Fn => callee_ty, | 4129 | .Fn => callee_ty, |
| 4144 | .Pointer => callee_ty.childType(), | 4130 | .Pointer => callee_ty.childType(mod), |
| 4145 | else => unreachable, | 4131 | else => unreachable, |
| 4146 | }; | 4132 | }; |
| 4147 | 4133 | ||
| 4148 | const ret_ty = fn_ty.fnReturnType(); | 4134 | const ret_ty = fn_ty.fnReturnType(mod); |
| 4149 | var lowered_ret_buf: LowerFnRetTyBuffer = undefined; | 4135 | const lowered_ret_ty = try lowerFnRetTy(ret_ty, mod); |
| 4150 | const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); | ||
| 4151 | 4136 | ||
| 4152 | const result_local = result: { | 4137 | const result_local = result: { |
| 4153 | if (modifier == .always_tail) { | 4138 | if (modifier == .always_tail) { |
| 4154 | try writer.writeAll("zig_always_tail return "); | 4139 | try writer.writeAll("zig_always_tail return "); |
| 4155 | break :result .none; | 4140 | break :result .none; |
| 4156 | } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) { | 4141 | } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4157 | break :result .none; | 4142 | break :result .none; |
| 4158 | } else if (f.liveness.isUnused(inst)) { | 4143 | } else if (f.liveness.isUnused(inst)) { |
| 4159 | try writer.writeByte('('); | 4144 | try writer.writeByte('('); |
| ... | @@ -4171,19 +4156,22 @@ fn airCall( | ... | @@ -4171,19 +4156,22 @@ fn airCall( |
| 4171 | callee: { | 4156 | callee: { |
| 4172 | known: { | 4157 | known: { |
| 4173 | const fn_decl = fn_decl: { | 4158 | const fn_decl = fn_decl: { |
| 4174 | const callee_val = f.air.value(pl_op.operand) orelse break :known; | 4159 | const callee_val = (try f.air.value(pl_op.operand, mod)) orelse break :known; |
| 4175 | break :fn_decl switch (callee_val.tag()) { | 4160 | break :fn_decl switch (mod.intern_pool.indexToKey(callee_val.ip_index)) { |
| 4176 | .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl, | 4161 | .extern_func => |extern_func| extern_func.decl, |
| 4177 | .function => callee_val.castTag(.function).?.data.owner_decl, | 4162 | .func => |func| mod.funcPtr(func.index).owner_decl, |
| 4178 | .decl_ref => callee_val.castTag(.decl_ref).?.data, | 4163 | .ptr => |ptr| switch (ptr.addr) { |
| 4164 | .decl => |decl| decl, | ||
| 4165 | else => break :known, | ||
| 4166 | }, | ||
| 4179 | else => break :known, | 4167 | else => break :known, |
| 4180 | }; | 4168 | }; |
| 4181 | }; | 4169 | }; |
| 4182 | switch (modifier) { | 4170 | switch (modifier) { |
| 4183 | .auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl, 0), | 4171 | .auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl, 0), |
| 4184 | inline .never_tail, .never_inline => |mod| try writer.writeAll(try f.getLazyFnName( | 4172 | inline .never_tail, .never_inline => |m| try writer.writeAll(try f.getLazyFnName( |
| 4185 | @unionInit(LazyFnKey, @tagName(mod), fn_decl), | 4173 | @unionInit(LazyFnKey, @tagName(m), fn_decl), |
| 4186 | @unionInit(LazyFnValue.Data, @tagName(mod), {}), | 4174 | @unionInit(LazyFnValue.Data, @tagName(m), {}), |
| 4187 | )), | 4175 | )), |
| 4188 | else => unreachable, | 4176 | else => unreachable, |
| 4189 | } | 4177 | } |
| ... | @@ -4211,7 +4199,7 @@ fn airCall( | ... | @@ -4211,7 +4199,7 @@ fn airCall( |
| 4211 | try writer.writeAll(");\n"); | 4199 | try writer.writeAll(");\n"); |
| 4212 | 4200 | ||
| 4213 | const result = result: { | 4201 | const result = result: { |
| 4214 | if (result_local == .none or !lowersToArray(ret_ty, target)) | 4202 | if (result_local == .none or !lowersToArray(ret_ty, mod)) |
| 4215 | break :result result_local; | 4203 | break :result result_local; |
| 4216 | 4204 | ||
| 4217 | const array_local = try f.allocLocal(inst, ret_ty); | 4205 | const array_local = try f.allocLocal(inst, ret_ty); |
| ... | @@ -4245,18 +4233,21 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4245,18 +4233,21 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4245 | } | 4233 | } |
| 4246 | 4234 | ||
| 4247 | fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue { | 4235 | fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4248 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 4236 | const ty_fn = f.air.instructions.items(.data)[inst].ty_fn; |
| 4249 | const writer = f.object.writer(); | ||
| 4250 | const function = f.air.values[ty_pl.payload].castTag(.function).?.data; | ||
| 4251 | const mod = f.object.dg.module; | 4237 | const mod = f.object.dg.module; |
| 4252 | try writer.print("/* dbg func:{s} */\n", .{mod.declPtr(function.owner_decl).name}); | 4238 | const writer = f.object.writer(); |
| 4239 | const function = mod.funcPtr(ty_fn.func); | ||
| 4240 | try writer.print("/* dbg func:{s} */\n", .{ | ||
| 4241 | mod.intern_pool.stringToSlice(mod.declPtr(function.owner_decl).name), | ||
| 4242 | }); | ||
| 4253 | return .none; | 4243 | return .none; |
| 4254 | } | 4244 | } |
| 4255 | 4245 | ||
| 4256 | fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { | 4246 | fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4247 | const mod = f.object.dg.module; | ||
| 4257 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 4248 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 4258 | const name = f.air.nullTerminatedString(pl_op.payload); | 4249 | const name = f.air.nullTerminatedString(pl_op.payload); |
| 4259 | const operand_is_undef = if (f.air.value(pl_op.operand)) |v| v.isUndefDeep() else false; | 4250 | const operand_is_undef = if (try f.air.value(pl_op.operand, mod)) |v| v.isUndefDeep(mod) else false; |
| 4260 | if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand); | 4251 | if (!operand_is_undef) _ = try f.resolveInst(pl_op.operand); |
| 4261 | 4252 | ||
| 4262 | try reap(f, inst, &.{pl_op.operand}); | 4253 | try reap(f, inst, &.{pl_op.operand}); |
| ... | @@ -4266,6 +4257,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4266,6 +4257,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4266 | } | 4257 | } |
| 4267 | 4258 | ||
| 4268 | fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { | 4259 | fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4260 | const mod = f.object.dg.module; | ||
| 4269 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 4261 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4270 | const extra = f.air.extraData(Air.Block, ty_pl.payload); | 4262 | const extra = f.air.extraData(Air.Block, ty_pl.payload); |
| 4271 | const body = f.air.extra[extra.end..][0..extra.data.body_len]; | 4263 | const body = f.air.extra[extra.end..][0..extra.data.body_len]; |
| ... | @@ -4275,8 +4267,8 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4275,8 +4267,8 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4275 | f.next_block_index += 1; | 4267 | f.next_block_index += 1; |
| 4276 | const writer = f.object.writer(); | 4268 | const writer = f.object.writer(); |
| 4277 | 4269 | ||
| 4278 | const inst_ty = f.air.typeOfIndex(inst); | 4270 | const inst_ty = f.typeOfIndex(inst); |
| 4279 | const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst)) | 4271 | const result = if (inst_ty.ip_index != .void_type and !f.liveness.isUnused(inst)) |
| 4280 | try f.allocLocal(inst, inst_ty) | 4272 | try f.allocLocal(inst, inst_ty) |
| 4281 | else | 4273 | else |
| 4282 | .none; | 4274 | .none; |
| ... | @@ -4298,7 +4290,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4298,7 +4290,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4298 | try f.object.indent_writer.insertNewline(); | 4290 | try f.object.indent_writer.insertNewline(); |
| 4299 | 4291 | ||
| 4300 | // noreturn blocks have no `br` instructions reaching them, so we don't want a label | 4292 | // noreturn blocks have no `br` instructions reaching them, so we don't want a label |
| 4301 | if (!f.air.typeOfIndex(inst).isNoReturn()) { | 4293 | if (!f.typeOfIndex(inst).isNoReturn(mod)) { |
| 4302 | // label must be followed by an expression, include an empty one. | 4294 | // label must be followed by an expression, include an empty one. |
| 4303 | try writer.print("zig_block_{d}:;\n", .{block_id}); | 4295 | try writer.print("zig_block_{d}:;\n", .{block_id}); |
| 4304 | } | 4296 | } |
| ... | @@ -4310,15 +4302,16 @@ fn airTry(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4310,15 +4302,16 @@ fn airTry(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4310 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 4302 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 4311 | const extra = f.air.extraData(Air.Try, pl_op.payload); | 4303 | const extra = f.air.extraData(Air.Try, pl_op.payload); |
| 4312 | const body = f.air.extra[extra.end..][0..extra.data.body_len]; | 4304 | const body = f.air.extra[extra.end..][0..extra.data.body_len]; |
| 4313 | const err_union_ty = f.air.typeOf(pl_op.operand); | 4305 | const err_union_ty = f.typeOf(pl_op.operand); |
| 4314 | return lowerTry(f, inst, pl_op.operand, body, err_union_ty, false); | 4306 | return lowerTry(f, inst, pl_op.operand, body, err_union_ty, false); |
| 4315 | } | 4307 | } |
| 4316 | 4308 | ||
| 4317 | fn airTryPtr(f: *Function, inst: Air.Inst.Index) !CValue { | 4309 | fn airTryPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4310 | const mod = f.object.dg.module; | ||
| 4318 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 4311 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4319 | const extra = f.air.extraData(Air.TryPtr, ty_pl.payload); | 4312 | const extra = f.air.extraData(Air.TryPtr, ty_pl.payload); |
| 4320 | const body = f.air.extra[extra.end..][0..extra.data.body_len]; | 4313 | const body = f.air.extra[extra.end..][0..extra.data.body_len]; |
| 4321 | const err_union_ty = f.air.typeOf(extra.data.ptr).childType(); | 4314 | const err_union_ty = f.typeOf(extra.data.ptr).childType(mod); |
| 4322 | return lowerTry(f, inst, extra.data.ptr, body, err_union_ty, true); | 4315 | return lowerTry(f, inst, extra.data.ptr, body, err_union_ty, true); |
| 4323 | } | 4316 | } |
| 4324 | 4317 | ||
| ... | @@ -4330,14 +4323,15 @@ fn lowerTry( | ... | @@ -4330,14 +4323,15 @@ fn lowerTry( |
| 4330 | err_union_ty: Type, | 4323 | err_union_ty: Type, |
| 4331 | is_ptr: bool, | 4324 | is_ptr: bool, |
| 4332 | ) !CValue { | 4325 | ) !CValue { |
| 4326 | const mod = f.object.dg.module; | ||
| 4333 | const err_union = try f.resolveInst(operand); | 4327 | const err_union = try f.resolveInst(operand); |
| 4334 | const inst_ty = f.air.typeOfIndex(inst); | 4328 | const inst_ty = f.typeOfIndex(inst); |
| 4335 | const liveness_condbr = f.liveness.getCondBr(inst); | 4329 | const liveness_condbr = f.liveness.getCondBr(inst); |
| 4336 | const writer = f.object.writer(); | 4330 | const writer = f.object.writer(); |
| 4337 | const payload_ty = err_union_ty.errorUnionPayload(); | 4331 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 4338 | const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(); | 4332 | const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod); |
| 4339 | 4333 | ||
| 4340 | if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 4334 | if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 4341 | try writer.writeAll("if ("); | 4335 | try writer.writeAll("if ("); |
| 4342 | if (!payload_has_bits) { | 4336 | if (!payload_has_bits) { |
| 4343 | if (is_ptr) | 4337 | if (is_ptr) |
| ... | @@ -4399,7 +4393,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4399,7 +4393,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4399 | 4393 | ||
| 4400 | // If result is .none then the value of the block is unused. | 4394 | // If result is .none then the value of the block is unused. |
| 4401 | if (result != .none) { | 4395 | if (result != .none) { |
| 4402 | const operand_ty = f.air.typeOf(branch.operand); | 4396 | const operand_ty = f.typeOf(branch.operand); |
| 4403 | const operand = try f.resolveInst(branch.operand); | 4397 | const operand = try f.resolveInst(branch.operand); |
| 4404 | try reap(f, inst, &.{branch.operand}); | 4398 | try reap(f, inst, &.{branch.operand}); |
| 4405 | 4399 | ||
| ... | @@ -4416,10 +4410,10 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4416,10 +4410,10 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4416 | 4410 | ||
| 4417 | fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { | 4411 | fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4418 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 4412 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 4419 | const dest_ty = f.air.typeOfIndex(inst); | 4413 | const dest_ty = f.typeOfIndex(inst); |
| 4420 | 4414 | ||
| 4421 | const operand = try f.resolveInst(ty_op.operand); | 4415 | const operand = try f.resolveInst(ty_op.operand); |
| 4422 | const operand_ty = f.air.typeOf(ty_op.operand); | 4416 | const operand_ty = f.typeOf(ty_op.operand); |
| 4423 | 4417 | ||
| 4424 | const bitcasted = try bitcast(f, dest_ty, operand, operand_ty); | 4418 | const bitcasted = try bitcast(f, dest_ty, operand, operand_ty); |
| 4425 | try reap(f, inst, &.{ty_op.operand}); | 4419 | try reap(f, inst, &.{ty_op.operand}); |
| ... | @@ -4431,6 +4425,8 @@ const LocalResult = struct { | ... | @@ -4431,6 +4425,8 @@ const LocalResult = struct { |
| 4431 | need_free: bool, | 4425 | need_free: bool, |
| 4432 | 4426 | ||
| 4433 | fn move(lr: LocalResult, f: *Function, inst: Air.Inst.Index, dest_ty: Type) !CValue { | 4427 | fn move(lr: LocalResult, f: *Function, inst: Air.Inst.Index, dest_ty: Type) !CValue { |
| 4428 | const mod = f.object.dg.module; | ||
| 4429 | |||
| 4434 | if (lr.need_free) { | 4430 | if (lr.need_free) { |
| 4435 | // Move the freshly allocated local to be owned by this instruction, | 4431 | // Move the freshly allocated local to be owned by this instruction, |
| 4436 | // by returning it here instead of freeing it. | 4432 | // by returning it here instead of freeing it. |
| ... | @@ -4441,7 +4437,7 @@ const LocalResult = struct { | ... | @@ -4441,7 +4437,7 @@ const LocalResult = struct { |
| 4441 | try lr.free(f); | 4437 | try lr.free(f); |
| 4442 | const writer = f.object.writer(); | 4438 | const writer = f.object.writer(); |
| 4443 | try f.writeCValue(writer, local, .Other); | 4439 | try f.writeCValue(writer, local, .Other); |
| 4444 | if (dest_ty.isAbiInt()) { | 4440 | if (dest_ty.isAbiInt(mod)) { |
| 4445 | try writer.writeAll(" = "); | 4441 | try writer.writeAll(" = "); |
| 4446 | } else { | 4442 | } else { |
| 4447 | try writer.writeAll(" = ("); | 4443 | try writer.writeAll(" = ("); |
| ... | @@ -4461,12 +4457,13 @@ const LocalResult = struct { | ... | @@ -4461,12 +4457,13 @@ const LocalResult = struct { |
| 4461 | }; | 4457 | }; |
| 4462 | 4458 | ||
| 4463 | fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult { | 4459 | fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult { |
| 4464 | const target = f.object.dg.module.getTarget(); | 4460 | const mod = f.object.dg.module; |
| 4461 | const target = mod.getTarget(); | ||
| 4465 | const writer = f.object.writer(); | 4462 | const writer = f.object.writer(); |
| 4466 | 4463 | ||
| 4467 | if (operand_ty.isAbiInt() and dest_ty.isAbiInt()) { | 4464 | if (operand_ty.isAbiInt(mod) and dest_ty.isAbiInt(mod)) { |
| 4468 | const src_info = dest_ty.intInfo(target); | 4465 | const src_info = dest_ty.intInfo(mod); |
| 4469 | const dest_info = operand_ty.intInfo(target); | 4466 | const dest_info = operand_ty.intInfo(mod); |
| 4470 | if (src_info.signedness == dest_info.signedness and | 4467 | if (src_info.signedness == dest_info.signedness and |
| 4471 | src_info.bits == dest_info.bits) | 4468 | src_info.bits == dest_info.bits) |
| 4472 | { | 4469 | { |
| ... | @@ -4477,7 +4474,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca | ... | @@ -4477,7 +4474,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4477 | } | 4474 | } |
| 4478 | } | 4475 | } |
| 4479 | 4476 | ||
| 4480 | if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) { | 4477 | if (dest_ty.isPtrAtRuntime(mod) and operand_ty.isPtrAtRuntime(mod)) { |
| 4481 | const local = try f.allocLocal(0, dest_ty); | 4478 | const local = try f.allocLocal(0, dest_ty); |
| 4482 | try f.writeCValue(writer, local, .Other); | 4479 | try f.writeCValue(writer, local, .Other); |
| 4483 | try writer.writeAll(" = ("); | 4480 | try writer.writeAll(" = ("); |
| ... | @@ -4494,7 +4491,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca | ... | @@ -4494,7 +4491,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4494 | const operand_lval = if (operand == .constant) blk: { | 4491 | const operand_lval = if (operand == .constant) blk: { |
| 4495 | const operand_local = try f.allocLocal(0, operand_ty); | 4492 | const operand_local = try f.allocLocal(0, operand_ty); |
| 4496 | try f.writeCValue(writer, operand_local, .Other); | 4493 | try f.writeCValue(writer, operand_local, .Other); |
| 4497 | if (operand_ty.isAbiInt()) { | 4494 | if (operand_ty.isAbiInt(mod)) { |
| 4498 | try writer.writeAll(" = "); | 4495 | try writer.writeAll(" = "); |
| 4499 | } else { | 4496 | } else { |
| 4500 | try writer.writeAll(" = ("); | 4497 | try writer.writeAll(" = ("); |
| ... | @@ -4516,13 +4513,10 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca | ... | @@ -4516,13 +4513,10 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4516 | try writer.writeAll("));\n"); | 4513 | try writer.writeAll("));\n"); |
| 4517 | 4514 | ||
| 4518 | // Ensure padding bits have the expected value. | 4515 | // Ensure padding bits have the expected value. |
| 4519 | if (dest_ty.isAbiInt()) { | 4516 | if (dest_ty.isAbiInt(mod)) { |
| 4520 | const dest_cty = try f.typeToCType(dest_ty, .complete); | 4517 | const dest_cty = try f.typeToCType(dest_ty, .complete); |
| 4521 | const dest_info = dest_ty.intInfo(target); | 4518 | const dest_info = dest_ty.intInfo(mod); |
| 4522 | var info_ty_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dest_info.signedness) { | 4519 | var bits: u16 = dest_info.bits; |
| 4523 | .unsigned => .int_unsigned, | ||
| 4524 | .signed => .int_signed, | ||
| 4525 | } }, .data = dest_info.bits }; | ||
| 4526 | var wrap_cty: ?CType = null; | 4520 | var wrap_cty: ?CType = null; |
| 4527 | var need_bitcasts = false; | 4521 | var need_bitcasts = false; |
| 4528 | 4522 | ||
| ... | @@ -4535,9 +4529,9 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca | ... | @@ -4535,9 +4529,9 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4535 | const elem_cty = f.indexToCType(pl.data.elem_type); | 4529 | const elem_cty = f.indexToCType(pl.data.elem_type); |
| 4536 | wrap_cty = elem_cty.toSignedness(dest_info.signedness); | 4530 | wrap_cty = elem_cty.toSignedness(dest_info.signedness); |
| 4537 | need_bitcasts = wrap_cty.?.tag() == .zig_i128; | 4531 | need_bitcasts = wrap_cty.?.tag() == .zig_i128; |
| 4538 | info_ty_pl.data -= 1; | 4532 | bits -= 1; |
| 4539 | info_ty_pl.data %= @intCast(u16, f.byteSize(elem_cty) * 8); | 4533 | bits %= @intCast(u16, f.byteSize(elem_cty) * 8); |
| 4540 | info_ty_pl.data += 1; | 4534 | bits += 1; |
| 4541 | } | 4535 | } |
| 4542 | try writer.writeAll(" = "); | 4536 | try writer.writeAll(" = "); |
| 4543 | if (need_bitcasts) { | 4537 | if (need_bitcasts) { |
| ... | @@ -4546,7 +4540,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca | ... | @@ -4546,7 +4540,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca |
| 4546 | try writer.writeByte('('); | 4540 | try writer.writeByte('('); |
| 4547 | } | 4541 | } |
| 4548 | try writer.writeAll("zig_wrap_"); | 4542 | try writer.writeAll("zig_wrap_"); |
| 4549 | const info_ty = Type.initPayload(&info_ty_pl.base); | 4543 | const info_ty = try mod.intType(dest_info.signedness, bits); |
| 4550 | if (wrap_cty) |cty| | 4544 | if (wrap_cty) |cty| |
| 4551 | try f.object.dg.renderCTypeForBuiltinFnName(writer, cty) | 4545 | try f.object.dg.renderCTypeForBuiltinFnName(writer, cty) |
| 4552 | else | 4546 | else |
| ... | @@ -4622,8 +4616,9 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4622,8 +4616,9 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4622 | } | 4616 | } |
| 4623 | 4617 | ||
| 4624 | fn airUnreach(f: *Function) !CValue { | 4618 | fn airUnreach(f: *Function) !CValue { |
| 4619 | const mod = f.object.dg.module; | ||
| 4625 | // Not even allowed to call unreachable in a naked function. | 4620 | // Not even allowed to call unreachable in a naked function. |
| 4626 | if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none; | 4621 | if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention(mod) == .Naked) return .none; |
| 4627 | 4622 | ||
| 4628 | try f.object.writer().writeAll("zig_unreachable();\n"); | 4623 | try f.object.writer().writeAll("zig_unreachable();\n"); |
| 4629 | return .none; | 4624 | return .none; |
| ... | @@ -4657,6 +4652,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4657,6 +4652,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4657 | try writer.writeAll(") "); | 4652 | try writer.writeAll(") "); |
| 4658 | 4653 | ||
| 4659 | try genBodyResolveState(f, inst, liveness_condbr.then_deaths, then_body, false); | 4654 | try genBodyResolveState(f, inst, liveness_condbr.then_deaths, then_body, false); |
| 4655 | try writer.writeByte('\n'); | ||
| 4660 | 4656 | ||
| 4661 | // We don't need to use `genBodyResolveState` for the else block, because this instruction is | 4657 | // We don't need to use `genBodyResolveState` for the else block, because this instruction is |
| 4662 | // noreturn so must terminate a body, therefore we don't need to leave `value_map` or | 4658 | // noreturn so must terminate a body, therefore we don't need to leave `value_map` or |
| ... | @@ -4675,19 +4671,20 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4675,19 +4671,20 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4675 | } | 4671 | } |
| 4676 | 4672 | ||
| 4677 | fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { | 4673 | fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4674 | const mod = f.object.dg.module; | ||
| 4678 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 4675 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 4679 | const condition = try f.resolveInst(pl_op.operand); | 4676 | const condition = try f.resolveInst(pl_op.operand); |
| 4680 | try reap(f, inst, &.{pl_op.operand}); | 4677 | try reap(f, inst, &.{pl_op.operand}); |
| 4681 | const condition_ty = f.air.typeOf(pl_op.operand); | 4678 | const condition_ty = f.typeOf(pl_op.operand); |
| 4682 | const switch_br = f.air.extraData(Air.SwitchBr, pl_op.payload); | 4679 | const switch_br = f.air.extraData(Air.SwitchBr, pl_op.payload); |
| 4683 | const writer = f.object.writer(); | 4680 | const writer = f.object.writer(); |
| 4684 | 4681 | ||
| 4685 | try writer.writeAll("switch ("); | 4682 | try writer.writeAll("switch ("); |
| 4686 | if (condition_ty.zigTypeTag() == .Bool) { | 4683 | if (condition_ty.zigTypeTag(mod) == .Bool) { |
| 4687 | try writer.writeByte('('); | 4684 | try writer.writeByte('('); |
| 4688 | try f.renderType(writer, Type.u1); | 4685 | try f.renderType(writer, Type.u1); |
| 4689 | try writer.writeByte(')'); | 4686 | try writer.writeByte(')'); |
| 4690 | } else if (condition_ty.isPtrAtRuntime()) { | 4687 | } else if (condition_ty.isPtrAtRuntime(mod)) { |
| 4691 | try writer.writeByte('('); | 4688 | try writer.writeByte('('); |
| 4692 | try f.renderType(writer, Type.usize); | 4689 | try f.renderType(writer, Type.usize); |
| 4693 | try writer.writeByte(')'); | 4690 | try writer.writeByte(')'); |
| ... | @@ -4714,12 +4711,12 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4714,12 +4711,12 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4714 | for (items) |item| { | 4711 | for (items) |item| { |
| 4715 | try f.object.indent_writer.insertNewline(); | 4712 | try f.object.indent_writer.insertNewline(); |
| 4716 | try writer.writeAll("case "); | 4713 | try writer.writeAll("case "); |
| 4717 | if (condition_ty.isPtrAtRuntime()) { | 4714 | if (condition_ty.isPtrAtRuntime(mod)) { |
| 4718 | try writer.writeByte('('); | 4715 | try writer.writeByte('('); |
| 4719 | try f.renderType(writer, Type.usize); | 4716 | try f.renderType(writer, Type.usize); |
| 4720 | try writer.writeByte(')'); | 4717 | try writer.writeByte(')'); |
| 4721 | } | 4718 | } |
| 4722 | try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other); | 4719 | try f.object.dg.renderValue(writer, condition_ty, (try f.air.value(item, mod)).?, .Other); |
| 4723 | try writer.writeByte(':'); | 4720 | try writer.writeByte(':'); |
| 4724 | } | 4721 | } |
| 4725 | try writer.writeByte(' '); | 4722 | try writer.writeByte(' '); |
| ... | @@ -4764,6 +4761,7 @@ fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool { | ... | @@ -4764,6 +4761,7 @@ fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool { |
| 4764 | } | 4761 | } |
| 4765 | 4762 | ||
| 4766 | fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | 4763 | fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4764 | const mod = f.object.dg.module; | ||
| 4767 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 4765 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4768 | const extra = f.air.extraData(Air.Asm, ty_pl.payload); | 4766 | const extra = f.air.extraData(Air.Asm, ty_pl.payload); |
| 4769 | const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0; | 4767 | const is_volatile = @truncate(u1, extra.data.flags >> 31) != 0; |
| ... | @@ -4777,8 +4775,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4777,8 +4775,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4777 | 4775 | ||
| 4778 | const result = result: { | 4776 | const result = result: { |
| 4779 | const writer = f.object.writer(); | 4777 | const writer = f.object.writer(); |
| 4780 | const inst_ty = f.air.typeOfIndex(inst); | 4778 | const inst_ty = f.typeOfIndex(inst); |
| 4781 | const local = if (inst_ty.hasRuntimeBitsIgnoreComptime()) local: { | 4779 | const local = if (inst_ty.hasRuntimeBitsIgnoreComptime(mod)) local: { |
| 4782 | const local = try f.allocLocal(inst, inst_ty); | 4780 | const local = try f.allocLocal(inst, inst_ty); |
| 4783 | if (f.wantSafety()) { | 4781 | if (f.wantSafety()) { |
| 4784 | try f.writeCValue(writer, local, .Other); | 4782 | try f.writeCValue(writer, local, .Other); |
| ... | @@ -4807,7 +4805,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4807,7 +4805,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4807 | 4805 | ||
| 4808 | const is_reg = constraint[1] == '{'; | 4806 | const is_reg = constraint[1] == '{'; |
| 4809 | if (is_reg) { | 4807 | if (is_reg) { |
| 4810 | const output_ty = if (output == .none) inst_ty else f.air.typeOf(output).childType(); | 4808 | const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(mod); |
| 4811 | try writer.writeAll("register "); | 4809 | try writer.writeAll("register "); |
| 4812 | const alignment = 0; | 4810 | const alignment = 0; |
| 4813 | const local_value = try f.allocLocalValue(output_ty, alignment); | 4811 | const local_value = try f.allocLocalValue(output_ty, alignment); |
| ... | @@ -4840,7 +4838,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4840,7 +4838,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4840 | const is_reg = constraint[0] == '{'; | 4838 | const is_reg = constraint[0] == '{'; |
| 4841 | const input_val = try f.resolveInst(input); | 4839 | const input_val = try f.resolveInst(input); |
| 4842 | if (asmInputNeedsLocal(constraint, input_val)) { | 4840 | if (asmInputNeedsLocal(constraint, input_val)) { |
| 4843 | const input_ty = f.air.typeOf(input); | 4841 | const input_ty = f.typeOf(input); |
| 4844 | if (is_reg) try writer.writeAll("register "); | 4842 | if (is_reg) try writer.writeAll("register "); |
| 4845 | const alignment = 0; | 4843 | const alignment = 0; |
| 4846 | const local_value = try f.allocLocalValue(input_ty, alignment); | 4844 | const local_value = try f.allocLocalValue(input_ty, alignment); |
| ... | @@ -5025,6 +5023,7 @@ fn airIsNull( | ... | @@ -5025,6 +5023,7 @@ fn airIsNull( |
| 5025 | operator: []const u8, | 5023 | operator: []const u8, |
| 5026 | is_ptr: bool, | 5024 | is_ptr: bool, |
| 5027 | ) !CValue { | 5025 | ) !CValue { |
| 5026 | const mod = f.object.dg.module; | ||
| 5028 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 5027 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 5029 | 5028 | ||
| 5030 | const writer = f.object.writer(); | 5029 | const writer = f.object.writer(); |
| ... | @@ -5040,23 +5039,22 @@ fn airIsNull( | ... | @@ -5040,23 +5039,22 @@ fn airIsNull( |
| 5040 | try f.writeCValue(writer, operand, .Other); | 5039 | try f.writeCValue(writer, operand, .Other); |
| 5041 | } | 5040 | } |
| 5042 | 5041 | ||
| 5043 | const operand_ty = f.air.typeOf(un_op); | 5042 | const operand_ty = f.typeOf(un_op); |
| 5044 | const optional_ty = if (is_ptr) operand_ty.childType() else operand_ty; | 5043 | const optional_ty = if (is_ptr) operand_ty.childType(mod) else operand_ty; |
| 5045 | var payload_buf: Type.Payload.ElemType = undefined; | 5044 | const payload_ty = optional_ty.optionalChild(mod); |
| 5046 | const payload_ty = optional_ty.optionalChild(&payload_buf); | ||
| 5047 | var slice_ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 5048 | 5045 | ||
| 5049 | const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime()) | 5046 | const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 5050 | TypedValue{ .ty = Type.bool, .val = Value.true } | 5047 | TypedValue{ .ty = Type.bool, .val = Value.true } |
| 5051 | else if (optional_ty.isPtrLikeOptional()) | 5048 | else if (optional_ty.isPtrLikeOptional(mod)) |
| 5052 | // operand is a regular pointer, test `operand !=/== NULL` | 5049 | // operand is a regular pointer, test `operand !=/== NULL` |
| 5053 | TypedValue{ .ty = optional_ty, .val = Value.null } | 5050 | TypedValue{ .ty = optional_ty, .val = try mod.getCoerced(Value.null, optional_ty) } |
| 5054 | else if (payload_ty.zigTypeTag() == .ErrorSet) | 5051 | else if (payload_ty.zigTypeTag(mod) == .ErrorSet) |
| 5055 | TypedValue{ .ty = payload_ty, .val = Value.zero } | 5052 | TypedValue{ .ty = Type.err_int, .val = try mod.intValue(Type.err_int, 0) } |
| 5056 | else if (payload_ty.isSlice() and optional_ty.optionalReprIsPayload()) rhs: { | 5053 | else if (payload_ty.isSlice(mod) and optional_ty.optionalReprIsPayload(mod)) rhs: { |
| 5057 | try writer.writeAll(".ptr"); | 5054 | try writer.writeAll(".ptr"); |
| 5058 | const slice_ptr_ty = payload_ty.slicePtrFieldType(&slice_ptr_buf); | 5055 | const slice_ptr_ty = payload_ty.slicePtrFieldType(mod); |
| 5059 | break :rhs TypedValue{ .ty = slice_ptr_ty, .val = Value.null }; | 5056 | const opt_slice_ptr_ty = try mod.optionalType(slice_ptr_ty.toIntern()); |
| 5057 | break :rhs TypedValue{ .ty = opt_slice_ptr_ty, .val = try mod.nullValue(opt_slice_ptr_ty) }; | ||
| 5060 | } else rhs: { | 5058 | } else rhs: { |
| 5061 | try writer.writeAll(".is_null"); | 5059 | try writer.writeAll(".is_null"); |
| 5062 | break :rhs TypedValue{ .ty = Type.bool, .val = Value.true }; | 5060 | break :rhs TypedValue{ .ty = Type.bool, .val = Value.true }; |
| ... | @@ -5070,24 +5068,24 @@ fn airIsNull( | ... | @@ -5070,24 +5068,24 @@ fn airIsNull( |
| 5070 | } | 5068 | } |
| 5071 | 5069 | ||
| 5072 | fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { | 5070 | fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5071 | const mod = f.object.dg.module; | ||
| 5073 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5072 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5074 | 5073 | ||
| 5075 | const operand = try f.resolveInst(ty_op.operand); | 5074 | const operand = try f.resolveInst(ty_op.operand); |
| 5076 | try reap(f, inst, &.{ty_op.operand}); | 5075 | try reap(f, inst, &.{ty_op.operand}); |
| 5077 | const opt_ty = f.air.typeOf(ty_op.operand); | 5076 | const opt_ty = f.typeOf(ty_op.operand); |
| 5078 | 5077 | ||
| 5079 | var buf: Type.Payload.ElemType = undefined; | 5078 | const payload_ty = opt_ty.optionalChild(mod); |
| 5080 | const payload_ty = opt_ty.optionalChild(&buf); | ||
| 5081 | 5079 | ||
| 5082 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 5080 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 5083 | return .none; | 5081 | return .none; |
| 5084 | } | 5082 | } |
| 5085 | 5083 | ||
| 5086 | const inst_ty = f.air.typeOfIndex(inst); | 5084 | const inst_ty = f.typeOfIndex(inst); |
| 5087 | const writer = f.object.writer(); | 5085 | const writer = f.object.writer(); |
| 5088 | const local = try f.allocLocal(inst, inst_ty); | 5086 | const local = try f.allocLocal(inst, inst_ty); |
| 5089 | 5087 | ||
| 5090 | if (opt_ty.optionalReprIsPayload()) { | 5088 | if (opt_ty.optionalReprIsPayload(mod)) { |
| 5091 | try f.writeCValue(writer, local, .Other); | 5089 | try f.writeCValue(writer, local, .Other); |
| 5092 | try writer.writeAll(" = "); | 5090 | try writer.writeAll(" = "); |
| 5093 | try f.writeCValue(writer, operand, .Other); | 5091 | try f.writeCValue(writer, operand, .Other); |
| ... | @@ -5104,23 +5102,24 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5104,23 +5102,24 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5104 | } | 5102 | } |
| 5105 | 5103 | ||
| 5106 | fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { | 5104 | fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5105 | const mod = f.object.dg.module; | ||
| 5107 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5106 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5108 | 5107 | ||
| 5109 | const writer = f.object.writer(); | 5108 | const writer = f.object.writer(); |
| 5110 | const operand = try f.resolveInst(ty_op.operand); | 5109 | const operand = try f.resolveInst(ty_op.operand); |
| 5111 | try reap(f, inst, &.{ty_op.operand}); | 5110 | try reap(f, inst, &.{ty_op.operand}); |
| 5112 | const ptr_ty = f.air.typeOf(ty_op.operand); | 5111 | const ptr_ty = f.typeOf(ty_op.operand); |
| 5113 | const opt_ty = ptr_ty.childType(); | 5112 | const opt_ty = ptr_ty.childType(mod); |
| 5114 | const inst_ty = f.air.typeOfIndex(inst); | 5113 | const inst_ty = f.typeOfIndex(inst); |
| 5115 | 5114 | ||
| 5116 | if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) { | 5115 | if (!inst_ty.childType(mod).hasRuntimeBitsIgnoreComptime(mod)) { |
| 5117 | return .{ .undef = inst_ty }; | 5116 | return .{ .undef = inst_ty }; |
| 5118 | } | 5117 | } |
| 5119 | 5118 | ||
| 5120 | const local = try f.allocLocal(inst, inst_ty); | 5119 | const local = try f.allocLocal(inst, inst_ty); |
| 5121 | try f.writeCValue(writer, local, .Other); | 5120 | try f.writeCValue(writer, local, .Other); |
| 5122 | 5121 | ||
| 5123 | if (opt_ty.optionalReprIsPayload()) { | 5122 | if (opt_ty.optionalReprIsPayload(mod)) { |
| 5124 | // the operand is just a regular pointer, no need to do anything special. | 5123 | // the operand is just a regular pointer, no need to do anything special. |
| 5125 | // *?*T -> **T and ?*T -> *T are **T -> **T and *T -> *T in C | 5124 | // *?*T -> **T and ?*T -> *T are **T -> **T and *T -> *T in C |
| 5126 | try writer.writeAll(" = "); | 5125 | try writer.writeAll(" = "); |
| ... | @@ -5134,17 +5133,18 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5134,17 +5133,18 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5134 | } | 5133 | } |
| 5135 | 5134 | ||
| 5136 | fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { | 5135 | fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5136 | const mod = f.object.dg.module; | ||
| 5137 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5137 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5138 | const writer = f.object.writer(); | 5138 | const writer = f.object.writer(); |
| 5139 | const operand = try f.resolveInst(ty_op.operand); | 5139 | const operand = try f.resolveInst(ty_op.operand); |
| 5140 | try reap(f, inst, &.{ty_op.operand}); | 5140 | try reap(f, inst, &.{ty_op.operand}); |
| 5141 | const operand_ty = f.air.typeOf(ty_op.operand); | 5141 | const operand_ty = f.typeOf(ty_op.operand); |
| 5142 | 5142 | ||
| 5143 | const opt_ty = operand_ty.elemType(); | 5143 | const opt_ty = operand_ty.childType(mod); |
| 5144 | 5144 | ||
| 5145 | const inst_ty = f.air.typeOfIndex(inst); | 5145 | const inst_ty = f.typeOfIndex(inst); |
| 5146 | 5146 | ||
| 5147 | if (opt_ty.optionalReprIsPayload()) { | 5147 | if (opt_ty.optionalReprIsPayload(mod)) { |
| 5148 | if (f.liveness.isUnused(inst)) { | 5148 | if (f.liveness.isUnused(inst)) { |
| 5149 | return .none; | 5149 | return .none; |
| 5150 | } | 5150 | } |
| ... | @@ -5179,48 +5179,49 @@ fn fieldLocation( | ... | @@ -5179,48 +5179,49 @@ fn fieldLocation( |
| 5179 | container_ty: Type, | 5179 | container_ty: Type, |
| 5180 | field_ptr_ty: Type, | 5180 | field_ptr_ty: Type, |
| 5181 | field_index: u32, | 5181 | field_index: u32, |
| 5182 | target: std.Target, | 5182 | mod: *Module, |
| 5183 | ) union(enum) { | 5183 | ) union(enum) { |
| 5184 | begin: void, | 5184 | begin: void, |
| 5185 | field: CValue, | 5185 | field: CValue, |
| 5186 | byte_offset: u32, | 5186 | byte_offset: u32, |
| 5187 | end: void, | 5187 | end: void, |
| 5188 | } { | 5188 | } { |
| 5189 | return switch (container_ty.zigTypeTag()) { | 5189 | const ip = &mod.intern_pool; |
| 5190 | .Struct => switch (container_ty.containerLayout()) { | 5190 | return switch (container_ty.zigTypeTag(mod)) { |
| 5191 | .Auto, .Extern => for (field_index..container_ty.structFieldCount()) |next_field_index| { | 5191 | .Struct => switch (container_ty.containerLayout(mod)) { |
| 5192 | if (container_ty.structFieldIsComptime(next_field_index)) continue; | 5192 | .Auto, .Extern => for (field_index..container_ty.structFieldCount(mod)) |next_field_index| { |
| 5193 | const field_ty = container_ty.structFieldType(next_field_index); | 5193 | if (container_ty.structFieldIsComptime(next_field_index, mod)) continue; |
| 5194 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 5194 | const field_ty = container_ty.structFieldType(next_field_index, mod); |
| 5195 | 5195 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 5196 | break .{ .field = if (container_ty.isSimpleTuple()) | 5196 | |
| 5197 | break .{ .field = if (container_ty.isSimpleTuple(mod)) | ||
| 5197 | .{ .field = next_field_index } | 5198 | .{ .field = next_field_index } |
| 5198 | else | 5199 | else |
| 5199 | .{ .identifier = container_ty.structFieldName(next_field_index) } }; | 5200 | .{ .identifier = ip.stringToSlice(container_ty.structFieldName(next_field_index, mod)) } }; |
| 5200 | } else if (container_ty.hasRuntimeBitsIgnoreComptime()) .end else .begin, | 5201 | } else if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin, |
| 5201 | .Packed => if (field_ptr_ty.ptrInfo().data.host_size == 0) | 5202 | .Packed => if (field_ptr_ty.ptrInfo(mod).host_size == 0) |
| 5202 | .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, target) } | 5203 | .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, mod) } |
| 5203 | else | 5204 | else |
| 5204 | .begin, | 5205 | .begin, |
| 5205 | }, | 5206 | }, |
| 5206 | .Union => switch (container_ty.containerLayout()) { | 5207 | .Union => switch (container_ty.containerLayout(mod)) { |
| 5207 | .Auto, .Extern => { | 5208 | .Auto, .Extern => { |
| 5208 | const field_ty = container_ty.structFieldType(field_index); | 5209 | const field_ty = container_ty.structFieldType(field_index, mod); |
| 5209 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) | 5210 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 5210 | return if (container_ty.unionTagTypeSafety() != null and | 5211 | return if (container_ty.unionTagTypeSafety(mod) != null and |
| 5211 | !container_ty.unionHasAllZeroBitFieldTypes()) | 5212 | !container_ty.unionHasAllZeroBitFieldTypes(mod)) |
| 5212 | .{ .field = .{ .identifier = "payload" } } | 5213 | .{ .field = .{ .identifier = "payload" } } |
| 5213 | else | 5214 | else |
| 5214 | .begin; | 5215 | .begin; |
| 5215 | const field_name = container_ty.unionFields().keys()[field_index]; | 5216 | const field_name = container_ty.unionFields(mod).keys()[field_index]; |
| 5216 | return .{ .field = if (container_ty.unionTagTypeSafety()) |_| | 5217 | return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_| |
| 5217 | .{ .payload_identifier = field_name } | 5218 | .{ .payload_identifier = ip.stringToSlice(field_name) } |
| 5218 | else | 5219 | else |
| 5219 | .{ .identifier = field_name } }; | 5220 | .{ .identifier = ip.stringToSlice(field_name) } }; |
| 5220 | }, | 5221 | }, |
| 5221 | .Packed => .begin, | 5222 | .Packed => .begin, |
| 5222 | }, | 5223 | }, |
| 5223 | .Pointer => switch (container_ty.ptrSize()) { | 5224 | .Pointer => switch (container_ty.ptrSize(mod)) { |
| 5224 | .Slice => switch (field_index) { | 5225 | .Slice => switch (field_index) { |
| 5225 | 0 => .{ .field = .{ .identifier = "ptr" } }, | 5226 | 0 => .{ .field = .{ .identifier = "ptr" } }, |
| 5226 | 1 => .{ .field = .{ .identifier = "len" } }, | 5227 | 1 => .{ .field = .{ .identifier = "len" } }, |
| ... | @@ -5238,7 +5239,7 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5238,7 +5239,7 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5238 | 5239 | ||
| 5239 | const container_ptr_val = try f.resolveInst(extra.struct_operand); | 5240 | const container_ptr_val = try f.resolveInst(extra.struct_operand); |
| 5240 | try reap(f, inst, &.{extra.struct_operand}); | 5241 | try reap(f, inst, &.{extra.struct_operand}); |
| 5241 | const container_ptr_ty = f.air.typeOf(extra.struct_operand); | 5242 | const container_ptr_ty = f.typeOf(extra.struct_operand); |
| 5242 | return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, extra.field_index); | 5243 | return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, extra.field_index); |
| 5243 | } | 5244 | } |
| 5244 | 5245 | ||
| ... | @@ -5247,19 +5248,19 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue | ... | @@ -5247,19 +5248,19 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue |
| 5247 | 5248 | ||
| 5248 | const container_ptr_val = try f.resolveInst(ty_op.operand); | 5249 | const container_ptr_val = try f.resolveInst(ty_op.operand); |
| 5249 | try reap(f, inst, &.{ty_op.operand}); | 5250 | try reap(f, inst, &.{ty_op.operand}); |
| 5250 | const container_ptr_ty = f.air.typeOf(ty_op.operand); | 5251 | const container_ptr_ty = f.typeOf(ty_op.operand); |
| 5251 | return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, index); | 5252 | return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, index); |
| 5252 | } | 5253 | } |
| 5253 | 5254 | ||
| 5254 | fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { | 5255 | fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5256 | const mod = f.object.dg.module; | ||
| 5255 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 5257 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 5256 | const extra = f.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; | 5258 | const extra = f.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 5257 | 5259 | ||
| 5258 | const target = f.object.dg.module.getTarget(); | 5260 | const container_ptr_ty = f.typeOfIndex(inst); |
| 5259 | const container_ptr_ty = f.air.typeOfIndex(inst); | 5261 | const container_ty = container_ptr_ty.childType(mod); |
| 5260 | const container_ty = container_ptr_ty.childType(); | ||
| 5261 | 5262 | ||
| 5262 | const field_ptr_ty = f.air.typeOf(extra.field_ptr); | 5263 | const field_ptr_ty = f.typeOf(extra.field_ptr); |
| 5263 | const field_ptr_val = try f.resolveInst(extra.field_ptr); | 5264 | const field_ptr_val = try f.resolveInst(extra.field_ptr); |
| 5264 | try reap(f, inst, &.{extra.field_ptr}); | 5265 | try reap(f, inst, &.{extra.field_ptr}); |
| 5265 | 5266 | ||
| ... | @@ -5270,12 +5271,10 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5270,12 +5271,10 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5270 | try f.renderType(writer, container_ptr_ty); | 5271 | try f.renderType(writer, container_ptr_ty); |
| 5271 | try writer.writeByte(')'); | 5272 | try writer.writeByte(')'); |
| 5272 | 5273 | ||
| 5273 | switch (fieldLocation(container_ty, field_ptr_ty, extra.field_index, target)) { | 5274 | switch (fieldLocation(container_ty, field_ptr_ty, extra.field_index, mod)) { |
| 5274 | .begin => try f.writeCValue(writer, field_ptr_val, .Initializer), | 5275 | .begin => try f.writeCValue(writer, field_ptr_val, .Initializer), |
| 5275 | .field => |field| { | 5276 | .field => |field| { |
| 5276 | var u8_ptr_pl = field_ptr_ty.ptrInfo(); | 5277 | const u8_ptr_ty = try mod.adjustPtrTypeChild(field_ptr_ty, Type.u8); |
| 5277 | u8_ptr_pl.data.pointee_type = Type.u8; | ||
| 5278 | const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); | ||
| 5279 | 5278 | ||
| 5280 | try writer.writeAll("(("); | 5279 | try writer.writeAll("(("); |
| 5281 | try f.renderType(writer, u8_ptr_ty); | 5280 | try f.renderType(writer, u8_ptr_ty); |
| ... | @@ -5288,15 +5287,9 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5288,15 +5287,9 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5288 | try writer.writeAll("))"); | 5287 | try writer.writeAll("))"); |
| 5289 | }, | 5288 | }, |
| 5290 | .byte_offset => |byte_offset| { | 5289 | .byte_offset => |byte_offset| { |
| 5291 | var u8_ptr_pl = field_ptr_ty.ptrInfo(); | 5290 | const u8_ptr_ty = try mod.adjustPtrTypeChild(field_ptr_ty, Type.u8); |
| 5292 | u8_ptr_pl.data.pointee_type = Type.u8; | ||
| 5293 | const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); | ||
| 5294 | 5291 | ||
| 5295 | var byte_offset_pl = Value.Payload.U64{ | 5292 | const byte_offset_val = try mod.intValue(Type.usize, byte_offset); |
| 5296 | .base = .{ .tag = .int_u64 }, | ||
| 5297 | .data = byte_offset, | ||
| 5298 | }; | ||
| 5299 | const byte_offset_val = Value.initPayload(&byte_offset_pl.base); | ||
| 5300 | 5293 | ||
| 5301 | try writer.writeAll("(("); | 5294 | try writer.writeAll("(("); |
| 5302 | try f.renderType(writer, u8_ptr_ty); | 5295 | try f.renderType(writer, u8_ptr_ty); |
| ... | @@ -5306,7 +5299,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5306,7 +5299,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5306 | }, | 5299 | }, |
| 5307 | .end => { | 5300 | .end => { |
| 5308 | try f.writeCValue(writer, field_ptr_val, .Other); | 5301 | try f.writeCValue(writer, field_ptr_val, .Other); |
| 5309 | try writer.print(" - {}", .{try f.fmtIntLiteral(Type.usize, Value.one)}); | 5302 | try writer.print(" - {}", .{try f.fmtIntLiteral(Type.usize, try mod.intValue(Type.usize, 1))}); |
| 5310 | }, | 5303 | }, |
| 5311 | } | 5304 | } |
| 5312 | 5305 | ||
| ... | @@ -5321,9 +5314,9 @@ fn fieldPtr( | ... | @@ -5321,9 +5314,9 @@ fn fieldPtr( |
| 5321 | container_ptr_val: CValue, | 5314 | container_ptr_val: CValue, |
| 5322 | field_index: u32, | 5315 | field_index: u32, |
| 5323 | ) !CValue { | 5316 | ) !CValue { |
| 5324 | const target = f.object.dg.module.getTarget(); | 5317 | const mod = f.object.dg.module; |
| 5325 | const container_ty = container_ptr_ty.elemType(); | 5318 | const container_ty = container_ptr_ty.childType(mod); |
| 5326 | const field_ptr_ty = f.air.typeOfIndex(inst); | 5319 | const field_ptr_ty = f.typeOfIndex(inst); |
| 5327 | 5320 | ||
| 5328 | // Ensure complete type definition is visible before accessing fields. | 5321 | // Ensure complete type definition is visible before accessing fields. |
| 5329 | _ = try f.typeToIndex(container_ty, .complete); | 5322 | _ = try f.typeToIndex(container_ty, .complete); |
| ... | @@ -5335,22 +5328,16 @@ fn fieldPtr( | ... | @@ -5335,22 +5328,16 @@ fn fieldPtr( |
| 5335 | try f.renderType(writer, field_ptr_ty); | 5328 | try f.renderType(writer, field_ptr_ty); |
| 5336 | try writer.writeByte(')'); | 5329 | try writer.writeByte(')'); |
| 5337 | 5330 | ||
| 5338 | switch (fieldLocation(container_ty, field_ptr_ty, field_index, target)) { | 5331 | switch (fieldLocation(container_ty, field_ptr_ty, field_index, mod)) { |
| 5339 | .begin => try f.writeCValue(writer, container_ptr_val, .Initializer), | 5332 | .begin => try f.writeCValue(writer, container_ptr_val, .Initializer), |
| 5340 | .field => |field| { | 5333 | .field => |field| { |
| 5341 | try writer.writeByte('&'); | 5334 | try writer.writeByte('&'); |
| 5342 | try f.writeCValueDerefMember(writer, container_ptr_val, field); | 5335 | try f.writeCValueDerefMember(writer, container_ptr_val, field); |
| 5343 | }, | 5336 | }, |
| 5344 | .byte_offset => |byte_offset| { | 5337 | .byte_offset => |byte_offset| { |
| 5345 | var u8_ptr_pl = field_ptr_ty.ptrInfo(); | 5338 | const u8_ptr_ty = try mod.adjustPtrTypeChild(field_ptr_ty, Type.u8); |
| 5346 | u8_ptr_pl.data.pointee_type = Type.u8; | ||
| 5347 | const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); | ||
| 5348 | 5339 | ||
| 5349 | var byte_offset_pl = Value.Payload.U64{ | 5340 | const byte_offset_val = try mod.intValue(Type.usize, byte_offset); |
| 5350 | .base = .{ .tag = .int_u64 }, | ||
| 5351 | .data = byte_offset, | ||
| 5352 | }; | ||
| 5353 | const byte_offset_val = Value.initPayload(&byte_offset_pl.base); | ||
| 5354 | 5341 | ||
| 5355 | try writer.writeAll("(("); | 5342 | try writer.writeAll("(("); |
| 5356 | try f.renderType(writer, u8_ptr_ty); | 5343 | try f.renderType(writer, u8_ptr_ty); |
| ... | @@ -5361,7 +5348,7 @@ fn fieldPtr( | ... | @@ -5361,7 +5348,7 @@ fn fieldPtr( |
| 5361 | .end => { | 5348 | .end => { |
| 5362 | try writer.writeByte('('); | 5349 | try writer.writeByte('('); |
| 5363 | try f.writeCValue(writer, container_ptr_val, .Other); | 5350 | try f.writeCValue(writer, container_ptr_val, .Other); |
| 5364 | try writer.print(" + {})", .{try f.fmtIntLiteral(Type.usize, Value.one)}); | 5351 | try writer.print(" + {})", .{try f.fmtIntLiteral(Type.usize, try mod.intValue(Type.usize, 1))}); |
| 5365 | }, | 5352 | }, |
| 5366 | } | 5353 | } |
| 5367 | 5354 | ||
| ... | @@ -5370,58 +5357,45 @@ fn fieldPtr( | ... | @@ -5370,58 +5357,45 @@ fn fieldPtr( |
| 5370 | } | 5357 | } |
| 5371 | 5358 | ||
| 5372 | fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | 5359 | fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5360 | const mod = f.object.dg.module; | ||
| 5361 | const ip = &mod.intern_pool; | ||
| 5373 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 5362 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 5374 | const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; | 5363 | const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; |
| 5375 | 5364 | ||
| 5376 | const inst_ty = f.air.typeOfIndex(inst); | 5365 | const inst_ty = f.typeOfIndex(inst); |
| 5377 | if (!inst_ty.hasRuntimeBitsIgnoreComptime()) { | 5366 | if (!inst_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 5378 | try reap(f, inst, &.{extra.struct_operand}); | 5367 | try reap(f, inst, &.{extra.struct_operand}); |
| 5379 | return .none; | 5368 | return .none; |
| 5380 | } | 5369 | } |
| 5381 | 5370 | ||
| 5382 | const target = f.object.dg.module.getTarget(); | ||
| 5383 | const struct_byval = try f.resolveInst(extra.struct_operand); | 5371 | const struct_byval = try f.resolveInst(extra.struct_operand); |
| 5384 | try reap(f, inst, &.{extra.struct_operand}); | 5372 | try reap(f, inst, &.{extra.struct_operand}); |
| 5385 | const struct_ty = f.air.typeOf(extra.struct_operand); | 5373 | const struct_ty = f.typeOf(extra.struct_operand); |
| 5386 | const writer = f.object.writer(); | 5374 | const writer = f.object.writer(); |
| 5387 | 5375 | ||
| 5388 | // Ensure complete type definition is visible before accessing fields. | 5376 | // Ensure complete type definition is visible before accessing fields. |
| 5389 | _ = try f.typeToIndex(struct_ty, .complete); | 5377 | _ = try f.typeToIndex(struct_ty, .complete); |
| 5390 | 5378 | ||
| 5391 | const field_name: CValue = switch (struct_ty.tag()) { | 5379 | const field_name: CValue = switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { |
| 5392 | .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) { | 5380 | .struct_type => switch (struct_ty.containerLayout(mod)) { |
| 5393 | .Auto, .Extern => if (struct_ty.isSimpleTuple()) | 5381 | .Auto, .Extern => if (struct_ty.isSimpleTuple(mod)) |
| 5394 | .{ .field = extra.field_index } | 5382 | .{ .field = extra.field_index } |
| 5395 | else | 5383 | else |
| 5396 | .{ .identifier = struct_ty.structFieldName(extra.field_index) }, | 5384 | .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) }, |
| 5397 | .Packed => { | 5385 | .Packed => { |
| 5398 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 5386 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| 5399 | const int_info = struct_ty.intInfo(target); | 5387 | const int_info = struct_ty.intInfo(mod); |
| 5400 | 5388 | ||
| 5401 | var bit_offset_ty_pl = Type.Payload.Bits{ | 5389 | const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1)); |
| 5402 | .base = .{ .tag = .int_unsigned }, | ||
| 5403 | .data = Type.smallestUnsignedBits(int_info.bits - 1), | ||
| 5404 | }; | ||
| 5405 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); | ||
| 5406 | 5390 | ||
| 5407 | var bit_offset_val_pl: Value.Payload.U64 = .{ | 5391 | const bit_offset = struct_obj.packedFieldBitOffset(mod, extra.field_index); |
| 5408 | .base = .{ .tag = .int_u64 }, | 5392 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); |
| 5409 | .data = struct_obj.packedFieldBitOffset(target, extra.field_index), | ||
| 5410 | }; | ||
| 5411 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); | ||
| 5412 | 5393 | ||
| 5413 | const field_int_signedness = if (inst_ty.isAbiInt()) | 5394 | const field_int_signedness = if (inst_ty.isAbiInt(mod)) |
| 5414 | inst_ty.intInfo(target).signedness | 5395 | inst_ty.intInfo(mod).signedness |
| 5415 | else | 5396 | else |
| 5416 | .unsigned; | 5397 | .unsigned; |
| 5417 | var field_int_pl = Type.Payload.Bits{ | 5398 | const field_int_ty = try mod.intType(field_int_signedness, @intCast(u16, inst_ty.bitSize(mod))); |
| 5418 | .base = .{ .tag = switch (field_int_signedness) { | ||
| 5419 | .unsigned => .int_unsigned, | ||
| 5420 | .signed => .int_signed, | ||
| 5421 | } }, | ||
| 5422 | .data = @intCast(u16, inst_ty.bitSize(target)), | ||
| 5423 | }; | ||
| 5424 | const field_int_ty = Type.initPayload(&field_int_pl.base); | ||
| 5425 | 5399 | ||
| 5426 | const temp_local = try f.allocLocal(inst, field_int_ty); | 5400 | const temp_local = try f.allocLocal(inst, field_int_ty); |
| 5427 | try f.writeCValue(writer, temp_local, .Other); | 5401 | try f.writeCValue(writer, temp_local, .Other); |
| ... | @@ -5432,18 +5406,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5432,18 +5406,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5432 | try writer.writeByte(')'); | 5406 | try writer.writeByte(')'); |
| 5433 | const cant_cast = int_info.bits > 64; | 5407 | const cant_cast = int_info.bits > 64; |
| 5434 | if (cant_cast) { | 5408 | if (cant_cast) { |
| 5435 | if (field_int_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); | 5409 | if (field_int_ty.bitSize(mod) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{}); |
| 5436 | try writer.writeAll("zig_lo_"); | 5410 | try writer.writeAll("zig_lo_"); |
| 5437 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); | 5411 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); |
| 5438 | try writer.writeByte('('); | 5412 | try writer.writeByte('('); |
| 5439 | } | 5413 | } |
| 5440 | if (bit_offset_val_pl.data > 0) { | 5414 | if (bit_offset > 0) { |
| 5441 | try writer.writeAll("zig_shr_"); | 5415 | try writer.writeAll("zig_shr_"); |
| 5442 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); | 5416 | try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); |
| 5443 | try writer.writeByte('('); | 5417 | try writer.writeByte('('); |
| 5444 | } | 5418 | } |
| 5445 | try f.writeCValue(writer, struct_byval, .Other); | 5419 | try f.writeCValue(writer, struct_byval, .Other); |
| 5446 | if (bit_offset_val_pl.data > 0) { | 5420 | if (bit_offset > 0) { |
| 5447 | try writer.writeAll(", "); | 5421 | try writer.writeAll(", "); |
| 5448 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | 5422 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 5449 | try writer.writeByte(')'); | 5423 | try writer.writeByte(')'); |
| ... | @@ -5465,36 +5439,46 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5465,36 +5439,46 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5465 | return local; | 5439 | return local; |
| 5466 | }, | 5440 | }, |
| 5467 | }, | 5441 | }, |
| 5468 | .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) { | ||
| 5469 | const operand_lval = if (struct_byval == .constant) blk: { | ||
| 5470 | const operand_local = try f.allocLocal(inst, struct_ty); | ||
| 5471 | try f.writeCValue(writer, operand_local, .Other); | ||
| 5472 | try writer.writeAll(" = "); | ||
| 5473 | try f.writeCValue(writer, struct_byval, .Initializer); | ||
| 5474 | try writer.writeAll(";\n"); | ||
| 5475 | break :blk operand_local; | ||
| 5476 | } else struct_byval; | ||
| 5477 | 5442 | ||
| 5478 | const local = try f.allocLocal(inst, inst_ty); | 5443 | .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0) |
| 5479 | try writer.writeAll("memcpy(&"); | 5444 | .{ .field = extra.field_index } |
| 5480 | try f.writeCValue(writer, local, .Other); | 5445 | else |
| 5481 | try writer.writeAll(", &"); | 5446 | .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) }, |
| 5482 | try f.writeCValue(writer, operand_lval, .Other); | 5447 | |
| 5483 | try writer.writeAll(", sizeof("); | 5448 | .union_type => |union_type| field_name: { |
| 5484 | try f.renderType(writer, inst_ty); | 5449 | const union_obj = mod.unionPtr(union_type.index); |
| 5485 | try writer.writeAll("));\n"); | 5450 | if (union_obj.layout == .Packed) { |
| 5451 | const operand_lval = if (struct_byval == .constant) blk: { | ||
| 5452 | const operand_local = try f.allocLocal(inst, struct_ty); | ||
| 5453 | try f.writeCValue(writer, operand_local, .Other); | ||
| 5454 | try writer.writeAll(" = "); | ||
| 5455 | try f.writeCValue(writer, struct_byval, .Initializer); | ||
| 5456 | try writer.writeAll(";\n"); | ||
| 5457 | break :blk operand_local; | ||
| 5458 | } else struct_byval; | ||
| 5486 | 5459 | ||
| 5487 | if (struct_byval == .constant) { | 5460 | const local = try f.allocLocal(inst, inst_ty); |
| 5488 | try freeLocal(f, inst, operand_lval.new_local, 0); | 5461 | try writer.writeAll("memcpy(&"); |
| 5489 | } | 5462 | try f.writeCValue(writer, local, .Other); |
| 5463 | try writer.writeAll(", &"); | ||
| 5464 | try f.writeCValue(writer, operand_lval, .Other); | ||
| 5465 | try writer.writeAll(", sizeof("); | ||
| 5466 | try f.renderType(writer, inst_ty); | ||
| 5467 | try writer.writeAll("));\n"); | ||
| 5490 | 5468 | ||
| 5491 | return local; | 5469 | if (struct_byval == .constant) { |
| 5492 | } else field_name: { | 5470 | try freeLocal(f, inst, operand_lval.new_local, 0); |
| 5493 | const name = struct_ty.unionFields().keys()[extra.field_index]; | 5471 | } |
| 5494 | break :field_name if (struct_ty.unionTagTypeSafety()) |_| | 5472 | |
| 5495 | .{ .payload_identifier = name } | 5473 | return local; |
| 5496 | else | 5474 | } else { |
| 5497 | .{ .identifier = name }; | 5475 | const name = union_obj.fields.keys()[extra.field_index]; |
| 5476 | break :field_name if (union_type.hasTag()) .{ | ||
| 5477 | .payload_identifier = ip.stringToSlice(name), | ||
| 5478 | } else .{ | ||
| 5479 | .identifier = ip.stringToSlice(name), | ||
| 5480 | }; | ||
| 5481 | } | ||
| 5498 | }, | 5482 | }, |
| 5499 | else => unreachable, | 5483 | else => unreachable, |
| 5500 | }; | 5484 | }; |
| ... | @@ -5511,20 +5495,21 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5511,20 +5495,21 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5511 | /// *(E!T) -> E | 5495 | /// *(E!T) -> E |
| 5512 | /// Note that the result is never a pointer. | 5496 | /// Note that the result is never a pointer. |
| 5513 | fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { | 5497 | fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5498 | const mod = f.object.dg.module; | ||
| 5514 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5499 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5515 | 5500 | ||
| 5516 | const inst_ty = f.air.typeOfIndex(inst); | 5501 | const inst_ty = f.typeOfIndex(inst); |
| 5517 | const operand = try f.resolveInst(ty_op.operand); | 5502 | const operand = try f.resolveInst(ty_op.operand); |
| 5518 | const operand_ty = f.air.typeOf(ty_op.operand); | 5503 | const operand_ty = f.typeOf(ty_op.operand); |
| 5519 | try reap(f, inst, &.{ty_op.operand}); | 5504 | try reap(f, inst, &.{ty_op.operand}); |
| 5520 | 5505 | ||
| 5521 | const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer; | 5506 | const operand_is_ptr = operand_ty.zigTypeTag(mod) == .Pointer; |
| 5522 | const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | 5507 | const error_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; |
| 5523 | const error_ty = error_union_ty.errorUnionSet(); | 5508 | const error_ty = error_union_ty.errorUnionSet(mod); |
| 5524 | const payload_ty = error_union_ty.errorUnionPayload(); | 5509 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 5525 | const local = try f.allocLocal(inst, inst_ty); | 5510 | const local = try f.allocLocal(inst, inst_ty); |
| 5526 | 5511 | ||
| 5527 | if (!payload_ty.hasRuntimeBits() and operand == .local and operand.local == local.new_local) { | 5512 | if (!payload_ty.hasRuntimeBits(mod) and operand == .local and operand.local == local.new_local) { |
| 5528 | // The store will be 'x = x'; elide it. | 5513 | // The store will be 'x = x'; elide it. |
| 5529 | return local; | 5514 | return local; |
| 5530 | } | 5515 | } |
| ... | @@ -5533,32 +5518,33 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5533,32 +5518,33 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5533 | try f.writeCValue(writer, local, .Other); | 5518 | try f.writeCValue(writer, local, .Other); |
| 5534 | try writer.writeAll(" = "); | 5519 | try writer.writeAll(" = "); |
| 5535 | 5520 | ||
| 5536 | if (!payload_ty.hasRuntimeBits()) { | 5521 | if (!payload_ty.hasRuntimeBits(mod)) { |
| 5537 | try f.writeCValue(writer, operand, .Other); | 5522 | try f.writeCValue(writer, operand, .Other); |
| 5538 | } else { | 5523 | } else { |
| 5539 | if (!error_ty.errorSetIsEmpty()) | 5524 | if (!error_ty.errorSetIsEmpty(mod)) |
| 5540 | if (operand_is_ptr) | 5525 | if (operand_is_ptr) |
| 5541 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) | 5526 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) |
| 5542 | else | 5527 | else |
| 5543 | try f.writeCValueMember(writer, operand, .{ .identifier = "error" }) | 5528 | try f.writeCValueMember(writer, operand, .{ .identifier = "error" }) |
| 5544 | else | 5529 | else |
| 5545 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer); | 5530 | try f.object.dg.renderValue(writer, error_ty, try mod.intValue(error_ty, 0), .Initializer); |
| 5546 | } | 5531 | } |
| 5547 | try writer.writeAll(";\n"); | 5532 | try writer.writeAll(";\n"); |
| 5548 | return local; | 5533 | return local; |
| 5549 | } | 5534 | } |
| 5550 | 5535 | ||
| 5551 | fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { | 5536 | fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { |
| 5537 | const mod = f.object.dg.module; | ||
| 5552 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5538 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5553 | 5539 | ||
| 5554 | const inst_ty = f.air.typeOfIndex(inst); | 5540 | const inst_ty = f.typeOfIndex(inst); |
| 5555 | const operand = try f.resolveInst(ty_op.operand); | 5541 | const operand = try f.resolveInst(ty_op.operand); |
| 5556 | try reap(f, inst, &.{ty_op.operand}); | 5542 | try reap(f, inst, &.{ty_op.operand}); |
| 5557 | const operand_ty = f.air.typeOf(ty_op.operand); | 5543 | const operand_ty = f.typeOf(ty_op.operand); |
| 5558 | const error_union_ty = if (is_ptr) operand_ty.childType() else operand_ty; | 5544 | const error_union_ty = if (is_ptr) operand_ty.childType(mod) else operand_ty; |
| 5559 | 5545 | ||
| 5560 | const writer = f.object.writer(); | 5546 | const writer = f.object.writer(); |
| 5561 | if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) { | 5547 | if (!error_union_ty.errorUnionPayload(mod).hasRuntimeBits(mod)) { |
| 5562 | if (!is_ptr) return .none; | 5548 | if (!is_ptr) return .none; |
| 5563 | 5549 | ||
| 5564 | const local = try f.allocLocal(inst, inst_ty); | 5550 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -5584,11 +5570,12 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu | ... | @@ -5584,11 +5570,12 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu |
| 5584 | } | 5570 | } |
| 5585 | 5571 | ||
| 5586 | fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { | 5572 | fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5573 | const mod = f.object.dg.module; | ||
| 5587 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5574 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5588 | 5575 | ||
| 5589 | const inst_ty = f.air.typeOfIndex(inst); | 5576 | const inst_ty = f.typeOfIndex(inst); |
| 5590 | const repr_is_payload = inst_ty.optionalReprIsPayload(); | 5577 | const repr_is_payload = inst_ty.optionalReprIsPayload(mod); |
| 5591 | const payload_ty = f.air.typeOf(ty_op.operand); | 5578 | const payload_ty = f.typeOf(ty_op.operand); |
| 5592 | const payload = try f.resolveInst(ty_op.operand); | 5579 | const payload = try f.resolveInst(ty_op.operand); |
| 5593 | try reap(f, inst, &.{ty_op.operand}); | 5580 | try reap(f, inst, &.{ty_op.operand}); |
| 5594 | 5581 | ||
| ... | @@ -5615,12 +5602,13 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5615,12 +5602,13 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5615 | } | 5602 | } |
| 5616 | 5603 | ||
| 5617 | fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { | 5604 | fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5605 | const mod = f.object.dg.module; | ||
| 5618 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5606 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5619 | 5607 | ||
| 5620 | const inst_ty = f.air.typeOfIndex(inst); | 5608 | const inst_ty = f.typeOfIndex(inst); |
| 5621 | const payload_ty = inst_ty.errorUnionPayload(); | 5609 | const payload_ty = inst_ty.errorUnionPayload(mod); |
| 5622 | const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(); | 5610 | const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(mod); |
| 5623 | const err_ty = inst_ty.errorUnionSet(); | 5611 | const err_ty = inst_ty.errorUnionSet(mod); |
| 5624 | const err = try f.resolveInst(ty_op.operand); | 5612 | const err = try f.resolveInst(ty_op.operand); |
| 5625 | try reap(f, inst, &.{ty_op.operand}); | 5613 | try reap(f, inst, &.{ty_op.operand}); |
| 5626 | 5614 | ||
| ... | @@ -5653,19 +5641,20 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5653,19 +5641,20 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5653 | } | 5641 | } |
| 5654 | 5642 | ||
| 5655 | fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { | 5643 | fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5644 | const mod = f.object.dg.module; | ||
| 5656 | const writer = f.object.writer(); | 5645 | const writer = f.object.writer(); |
| 5657 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5646 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5658 | const operand = try f.resolveInst(ty_op.operand); | 5647 | const operand = try f.resolveInst(ty_op.operand); |
| 5659 | const error_union_ty = f.air.typeOf(ty_op.operand).childType(); | 5648 | const error_union_ty = f.typeOf(ty_op.operand).childType(mod); |
| 5660 | 5649 | ||
| 5661 | const error_ty = error_union_ty.errorUnionSet(); | 5650 | const error_ty = error_union_ty.errorUnionSet(mod); |
| 5662 | const payload_ty = error_union_ty.errorUnionPayload(); | 5651 | const payload_ty = error_union_ty.errorUnionPayload(mod); |
| 5663 | 5652 | ||
| 5664 | // First, set the non-error value. | 5653 | // First, set the non-error value. |
| 5665 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 5654 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 5666 | try f.writeCValueDeref(writer, operand); | 5655 | try f.writeCValueDeref(writer, operand); |
| 5667 | try writer.writeAll(" = "); | 5656 | try writer.writeAll(" = "); |
| 5668 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); | 5657 | try f.object.dg.renderValue(writer, error_ty, try mod.intValue(error_ty, 0), .Other); |
| 5669 | try writer.writeAll(";\n "); | 5658 | try writer.writeAll(";\n "); |
| 5670 | 5659 | ||
| 5671 | return operand; | 5660 | return operand; |
| ... | @@ -5673,13 +5662,13 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5673,13 +5662,13 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5673 | try reap(f, inst, &.{ty_op.operand}); | 5662 | try reap(f, inst, &.{ty_op.operand}); |
| 5674 | try f.writeCValueDeref(writer, operand); | 5663 | try f.writeCValueDeref(writer, operand); |
| 5675 | try writer.writeAll(".error = "); | 5664 | try writer.writeAll(".error = "); |
| 5676 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); | 5665 | try f.object.dg.renderValue(writer, Type.err_int, try mod.intValue(Type.err_int, 0), .Other); |
| 5677 | try writer.writeAll(";\n"); | 5666 | try writer.writeAll(";\n"); |
| 5678 | 5667 | ||
| 5679 | // Then return the payload pointer (only if it is used) | 5668 | // Then return the payload pointer (only if it is used) |
| 5680 | if (f.liveness.isUnused(inst)) return .none; | 5669 | if (f.liveness.isUnused(inst)) return .none; |
| 5681 | 5670 | ||
| 5682 | const local = try f.allocLocal(inst, f.air.typeOfIndex(inst)); | 5671 | const local = try f.allocLocal(inst, f.typeOfIndex(inst)); |
| 5683 | try f.writeCValue(writer, local, .Other); | 5672 | try f.writeCValue(writer, local, .Other); |
| 5684 | try writer.writeAll(" = &("); | 5673 | try writer.writeAll(" = &("); |
| 5685 | try f.writeCValueDeref(writer, operand); | 5674 | try f.writeCValueDeref(writer, operand); |
| ... | @@ -5703,13 +5692,14 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5703,13 +5692,14 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5703 | } | 5692 | } |
| 5704 | 5693 | ||
| 5705 | fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { | 5694 | fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5695 | const mod = f.object.dg.module; | ||
| 5706 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5696 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5707 | 5697 | ||
| 5708 | const inst_ty = f.air.typeOfIndex(inst); | 5698 | const inst_ty = f.typeOfIndex(inst); |
| 5709 | const payload_ty = inst_ty.errorUnionPayload(); | 5699 | const payload_ty = inst_ty.errorUnionPayload(mod); |
| 5710 | const payload = try f.resolveInst(ty_op.operand); | 5700 | const payload = try f.resolveInst(ty_op.operand); |
| 5711 | const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(); | 5701 | const repr_is_err = !payload_ty.hasRuntimeBitsIgnoreComptime(mod); |
| 5712 | const err_ty = inst_ty.errorUnionSet(); | 5702 | const err_ty = inst_ty.errorUnionSet(mod); |
| 5713 | try reap(f, inst, &.{ty_op.operand}); | 5703 | try reap(f, inst, &.{ty_op.operand}); |
| 5714 | 5704 | ||
| 5715 | const writer = f.object.writer(); | 5705 | const writer = f.object.writer(); |
| ... | @@ -5728,29 +5718,30 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5728,29 +5718,30 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5728 | else | 5718 | else |
| 5729 | try f.writeCValueMember(writer, local, .{ .identifier = "error" }); | 5719 | try f.writeCValueMember(writer, local, .{ .identifier = "error" }); |
| 5730 | try a.assign(f, writer); | 5720 | try a.assign(f, writer); |
| 5731 | try f.object.dg.renderValue(writer, err_ty, Value.zero, .Other); | 5721 | try f.object.dg.renderValue(writer, Type.err_int, try mod.intValue(Type.err_int, 0), .Other); |
| 5732 | try a.end(f, writer); | 5722 | try a.end(f, writer); |
| 5733 | } | 5723 | } |
| 5734 | return local; | 5724 | return local; |
| 5735 | } | 5725 | } |
| 5736 | 5726 | ||
| 5737 | fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue { | 5727 | fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue { |
| 5728 | const mod = f.object.dg.module; | ||
| 5738 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 5729 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 5739 | 5730 | ||
| 5740 | const writer = f.object.writer(); | 5731 | const writer = f.object.writer(); |
| 5741 | const operand = try f.resolveInst(un_op); | 5732 | const operand = try f.resolveInst(un_op); |
| 5742 | try reap(f, inst, &.{un_op}); | 5733 | try reap(f, inst, &.{un_op}); |
| 5743 | const operand_ty = f.air.typeOf(un_op); | 5734 | const operand_ty = f.typeOf(un_op); |
| 5744 | const local = try f.allocLocal(inst, Type.bool); | 5735 | const local = try f.allocLocal(inst, Type.bool); |
| 5745 | const err_union_ty = if (is_ptr) operand_ty.childType() else operand_ty; | 5736 | const err_union_ty = if (is_ptr) operand_ty.childType(mod) else operand_ty; |
| 5746 | const payload_ty = err_union_ty.errorUnionPayload(); | 5737 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 5747 | const error_ty = err_union_ty.errorUnionSet(); | 5738 | const error_ty = err_union_ty.errorUnionSet(mod); |
| 5748 | 5739 | ||
| 5749 | try f.writeCValue(writer, local, .Other); | 5740 | try f.writeCValue(writer, local, .Other); |
| 5750 | try writer.writeAll(" = "); | 5741 | try writer.writeAll(" = "); |
| 5751 | 5742 | ||
| 5752 | if (!error_ty.errorSetIsEmpty()) | 5743 | if (!error_ty.errorSetIsEmpty(mod)) |
| 5753 | if (payload_ty.hasRuntimeBits()) | 5744 | if (payload_ty.hasRuntimeBits(mod)) |
| 5754 | if (is_ptr) | 5745 | if (is_ptr) |
| 5755 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) | 5746 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) |
| 5756 | else | 5747 | else |
| ... | @@ -5758,42 +5749,40 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const | ... | @@ -5758,42 +5749,40 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const |
| 5758 | else | 5749 | else |
| 5759 | try f.writeCValue(writer, operand, .Other) | 5750 | try f.writeCValue(writer, operand, .Other) |
| 5760 | else | 5751 | else |
| 5761 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); | 5752 | try f.object.dg.renderValue(writer, Type.err_int, try mod.intValue(Type.err_int, 0), .Other); |
| 5762 | try writer.writeByte(' '); | 5753 | try writer.writeByte(' '); |
| 5763 | try writer.writeAll(operator); | 5754 | try writer.writeAll(operator); |
| 5764 | try writer.writeByte(' '); | 5755 | try writer.writeByte(' '); |
| 5765 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); | 5756 | try f.object.dg.renderValue(writer, Type.err_int, try mod.intValue(Type.err_int, 0), .Other); |
| 5766 | try writer.writeAll(";\n"); | 5757 | try writer.writeAll(";\n"); |
| 5767 | return local; | 5758 | return local; |
| 5768 | } | 5759 | } |
| 5769 | 5760 | ||
| 5770 | fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { | 5761 | fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5762 | const mod = f.object.dg.module; | ||
| 5771 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5763 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5772 | 5764 | ||
| 5773 | const operand = try f.resolveInst(ty_op.operand); | 5765 | const operand = try f.resolveInst(ty_op.operand); |
| 5774 | try reap(f, inst, &.{ty_op.operand}); | 5766 | try reap(f, inst, &.{ty_op.operand}); |
| 5775 | const inst_ty = f.air.typeOfIndex(inst); | 5767 | const inst_ty = f.typeOfIndex(inst); |
| 5776 | const writer = f.object.writer(); | 5768 | const writer = f.object.writer(); |
| 5777 | const local = try f.allocLocal(inst, inst_ty); | 5769 | const local = try f.allocLocal(inst, inst_ty); |
| 5778 | const array_ty = f.air.typeOf(ty_op.operand).childType(); | 5770 | const array_ty = f.typeOf(ty_op.operand).childType(mod); |
| 5779 | 5771 | ||
| 5780 | try f.writeCValueMember(writer, local, .{ .identifier = "ptr" }); | 5772 | try f.writeCValueMember(writer, local, .{ .identifier = "ptr" }); |
| 5781 | try writer.writeAll(" = "); | 5773 | try writer.writeAll(" = "); |
| 5782 | // Unfortunately, C does not support any equivalent to | 5774 | // Unfortunately, C does not support any equivalent to |
| 5783 | // &(*(void *)p)[0], although LLVM does via GetElementPtr | 5775 | // &(*(void *)p)[0], although LLVM does via GetElementPtr |
| 5784 | if (operand == .undef) { | 5776 | if (operand == .undef) { |
| 5785 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 5777 | try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(mod) }, .Initializer); |
| 5786 | try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(&buf) }, .Initializer); | 5778 | } else if (array_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 5787 | } else if (array_ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 5788 | try writer.writeAll("&("); | 5779 | try writer.writeAll("&("); |
| 5789 | try f.writeCValueDeref(writer, operand); | 5780 | try f.writeCValueDeref(writer, operand); |
| 5790 | try writer.print(")[{}]", .{try f.fmtIntLiteral(Type.usize, Value.zero)}); | 5781 | try writer.print(")[{}]", .{try f.fmtIntLiteral(Type.usize, try mod.intValue(Type.usize, 0))}); |
| 5791 | } else try f.writeCValue(writer, operand, .Initializer); | 5782 | } else try f.writeCValue(writer, operand, .Initializer); |
| 5792 | try writer.writeAll("; "); | 5783 | try writer.writeAll("; "); |
| 5793 | 5784 | ||
| 5794 | const array_len = array_ty.arrayLen(); | 5785 | const len_val = try mod.intValue(Type.usize, array_ty.arrayLen(mod)); |
| 5795 | var len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = array_len }; | ||
| 5796 | const len_val = Value.initPayload(&len_pl.base); | ||
| 5797 | try f.writeCValueMember(writer, local, .{ .identifier = "len" }); | 5786 | try f.writeCValueMember(writer, local, .{ .identifier = "len" }); |
| 5798 | try writer.print(" = {};\n", .{try f.fmtIntLiteral(Type.usize, len_val)}); | 5787 | try writer.print(" = {};\n", .{try f.fmtIntLiteral(Type.usize, len_val)}); |
| 5799 | 5788 | ||
| ... | @@ -5801,19 +5790,20 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5801,19 +5790,20 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5801 | } | 5790 | } |
| 5802 | 5791 | ||
| 5803 | fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { | 5792 | fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5793 | const mod = f.object.dg.module; | ||
| 5804 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5794 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5805 | 5795 | ||
| 5806 | const inst_ty = f.air.typeOfIndex(inst); | 5796 | const inst_ty = f.typeOfIndex(inst); |
| 5807 | const operand = try f.resolveInst(ty_op.operand); | 5797 | const operand = try f.resolveInst(ty_op.operand); |
| 5808 | try reap(f, inst, &.{ty_op.operand}); | 5798 | try reap(f, inst, &.{ty_op.operand}); |
| 5809 | const operand_ty = f.air.typeOf(ty_op.operand); | 5799 | const operand_ty = f.typeOf(ty_op.operand); |
| 5810 | const target = f.object.dg.module.getTarget(); | 5800 | const target = f.object.dg.module.getTarget(); |
| 5811 | const operation = if (inst_ty.isRuntimeFloat() and operand_ty.isRuntimeFloat()) | 5801 | const operation = if (inst_ty.isRuntimeFloat() and operand_ty.isRuntimeFloat()) |
| 5812 | if (inst_ty.floatBits(target) < operand_ty.floatBits(target)) "trunc" else "extend" | 5802 | if (inst_ty.floatBits(target) < operand_ty.floatBits(target)) "trunc" else "extend" |
| 5813 | else if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) | 5803 | else if (inst_ty.isInt(mod) and operand_ty.isRuntimeFloat()) |
| 5814 | if (inst_ty.isSignedInt()) "fix" else "fixuns" | 5804 | if (inst_ty.isSignedInt(mod)) "fix" else "fixuns" |
| 5815 | else if (inst_ty.isRuntimeFloat() and operand_ty.isInt()) | 5805 | else if (inst_ty.isRuntimeFloat() and operand_ty.isInt(mod)) |
| 5816 | if (operand_ty.isSignedInt()) "float" else "floatun" | 5806 | if (operand_ty.isSignedInt(mod)) "float" else "floatun" |
| 5817 | else | 5807 | else |
| 5818 | unreachable; | 5808 | unreachable; |
| 5819 | 5809 | ||
| ... | @@ -5822,19 +5812,19 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5822,19 +5812,19 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5822 | try f.writeCValue(writer, local, .Other); | 5812 | try f.writeCValue(writer, local, .Other); |
| 5823 | 5813 | ||
| 5824 | try writer.writeAll(" = "); | 5814 | try writer.writeAll(" = "); |
| 5825 | if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) { | 5815 | if (inst_ty.isInt(mod) and operand_ty.isRuntimeFloat()) { |
| 5826 | try writer.writeAll("zig_wrap_"); | 5816 | try writer.writeAll("zig_wrap_"); |
| 5827 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); | 5817 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); |
| 5828 | try writer.writeByte('('); | 5818 | try writer.writeByte('('); |
| 5829 | } | 5819 | } |
| 5830 | try writer.writeAll("zig_"); | 5820 | try writer.writeAll("zig_"); |
| 5831 | try writer.writeAll(operation); | 5821 | try writer.writeAll(operation); |
| 5832 | try writer.writeAll(compilerRtAbbrev(operand_ty, target)); | 5822 | try writer.writeAll(compilerRtAbbrev(operand_ty, mod)); |
| 5833 | try writer.writeAll(compilerRtAbbrev(inst_ty, target)); | 5823 | try writer.writeAll(compilerRtAbbrev(inst_ty, mod)); |
| 5834 | try writer.writeByte('('); | 5824 | try writer.writeByte('('); |
| 5835 | try f.writeCValue(writer, operand, .FunctionArgument); | 5825 | try f.writeCValue(writer, operand, .FunctionArgument); |
| 5836 | try writer.writeByte(')'); | 5826 | try writer.writeByte(')'); |
| 5837 | if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) { | 5827 | if (inst_ty.isInt(mod) and operand_ty.isRuntimeFloat()) { |
| 5838 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); | 5828 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); |
| 5839 | try writer.writeByte(')'); | 5829 | try writer.writeByte(')'); |
| 5840 | } | 5830 | } |
| ... | @@ -5843,12 +5833,13 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5843,12 +5833,13 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5843 | } | 5833 | } |
| 5844 | 5834 | ||
| 5845 | fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { | 5835 | fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5836 | const mod = f.object.dg.module; | ||
| 5846 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 5837 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 5847 | 5838 | ||
| 5848 | const operand = try f.resolveInst(un_op); | 5839 | const operand = try f.resolveInst(un_op); |
| 5849 | const operand_ty = f.air.typeOf(un_op); | 5840 | const operand_ty = f.typeOf(un_op); |
| 5850 | try reap(f, inst, &.{un_op}); | 5841 | try reap(f, inst, &.{un_op}); |
| 5851 | const inst_ty = f.air.typeOfIndex(inst); | 5842 | const inst_ty = f.typeOfIndex(inst); |
| 5852 | const writer = f.object.writer(); | 5843 | const writer = f.object.writer(); |
| 5853 | const local = try f.allocLocal(inst, inst_ty); | 5844 | const local = try f.allocLocal(inst, inst_ty); |
| 5854 | try f.writeCValue(writer, local, .Other); | 5845 | try f.writeCValue(writer, local, .Other); |
| ... | @@ -5856,7 +5847,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -5856,7 +5847,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 5856 | try writer.writeAll(" = ("); | 5847 | try writer.writeAll(" = ("); |
| 5857 | try f.renderType(writer, inst_ty); | 5848 | try f.renderType(writer, inst_ty); |
| 5858 | try writer.writeByte(')'); | 5849 | try writer.writeByte(')'); |
| 5859 | if (operand_ty.isSlice()) { | 5850 | if (operand_ty.isSlice(mod)) { |
| 5860 | try f.writeCValueMember(writer, operand, .{ .identifier = "len" }); | 5851 | try f.writeCValueMember(writer, operand, .{ .identifier = "len" }); |
| 5861 | } else { | 5852 | } else { |
| 5862 | try f.writeCValue(writer, operand, .Other); | 5853 | try f.writeCValue(writer, operand, .Other); |
| ... | @@ -5871,14 +5862,15 @@ fn airUnBuiltinCall( | ... | @@ -5871,14 +5862,15 @@ fn airUnBuiltinCall( |
| 5871 | operation: []const u8, | 5862 | operation: []const u8, |
| 5872 | info: BuiltinInfo, | 5863 | info: BuiltinInfo, |
| 5873 | ) !CValue { | 5864 | ) !CValue { |
| 5865 | const mod = f.object.dg.module; | ||
| 5874 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 5866 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 5875 | 5867 | ||
| 5876 | const operand = try f.resolveInst(ty_op.operand); | 5868 | const operand = try f.resolveInst(ty_op.operand); |
| 5877 | try reap(f, inst, &.{ty_op.operand}); | 5869 | try reap(f, inst, &.{ty_op.operand}); |
| 5878 | const inst_ty = f.air.typeOfIndex(inst); | 5870 | const inst_ty = f.typeOfIndex(inst); |
| 5879 | const inst_scalar_ty = inst_ty.scalarType(); | 5871 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 5880 | const operand_ty = f.air.typeOf(ty_op.operand); | 5872 | const operand_ty = f.typeOf(ty_op.operand); |
| 5881 | const scalar_ty = operand_ty.scalarType(); | 5873 | const scalar_ty = operand_ty.scalarType(mod); |
| 5882 | 5874 | ||
| 5883 | const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete); | 5875 | const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete); |
| 5884 | const ref_ret = inst_scalar_cty.tag() == .array; | 5876 | const ref_ret = inst_scalar_cty.tag() == .array; |
| ... | @@ -5914,9 +5906,10 @@ fn airBinBuiltinCall( | ... | @@ -5914,9 +5906,10 @@ fn airBinBuiltinCall( |
| 5914 | operation: []const u8, | 5906 | operation: []const u8, |
| 5915 | info: BuiltinInfo, | 5907 | info: BuiltinInfo, |
| 5916 | ) !CValue { | 5908 | ) !CValue { |
| 5909 | const mod = f.object.dg.module; | ||
| 5917 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 5910 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 5918 | 5911 | ||
| 5919 | const operand_ty = f.air.typeOf(bin_op.lhs); | 5912 | const operand_ty = f.typeOf(bin_op.lhs); |
| 5920 | const operand_cty = try f.typeToCType(operand_ty, .complete); | 5913 | const operand_cty = try f.typeToCType(operand_ty, .complete); |
| 5921 | const is_big = operand_cty.tag() == .array; | 5914 | const is_big = operand_cty.tag() == .array; |
| 5922 | 5915 | ||
| ... | @@ -5924,9 +5917,9 @@ fn airBinBuiltinCall( | ... | @@ -5924,9 +5917,9 @@ fn airBinBuiltinCall( |
| 5924 | const rhs = try f.resolveInst(bin_op.rhs); | 5917 | const rhs = try f.resolveInst(bin_op.rhs); |
| 5925 | if (!is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 5918 | if (!is_big) try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 5926 | 5919 | ||
| 5927 | const inst_ty = f.air.typeOfIndex(inst); | 5920 | const inst_ty = f.typeOfIndex(inst); |
| 5928 | const inst_scalar_ty = inst_ty.scalarType(); | 5921 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 5929 | const scalar_ty = operand_ty.scalarType(); | 5922 | const scalar_ty = operand_ty.scalarType(mod); |
| 5930 | 5923 | ||
| 5931 | const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete); | 5924 | const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete); |
| 5932 | const ref_ret = inst_scalar_cty.tag() == .array; | 5925 | const ref_ret = inst_scalar_cty.tag() == .array; |
| ... | @@ -5968,14 +5961,15 @@ fn airCmpBuiltinCall( | ... | @@ -5968,14 +5961,15 @@ fn airCmpBuiltinCall( |
| 5968 | operation: enum { cmp, operator }, | 5961 | operation: enum { cmp, operator }, |
| 5969 | info: BuiltinInfo, | 5962 | info: BuiltinInfo, |
| 5970 | ) !CValue { | 5963 | ) !CValue { |
| 5964 | const mod = f.object.dg.module; | ||
| 5971 | const lhs = try f.resolveInst(data.lhs); | 5965 | const lhs = try f.resolveInst(data.lhs); |
| 5972 | const rhs = try f.resolveInst(data.rhs); | 5966 | const rhs = try f.resolveInst(data.rhs); |
| 5973 | try reap(f, inst, &.{ data.lhs, data.rhs }); | 5967 | try reap(f, inst, &.{ data.lhs, data.rhs }); |
| 5974 | 5968 | ||
| 5975 | const inst_ty = f.air.typeOfIndex(inst); | 5969 | const inst_ty = f.typeOfIndex(inst); |
| 5976 | const inst_scalar_ty = inst_ty.scalarType(); | 5970 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 5977 | const operand_ty = f.air.typeOf(data.lhs); | 5971 | const operand_ty = f.typeOf(data.lhs); |
| 5978 | const scalar_ty = operand_ty.scalarType(); | 5972 | const scalar_ty = operand_ty.scalarType(mod); |
| 5979 | 5973 | ||
| 5980 | const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete); | 5974 | const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete); |
| 5981 | const ref_ret = inst_scalar_cty.tag() == .array; | 5975 | const ref_ret = inst_scalar_cty.tag() == .array; |
| ... | @@ -6008,7 +6002,7 @@ fn airCmpBuiltinCall( | ... | @@ -6008,7 +6002,7 @@ fn airCmpBuiltinCall( |
| 6008 | try writer.writeByte(')'); | 6002 | try writer.writeByte(')'); |
| 6009 | if (!ref_ret) try writer.print(" {s} {}", .{ | 6003 | if (!ref_ret) try writer.print(" {s} {}", .{ |
| 6010 | compareOperatorC(operator), | 6004 | compareOperatorC(operator), |
| 6011 | try f.fmtIntLiteral(Type.initTag(.i32), Value.zero), | 6005 | try f.fmtIntLiteral(Type.i32, try mod.intValue(Type.i32, 0)), |
| 6012 | }); | 6006 | }); |
| 6013 | try writer.writeAll(";\n"); | 6007 | try writer.writeAll(";\n"); |
| 6014 | try v.end(f, inst, writer); | 6008 | try v.end(f, inst, writer); |
| ... | @@ -6017,28 +6011,27 @@ fn airCmpBuiltinCall( | ... | @@ -6017,28 +6011,27 @@ fn airCmpBuiltinCall( |
| 6017 | } | 6011 | } |
| 6018 | 6012 | ||
| 6019 | fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { | 6013 | fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { |
| 6014 | const mod = f.object.dg.module; | ||
| 6020 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 6015 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 6021 | const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data; | 6016 | const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 6022 | const inst_ty = f.air.typeOfIndex(inst); | 6017 | const inst_ty = f.typeOfIndex(inst); |
| 6023 | const ptr = try f.resolveInst(extra.ptr); | 6018 | const ptr = try f.resolveInst(extra.ptr); |
| 6024 | const expected_value = try f.resolveInst(extra.expected_value); | 6019 | const expected_value = try f.resolveInst(extra.expected_value); |
| 6025 | const new_value = try f.resolveInst(extra.new_value); | 6020 | const new_value = try f.resolveInst(extra.new_value); |
| 6026 | const ptr_ty = f.air.typeOf(extra.ptr); | 6021 | const ptr_ty = f.typeOf(extra.ptr); |
| 6027 | const ty = ptr_ty.childType(); | 6022 | const ty = ptr_ty.childType(mod); |
| 6028 | 6023 | ||
| 6029 | const writer = f.object.writer(); | 6024 | const writer = f.object.writer(); |
| 6030 | const new_value_mat = try Materialize.start(f, inst, writer, ty, new_value); | 6025 | const new_value_mat = try Materialize.start(f, inst, writer, ty, new_value); |
| 6031 | try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value }); | 6026 | try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value }); |
| 6032 | 6027 | ||
| 6033 | const target = f.object.dg.module.getTarget(); | 6028 | const repr_ty = if (ty.isRuntimeFloat()) |
| 6034 | var repr_pl = Type.Payload.Bits{ | 6029 | mod.intType(.unsigned, @intCast(u16, ty.abiSize(mod) * 8)) catch unreachable |
| 6035 | .base = .{ .tag = .int_unsigned }, | 6030 | else |
| 6036 | .data = @intCast(u16, ty.abiSize(target) * 8), | 6031 | ty; |
| 6037 | }; | ||
| 6038 | const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty; | ||
| 6039 | 6032 | ||
| 6040 | const local = try f.allocLocal(inst, inst_ty); | 6033 | const local = try f.allocLocal(inst, inst_ty); |
| 6041 | if (inst_ty.isPtrLikeOptional()) { | 6034 | if (inst_ty.isPtrLikeOptional(mod)) { |
| 6042 | { | 6035 | { |
| 6043 | const a = try Assignment.start(f, writer, ty); | 6036 | const a = try Assignment.start(f, writer, ty); |
| 6044 | try f.writeCValue(writer, local, .Other); | 6037 | try f.writeCValue(writer, local, .Other); |
| ... | @@ -6051,7 +6044,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -6051,7 +6044,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 6051 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); | 6044 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 6052 | try f.renderType(writer, ty); | 6045 | try f.renderType(writer, ty); |
| 6053 | try writer.writeByte(')'); | 6046 | try writer.writeByte(')'); |
| 6054 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6047 | if (ptr_ty.isVolatilePtr(mod)) try writer.writeAll(" volatile"); |
| 6055 | try writer.writeAll(" *)"); | 6048 | try writer.writeAll(" *)"); |
| 6056 | try f.writeCValue(writer, ptr, .Other); | 6049 | try f.writeCValue(writer, ptr, .Other); |
| 6057 | try writer.writeAll(", "); | 6050 | try writer.writeAll(", "); |
| ... | @@ -6093,7 +6086,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -6093,7 +6086,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 6093 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); | 6086 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 6094 | try f.renderType(writer, ty); | 6087 | try f.renderType(writer, ty); |
| 6095 | try writer.writeByte(')'); | 6088 | try writer.writeByte(')'); |
| 6096 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6089 | if (ptr_ty.isVolatilePtr(mod)) try writer.writeAll(" volatile"); |
| 6097 | try writer.writeAll(" *)"); | 6090 | try writer.writeAll(" *)"); |
| 6098 | try f.writeCValue(writer, ptr, .Other); | 6091 | try f.writeCValue(writer, ptr, .Other); |
| 6099 | try writer.writeAll(", "); | 6092 | try writer.writeAll(", "); |
| ... | @@ -6123,11 +6116,12 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -6123,11 +6116,12 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 6123 | } | 6116 | } |
| 6124 | 6117 | ||
| 6125 | fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { | 6118 | fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6119 | const mod = f.object.dg.module; | ||
| 6126 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 6120 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 6127 | const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data; | 6121 | const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 6128 | const inst_ty = f.air.typeOfIndex(inst); | 6122 | const inst_ty = f.typeOfIndex(inst); |
| 6129 | const ptr_ty = f.air.typeOf(pl_op.operand); | 6123 | const ptr_ty = f.typeOf(pl_op.operand); |
| 6130 | const ty = ptr_ty.childType(); | 6124 | const ty = ptr_ty.childType(mod); |
| 6131 | const ptr = try f.resolveInst(pl_op.operand); | 6125 | const ptr = try f.resolveInst(pl_op.operand); |
| 6132 | const operand = try f.resolveInst(extra.operand); | 6126 | const operand = try f.resolveInst(extra.operand); |
| 6133 | 6127 | ||
| ... | @@ -6135,14 +6129,10 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6135,14 +6129,10 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6135 | const operand_mat = try Materialize.start(f, inst, writer, ty, operand); | 6129 | const operand_mat = try Materialize.start(f, inst, writer, ty, operand); |
| 6136 | try reap(f, inst, &.{ pl_op.operand, extra.operand }); | 6130 | try reap(f, inst, &.{ pl_op.operand, extra.operand }); |
| 6137 | 6131 | ||
| 6138 | const target = f.object.dg.module.getTarget(); | 6132 | const repr_bits = @intCast(u16, ty.abiSize(mod) * 8); |
| 6139 | var repr_pl = Type.Payload.Bits{ | ||
| 6140 | .base = .{ .tag = .int_unsigned }, | ||
| 6141 | .data = @intCast(u16, ty.abiSize(target) * 8), | ||
| 6142 | }; | ||
| 6143 | const is_float = ty.isRuntimeFloat(); | 6133 | const is_float = ty.isRuntimeFloat(); |
| 6144 | const is_128 = repr_pl.data == 128; | 6134 | const is_128 = repr_bits == 128; |
| 6145 | const repr_ty = if (is_float) Type.initPayload(&repr_pl.base) else ty; | 6135 | const repr_ty = if (is_float) mod.intType(.unsigned, repr_bits) catch unreachable else ty; |
| 6146 | 6136 | ||
| 6147 | const local = try f.allocLocal(inst, inst_ty); | 6137 | const local = try f.allocLocal(inst, inst_ty); |
| 6148 | try writer.print("zig_atomicrmw_{s}", .{toAtomicRmwSuffix(extra.op())}); | 6138 | try writer.print("zig_atomicrmw_{s}", .{toAtomicRmwSuffix(extra.op())}); |
| ... | @@ -6158,7 +6148,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6158,7 +6148,7 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6158 | if (use_atomic) try writer.writeAll("zig_atomic("); | 6148 | if (use_atomic) try writer.writeAll("zig_atomic("); |
| 6159 | try f.renderType(writer, ty); | 6149 | try f.renderType(writer, ty); |
| 6160 | if (use_atomic) try writer.writeByte(')'); | 6150 | if (use_atomic) try writer.writeByte(')'); |
| 6161 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6151 | if (ptr_ty.isVolatilePtr(mod)) try writer.writeAll(" volatile"); |
| 6162 | try writer.writeAll(" *)"); | 6152 | try writer.writeAll(" *)"); |
| 6163 | try f.writeCValue(writer, ptr, .Other); | 6153 | try f.writeCValue(writer, ptr, .Other); |
| 6164 | try writer.writeAll(", "); | 6154 | try writer.writeAll(", "); |
| ... | @@ -6181,20 +6171,19 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6181,20 +6171,19 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6181 | } | 6171 | } |
| 6182 | 6172 | ||
| 6183 | fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { | 6173 | fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6174 | const mod = f.object.dg.module; | ||
| 6184 | const atomic_load = f.air.instructions.items(.data)[inst].atomic_load; | 6175 | const atomic_load = f.air.instructions.items(.data)[inst].atomic_load; |
| 6185 | const ptr = try f.resolveInst(atomic_load.ptr); | 6176 | const ptr = try f.resolveInst(atomic_load.ptr); |
| 6186 | try reap(f, inst, &.{atomic_load.ptr}); | 6177 | try reap(f, inst, &.{atomic_load.ptr}); |
| 6187 | const ptr_ty = f.air.typeOf(atomic_load.ptr); | 6178 | const ptr_ty = f.typeOf(atomic_load.ptr); |
| 6188 | const ty = ptr_ty.childType(); | 6179 | const ty = ptr_ty.childType(mod); |
| 6189 | 6180 | ||
| 6190 | const target = f.object.dg.module.getTarget(); | 6181 | const repr_ty = if (ty.isRuntimeFloat()) |
| 6191 | var repr_pl = Type.Payload.Bits{ | 6182 | mod.intType(.unsigned, @intCast(u16, ty.abiSize(mod) * 8)) catch unreachable |
| 6192 | .base = .{ .tag = .int_unsigned }, | 6183 | else |
| 6193 | .data = @intCast(u16, ty.abiSize(target) * 8), | 6184 | ty; |
| 6194 | }; | ||
| 6195 | const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty; | ||
| 6196 | 6185 | ||
| 6197 | const inst_ty = f.air.typeOfIndex(inst); | 6186 | const inst_ty = f.typeOfIndex(inst); |
| 6198 | const writer = f.object.writer(); | 6187 | const writer = f.object.writer(); |
| 6199 | const local = try f.allocLocal(inst, inst_ty); | 6188 | const local = try f.allocLocal(inst, inst_ty); |
| 6200 | 6189 | ||
| ... | @@ -6203,7 +6192,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6203,7 +6192,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6203 | try writer.writeAll(", (zig_atomic("); | 6192 | try writer.writeAll(", (zig_atomic("); |
| 6204 | try f.renderType(writer, ty); | 6193 | try f.renderType(writer, ty); |
| 6205 | try writer.writeByte(')'); | 6194 | try writer.writeByte(')'); |
| 6206 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6195 | if (ptr_ty.isVolatilePtr(mod)) try writer.writeAll(" volatile"); |
| 6207 | try writer.writeAll(" *)"); | 6196 | try writer.writeAll(" *)"); |
| 6208 | try f.writeCValue(writer, ptr, .Other); | 6197 | try f.writeCValue(writer, ptr, .Other); |
| 6209 | try writer.writeAll(", "); | 6198 | try writer.writeAll(", "); |
| ... | @@ -6218,9 +6207,10 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6218,9 +6207,10 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6218 | } | 6207 | } |
| 6219 | 6208 | ||
| 6220 | fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue { | 6209 | fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue { |
| 6210 | const mod = f.object.dg.module; | ||
| 6221 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 6211 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 6222 | const ptr_ty = f.air.typeOf(bin_op.lhs); | 6212 | const ptr_ty = f.typeOf(bin_op.lhs); |
| 6223 | const ty = ptr_ty.childType(); | 6213 | const ty = ptr_ty.childType(mod); |
| 6224 | const ptr = try f.resolveInst(bin_op.lhs); | 6214 | const ptr = try f.resolveInst(bin_op.lhs); |
| 6225 | const element = try f.resolveInst(bin_op.rhs); | 6215 | const element = try f.resolveInst(bin_op.rhs); |
| 6226 | 6216 | ||
| ... | @@ -6228,17 +6218,15 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa | ... | @@ -6228,17 +6218,15 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa |
| 6228 | const element_mat = try Materialize.start(f, inst, writer, ty, element); | 6218 | const element_mat = try Materialize.start(f, inst, writer, ty, element); |
| 6229 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 6219 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 6230 | 6220 | ||
| 6231 | const target = f.object.dg.module.getTarget(); | 6221 | const repr_ty = if (ty.isRuntimeFloat()) |
| 6232 | var repr_pl = Type.Payload.Bits{ | 6222 | mod.intType(.unsigned, @intCast(u16, ty.abiSize(mod) * 8)) catch unreachable |
| 6233 | .base = .{ .tag = .int_unsigned }, | 6223 | else |
| 6234 | .data = @intCast(u16, ty.abiSize(target) * 8), | 6224 | ty; |
| 6235 | }; | ||
| 6236 | const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty; | ||
| 6237 | 6225 | ||
| 6238 | try writer.writeAll("zig_atomic_store((zig_atomic("); | 6226 | try writer.writeAll("zig_atomic_store((zig_atomic("); |
| 6239 | try f.renderType(writer, ty); | 6227 | try f.renderType(writer, ty); |
| 6240 | try writer.writeByte(')'); | 6228 | try writer.writeByte(')'); |
| 6241 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6229 | if (ptr_ty.isVolatilePtr(mod)) try writer.writeAll(" volatile"); |
| 6242 | try writer.writeAll(" *)"); | 6230 | try writer.writeAll(" *)"); |
| 6243 | try f.writeCValue(writer, ptr, .Other); | 6231 | try f.writeCValue(writer, ptr, .Other); |
| 6244 | try writer.writeAll(", "); | 6232 | try writer.writeAll(", "); |
| ... | @@ -6254,7 +6242,8 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa | ... | @@ -6254,7 +6242,8 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa |
| 6254 | } | 6242 | } |
| 6255 | 6243 | ||
| 6256 | fn writeSliceOrPtr(f: *Function, writer: anytype, ptr: CValue, ptr_ty: Type) !void { | 6244 | fn writeSliceOrPtr(f: *Function, writer: anytype, ptr: CValue, ptr_ty: Type) !void { |
| 6257 | if (ptr_ty.isSlice()) { | 6245 | const mod = f.object.dg.module; |
| 6246 | if (ptr_ty.isSlice(mod)) { | ||
| 6258 | try f.writeCValueMember(writer, ptr, .{ .identifier = "ptr" }); | 6247 | try f.writeCValueMember(writer, ptr, .{ .identifier = "ptr" }); |
| 6259 | } else { | 6248 | } else { |
| 6260 | try f.writeCValue(writer, ptr, .FunctionArgument); | 6249 | try f.writeCValue(writer, ptr, .FunctionArgument); |
| ... | @@ -6262,14 +6251,14 @@ fn writeSliceOrPtr(f: *Function, writer: anytype, ptr: CValue, ptr_ty: Type) !vo | ... | @@ -6262,14 +6251,14 @@ fn writeSliceOrPtr(f: *Function, writer: anytype, ptr: CValue, ptr_ty: Type) !vo |
| 6262 | } | 6251 | } |
| 6263 | 6252 | ||
| 6264 | fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | 6253 | fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6254 | const mod = f.object.dg.module; | ||
| 6265 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 6255 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 6266 | const dest_ty = f.air.typeOf(bin_op.lhs); | 6256 | const dest_ty = f.typeOf(bin_op.lhs); |
| 6267 | const dest_slice = try f.resolveInst(bin_op.lhs); | 6257 | const dest_slice = try f.resolveInst(bin_op.lhs); |
| 6268 | const value = try f.resolveInst(bin_op.rhs); | 6258 | const value = try f.resolveInst(bin_op.rhs); |
| 6269 | const elem_ty = f.air.typeOf(bin_op.rhs); | 6259 | const elem_ty = f.typeOf(bin_op.rhs); |
| 6270 | const target = f.object.dg.module.getTarget(); | 6260 | const elem_abi_size = elem_ty.abiSize(mod); |
| 6271 | const elem_abi_size = elem_ty.abiSize(target); | 6261 | const val_is_undef = if (try f.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep(mod) else false; |
| 6272 | const val_is_undef = if (f.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false; | ||
| 6273 | const writer = f.object.writer(); | 6262 | const writer = f.object.writer(); |
| 6274 | 6263 | ||
| 6275 | if (val_is_undef) { | 6264 | if (val_is_undef) { |
| ... | @@ -6279,7 +6268,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -6279,7 +6268,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6279 | } | 6268 | } |
| 6280 | 6269 | ||
| 6281 | try writer.writeAll("memset("); | 6270 | try writer.writeAll("memset("); |
| 6282 | switch (dest_ty.ptrSize()) { | 6271 | switch (dest_ty.ptrSize(mod)) { |
| 6283 | .Slice => { | 6272 | .Slice => { |
| 6284 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }); | 6273 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }); |
| 6285 | try writer.writeAll(", 0xaa, "); | 6274 | try writer.writeAll(", 0xaa, "); |
| ... | @@ -6291,8 +6280,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -6291,8 +6280,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6291 | } | 6280 | } |
| 6292 | }, | 6281 | }, |
| 6293 | .One => { | 6282 | .One => { |
| 6294 | const array_ty = dest_ty.childType(); | 6283 | const array_ty = dest_ty.childType(mod); |
| 6295 | const len = array_ty.arrayLen() * elem_abi_size; | 6284 | const len = array_ty.arrayLen(mod) * elem_abi_size; |
| 6296 | 6285 | ||
| 6297 | try f.writeCValue(writer, dest_slice, .FunctionArgument); | 6286 | try f.writeCValue(writer, dest_slice, .FunctionArgument); |
| 6298 | try writer.print(", 0xaa, {d});\n", .{len}); | 6287 | try writer.print(", 0xaa, {d});\n", .{len}); |
| ... | @@ -6303,32 +6292,33 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -6303,32 +6292,33 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6303 | return .none; | 6292 | return .none; |
| 6304 | } | 6293 | } |
| 6305 | 6294 | ||
| 6306 | if (elem_abi_size > 1 or dest_ty.isVolatilePtr()) { | 6295 | if (elem_abi_size > 1 or dest_ty.isVolatilePtr(mod)) { |
| 6307 | // For the assignment in this loop, the array pointer needs to get | 6296 | // For the assignment in this loop, the array pointer needs to get |
| 6308 | // casted to a regular pointer, otherwise an error like this occurs: | 6297 | // casted to a regular pointer, otherwise an error like this occurs: |
| 6309 | // error: array type 'uint32_t[20]' (aka 'unsigned int[20]') is not assignable | 6298 | // error: array type 'uint32_t[20]' (aka 'unsigned int[20]') is not assignable |
| 6310 | var elem_ptr_ty_pl: Type.Payload.ElemType = .{ | 6299 | const elem_ptr_ty = try mod.ptrType(.{ |
| 6311 | .base = .{ .tag = .c_mut_pointer }, | 6300 | .child = elem_ty.ip_index, |
| 6312 | .data = elem_ty, | 6301 | .flags = .{ |
| 6313 | }; | 6302 | .size = .C, |
| 6314 | const elem_ptr_ty = Type.initPayload(&elem_ptr_ty_pl.base); | 6303 | }, |
| 6304 | }); | ||
| 6315 | 6305 | ||
| 6316 | const index = try f.allocLocal(inst, Type.usize); | 6306 | const index = try f.allocLocal(inst, Type.usize); |
| 6317 | 6307 | ||
| 6318 | try writer.writeAll("for ("); | 6308 | try writer.writeAll("for ("); |
| 6319 | try f.writeCValue(writer, index, .Other); | 6309 | try f.writeCValue(writer, index, .Other); |
| 6320 | try writer.writeAll(" = "); | 6310 | try writer.writeAll(" = "); |
| 6321 | try f.object.dg.renderValue(writer, Type.usize, Value.zero, .Initializer); | 6311 | try f.object.dg.renderValue(writer, Type.usize, try mod.intValue(Type.usize, 0), .Initializer); |
| 6322 | try writer.writeAll("; "); | 6312 | try writer.writeAll("; "); |
| 6323 | try f.writeCValue(writer, index, .Other); | 6313 | try f.writeCValue(writer, index, .Other); |
| 6324 | try writer.writeAll(" != "); | 6314 | try writer.writeAll(" != "); |
| 6325 | switch (dest_ty.ptrSize()) { | 6315 | switch (dest_ty.ptrSize(mod)) { |
| 6326 | .Slice => { | 6316 | .Slice => { |
| 6327 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" }); | 6317 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "len" }); |
| 6328 | }, | 6318 | }, |
| 6329 | .One => { | 6319 | .One => { |
| 6330 | const array_ty = dest_ty.childType(); | 6320 | const array_ty = dest_ty.childType(mod); |
| 6331 | try writer.print("{d}", .{array_ty.arrayLen()}); | 6321 | try writer.print("{d}", .{array_ty.arrayLen(mod)}); |
| 6332 | }, | 6322 | }, |
| 6333 | .Many, .C => unreachable, | 6323 | .Many, .C => unreachable, |
| 6334 | } | 6324 | } |
| ... | @@ -6357,7 +6347,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -6357,7 +6347,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6357 | const bitcasted = try bitcast(f, Type.u8, value, elem_ty); | 6347 | const bitcasted = try bitcast(f, Type.u8, value, elem_ty); |
| 6358 | 6348 | ||
| 6359 | try writer.writeAll("memset("); | 6349 | try writer.writeAll("memset("); |
| 6360 | switch (dest_ty.ptrSize()) { | 6350 | switch (dest_ty.ptrSize(mod)) { |
| 6361 | .Slice => { | 6351 | .Slice => { |
| 6362 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }); | 6352 | try f.writeCValueMember(writer, dest_slice, .{ .identifier = "ptr" }); |
| 6363 | try writer.writeAll(", "); | 6353 | try writer.writeAll(", "); |
| ... | @@ -6367,8 +6357,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -6367,8 +6357,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6367 | try writer.writeAll(");\n"); | 6357 | try writer.writeAll(");\n"); |
| 6368 | }, | 6358 | }, |
| 6369 | .One => { | 6359 | .One => { |
| 6370 | const array_ty = dest_ty.childType(); | 6360 | const array_ty = dest_ty.childType(mod); |
| 6371 | const len = array_ty.arrayLen() * elem_abi_size; | 6361 | const len = array_ty.arrayLen(mod) * elem_abi_size; |
| 6372 | 6362 | ||
| 6373 | try f.writeCValue(writer, dest_slice, .FunctionArgument); | 6363 | try f.writeCValue(writer, dest_slice, .FunctionArgument); |
| 6374 | try writer.writeAll(", "); | 6364 | try writer.writeAll(", "); |
| ... | @@ -6383,12 +6373,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { | ... | @@ -6383,12 +6373,12 @@ fn airMemset(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 6383 | } | 6373 | } |
| 6384 | 6374 | ||
| 6385 | fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { | 6375 | fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6376 | const mod = f.object.dg.module; | ||
| 6386 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 6377 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 6387 | const dest_ptr = try f.resolveInst(bin_op.lhs); | 6378 | const dest_ptr = try f.resolveInst(bin_op.lhs); |
| 6388 | const src_ptr = try f.resolveInst(bin_op.rhs); | 6379 | const src_ptr = try f.resolveInst(bin_op.rhs); |
| 6389 | const dest_ty = f.air.typeOf(bin_op.lhs); | 6380 | const dest_ty = f.typeOf(bin_op.lhs); |
| 6390 | const src_ty = f.air.typeOf(bin_op.rhs); | 6381 | const src_ty = f.typeOf(bin_op.rhs); |
| 6391 | const target = f.object.dg.module.getTarget(); | ||
| 6392 | const writer = f.object.writer(); | 6382 | const writer = f.object.writer(); |
| 6393 | 6383 | ||
| 6394 | try writer.writeAll("memcpy("); | 6384 | try writer.writeAll("memcpy("); |
| ... | @@ -6396,10 +6386,10 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6396,10 +6386,10 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6396 | try writer.writeAll(", "); | 6386 | try writer.writeAll(", "); |
| 6397 | try writeSliceOrPtr(f, writer, src_ptr, src_ty); | 6387 | try writeSliceOrPtr(f, writer, src_ptr, src_ty); |
| 6398 | try writer.writeAll(", "); | 6388 | try writer.writeAll(", "); |
| 6399 | switch (dest_ty.ptrSize()) { | 6389 | switch (dest_ty.ptrSize(mod)) { |
| 6400 | .Slice => { | 6390 | .Slice => { |
| 6401 | const elem_ty = dest_ty.childType(); | 6391 | const elem_ty = dest_ty.childType(mod); |
| 6402 | const elem_abi_size = elem_ty.abiSize(target); | 6392 | const elem_abi_size = elem_ty.abiSize(mod); |
| 6403 | try f.writeCValueMember(writer, dest_ptr, .{ .identifier = "len" }); | 6393 | try f.writeCValueMember(writer, dest_ptr, .{ .identifier = "len" }); |
| 6404 | if (elem_abi_size > 1) { | 6394 | if (elem_abi_size > 1) { |
| 6405 | try writer.print(" * {d});\n", .{elem_abi_size}); | 6395 | try writer.print(" * {d});\n", .{elem_abi_size}); |
| ... | @@ -6408,10 +6398,10 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6408,10 +6398,10 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6408 | } | 6398 | } |
| 6409 | }, | 6399 | }, |
| 6410 | .One => { | 6400 | .One => { |
| 6411 | const array_ty = dest_ty.childType(); | 6401 | const array_ty = dest_ty.childType(mod); |
| 6412 | const elem_ty = array_ty.childType(); | 6402 | const elem_ty = array_ty.childType(mod); |
| 6413 | const elem_abi_size = elem_ty.abiSize(target); | 6403 | const elem_abi_size = elem_ty.abiSize(mod); |
| 6414 | const len = array_ty.arrayLen() * elem_abi_size; | 6404 | const len = array_ty.arrayLen(mod) * elem_abi_size; |
| 6415 | try writer.print("{d});\n", .{len}); | 6405 | try writer.print("{d});\n", .{len}); |
| 6416 | }, | 6406 | }, |
| 6417 | .Many, .C => unreachable, | 6407 | .Many, .C => unreachable, |
| ... | @@ -6422,16 +6412,16 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6422,16 +6412,16 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6422 | } | 6412 | } |
| 6423 | 6413 | ||
| 6424 | fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { | 6414 | fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6415 | const mod = f.object.dg.module; | ||
| 6425 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 6416 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 6426 | const union_ptr = try f.resolveInst(bin_op.lhs); | 6417 | const union_ptr = try f.resolveInst(bin_op.lhs); |
| 6427 | const new_tag = try f.resolveInst(bin_op.rhs); | 6418 | const new_tag = try f.resolveInst(bin_op.rhs); |
| 6428 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 6419 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 6429 | 6420 | ||
| 6430 | const target = f.object.dg.module.getTarget(); | 6421 | const union_ty = f.typeOf(bin_op.lhs).childType(mod); |
| 6431 | const union_ty = f.air.typeOf(bin_op.lhs).childType(); | 6422 | const layout = union_ty.unionGetLayout(mod); |
| 6432 | const layout = union_ty.unionGetLayout(target); | ||
| 6433 | if (layout.tag_size == 0) return .none; | 6423 | if (layout.tag_size == 0) return .none; |
| 6434 | const tag_ty = union_ty.unionTagTypeSafety().?; | 6424 | const tag_ty = union_ty.unionTagTypeSafety(mod).?; |
| 6435 | 6425 | ||
| 6436 | const writer = f.object.writer(); | 6426 | const writer = f.object.writer(); |
| 6437 | const a = try Assignment.start(f, writer, tag_ty); | 6427 | const a = try Assignment.start(f, writer, tag_ty); |
| ... | @@ -6443,17 +6433,17 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6443,17 +6433,17 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6443 | } | 6433 | } |
| 6444 | 6434 | ||
| 6445 | fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { | 6435 | fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6436 | const mod = f.object.dg.module; | ||
| 6446 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 6437 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 6447 | 6438 | ||
| 6448 | const operand = try f.resolveInst(ty_op.operand); | 6439 | const operand = try f.resolveInst(ty_op.operand); |
| 6449 | try reap(f, inst, &.{ty_op.operand}); | 6440 | try reap(f, inst, &.{ty_op.operand}); |
| 6450 | 6441 | ||
| 6451 | const union_ty = f.air.typeOf(ty_op.operand); | 6442 | const union_ty = f.typeOf(ty_op.operand); |
| 6452 | const target = f.object.dg.module.getTarget(); | 6443 | const layout = union_ty.unionGetLayout(mod); |
| 6453 | const layout = union_ty.unionGetLayout(target); | ||
| 6454 | if (layout.tag_size == 0) return .none; | 6444 | if (layout.tag_size == 0) return .none; |
| 6455 | 6445 | ||
| 6456 | const inst_ty = f.air.typeOfIndex(inst); | 6446 | const inst_ty = f.typeOfIndex(inst); |
| 6457 | const writer = f.object.writer(); | 6447 | const writer = f.object.writer(); |
| 6458 | const local = try f.allocLocal(inst, inst_ty); | 6448 | const local = try f.allocLocal(inst, inst_ty); |
| 6459 | const a = try Assignment.start(f, writer, inst_ty); | 6449 | const a = try Assignment.start(f, writer, inst_ty); |
| ... | @@ -6465,10 +6455,11 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6465,10 +6455,11 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6465 | } | 6455 | } |
| 6466 | 6456 | ||
| 6467 | fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { | 6457 | fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6458 | const mod = f.object.dg.module; | ||
| 6468 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 6459 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 6469 | 6460 | ||
| 6470 | const inst_ty = f.air.typeOfIndex(inst); | 6461 | const inst_ty = f.typeOfIndex(inst); |
| 6471 | const enum_ty = f.air.typeOf(un_op); | 6462 | const enum_ty = f.typeOf(un_op); |
| 6472 | const operand = try f.resolveInst(un_op); | 6463 | const operand = try f.resolveInst(un_op); |
| 6473 | try reap(f, inst, &.{un_op}); | 6464 | try reap(f, inst, &.{un_op}); |
| 6474 | 6465 | ||
| ... | @@ -6476,7 +6467,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6476,7 +6467,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6476 | const local = try f.allocLocal(inst, inst_ty); | 6467 | const local = try f.allocLocal(inst, inst_ty); |
| 6477 | try f.writeCValue(writer, local, .Other); | 6468 | try f.writeCValue(writer, local, .Other); |
| 6478 | try writer.print(" = {s}(", .{ | 6469 | try writer.print(" = {s}(", .{ |
| 6479 | try f.getLazyFnName(.{ .tag_name = enum_ty.getOwnerDecl() }, .{ .tag_name = enum_ty }), | 6470 | try f.getLazyFnName(.{ .tag_name = enum_ty.getOwnerDecl(mod) }, .{ .tag_name = enum_ty }), |
| 6480 | }); | 6471 | }); |
| 6481 | try f.writeCValue(writer, operand, .Other); | 6472 | try f.writeCValue(writer, operand, .Other); |
| 6482 | try writer.writeAll(");\n"); | 6473 | try writer.writeAll(");\n"); |
| ... | @@ -6488,7 +6479,7 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6488,7 +6479,7 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6488 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 6479 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 6489 | 6480 | ||
| 6490 | const writer = f.object.writer(); | 6481 | const writer = f.object.writer(); |
| 6491 | const inst_ty = f.air.typeOfIndex(inst); | 6482 | const inst_ty = f.typeOfIndex(inst); |
| 6492 | const operand = try f.resolveInst(un_op); | 6483 | const operand = try f.resolveInst(un_op); |
| 6493 | try reap(f, inst, &.{un_op}); | 6484 | try reap(f, inst, &.{un_op}); |
| 6494 | const local = try f.allocLocal(inst, inst_ty); | 6485 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -6501,13 +6492,14 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6501,13 +6492,14 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6501 | } | 6492 | } |
| 6502 | 6493 | ||
| 6503 | fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue { | 6494 | fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6495 | const mod = f.object.dg.module; | ||
| 6504 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 6496 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 6505 | 6497 | ||
| 6506 | const operand = try f.resolveInst(ty_op.operand); | 6498 | const operand = try f.resolveInst(ty_op.operand); |
| 6507 | try reap(f, inst, &.{ty_op.operand}); | 6499 | try reap(f, inst, &.{ty_op.operand}); |
| 6508 | 6500 | ||
| 6509 | const inst_ty = f.air.typeOfIndex(inst); | 6501 | const inst_ty = f.typeOfIndex(inst); |
| 6510 | const inst_scalar_ty = inst_ty.scalarType(); | 6502 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 6511 | 6503 | ||
| 6512 | const writer = f.object.writer(); | 6504 | const writer = f.object.writer(); |
| 6513 | const local = try f.allocLocal(inst, inst_ty); | 6505 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -6532,7 +6524,7 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6532,7 +6524,7 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6532 | const rhs = try f.resolveInst(extra.rhs); | 6524 | const rhs = try f.resolveInst(extra.rhs); |
| 6533 | try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs }); | 6525 | try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs }); |
| 6534 | 6526 | ||
| 6535 | const inst_ty = f.air.typeOfIndex(inst); | 6527 | const inst_ty = f.typeOfIndex(inst); |
| 6536 | 6528 | ||
| 6537 | const writer = f.object.writer(); | 6529 | const writer = f.object.writer(); |
| 6538 | const local = try f.allocLocal(inst, inst_ty); | 6530 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -6555,41 +6547,31 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6555,41 +6547,31 @@ fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6555 | } | 6547 | } |
| 6556 | 6548 | ||
| 6557 | fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue { | 6549 | fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6550 | const mod = f.object.dg.module; | ||
| 6558 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 6551 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 6559 | const extra = f.air.extraData(Air.Shuffle, ty_pl.payload).data; | 6552 | const extra = f.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 6560 | 6553 | ||
| 6561 | const mask = f.air.values[extra.mask]; | 6554 | const mask = extra.mask.toValue(); |
| 6562 | const lhs = try f.resolveInst(extra.a); | 6555 | const lhs = try f.resolveInst(extra.a); |
| 6563 | const rhs = try f.resolveInst(extra.b); | 6556 | const rhs = try f.resolveInst(extra.b); |
| 6564 | 6557 | ||
| 6565 | const module = f.object.dg.module; | 6558 | const inst_ty = f.typeOfIndex(inst); |
| 6566 | const target = module.getTarget(); | ||
| 6567 | const inst_ty = f.air.typeOfIndex(inst); | ||
| 6568 | 6559 | ||
| 6569 | const writer = f.object.writer(); | 6560 | const writer = f.object.writer(); |
| 6570 | const local = try f.allocLocal(inst, inst_ty); | 6561 | const local = try f.allocLocal(inst, inst_ty); |
| 6571 | try reap(f, inst, &.{ extra.a, extra.b }); // local cannot alias operands | 6562 | try reap(f, inst, &.{ extra.a, extra.b }); // local cannot alias operands |
| 6572 | for (0..extra.mask_len) |index| { | 6563 | for (0..extra.mask_len) |index| { |
| 6573 | var dst_pl = Value.Payload.U64{ | ||
| 6574 | .base = .{ .tag = .int_u64 }, | ||
| 6575 | .data = @intCast(u64, index), | ||
| 6576 | }; | ||
| 6577 | |||
| 6578 | try f.writeCValue(writer, local, .Other); | 6564 | try f.writeCValue(writer, local, .Other); |
| 6579 | try writer.writeByte('['); | 6565 | try writer.writeByte('['); |
| 6580 | try f.object.dg.renderValue(writer, Type.usize, Value.initPayload(&dst_pl.base), .Other); | 6566 | try f.object.dg.renderValue(writer, Type.usize, try mod.intValue(Type.usize, index), .Other); |
| 6581 | try writer.writeAll("] = "); | 6567 | try writer.writeAll("] = "); |
| 6582 | 6568 | ||
| 6583 | var buf: Value.ElemValueBuffer = undefined; | 6569 | const mask_elem = (try mask.elemValue(mod, index)).toSignedInt(mod); |
| 6584 | const mask_elem = mask.elemValueBuffer(module, index, &buf).toSignedInt(target); | 6570 | const src_val = try mod.intValue(Type.usize, @intCast(u64, mask_elem ^ mask_elem >> 63)); |
| 6585 | var src_pl = Value.Payload.U64{ | ||
| 6586 | .base = .{ .tag = .int_u64 }, | ||
| 6587 | .data = @intCast(u64, mask_elem ^ mask_elem >> 63), | ||
| 6588 | }; | ||
| 6589 | 6571 | ||
| 6590 | try f.writeCValue(writer, if (mask_elem >= 0) lhs else rhs, .Other); | 6572 | try f.writeCValue(writer, if (mask_elem >= 0) lhs else rhs, .Other); |
| 6591 | try writer.writeByte('['); | 6573 | try writer.writeByte('['); |
| 6592 | try f.object.dg.renderValue(writer, Type.usize, Value.initPayload(&src_pl.base), .Other); | 6574 | try f.object.dg.renderValue(writer, Type.usize, src_val, .Other); |
| 6593 | try writer.writeAll("];\n"); | 6575 | try writer.writeAll("];\n"); |
| 6594 | } | 6576 | } |
| 6595 | 6577 | ||
| ... | @@ -6597,16 +6579,16 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6597,16 +6579,16 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6597 | } | 6579 | } |
| 6598 | 6580 | ||
| 6599 | fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { | 6581 | fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6582 | const mod = f.object.dg.module; | ||
| 6600 | const reduce = f.air.instructions.items(.data)[inst].reduce; | 6583 | const reduce = f.air.instructions.items(.data)[inst].reduce; |
| 6601 | 6584 | ||
| 6602 | const target = f.object.dg.module.getTarget(); | 6585 | const scalar_ty = f.typeOfIndex(inst); |
| 6603 | const scalar_ty = f.air.typeOfIndex(inst); | ||
| 6604 | const operand = try f.resolveInst(reduce.operand); | 6586 | const operand = try f.resolveInst(reduce.operand); |
| 6605 | try reap(f, inst, &.{reduce.operand}); | 6587 | try reap(f, inst, &.{reduce.operand}); |
| 6606 | const operand_ty = f.air.typeOf(reduce.operand); | 6588 | const operand_ty = f.typeOf(reduce.operand); |
| 6607 | const writer = f.object.writer(); | 6589 | const writer = f.object.writer(); |
| 6608 | 6590 | ||
| 6609 | const use_operator = scalar_ty.bitSize(target) <= 64; | 6591 | const use_operator = scalar_ty.bitSize(mod) <= 64; |
| 6610 | const op: union(enum) { | 6592 | const op: union(enum) { |
| 6611 | const Func = struct { operation: []const u8, info: BuiltinInfo = .none }; | 6593 | const Func = struct { operation: []const u8, info: BuiltinInfo = .none }; |
| 6612 | float_op: Func, | 6594 | float_op: Func, |
| ... | @@ -6617,28 +6599,28 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6617,28 +6599,28 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6617 | .And => if (use_operator) .{ .infix = " &= " } else .{ .builtin = .{ .operation = "and" } }, | 6599 | .And => if (use_operator) .{ .infix = " &= " } else .{ .builtin = .{ .operation = "and" } }, |
| 6618 | .Or => if (use_operator) .{ .infix = " |= " } else .{ .builtin = .{ .operation = "or" } }, | 6600 | .Or => if (use_operator) .{ .infix = " |= " } else .{ .builtin = .{ .operation = "or" } }, |
| 6619 | .Xor => if (use_operator) .{ .infix = " ^= " } else .{ .builtin = .{ .operation = "xor" } }, | 6601 | .Xor => if (use_operator) .{ .infix = " ^= " } else .{ .builtin = .{ .operation = "xor" } }, |
| 6620 | .Min => switch (scalar_ty.zigTypeTag()) { | 6602 | .Min => switch (scalar_ty.zigTypeTag(mod)) { |
| 6621 | .Int => if (use_operator) .{ .ternary = " < " } else .{ | 6603 | .Int => if (use_operator) .{ .ternary = " < " } else .{ |
| 6622 | .builtin = .{ .operation = "min" }, | 6604 | .builtin = .{ .operation = "min" }, |
| 6623 | }, | 6605 | }, |
| 6624 | .Float => .{ .float_op = .{ .operation = "fmin" } }, | 6606 | .Float => .{ .float_op = .{ .operation = "fmin" } }, |
| 6625 | else => unreachable, | 6607 | else => unreachable, |
| 6626 | }, | 6608 | }, |
| 6627 | .Max => switch (scalar_ty.zigTypeTag()) { | 6609 | .Max => switch (scalar_ty.zigTypeTag(mod)) { |
| 6628 | .Int => if (use_operator) .{ .ternary = " > " } else .{ | 6610 | .Int => if (use_operator) .{ .ternary = " > " } else .{ |
| 6629 | .builtin = .{ .operation = "max" }, | 6611 | .builtin = .{ .operation = "max" }, |
| 6630 | }, | 6612 | }, |
| 6631 | .Float => .{ .float_op = .{ .operation = "fmax" } }, | 6613 | .Float => .{ .float_op = .{ .operation = "fmax" } }, |
| 6632 | else => unreachable, | 6614 | else => unreachable, |
| 6633 | }, | 6615 | }, |
| 6634 | .Add => switch (scalar_ty.zigTypeTag()) { | 6616 | .Add => switch (scalar_ty.zigTypeTag(mod)) { |
| 6635 | .Int => if (use_operator) .{ .infix = " += " } else .{ | 6617 | .Int => if (use_operator) .{ .infix = " += " } else .{ |
| 6636 | .builtin = .{ .operation = "addw", .info = .bits }, | 6618 | .builtin = .{ .operation = "addw", .info = .bits }, |
| 6637 | }, | 6619 | }, |
| 6638 | .Float => .{ .builtin = .{ .operation = "add" } }, | 6620 | .Float => .{ .builtin = .{ .operation = "add" } }, |
| 6639 | else => unreachable, | 6621 | else => unreachable, |
| 6640 | }, | 6622 | }, |
| 6641 | .Mul => switch (scalar_ty.zigTypeTag()) { | 6623 | .Mul => switch (scalar_ty.zigTypeTag(mod)) { |
| 6642 | .Int => if (use_operator) .{ .infix = " *= " } else .{ | 6624 | .Int => if (use_operator) .{ .infix = " *= " } else .{ |
| 6643 | .builtin = .{ .operation = "mulw", .info = .bits }, | 6625 | .builtin = .{ .operation = "mulw", .info = .bits }, |
| 6644 | }, | 6626 | }, |
| ... | @@ -6663,43 +6645,42 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6663,43 +6645,42 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6663 | try f.writeCValue(writer, accum, .Other); | 6645 | try f.writeCValue(writer, accum, .Other); |
| 6664 | try writer.writeAll(" = "); | 6646 | try writer.writeAll(" = "); |
| 6665 | 6647 | ||
| 6666 | var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa); | ||
| 6667 | defer arena.deinit(); | ||
| 6668 | |||
| 6669 | const ExpectedContents = union { | ||
| 6670 | u: Value.Payload.U64, | ||
| 6671 | i: Value.Payload.I64, | ||
| 6672 | f16: Value.Payload.Float_16, | ||
| 6673 | f32: Value.Payload.Float_32, | ||
| 6674 | f64: Value.Payload.Float_64, | ||
| 6675 | f80: Value.Payload.Float_80, | ||
| 6676 | f128: Value.Payload.Float_128, | ||
| 6677 | }; | ||
| 6678 | var stack align(@alignOf(ExpectedContents)) = | ||
| 6679 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); | ||
| 6680 | |||
| 6681 | try f.object.dg.renderValue(writer, scalar_ty, switch (reduce.operation) { | 6648 | try f.object.dg.renderValue(writer, scalar_ty, switch (reduce.operation) { |
| 6682 | .Or, .Xor, .Add => Value.zero, | 6649 | .Or, .Xor => switch (scalar_ty.zigTypeTag(mod)) { |
| 6683 | .And => switch (scalar_ty.zigTypeTag()) { | 6650 | .Bool => Value.false, |
| 6684 | .Bool => Value.one, | 6651 | .Int => try mod.intValue(scalar_ty, 0), |
| 6685 | else => switch (scalar_ty.intInfo(target).signedness) { | 6652 | else => unreachable, |
| 6686 | .unsigned => try scalar_ty.maxInt(stack.get(), target), | 6653 | }, |
| 6687 | .signed => Value.negative_one, | 6654 | .And => switch (scalar_ty.zigTypeTag(mod)) { |
| 6655 | .Bool => Value.true, | ||
| 6656 | .Int => switch (scalar_ty.intInfo(mod).signedness) { | ||
| 6657 | .unsigned => try scalar_ty.maxIntScalar(mod, scalar_ty), | ||
| 6658 | .signed => try mod.intValue(scalar_ty, -1), | ||
| 6688 | }, | 6659 | }, |
| 6660 | else => unreachable, | ||
| 6661 | }, | ||
| 6662 | .Add => switch (scalar_ty.zigTypeTag(mod)) { | ||
| 6663 | .Int => try mod.intValue(scalar_ty, 0), | ||
| 6664 | .Float => try mod.floatValue(scalar_ty, 0.0), | ||
| 6665 | else => unreachable, | ||
| 6689 | }, | 6666 | }, |
| 6690 | .Min => switch (scalar_ty.zigTypeTag()) { | 6667 | .Mul => switch (scalar_ty.zigTypeTag(mod)) { |
| 6691 | .Bool => Value.one, | 6668 | .Int => try mod.intValue(scalar_ty, 1), |
| 6692 | .Int => try scalar_ty.maxInt(stack.get(), target), | 6669 | .Float => try mod.floatValue(scalar_ty, 1.0), |
| 6693 | .Float => try Value.floatToValue(std.math.nan(f128), stack.get(), scalar_ty, target), | ||
| 6694 | else => unreachable, | 6670 | else => unreachable, |
| 6695 | }, | 6671 | }, |
| 6696 | .Max => switch (scalar_ty.zigTypeTag()) { | 6672 | .Min => switch (scalar_ty.zigTypeTag(mod)) { |
| 6697 | .Bool => Value.zero, | 6673 | .Bool => Value.true, |
| 6698 | .Int => try scalar_ty.minInt(stack.get(), target), | 6674 | .Int => try scalar_ty.maxIntScalar(mod, scalar_ty), |
| 6699 | .Float => try Value.floatToValue(std.math.nan(f128), stack.get(), scalar_ty, target), | 6675 | .Float => try mod.floatValue(scalar_ty, std.math.nan_f128), |
| 6676 | else => unreachable, | ||
| 6677 | }, | ||
| 6678 | .Max => switch (scalar_ty.zigTypeTag(mod)) { | ||
| 6679 | .Bool => Value.false, | ||
| 6680 | .Int => try scalar_ty.minIntScalar(mod, scalar_ty), | ||
| 6681 | .Float => try mod.floatValue(scalar_ty, std.math.nan_f128), | ||
| 6700 | else => unreachable, | 6682 | else => unreachable, |
| 6701 | }, | 6683 | }, |
| 6702 | .Mul => Value.one, | ||
| 6703 | }, .Initializer); | 6684 | }, .Initializer); |
| 6704 | try writer.writeAll(";\n"); | 6685 | try writer.writeAll(";\n"); |
| 6705 | 6686 | ||
| ... | @@ -6753,9 +6734,11 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6753,9 +6734,11 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6753 | } | 6734 | } |
| 6754 | 6735 | ||
| 6755 | fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | 6736 | fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6737 | const mod = f.object.dg.module; | ||
| 6738 | const ip = &mod.intern_pool; | ||
| 6756 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 6739 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 6757 | const inst_ty = f.air.typeOfIndex(inst); | 6740 | const inst_ty = f.typeOfIndex(inst); |
| 6758 | const len = @intCast(usize, inst_ty.arrayLen()); | 6741 | const len = @intCast(usize, inst_ty.arrayLen(mod)); |
| 6759 | const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]); | 6742 | const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]); |
| 6760 | const gpa = f.object.dg.gpa; | 6743 | const gpa = f.object.dg.gpa; |
| 6761 | const resolved_elements = try gpa.alloc(CValue, elements.len); | 6744 | const resolved_elements = try gpa.alloc(CValue, elements.len); |
| ... | @@ -6770,13 +6753,11 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6770,13 +6753,11 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6770 | } | 6753 | } |
| 6771 | } | 6754 | } |
| 6772 | 6755 | ||
| 6773 | const target = f.object.dg.module.getTarget(); | ||
| 6774 | |||
| 6775 | const writer = f.object.writer(); | 6756 | const writer = f.object.writer(); |
| 6776 | const local = try f.allocLocal(inst, inst_ty); | 6757 | const local = try f.allocLocal(inst, inst_ty); |
| 6777 | switch (inst_ty.zigTypeTag()) { | 6758 | switch (inst_ty.zigTypeTag(mod)) { |
| 6778 | .Array, .Vector => { | 6759 | .Array, .Vector => { |
| 6779 | const elem_ty = inst_ty.childType(); | 6760 | const elem_ty = inst_ty.childType(mod); |
| 6780 | const a = try Assignment.init(f, elem_ty); | 6761 | const a = try Assignment.init(f, elem_ty); |
| 6781 | for (resolved_elements, 0..) |element, i| { | 6762 | for (resolved_elements, 0..) |element, i| { |
| 6782 | try a.restart(f, writer); | 6763 | try a.restart(f, writer); |
| ... | @@ -6786,7 +6767,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6786,7 +6767,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6786 | try f.writeCValue(writer, element, .Other); | 6767 | try f.writeCValue(writer, element, .Other); |
| 6787 | try a.end(f, writer); | 6768 | try a.end(f, writer); |
| 6788 | } | 6769 | } |
| 6789 | if (inst_ty.sentinel()) |sentinel| { | 6770 | if (inst_ty.sentinel(mod)) |sentinel| { |
| 6790 | try a.restart(f, writer); | 6771 | try a.restart(f, writer); |
| 6791 | try f.writeCValue(writer, local, .Other); | 6772 | try f.writeCValue(writer, local, .Other); |
| 6792 | try writer.print("[{d}]", .{resolved_elements.len}); | 6773 | try writer.print("[{d}]", .{resolved_elements.len}); |
| ... | @@ -6795,17 +6776,17 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6795,17 +6776,17 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6795 | try a.end(f, writer); | 6776 | try a.end(f, writer); |
| 6796 | } | 6777 | } |
| 6797 | }, | 6778 | }, |
| 6798 | .Struct => switch (inst_ty.containerLayout()) { | 6779 | .Struct => switch (inst_ty.containerLayout(mod)) { |
| 6799 | .Auto, .Extern => for (resolved_elements, 0..) |element, field_i| { | 6780 | .Auto, .Extern => for (resolved_elements, 0..) |element, field_i| { |
| 6800 | if (inst_ty.structFieldIsComptime(field_i)) continue; | 6781 | if (inst_ty.structFieldIsComptime(field_i, mod)) continue; |
| 6801 | const field_ty = inst_ty.structFieldType(field_i); | 6782 | const field_ty = inst_ty.structFieldType(field_i, mod); |
| 6802 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 6783 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 6803 | 6784 | ||
| 6804 | const a = try Assignment.start(f, writer, field_ty); | 6785 | const a = try Assignment.start(f, writer, field_ty); |
| 6805 | try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple()) | 6786 | try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(mod)) |
| 6806 | .{ .field = field_i } | 6787 | .{ .field = field_i } |
| 6807 | else | 6788 | else |
| 6808 | .{ .identifier = inst_ty.structFieldName(field_i) }); | 6789 | .{ .identifier = ip.stringToSlice(inst_ty.structFieldName(field_i, mod)) }); |
| 6809 | try a.assign(f, writer); | 6790 | try a.assign(f, writer); |
| 6810 | try f.writeCValue(writer, element, .Other); | 6791 | try f.writeCValue(writer, element, .Other); |
| 6811 | try a.end(f, writer); | 6792 | try a.end(f, writer); |
| ... | @@ -6813,22 +6794,17 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6813,22 +6794,17 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6813 | .Packed => { | 6794 | .Packed => { |
| 6814 | try f.writeCValue(writer, local, .Other); | 6795 | try f.writeCValue(writer, local, .Other); |
| 6815 | try writer.writeAll(" = "); | 6796 | try writer.writeAll(" = "); |
| 6816 | const int_info = inst_ty.intInfo(target); | 6797 | const int_info = inst_ty.intInfo(mod); |
| 6817 | 6798 | ||
| 6818 | var bit_offset_ty_pl = Type.Payload.Bits{ | 6799 | const bit_offset_ty = try mod.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1)); |
| 6819 | .base = .{ .tag = .int_unsigned }, | ||
| 6820 | .data = Type.smallestUnsignedBits(int_info.bits - 1), | ||
| 6821 | }; | ||
| 6822 | const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); | ||
| 6823 | 6800 | ||
| 6824 | var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; | 6801 | var bit_offset: u64 = 0; |
| 6825 | const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); | ||
| 6826 | 6802 | ||
| 6827 | var empty = true; | 6803 | var empty = true; |
| 6828 | for (0..elements.len) |field_i| { | 6804 | for (0..elements.len) |field_i| { |
| 6829 | if (inst_ty.structFieldIsComptime(field_i)) continue; | 6805 | if (inst_ty.structFieldIsComptime(field_i, mod)) continue; |
| 6830 | const field_ty = inst_ty.structFieldType(field_i); | 6806 | const field_ty = inst_ty.structFieldType(field_i, mod); |
| 6831 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 6807 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 6832 | 6808 | ||
| 6833 | if (!empty) { | 6809 | if (!empty) { |
| 6834 | try writer.writeAll("zig_or_"); | 6810 | try writer.writeAll("zig_or_"); |
| ... | @@ -6839,9 +6815,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6839,9 +6815,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6839 | } | 6815 | } |
| 6840 | empty = true; | 6816 | empty = true; |
| 6841 | for (resolved_elements, 0..) |element, field_i| { | 6817 | for (resolved_elements, 0..) |element, field_i| { |
| 6842 | if (inst_ty.structFieldIsComptime(field_i)) continue; | 6818 | if (inst_ty.structFieldIsComptime(field_i, mod)) continue; |
| 6843 | const field_ty = inst_ty.structFieldType(field_i); | 6819 | const field_ty = inst_ty.structFieldType(field_i, mod); |
| 6844 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 6820 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 6845 | 6821 | ||
| 6846 | if (!empty) try writer.writeAll(", "); | 6822 | if (!empty) try writer.writeAll(", "); |
| 6847 | // TODO: Skip this entire shift if val is 0? | 6823 | // TODO: Skip this entire shift if val is 0? |
| ... | @@ -6849,13 +6825,13 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6849,13 +6825,13 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6849 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); | 6825 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); |
| 6850 | try writer.writeByte('('); | 6826 | try writer.writeByte('('); |
| 6851 | 6827 | ||
| 6852 | if (inst_ty.isAbiInt() and (field_ty.isAbiInt() or field_ty.isPtrAtRuntime())) { | 6828 | if (inst_ty.isAbiInt(mod) and (field_ty.isAbiInt(mod) or field_ty.isPtrAtRuntime(mod))) { |
| 6853 | try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument); | 6829 | try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument); |
| 6854 | } else { | 6830 | } else { |
| 6855 | try writer.writeByte('('); | 6831 | try writer.writeByte('('); |
| 6856 | try f.renderType(writer, inst_ty); | 6832 | try f.renderType(writer, inst_ty); |
| 6857 | try writer.writeByte(')'); | 6833 | try writer.writeByte(')'); |
| 6858 | if (field_ty.isPtrAtRuntime()) { | 6834 | if (field_ty.isPtrAtRuntime(mod)) { |
| 6859 | try writer.writeByte('('); | 6835 | try writer.writeByte('('); |
| 6860 | try f.renderType(writer, switch (int_info.signedness) { | 6836 | try f.renderType(writer, switch (int_info.signedness) { |
| 6861 | .unsigned => Type.usize, | 6837 | .unsigned => Type.usize, |
| ... | @@ -6867,12 +6843,13 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6867,12 +6843,13 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6867 | } | 6843 | } |
| 6868 | 6844 | ||
| 6869 | try writer.writeAll(", "); | 6845 | try writer.writeAll(", "); |
| 6846 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | ||
| 6870 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | 6847 | try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); |
| 6871 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); | 6848 | try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); |
| 6872 | try writer.writeByte(')'); | 6849 | try writer.writeByte(')'); |
| 6873 | if (!empty) try writer.writeByte(')'); | 6850 | if (!empty) try writer.writeByte(')'); |
| 6874 | 6851 | ||
| 6875 | bit_offset_val_pl.data += field_ty.bitSize(target); | 6852 | bit_offset += field_ty.bitSize(mod); |
| 6876 | empty = false; | 6853 | empty = false; |
| 6877 | } | 6854 | } |
| 6878 | 6855 | ||
| ... | @@ -6886,14 +6863,15 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6886,14 +6863,15 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6886 | } | 6863 | } |
| 6887 | 6864 | ||
| 6888 | fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { | 6865 | fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6866 | const mod = f.object.dg.module; | ||
| 6867 | const ip = &mod.intern_pool; | ||
| 6889 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 6868 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 6890 | const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data; | 6869 | const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 6891 | 6870 | ||
| 6892 | const union_ty = f.air.typeOfIndex(inst); | 6871 | const union_ty = f.typeOfIndex(inst); |
| 6893 | const target = f.object.dg.module.getTarget(); | 6872 | const union_obj = mod.typeToUnion(union_ty).?; |
| 6894 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | ||
| 6895 | const field_name = union_obj.fields.keys()[extra.field_index]; | 6873 | const field_name = union_obj.fields.keys()[extra.field_index]; |
| 6896 | const payload_ty = f.air.typeOf(extra.init); | 6874 | const payload_ty = f.typeOf(extra.init); |
| 6897 | const payload = try f.resolveInst(extra.init); | 6875 | const payload = try f.resolveInst(extra.init); |
| 6898 | try reap(f, inst, &.{extra.init}); | 6876 | try reap(f, inst, &.{extra.init}); |
| 6899 | 6877 | ||
| ... | @@ -6907,19 +6885,14 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6907,19 +6885,14 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6907 | return local; | 6885 | return local; |
| 6908 | } | 6886 | } |
| 6909 | 6887 | ||
| 6910 | const field: CValue = if (union_ty.unionTagTypeSafety()) |tag_ty| field: { | 6888 | const field: CValue = if (union_ty.unionTagTypeSafety(mod)) |tag_ty| field: { |
| 6911 | const layout = union_ty.unionGetLayout(target); | 6889 | const layout = union_ty.unionGetLayout(mod); |
| 6912 | if (layout.tag_size != 0) { | 6890 | if (layout.tag_size != 0) { |
| 6913 | const field_index = tag_ty.enumFieldIndex(field_name).?; | 6891 | const field_index = tag_ty.enumFieldIndex(field_name, mod).?; |
| 6914 | 6892 | ||
| 6915 | var tag_pl: Value.Payload.U32 = .{ | 6893 | const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index); |
| 6916 | .base = .{ .tag = .enum_field_index }, | ||
| 6917 | .data = @intCast(u32, field_index), | ||
| 6918 | }; | ||
| 6919 | const tag_val = Value.initPayload(&tag_pl.base); | ||
| 6920 | 6894 | ||
| 6921 | var int_pl: Value.Payload.U64 = undefined; | 6895 | const int_val = try tag_val.enumToInt(tag_ty, mod); |
| 6922 | const int_val = tag_val.enumToInt(tag_ty, &int_pl); | ||
| 6923 | 6896 | ||
| 6924 | const a = try Assignment.start(f, writer, tag_ty); | 6897 | const a = try Assignment.start(f, writer, tag_ty); |
| 6925 | try f.writeCValueMember(writer, local, .{ .identifier = "tag" }); | 6898 | try f.writeCValueMember(writer, local, .{ .identifier = "tag" }); |
| ... | @@ -6927,8 +6900,8 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6927,8 +6900,8 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6927 | try writer.print("{}", .{try f.fmtIntLiteral(tag_ty, int_val)}); | 6900 | try writer.print("{}", .{try f.fmtIntLiteral(tag_ty, int_val)}); |
| 6928 | try a.end(f, writer); | 6901 | try a.end(f, writer); |
| 6929 | } | 6902 | } |
| 6930 | break :field .{ .payload_identifier = field_name }; | 6903 | break :field .{ .payload_identifier = ip.stringToSlice(field_name) }; |
| 6931 | } else .{ .identifier = field_name }; | 6904 | } else .{ .identifier = ip.stringToSlice(field_name) }; |
| 6932 | 6905 | ||
| 6933 | const a = try Assignment.start(f, writer, payload_ty); | 6906 | const a = try Assignment.start(f, writer, payload_ty); |
| 6934 | try f.writeCValueMember(writer, local, field); | 6907 | try f.writeCValueMember(writer, local, field); |
| ... | @@ -6963,7 +6936,7 @@ fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6963,7 +6936,7 @@ fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6963 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 6936 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 6964 | 6937 | ||
| 6965 | const writer = f.object.writer(); | 6938 | const writer = f.object.writer(); |
| 6966 | const inst_ty = f.air.typeOfIndex(inst); | 6939 | const inst_ty = f.typeOfIndex(inst); |
| 6967 | const local = try f.allocLocal(inst, inst_ty); | 6940 | const local = try f.allocLocal(inst, inst_ty); |
| 6968 | try f.writeCValue(writer, local, .Other); | 6941 | try f.writeCValue(writer, local, .Other); |
| 6969 | 6942 | ||
| ... | @@ -6977,7 +6950,7 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6977,7 +6950,7 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6977 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 6950 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 6978 | 6951 | ||
| 6979 | const writer = f.object.writer(); | 6952 | const writer = f.object.writer(); |
| 6980 | const inst_ty = f.air.typeOfIndex(inst); | 6953 | const inst_ty = f.typeOfIndex(inst); |
| 6981 | const operand = try f.resolveInst(pl_op.operand); | 6954 | const operand = try f.resolveInst(pl_op.operand); |
| 6982 | try reap(f, inst, &.{pl_op.operand}); | 6955 | try reap(f, inst, &.{pl_op.operand}); |
| 6983 | const local = try f.allocLocal(inst, inst_ty); | 6956 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -6991,13 +6964,14 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6991,13 +6964,14 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6991 | } | 6964 | } |
| 6992 | 6965 | ||
| 6993 | fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue { | 6966 | fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6967 | const mod = f.object.dg.module; | ||
| 6994 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 6968 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 6995 | 6969 | ||
| 6996 | const operand = try f.resolveInst(un_op); | 6970 | const operand = try f.resolveInst(un_op); |
| 6997 | try reap(f, inst, &.{un_op}); | 6971 | try reap(f, inst, &.{un_op}); |
| 6998 | 6972 | ||
| 6999 | const operand_ty = f.air.typeOf(un_op); | 6973 | const operand_ty = f.typeOf(un_op); |
| 7000 | const scalar_ty = operand_ty.scalarType(); | 6974 | const scalar_ty = operand_ty.scalarType(mod); |
| 7001 | 6975 | ||
| 7002 | const writer = f.object.writer(); | 6976 | const writer = f.object.writer(); |
| 7003 | const local = try f.allocLocal(inst, operand_ty); | 6977 | const local = try f.allocLocal(inst, operand_ty); |
| ... | @@ -7016,13 +6990,14 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -7016,13 +6990,14 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7016 | } | 6990 | } |
| 7017 | 6991 | ||
| 7018 | fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { | 6992 | fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { |
| 6993 | const mod = f.object.dg.module; | ||
| 7019 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 6994 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 7020 | 6995 | ||
| 7021 | const operand = try f.resolveInst(un_op); | 6996 | const operand = try f.resolveInst(un_op); |
| 7022 | try reap(f, inst, &.{un_op}); | 6997 | try reap(f, inst, &.{un_op}); |
| 7023 | 6998 | ||
| 7024 | const inst_ty = f.air.typeOfIndex(inst); | 6999 | const inst_ty = f.typeOfIndex(inst); |
| 7025 | const inst_scalar_ty = inst_ty.scalarType(); | 7000 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 7026 | 7001 | ||
| 7027 | const writer = f.object.writer(); | 7002 | const writer = f.object.writer(); |
| 7028 | const local = try f.allocLocal(inst, inst_ty); | 7003 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -7043,14 +7018,15 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal | ... | @@ -7043,14 +7018,15 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal |
| 7043 | } | 7018 | } |
| 7044 | 7019 | ||
| 7045 | fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { | 7020 | fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { |
| 7021 | const mod = f.object.dg.module; | ||
| 7046 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 7022 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 7047 | 7023 | ||
| 7048 | const lhs = try f.resolveInst(bin_op.lhs); | 7024 | const lhs = try f.resolveInst(bin_op.lhs); |
| 7049 | const rhs = try f.resolveInst(bin_op.rhs); | 7025 | const rhs = try f.resolveInst(bin_op.rhs); |
| 7050 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 7026 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 7051 | 7027 | ||
| 7052 | const inst_ty = f.air.typeOfIndex(inst); | 7028 | const inst_ty = f.typeOfIndex(inst); |
| 7053 | const inst_scalar_ty = inst_ty.scalarType(); | 7029 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 7054 | 7030 | ||
| 7055 | const writer = f.object.writer(); | 7031 | const writer = f.object.writer(); |
| 7056 | const local = try f.allocLocal(inst, inst_ty); | 7032 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -7074,6 +7050,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa | ... | @@ -7074,6 +7050,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa |
| 7074 | } | 7050 | } |
| 7075 | 7051 | ||
| 7076 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { | 7052 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7053 | const mod = f.object.dg.module; | ||
| 7077 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | 7054 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 7078 | const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data; | 7055 | const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data; |
| 7079 | 7056 | ||
| ... | @@ -7082,8 +7059,8 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -7082,8 +7059,8 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7082 | const addend = try f.resolveInst(pl_op.operand); | 7059 | const addend = try f.resolveInst(pl_op.operand); |
| 7083 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand }); | 7060 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand }); |
| 7084 | 7061 | ||
| 7085 | const inst_ty = f.air.typeOfIndex(inst); | 7062 | const inst_ty = f.typeOfIndex(inst); |
| 7086 | const inst_scalar_ty = inst_ty.scalarType(); | 7063 | const inst_scalar_ty = inst_ty.scalarType(mod); |
| 7087 | 7064 | ||
| 7088 | const writer = f.object.writer(); | 7065 | const writer = f.object.writer(); |
| 7089 | const local = try f.allocLocal(inst, inst_ty); | 7066 | const local = try f.allocLocal(inst, inst_ty); |
| ... | @@ -7108,7 +7085,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -7108,7 +7085,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7108 | } | 7085 | } |
| 7109 | 7086 | ||
| 7110 | fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue { | 7087 | fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7111 | const inst_ty = f.air.typeOfIndex(inst); | 7088 | const inst_ty = f.typeOfIndex(inst); |
| 7112 | const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete); | 7089 | const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete); |
| 7113 | const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len; | 7090 | const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len; |
| 7114 | 7091 | ||
| ... | @@ -7127,7 +7104,7 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -7127,7 +7104,7 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7127 | fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue { | 7104 | fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7128 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 7105 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 7129 | 7106 | ||
| 7130 | const inst_ty = f.air.typeOfIndex(inst); | 7107 | const inst_ty = f.typeOfIndex(inst); |
| 7131 | const va_list = try f.resolveInst(ty_op.operand); | 7108 | const va_list = try f.resolveInst(ty_op.operand); |
| 7132 | try reap(f, inst, &.{ty_op.operand}); | 7109 | try reap(f, inst, &.{ty_op.operand}); |
| 7133 | 7110 | ||
| ... | @@ -7158,7 +7135,7 @@ fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -7158,7 +7135,7 @@ fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7158 | fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue { | 7135 | fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue { |
| 7159 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 7136 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 7160 | 7137 | ||
| 7161 | const inst_ty = f.air.typeOfIndex(inst); | 7138 | const inst_ty = f.typeOfIndex(inst); |
| 7162 | const va_list = try f.resolveInst(ty_op.operand); | 7139 | const va_list = try f.resolveInst(ty_op.operand); |
| 7163 | try reap(f, inst, &.{ty_op.operand}); | 7140 | try reap(f, inst, &.{ty_op.operand}); |
| 7164 | 7141 | ||
| ... | @@ -7279,8 +7256,9 @@ fn signAbbrev(signedness: std.builtin.Signedness) u8 { | ... | @@ -7279,8 +7256,9 @@ fn signAbbrev(signedness: std.builtin.Signedness) u8 { |
| 7279 | }; | 7256 | }; |
| 7280 | } | 7257 | } |
| 7281 | 7258 | ||
| 7282 | fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 { | 7259 | fn compilerRtAbbrev(ty: Type, mod: *Module) []const u8 { |
| 7283 | return if (ty.isInt()) switch (ty.intInfo(target).bits) { | 7260 | const target = mod.getTarget(); |
| 7261 | return if (ty.isInt(mod)) switch (ty.intInfo(mod).bits) { | ||
| 7284 | 1...32 => "si", | 7262 | 1...32 => "si", |
| 7285 | 33...64 => "di", | 7263 | 33...64 => "di", |
| 7286 | 65...128 => "ti", | 7264 | 65...128 => "ti", |
| ... | @@ -7407,7 +7385,7 @@ fn undefPattern(comptime IntType: type) IntType { | ... | @@ -7407,7 +7385,7 @@ fn undefPattern(comptime IntType: type) IntType { |
| 7407 | 7385 | ||
| 7408 | const FormatIntLiteralContext = struct { | 7386 | const FormatIntLiteralContext = struct { |
| 7409 | dg: *DeclGen, | 7387 | dg: *DeclGen, |
| 7410 | int_info: std.builtin.Type.Int, | 7388 | int_info: InternPool.Key.IntType, |
| 7411 | kind: CType.Kind, | 7389 | kind: CType.Kind, |
| 7412 | cty: CType, | 7390 | cty: CType, |
| 7413 | val: Value, | 7391 | val: Value, |
| ... | @@ -7418,7 +7396,8 @@ fn formatIntLiteral( | ... | @@ -7418,7 +7396,8 @@ fn formatIntLiteral( |
| 7418 | options: std.fmt.FormatOptions, | 7396 | options: std.fmt.FormatOptions, |
| 7419 | writer: anytype, | 7397 | writer: anytype, |
| 7420 | ) @TypeOf(writer).Error!void { | 7398 | ) @TypeOf(writer).Error!void { |
| 7421 | const target = data.dg.module.getTarget(); | 7399 | const mod = data.dg.module; |
| 7400 | const target = mod.getTarget(); | ||
| 7422 | 7401 | ||
| 7423 | const ExpectedContents = struct { | 7402 | const ExpectedContents = struct { |
| 7424 | const base = 10; | 7403 | const base = 10; |
| ... | @@ -7438,7 +7417,7 @@ fn formatIntLiteral( | ... | @@ -7438,7 +7417,7 @@ fn formatIntLiteral( |
| 7438 | defer allocator.free(undef_limbs); | 7417 | defer allocator.free(undef_limbs); |
| 7439 | 7418 | ||
| 7440 | var int_buf: Value.BigIntSpace = undefined; | 7419 | var int_buf: Value.BigIntSpace = undefined; |
| 7441 | const int = if (data.val.isUndefDeep()) blk: { | 7420 | const int = if (data.val.isUndefDeep(mod)) blk: { |
| 7442 | undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits)); | 7421 | undef_limbs = try allocator.alloc(BigIntLimb, BigInt.calcTwosCompLimbCount(data.int_info.bits)); |
| 7443 | @memset(undef_limbs, undefPattern(BigIntLimb)); | 7422 | @memset(undef_limbs, undefPattern(BigIntLimb)); |
| 7444 | 7423 | ||
| ... | @@ -7449,7 +7428,7 @@ fn formatIntLiteral( | ... | @@ -7449,7 +7428,7 @@ fn formatIntLiteral( |
| 7449 | }; | 7428 | }; |
| 7450 | undef_int.truncate(undef_int.toConst(), data.int_info.signedness, data.int_info.bits); | 7429 | undef_int.truncate(undef_int.toConst(), data.int_info.signedness, data.int_info.bits); |
| 7451 | break :blk undef_int.toConst(); | 7430 | break :blk undef_int.toConst(); |
| 7452 | } else data.val.toBigInt(&int_buf, target); | 7431 | } else data.val.toBigInt(&int_buf, mod); |
| 7453 | assert(int.fitsInTwosComp(data.int_info.signedness, data.int_info.bits)); | 7432 | assert(int.fitsInTwosComp(data.int_info.signedness, data.int_info.bits)); |
| 7454 | 7433 | ||
| 7455 | const c_bits = @intCast(usize, data.cty.byteSize(data.dg.ctypes.set, target) * 8); | 7434 | const c_bits = @intCast(usize, data.cty.byteSize(data.dg.ctypes.set, target) * 8); |
| ... | @@ -7576,10 +7555,6 @@ fn formatIntLiteral( | ... | @@ -7576,10 +7555,6 @@ fn formatIntLiteral( |
| 7576 | c_limb_int_info.signedness = .unsigned; | 7555 | c_limb_int_info.signedness = .unsigned; |
| 7577 | c_limb_cty = c_limb_info.cty; | 7556 | c_limb_cty = c_limb_info.cty; |
| 7578 | } | 7557 | } |
| 7579 | var c_limb_val_pl = Value.Payload.BigInt{ | ||
| 7580 | .base = .{ .tag = if (c_limb_mut.positive) .int_big_positive else .int_big_negative }, | ||
| 7581 | .data = c_limb_mut.limbs[0..c_limb_mut.len], | ||
| 7582 | }; | ||
| 7583 | 7558 | ||
| 7584 | if (limb_offset > 0) try writer.writeAll(", "); | 7559 | if (limb_offset > 0) try writer.writeAll(", "); |
| 7585 | try formatIntLiteral(.{ | 7560 | try formatIntLiteral(.{ |
| ... | @@ -7587,7 +7562,7 @@ fn formatIntLiteral( | ... | @@ -7587,7 +7562,7 @@ fn formatIntLiteral( |
| 7587 | .int_info = c_limb_int_info, | 7562 | .int_info = c_limb_int_info, |
| 7588 | .kind = data.kind, | 7563 | .kind = data.kind, |
| 7589 | .cty = c_limb_cty, | 7564 | .cty = c_limb_cty, |
| 7590 | .val = Value.initPayload(&c_limb_val_pl.base), | 7565 | .val = try mod.intValue_big(Type.comptime_int, c_limb_mut.toConst()), |
| 7591 | }, fmt, options, writer); | 7566 | }, fmt, options, writer); |
| 7592 | } | 7567 | } |
| 7593 | } | 7568 | } |
| ... | @@ -7684,20 +7659,21 @@ const Vectorize = struct { | ... | @@ -7684,20 +7659,21 @@ const Vectorize = struct { |
| 7684 | index: CValue = .none, | 7659 | index: CValue = .none, |
| 7685 | 7660 | ||
| 7686 | pub fn start(f: *Function, inst: Air.Inst.Index, writer: anytype, ty: Type) !Vectorize { | 7661 | pub fn start(f: *Function, inst: Air.Inst.Index, writer: anytype, ty: Type) !Vectorize { |
| 7687 | return if (ty.zigTypeTag() == .Vector) index: { | 7662 | const mod = f.object.dg.module; |
| 7688 | var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = ty.vectorLen() }; | 7663 | return if (ty.zigTypeTag(mod) == .Vector) index: { |
| 7664 | const len_val = try mod.intValue(Type.usize, ty.vectorLen(mod)); | ||
| 7689 | 7665 | ||
| 7690 | const local = try f.allocLocal(inst, Type.usize); | 7666 | const local = try f.allocLocal(inst, Type.usize); |
| 7691 | 7667 | ||
| 7692 | try writer.writeAll("for ("); | 7668 | try writer.writeAll("for ("); |
| 7693 | try f.writeCValue(writer, local, .Other); | 7669 | try f.writeCValue(writer, local, .Other); |
| 7694 | try writer.print(" = {d}; ", .{try f.fmtIntLiteral(Type.usize, Value.zero)}); | 7670 | try writer.print(" = {d}; ", .{try f.fmtIntLiteral(Type.usize, try mod.intValue(Type.usize, 0))}); |
| 7695 | try f.writeCValue(writer, local, .Other); | 7671 | try f.writeCValue(writer, local, .Other); |
| 7696 | try writer.print(" < {d}; ", .{ | 7672 | try writer.print(" < {d}; ", .{ |
| 7697 | try f.fmtIntLiteral(Type.usize, Value.initPayload(&len_pl.base)), | 7673 | try f.fmtIntLiteral(Type.usize, len_val), |
| 7698 | }); | 7674 | }); |
| 7699 | try f.writeCValue(writer, local, .Other); | 7675 | try f.writeCValue(writer, local, .Other); |
| 7700 | try writer.print(" += {d}) {{\n", .{try f.fmtIntLiteral(Type.usize, Value.one)}); | 7676 | try writer.print(" += {d}) {{\n", .{try f.fmtIntLiteral(Type.usize, try mod.intValue(Type.usize, 1))}); |
| 7701 | f.object.indent_writer.pushIndent(); | 7677 | f.object.indent_writer.pushIndent(); |
| 7702 | 7678 | ||
| 7703 | break :index .{ .index = local }; | 7679 | break :index .{ .index = local }; |
| ... | @@ -7721,34 +7697,30 @@ const Vectorize = struct { | ... | @@ -7721,34 +7697,30 @@ const Vectorize = struct { |
| 7721 | } | 7697 | } |
| 7722 | }; | 7698 | }; |
| 7723 | 7699 | ||
| 7724 | const LowerFnRetTyBuffer = struct { | 7700 | fn lowerFnRetTy(ret_ty: Type, mod: *Module) !Type { |
| 7725 | names: [1][]const u8, | 7701 | if (ret_ty.ip_index == .noreturn_type) return Type.noreturn; |
| 7726 | types: [1]Type, | 7702 | |
| 7727 | values: [1]Value, | 7703 | if (lowersToArray(ret_ty, mod)) { |
| 7728 | payload: Type.Payload.AnonStruct, | 7704 | const names = [1]InternPool.NullTerminatedString{ |
| 7729 | }; | 7705 | try mod.intern_pool.getOrPutString(mod.gpa, "array"), |
| 7730 | fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type { | 7706 | }; |
| 7731 | if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn); | 7707 | const types = [1]InternPool.Index{ret_ty.ip_index}; |
| 7732 | 7708 | const values = [1]InternPool.Index{.none}; | |
| 7733 | if (lowersToArray(ret_ty, target)) { | 7709 | const interned = try mod.intern(.{ .anon_struct_type = .{ |
| 7734 | buffer.names = [1][]const u8{"array"}; | 7710 | .names = &names, |
| 7735 | buffer.types = [1]Type{ret_ty}; | 7711 | .types = &types, |
| 7736 | buffer.values = [1]Value{Value.initTag(.unreachable_value)}; | 7712 | .values = &values, |
| 7737 | buffer.payload = .{ .data = .{ | 7713 | } }); |
| 7738 | .names = &buffer.names, | 7714 | return interned.toType(); |
| 7739 | .types = &buffer.types, | ||
| 7740 | .values = &buffer.values, | ||
| 7741 | } }; | ||
| 7742 | return Type.initPayload(&buffer.payload.base); | ||
| 7743 | } | 7715 | } |
| 7744 | 7716 | ||
| 7745 | return if (ret_ty.hasRuntimeBitsIgnoreComptime()) ret_ty else Type.void; | 7717 | return if (ret_ty.hasRuntimeBitsIgnoreComptime(mod)) ret_ty else Type.void; |
| 7746 | } | 7718 | } |
| 7747 | 7719 | ||
| 7748 | fn lowersToArray(ty: Type, target: std.Target) bool { | 7720 | fn lowersToArray(ty: Type, mod: *Module) bool { |
| 7749 | return switch (ty.zigTypeTag()) { | 7721 | return switch (ty.zigTypeTag(mod)) { |
| 7750 | .Array, .Vector => return true, | 7722 | .Array, .Vector => return true, |
| 7751 | else => return ty.isAbiInt() and toCIntBits(@intCast(u32, ty.bitSize(target))) == null, | 7723 | else => return ty.isAbiInt(mod) and toCIntBits(@intCast(u32, ty.bitSize(mod))) == null, |
| 7752 | }; | 7724 | }; |
| 7753 | } | 7725 | } |
| 7754 | 7726 | ||
| ... | @@ -7765,8 +7737,8 @@ fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !voi | ... | @@ -7765,8 +7737,8 @@ fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !voi |
| 7765 | 7737 | ||
| 7766 | fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void { | 7738 | fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void { |
| 7767 | const ref_inst = Air.refToIndex(ref) orelse return; | 7739 | const ref_inst = Air.refToIndex(ref) orelse return; |
| 7740 | assert(f.air.instructions.items(.tag)[ref_inst] != .interned); | ||
| 7768 | const c_value = (f.value_map.fetchRemove(ref_inst) orelse return).value; | 7741 | const c_value = (f.value_map.fetchRemove(ref_inst) orelse return).value; |
| 7769 | if (f.air.instructions.items(.tag)[ref_inst] == .constant) return; | ||
| 7770 | const local_index = switch (c_value) { | 7742 | const local_index = switch (c_value) { |
| 7771 | .local, .new_local => |l| l, | 7743 | .local, .new_local => |l| l, |
| 7772 | else => return, | 7744 | else => return, |
src/codegen/c/type.zig+165-167| ... | @@ -292,19 +292,19 @@ pub const CType = extern union { | ... | @@ -292,19 +292,19 @@ pub const CType = extern union { |
| 292 | .abi = std.math.log2_int(u32, abi_alignment), | 292 | .abi = std.math.log2_int(u32, abi_alignment), |
| 293 | }; | 293 | }; |
| 294 | } | 294 | } |
| 295 | pub fn abiAlign(ty: Type, target: Target) AlignAs { | 295 | pub fn abiAlign(ty: Type, mod: *Module) AlignAs { |
| 296 | const abi_align = ty.abiAlignment(target); | 296 | const abi_align = ty.abiAlignment(mod); |
| 297 | return init(abi_align, abi_align); | 297 | return init(abi_align, abi_align); |
| 298 | } | 298 | } |
| 299 | pub fn fieldAlign(struct_ty: Type, field_i: usize, target: Target) AlignAs { | 299 | pub fn fieldAlign(struct_ty: Type, field_i: usize, mod: *Module) AlignAs { |
| 300 | return init( | 300 | return init( |
| 301 | struct_ty.structFieldAlign(field_i, target), | 301 | struct_ty.structFieldAlign(field_i, mod), |
| 302 | struct_ty.structFieldType(field_i).abiAlignment(target), | 302 | struct_ty.structFieldType(field_i, mod).abiAlignment(mod), |
| 303 | ); | 303 | ); |
| 304 | } | 304 | } |
| 305 | pub fn unionPayloadAlign(union_ty: Type, target: Target) AlignAs { | 305 | pub fn unionPayloadAlign(union_ty: Type, mod: *Module) AlignAs { |
| 306 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | 306 | const union_obj = mod.typeToUnion(union_ty).?; |
| 307 | const union_payload_align = union_obj.abiAlignment(target, false); | 307 | const union_payload_align = union_obj.abiAlignment(mod, false); |
| 308 | return init(union_payload_align, union_payload_align); | 308 | return init(union_payload_align, union_payload_align); |
| 309 | } | 309 | } |
| 310 | 310 | ||
| ... | @@ -344,8 +344,8 @@ pub const CType = extern union { | ... | @@ -344,8 +344,8 @@ pub const CType = extern union { |
| 344 | return self.map.entries.items(.hash)[index - Tag.no_payload_count]; | 344 | return self.map.entries.items(.hash)[index - Tag.no_payload_count]; |
| 345 | } | 345 | } |
| 346 | 346 | ||
| 347 | pub fn typeToIndex(self: Set, ty: Type, target: Target, kind: Kind) ?Index { | 347 | pub fn typeToIndex(self: Set, ty: Type, mod: *Module, kind: Kind) ?Index { |
| 348 | const lookup = Convert.Lookup{ .imm = .{ .set = &self, .target = target } }; | 348 | const lookup = Convert.Lookup{ .imm = .{ .set = &self, .mod = mod } }; |
| 349 | 349 | ||
| 350 | var convert: Convert = undefined; | 350 | var convert: Convert = undefined; |
| 351 | convert.initType(ty, kind, lookup) catch unreachable; | 351 | convert.initType(ty, kind, lookup) catch unreachable; |
| ... | @@ -405,7 +405,7 @@ pub const CType = extern union { | ... | @@ -405,7 +405,7 @@ pub const CType = extern union { |
| 405 | ); | 405 | ); |
| 406 | if (!gop.found_existing) { | 406 | if (!gop.found_existing) { |
| 407 | errdefer _ = self.set.map.pop(); | 407 | errdefer _ = self.set.map.pop(); |
| 408 | gop.key_ptr.* = try createFromConvert(self, ty, lookup.getTarget(), kind, convert); | 408 | gop.key_ptr.* = try createFromConvert(self, ty, lookup.getModule(), kind, convert); |
| 409 | } | 409 | } |
| 410 | if (std.debug.runtime_safety) { | 410 | if (std.debug.runtime_safety) { |
| 411 | const adapter = TypeAdapter64{ | 411 | const adapter = TypeAdapter64{ |
| ... | @@ -1236,10 +1236,10 @@ pub const CType = extern union { | ... | @@ -1236,10 +1236,10 @@ pub const CType = extern union { |
| 1236 | } | 1236 | } |
| 1237 | 1237 | ||
| 1238 | pub const Lookup = union(enum) { | 1238 | pub const Lookup = union(enum) { |
| 1239 | fail: Target, | 1239 | fail: *Module, |
| 1240 | imm: struct { | 1240 | imm: struct { |
| 1241 | set: *const Store.Set, | 1241 | set: *const Store.Set, |
| 1242 | target: Target, | 1242 | mod: *Module, |
| 1243 | }, | 1243 | }, |
| 1244 | mut: struct { | 1244 | mut: struct { |
| 1245 | promoted: *Store.Promoted, | 1245 | promoted: *Store.Promoted, |
| ... | @@ -1254,10 +1254,14 @@ pub const CType = extern union { | ... | @@ -1254,10 +1254,14 @@ pub const CType = extern union { |
| 1254 | } | 1254 | } |
| 1255 | 1255 | ||
| 1256 | pub fn getTarget(self: @This()) Target { | 1256 | pub fn getTarget(self: @This()) Target { |
| 1257 | return self.getModule().getTarget(); | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | pub fn getModule(self: @This()) *Module { | ||
| 1257 | return switch (self) { | 1261 | return switch (self) { |
| 1258 | .fail => |target| target, | 1262 | .fail => |mod| mod, |
| 1259 | .imm => |imm| imm.target, | 1263 | .imm => |imm| imm.mod, |
| 1260 | .mut => |mut| mut.mod.getTarget(), | 1264 | .mut => |mut| mut.mod, |
| 1261 | }; | 1265 | }; |
| 1262 | } | 1266 | } |
| 1263 | 1267 | ||
| ... | @@ -1272,7 +1276,7 @@ pub const CType = extern union { | ... | @@ -1272,7 +1276,7 @@ pub const CType = extern union { |
| 1272 | pub fn typeToIndex(self: @This(), ty: Type, kind: Kind) !?Index { | 1276 | pub fn typeToIndex(self: @This(), ty: Type, kind: Kind) !?Index { |
| 1273 | return switch (self) { | 1277 | return switch (self) { |
| 1274 | .fail => null, | 1278 | .fail => null, |
| 1275 | .imm => |imm| imm.set.typeToIndex(ty, imm.target, kind), | 1279 | .imm => |imm| imm.set.typeToIndex(ty, imm.mod, kind), |
| 1276 | .mut => |mut| try mut.promoted.typeToIndex(ty, mut.mod, kind), | 1280 | .mut => |mut| try mut.promoted.typeToIndex(ty, mut.mod, kind), |
| 1277 | }; | 1281 | }; |
| 1278 | } | 1282 | } |
| ... | @@ -1284,7 +1288,7 @@ pub const CType = extern union { | ... | @@ -1284,7 +1288,7 @@ pub const CType = extern union { |
| 1284 | pub fn freeze(self: @This()) @This() { | 1288 | pub fn freeze(self: @This()) @This() { |
| 1285 | return switch (self) { | 1289 | return switch (self) { |
| 1286 | .fail, .imm => self, | 1290 | .fail, .imm => self, |
| 1287 | .mut => |mut| .{ .imm = .{ .set = &mut.promoted.set, .target = self.getTarget() } }, | 1291 | .mut => |mut| .{ .imm = .{ .set = &mut.promoted.set, .mod = mut.mod } }, |
| 1288 | }; | 1292 | }; |
| 1289 | } | 1293 | } |
| 1290 | }; | 1294 | }; |
| ... | @@ -1338,7 +1342,7 @@ pub const CType = extern union { | ... | @@ -1338,7 +1342,7 @@ pub const CType = extern union { |
| 1338 | self.storage.anon.fields[0] = .{ | 1342 | self.storage.anon.fields[0] = .{ |
| 1339 | .name = "array", | 1343 | .name = "array", |
| 1340 | .type = array_idx, | 1344 | .type = array_idx, |
| 1341 | .alignas = AlignAs.abiAlign(ty, lookup.getTarget()), | 1345 | .alignas = AlignAs.abiAlign(ty, lookup.getModule()), |
| 1342 | }; | 1346 | }; |
| 1343 | self.initAnon(kind, fwd_idx, 1); | 1347 | self.initAnon(kind, fwd_idx, 1); |
| 1344 | } else self.init(switch (kind) { | 1348 | } else self.init(switch (kind) { |
| ... | @@ -1350,30 +1354,30 @@ pub const CType = extern union { | ... | @@ -1350,30 +1354,30 @@ pub const CType = extern union { |
| 1350 | } | 1354 | } |
| 1351 | 1355 | ||
| 1352 | pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void { | 1356 | pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void { |
| 1353 | const target = lookup.getTarget(); | 1357 | const mod = lookup.getModule(); |
| 1354 | 1358 | ||
| 1355 | self.* = undefined; | 1359 | self.* = undefined; |
| 1356 | if (!ty.isFnOrHasRuntimeBitsIgnoreComptime()) | 1360 | if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) |
| 1357 | self.init(.void) | 1361 | self.init(.void) |
| 1358 | else if (ty.isAbiInt()) switch (ty.tag()) { | 1362 | else if (ty.isAbiInt(mod)) switch (ty.ip_index) { |
| 1359 | .usize => self.init(.uintptr_t), | 1363 | .usize_type => self.init(.uintptr_t), |
| 1360 | .isize => self.init(.intptr_t), | 1364 | .isize_type => self.init(.intptr_t), |
| 1361 | .c_char => self.init(.char), | 1365 | .c_char_type => self.init(.char), |
| 1362 | .c_short => self.init(.short), | 1366 | .c_short_type => self.init(.short), |
| 1363 | .c_ushort => self.init(.@"unsigned short"), | 1367 | .c_ushort_type => self.init(.@"unsigned short"), |
| 1364 | .c_int => self.init(.int), | 1368 | .c_int_type => self.init(.int), |
| 1365 | .c_uint => self.init(.@"unsigned int"), | 1369 | .c_uint_type => self.init(.@"unsigned int"), |
| 1366 | .c_long => self.init(.long), | 1370 | .c_long_type => self.init(.long), |
| 1367 | .c_ulong => self.init(.@"unsigned long"), | 1371 | .c_ulong_type => self.init(.@"unsigned long"), |
| 1368 | .c_longlong => self.init(.@"long long"), | 1372 | .c_longlong_type => self.init(.@"long long"), |
| 1369 | .c_ulonglong => self.init(.@"unsigned long long"), | 1373 | .c_ulonglong_type => self.init(.@"unsigned long long"), |
| 1370 | else => switch (tagFromIntInfo(ty.intInfo(target))) { | 1374 | else => switch (tagFromIntInfo(ty.intInfo(mod))) { |
| 1371 | .void => unreachable, | 1375 | .void => unreachable, |
| 1372 | else => |t| self.init(t), | 1376 | else => |t| self.init(t), |
| 1373 | .array => switch (kind) { | 1377 | .array => switch (kind) { |
| 1374 | .forward, .complete, .global => { | 1378 | .forward, .complete, .global => { |
| 1375 | const abi_size = ty.abiSize(target); | 1379 | const abi_size = ty.abiSize(mod); |
| 1376 | const abi_align = ty.abiAlignment(target); | 1380 | const abi_align = ty.abiAlignment(mod); |
| 1377 | self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{ | 1381 | self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{ |
| 1378 | .len = @divExact(abi_size, abi_align), | 1382 | .len = @divExact(abi_size, abi_align), |
| 1379 | .elem_type = tagFromIntInfo(.{ | 1383 | .elem_type = tagFromIntInfo(.{ |
| ... | @@ -1389,7 +1393,7 @@ pub const CType = extern union { | ... | @@ -1389,7 +1393,7 @@ pub const CType = extern union { |
| 1389 | .payload => unreachable, | 1393 | .payload => unreachable, |
| 1390 | }, | 1394 | }, |
| 1391 | }, | 1395 | }, |
| 1392 | } else switch (ty.zigTypeTag()) { | 1396 | } else switch (ty.zigTypeTag(mod)) { |
| 1393 | .Frame => unreachable, | 1397 | .Frame => unreachable, |
| 1394 | .AnyFrame => unreachable, | 1398 | .AnyFrame => unreachable, |
| 1395 | 1399 | ||
| ... | @@ -1408,18 +1412,18 @@ pub const CType = extern union { | ... | @@ -1408,18 +1412,18 @@ pub const CType = extern union { |
| 1408 | 1412 | ||
| 1409 | .Bool => self.init(.bool), | 1413 | .Bool => self.init(.bool), |
| 1410 | 1414 | ||
| 1411 | .Float => self.init(switch (ty.tag()) { | 1415 | .Float => self.init(switch (ty.ip_index) { |
| 1412 | .f16 => .zig_f16, | 1416 | .f16_type => .zig_f16, |
| 1413 | .f32 => .zig_f32, | 1417 | .f32_type => .zig_f32, |
| 1414 | .f64 => .zig_f64, | 1418 | .f64_type => .zig_f64, |
| 1415 | .f80 => .zig_f80, | 1419 | .f80_type => .zig_f80, |
| 1416 | .f128 => .zig_f128, | 1420 | .f128_type => .zig_f128, |
| 1417 | .c_longdouble => .zig_c_longdouble, | 1421 | .c_longdouble_type => .zig_c_longdouble, |
| 1418 | else => unreachable, | 1422 | else => unreachable, |
| 1419 | }), | 1423 | }), |
| 1420 | 1424 | ||
| 1421 | .Pointer => { | 1425 | .Pointer => { |
| 1422 | const info = ty.ptrInfo().data; | 1426 | const info = ty.ptrInfo(mod); |
| 1423 | switch (info.size) { | 1427 | switch (info.size) { |
| 1424 | .Slice => { | 1428 | .Slice => { |
| 1425 | if (switch (kind) { | 1429 | if (switch (kind) { |
| ... | @@ -1427,19 +1431,18 @@ pub const CType = extern union { | ... | @@ -1427,19 +1431,18 @@ pub const CType = extern union { |
| 1427 | .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward), | 1431 | .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward), |
| 1428 | .payload => unreachable, | 1432 | .payload => unreachable, |
| 1429 | }) |fwd_idx| { | 1433 | }) |fwd_idx| { |
| 1430 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1434 | const ptr_ty = ty.slicePtrFieldType(mod); |
| 1431 | const ptr_ty = ty.slicePtrFieldType(&buf); | ||
| 1432 | if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| { | 1435 | if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| { |
| 1433 | self.storage = .{ .anon = undefined }; | 1436 | self.storage = .{ .anon = undefined }; |
| 1434 | self.storage.anon.fields[0] = .{ | 1437 | self.storage.anon.fields[0] = .{ |
| 1435 | .name = "ptr", | 1438 | .name = "ptr", |
| 1436 | .type = ptr_idx, | 1439 | .type = ptr_idx, |
| 1437 | .alignas = AlignAs.abiAlign(ptr_ty, target), | 1440 | .alignas = AlignAs.abiAlign(ptr_ty, mod), |
| 1438 | }; | 1441 | }; |
| 1439 | self.storage.anon.fields[1] = .{ | 1442 | self.storage.anon.fields[1] = .{ |
| 1440 | .name = "len", | 1443 | .name = "len", |
| 1441 | .type = Tag.uintptr_t.toIndex(), | 1444 | .type = Tag.uintptr_t.toIndex(), |
| 1442 | .alignas = AlignAs.abiAlign(Type.usize, target), | 1445 | .alignas = AlignAs.abiAlign(Type.usize, mod), |
| 1443 | }; | 1446 | }; |
| 1444 | self.initAnon(kind, fwd_idx, 2); | 1447 | self.initAnon(kind, fwd_idx, 2); |
| 1445 | } else self.init(switch (kind) { | 1448 | } else self.init(switch (kind) { |
| ... | @@ -1462,16 +1465,12 @@ pub const CType = extern union { | ... | @@ -1462,16 +1465,12 @@ pub const CType = extern union { |
| 1462 | }, | 1465 | }, |
| 1463 | }; | 1466 | }; |
| 1464 | 1467 | ||
| 1465 | var host_int_pl = Type.Payload.Bits{ | ||
| 1466 | .base = .{ .tag = .int_unsigned }, | ||
| 1467 | .data = info.host_size * 8, | ||
| 1468 | }; | ||
| 1469 | const pointee_ty = if (info.host_size > 0 and info.vector_index == .none) | 1468 | const pointee_ty = if (info.host_size > 0 and info.vector_index == .none) |
| 1470 | Type.initPayload(&host_int_pl.base) | 1469 | try mod.intType(.unsigned, info.host_size * 8) |
| 1471 | else | 1470 | else |
| 1472 | info.pointee_type; | 1471 | info.pointee_type; |
| 1473 | 1472 | ||
| 1474 | if (if (info.size == .C and pointee_ty.tag() == .u8) | 1473 | if (if (info.size == .C and pointee_ty.ip_index == .u8_type) |
| 1475 | Tag.char.toIndex() | 1474 | Tag.char.toIndex() |
| 1476 | else | 1475 | else |
| 1477 | try lookup.typeToIndex(pointee_ty, .forward)) |child_idx| | 1476 | try lookup.typeToIndex(pointee_ty, .forward)) |child_idx| |
| ... | @@ -1486,26 +1485,24 @@ pub const CType = extern union { | ... | @@ -1486,26 +1485,24 @@ pub const CType = extern union { |
| 1486 | } | 1485 | } |
| 1487 | }, | 1486 | }, |
| 1488 | 1487 | ||
| 1489 | .Struct, .Union => |zig_ty_tag| if (ty.containerLayout() == .Packed) { | 1488 | .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(mod) == .Packed) { |
| 1490 | if (ty.castTag(.@"struct")) |struct_obj| { | 1489 | if (mod.typeToStruct(ty)) |struct_obj| { |
| 1491 | try self.initType(struct_obj.data.backing_int_ty, kind, lookup); | 1490 | try self.initType(struct_obj.backing_int_ty, kind, lookup); |
| 1492 | } else { | 1491 | } else { |
| 1493 | var buf: Type.Payload.Bits = .{ | 1492 | const bits = @intCast(u16, ty.bitSize(mod)); |
| 1494 | .base = .{ .tag = .int_unsigned }, | 1493 | const int_ty = try mod.intType(.unsigned, bits); |
| 1495 | .data = @intCast(u16, ty.bitSize(target)), | 1494 | try self.initType(int_ty, kind, lookup); |
| 1496 | }; | ||
| 1497 | try self.initType(Type.initPayload(&buf.base), kind, lookup); | ||
| 1498 | } | 1495 | } |
| 1499 | } else if (ty.isTupleOrAnonStruct()) { | 1496 | } else if (ty.isTupleOrAnonStruct(mod)) { |
| 1500 | if (lookup.isMutable()) { | 1497 | if (lookup.isMutable()) { |
| 1501 | for (0..switch (zig_ty_tag) { | 1498 | for (0..switch (zig_ty_tag) { |
| 1502 | .Struct => ty.structFieldCount(), | 1499 | .Struct => ty.structFieldCount(mod), |
| 1503 | .Union => ty.unionFields().count(), | 1500 | .Union => ty.unionFields(mod).count(), |
| 1504 | else => unreachable, | 1501 | else => unreachable, |
| 1505 | }) |field_i| { | 1502 | }) |field_i| { |
| 1506 | const field_ty = ty.structFieldType(field_i); | 1503 | const field_ty = ty.structFieldType(field_i, mod); |
| 1507 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or | 1504 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or |
| 1508 | !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 1505 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 1509 | _ = try lookup.typeToIndex(field_ty, switch (kind) { | 1506 | _ = try lookup.typeToIndex(field_ty, switch (kind) { |
| 1510 | .forward, .forward_parameter => .forward, | 1507 | .forward, .forward_parameter => .forward, |
| 1511 | .complete, .parameter => .complete, | 1508 | .complete, .parameter => .complete, |
| ... | @@ -1533,14 +1530,14 @@ pub const CType = extern union { | ... | @@ -1533,14 +1530,14 @@ pub const CType = extern union { |
| 1533 | .payload => unreachable, | 1530 | .payload => unreachable, |
| 1534 | }); | 1531 | }); |
| 1535 | } else { | 1532 | } else { |
| 1536 | const tag_ty = ty.unionTagTypeSafety(); | 1533 | const tag_ty = ty.unionTagTypeSafety(mod); |
| 1537 | const is_tagged_union_wrapper = kind != .payload and tag_ty != null; | 1534 | const is_tagged_union_wrapper = kind != .payload and tag_ty != null; |
| 1538 | const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper; | 1535 | const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper; |
| 1539 | switch (kind) { | 1536 | switch (kind) { |
| 1540 | .forward, .forward_parameter => { | 1537 | .forward, .forward_parameter => { |
| 1541 | self.storage = .{ .fwd = .{ | 1538 | self.storage = .{ .fwd = .{ |
| 1542 | .base = .{ .tag = if (is_struct) .fwd_struct else .fwd_union }, | 1539 | .base = .{ .tag = if (is_struct) .fwd_struct else .fwd_union }, |
| 1543 | .data = ty.getOwnerDecl(), | 1540 | .data = ty.getOwnerDecl(mod), |
| 1544 | } }; | 1541 | } }; |
| 1545 | self.value = .{ .cty = initPayload(&self.storage.fwd) }; | 1542 | self.value = .{ .cty = initPayload(&self.storage.fwd) }; |
| 1546 | }, | 1543 | }, |
| ... | @@ -1555,7 +1552,7 @@ pub const CType = extern union { | ... | @@ -1555,7 +1552,7 @@ pub const CType = extern union { |
| 1555 | self.storage.anon.fields[field_count] = .{ | 1552 | self.storage.anon.fields[field_count] = .{ |
| 1556 | .name = "payload", | 1553 | .name = "payload", |
| 1557 | .type = payload_idx.?, | 1554 | .type = payload_idx.?, |
| 1558 | .alignas = AlignAs.unionPayloadAlign(ty, target), | 1555 | .alignas = AlignAs.unionPayloadAlign(ty, mod), |
| 1559 | }; | 1556 | }; |
| 1560 | field_count += 1; | 1557 | field_count += 1; |
| 1561 | } | 1558 | } |
| ... | @@ -1563,7 +1560,7 @@ pub const CType = extern union { | ... | @@ -1563,7 +1560,7 @@ pub const CType = extern union { |
| 1563 | self.storage.anon.fields[field_count] = .{ | 1560 | self.storage.anon.fields[field_count] = .{ |
| 1564 | .name = "tag", | 1561 | .name = "tag", |
| 1565 | .type = tag_idx.?, | 1562 | .type = tag_idx.?, |
| 1566 | .alignas = AlignAs.abiAlign(tag_ty.?, target), | 1563 | .alignas = AlignAs.abiAlign(tag_ty.?, mod), |
| 1567 | }; | 1564 | }; |
| 1568 | field_count += 1; | 1565 | field_count += 1; |
| 1569 | } | 1566 | } |
| ... | @@ -1576,19 +1573,19 @@ pub const CType = extern union { | ... | @@ -1576,19 +1573,19 @@ pub const CType = extern union { |
| 1576 | } }; | 1573 | } }; |
| 1577 | self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) }; | 1574 | self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) }; |
| 1578 | } else self.init(.@"struct"); | 1575 | } else self.init(.@"struct"); |
| 1579 | } else if (kind == .payload and ty.unionHasAllZeroBitFieldTypes()) { | 1576 | } else if (kind == .payload and ty.unionHasAllZeroBitFieldTypes(mod)) { |
| 1580 | self.init(.void); | 1577 | self.init(.void); |
| 1581 | } else { | 1578 | } else { |
| 1582 | var is_packed = false; | 1579 | var is_packed = false; |
| 1583 | for (0..switch (zig_ty_tag) { | 1580 | for (0..switch (zig_ty_tag) { |
| 1584 | .Struct => ty.structFieldCount(), | 1581 | .Struct => ty.structFieldCount(mod), |
| 1585 | .Union => ty.unionFields().count(), | 1582 | .Union => ty.unionFields(mod).count(), |
| 1586 | else => unreachable, | 1583 | else => unreachable, |
| 1587 | }) |field_i| { | 1584 | }) |field_i| { |
| 1588 | const field_ty = ty.structFieldType(field_i); | 1585 | const field_ty = ty.structFieldType(field_i, mod); |
| 1589 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 1586 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 1590 | 1587 | ||
| 1591 | const field_align = AlignAs.fieldAlign(ty, field_i, target); | 1588 | const field_align = AlignAs.fieldAlign(ty, field_i, mod); |
| 1592 | if (field_align.@"align" < field_align.abi) { | 1589 | if (field_align.@"align" < field_align.abi) { |
| 1593 | is_packed = true; | 1590 | is_packed = true; |
| 1594 | if (!lookup.isMutable()) break; | 1591 | if (!lookup.isMutable()) break; |
| ... | @@ -1627,9 +1624,9 @@ pub const CType = extern union { | ... | @@ -1627,9 +1624,9 @@ pub const CType = extern union { |
| 1627 | .Vector => .vector, | 1624 | .Vector => .vector, |
| 1628 | else => unreachable, | 1625 | else => unreachable, |
| 1629 | }; | 1626 | }; |
| 1630 | if (try lookup.typeToIndex(ty.childType(), kind)) |child_idx| { | 1627 | if (try lookup.typeToIndex(ty.childType(mod), kind)) |child_idx| { |
| 1631 | self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{ | 1628 | self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{ |
| 1632 | .len = ty.arrayLenIncludingSentinel(), | 1629 | .len = ty.arrayLenIncludingSentinel(mod), |
| 1633 | .elem_type = child_idx, | 1630 | .elem_type = child_idx, |
| 1634 | } } }; | 1631 | } } }; |
| 1635 | self.value = .{ .cty = initPayload(&self.storage.seq) }; | 1632 | self.value = .{ .cty = initPayload(&self.storage.seq) }; |
| ... | @@ -1641,10 +1638,9 @@ pub const CType = extern union { | ... | @@ -1641,10 +1638,9 @@ pub const CType = extern union { |
| 1641 | }, | 1638 | }, |
| 1642 | 1639 | ||
| 1643 | .Optional => { | 1640 | .Optional => { |
| 1644 | var buf: Type.Payload.ElemType = undefined; | 1641 | const payload_ty = ty.optionalChild(mod); |
| 1645 | const payload_ty = ty.optionalChild(&buf); | 1642 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1646 | if (payload_ty.hasRuntimeBitsIgnoreComptime()) { | 1643 | if (ty.optionalReprIsPayload(mod)) { |
| 1647 | if (ty.optionalReprIsPayload()) { | ||
| 1648 | try self.initType(payload_ty, kind, lookup); | 1644 | try self.initType(payload_ty, kind, lookup); |
| 1649 | } else if (switch (kind) { | 1645 | } else if (switch (kind) { |
| 1650 | .forward, .forward_parameter => @as(Index, undefined), | 1646 | .forward, .forward_parameter => @as(Index, undefined), |
| ... | @@ -1661,12 +1657,12 @@ pub const CType = extern union { | ... | @@ -1661,12 +1657,12 @@ pub const CType = extern union { |
| 1661 | self.storage.anon.fields[0] = .{ | 1657 | self.storage.anon.fields[0] = .{ |
| 1662 | .name = "payload", | 1658 | .name = "payload", |
| 1663 | .type = payload_idx, | 1659 | .type = payload_idx, |
| 1664 | .alignas = AlignAs.abiAlign(payload_ty, target), | 1660 | .alignas = AlignAs.abiAlign(payload_ty, mod), |
| 1665 | }; | 1661 | }; |
| 1666 | self.storage.anon.fields[1] = .{ | 1662 | self.storage.anon.fields[1] = .{ |
| 1667 | .name = "is_null", | 1663 | .name = "is_null", |
| 1668 | .type = Tag.bool.toIndex(), | 1664 | .type = Tag.bool.toIndex(), |
| 1669 | .alignas = AlignAs.abiAlign(Type.bool, target), | 1665 | .alignas = AlignAs.abiAlign(Type.bool, mod), |
| 1670 | }; | 1666 | }; |
| 1671 | self.initAnon(kind, fwd_idx, 2); | 1667 | self.initAnon(kind, fwd_idx, 2); |
| 1672 | } else self.init(switch (kind) { | 1668 | } else self.init(switch (kind) { |
| ... | @@ -1684,14 +1680,14 @@ pub const CType = extern union { | ... | @@ -1684,14 +1680,14 @@ pub const CType = extern union { |
| 1684 | .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward), | 1680 | .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward), |
| 1685 | .payload => unreachable, | 1681 | .payload => unreachable, |
| 1686 | }) |fwd_idx| { | 1682 | }) |fwd_idx| { |
| 1687 | const payload_ty = ty.errorUnionPayload(); | 1683 | const payload_ty = ty.errorUnionPayload(mod); |
| 1688 | if (try lookup.typeToIndex(payload_ty, switch (kind) { | 1684 | if (try lookup.typeToIndex(payload_ty, switch (kind) { |
| 1689 | .forward, .forward_parameter => .forward, | 1685 | .forward, .forward_parameter => .forward, |
| 1690 | .complete, .parameter => .complete, | 1686 | .complete, .parameter => .complete, |
| 1691 | .global => .global, | 1687 | .global => .global, |
| 1692 | .payload => unreachable, | 1688 | .payload => unreachable, |
| 1693 | })) |payload_idx| { | 1689 | })) |payload_idx| { |
| 1694 | const error_ty = ty.errorUnionSet(); | 1690 | const error_ty = ty.errorUnionSet(mod); |
| 1695 | if (payload_idx == Tag.void.toIndex()) { | 1691 | if (payload_idx == Tag.void.toIndex()) { |
| 1696 | try self.initType(error_ty, kind, lookup); | 1692 | try self.initType(error_ty, kind, lookup); |
| 1697 | } else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| { | 1693 | } else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| { |
| ... | @@ -1699,12 +1695,12 @@ pub const CType = extern union { | ... | @@ -1699,12 +1695,12 @@ pub const CType = extern union { |
| 1699 | self.storage.anon.fields[0] = .{ | 1695 | self.storage.anon.fields[0] = .{ |
| 1700 | .name = "payload", | 1696 | .name = "payload", |
| 1701 | .type = payload_idx, | 1697 | .type = payload_idx, |
| 1702 | .alignas = AlignAs.abiAlign(payload_ty, target), | 1698 | .alignas = AlignAs.abiAlign(payload_ty, mod), |
| 1703 | }; | 1699 | }; |
| 1704 | self.storage.anon.fields[1] = .{ | 1700 | self.storage.anon.fields[1] = .{ |
| 1705 | .name = "error", | 1701 | .name = "error", |
| 1706 | .type = error_idx, | 1702 | .type = error_idx, |
| 1707 | .alignas = AlignAs.abiAlign(error_ty, target), | 1703 | .alignas = AlignAs.abiAlign(error_ty, mod), |
| 1708 | }; | 1704 | }; |
| 1709 | self.initAnon(kind, fwd_idx, 2); | 1705 | self.initAnon(kind, fwd_idx, 2); |
| 1710 | } else self.init(switch (kind) { | 1706 | } else self.init(switch (kind) { |
| ... | @@ -1723,7 +1719,7 @@ pub const CType = extern union { | ... | @@ -1723,7 +1719,7 @@ pub const CType = extern union { |
| 1723 | .Opaque => self.init(.void), | 1719 | .Opaque => self.init(.void), |
| 1724 | 1720 | ||
| 1725 | .Fn => { | 1721 | .Fn => { |
| 1726 | const info = ty.fnInfo(); | 1722 | const info = mod.typeToFunc(ty).?; |
| 1727 | if (!info.is_generic) { | 1723 | if (!info.is_generic) { |
| 1728 | if (lookup.isMutable()) { | 1724 | if (lookup.isMutable()) { |
| 1729 | const param_kind: Kind = switch (kind) { | 1725 | const param_kind: Kind = switch (kind) { |
| ... | @@ -1731,10 +1727,10 @@ pub const CType = extern union { | ... | @@ -1731,10 +1727,10 @@ pub const CType = extern union { |
| 1731 | .complete, .parameter, .global => .parameter, | 1727 | .complete, .parameter, .global => .parameter, |
| 1732 | .payload => unreachable, | 1728 | .payload => unreachable, |
| 1733 | }; | 1729 | }; |
| 1734 | _ = try lookup.typeToIndex(info.return_type, param_kind); | 1730 | _ = try lookup.typeToIndex(info.return_type.toType(), param_kind); |
| 1735 | for (info.param_types) |param_type| { | 1731 | for (info.param_types) |param_type| { |
| 1736 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | 1732 | if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 1737 | _ = try lookup.typeToIndex(param_type, param_kind); | 1733 | _ = try lookup.typeToIndex(param_type.toType(), param_kind); |
| 1738 | } | 1734 | } |
| 1739 | } | 1735 | } |
| 1740 | self.init(if (info.is_var_args) .varargs_function else .function); | 1736 | self.init(if (info.is_var_args) .varargs_function else .function); |
| ... | @@ -1900,16 +1896,16 @@ pub const CType = extern union { | ... | @@ -1900,16 +1896,16 @@ pub const CType = extern union { |
| 1900 | } | 1896 | } |
| 1901 | } | 1897 | } |
| 1902 | 1898 | ||
| 1903 | fn createFromType(store: *Store.Promoted, ty: Type, target: Target, kind: Kind) !CType { | 1899 | fn createFromType(store: *Store.Promoted, ty: Type, mod: *Module, kind: Kind) !CType { |
| 1904 | var convert: Convert = undefined; | 1900 | var convert: Convert = undefined; |
| 1905 | try convert.initType(ty, kind, .{ .imm = .{ .set = &store.set, .target = target } }); | 1901 | try convert.initType(ty, kind, .{ .imm = .{ .set = &store.set, .mod = mod } }); |
| 1906 | return createFromConvert(store, ty, target, kind, &convert); | 1902 | return createFromConvert(store, ty, mod, kind, &convert); |
| 1907 | } | 1903 | } |
| 1908 | 1904 | ||
| 1909 | fn createFromConvert( | 1905 | fn createFromConvert( |
| 1910 | store: *Store.Promoted, | 1906 | store: *Store.Promoted, |
| 1911 | ty: Type, | 1907 | ty: Type, |
| 1912 | target: Target, | 1908 | mod: *Module, |
| 1913 | kind: Kind, | 1909 | kind: Kind, |
| 1914 | convert: Convert, | 1910 | convert: Convert, |
| 1915 | ) !CType { | 1911 | ) !CType { |
| ... | @@ -1930,44 +1926,44 @@ pub const CType = extern union { | ... | @@ -1930,44 +1926,44 @@ pub const CType = extern union { |
| 1930 | .packed_struct, | 1926 | .packed_struct, |
| 1931 | .packed_union, | 1927 | .packed_union, |
| 1932 | => { | 1928 | => { |
| 1933 | const zig_ty_tag = ty.zigTypeTag(); | 1929 | const zig_ty_tag = ty.zigTypeTag(mod); |
| 1934 | const fields_len = switch (zig_ty_tag) { | 1930 | const fields_len = switch (zig_ty_tag) { |
| 1935 | .Struct => ty.structFieldCount(), | 1931 | .Struct => ty.structFieldCount(mod), |
| 1936 | .Union => ty.unionFields().count(), | 1932 | .Union => ty.unionFields(mod).count(), |
| 1937 | else => unreachable, | 1933 | else => unreachable, |
| 1938 | }; | 1934 | }; |
| 1939 | 1935 | ||
| 1940 | var c_fields_len: usize = 0; | 1936 | var c_fields_len: usize = 0; |
| 1941 | for (0..fields_len) |field_i| { | 1937 | for (0..fields_len) |field_i| { |
| 1942 | const field_ty = ty.structFieldType(field_i); | 1938 | const field_ty = ty.structFieldType(field_i, mod); |
| 1943 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or | 1939 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or |
| 1944 | !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 1940 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 1945 | c_fields_len += 1; | 1941 | c_fields_len += 1; |
| 1946 | } | 1942 | } |
| 1947 | 1943 | ||
| 1948 | const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len); | 1944 | const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len); |
| 1949 | var c_field_i: usize = 0; | 1945 | var c_field_i: usize = 0; |
| 1950 | for (0..fields_len) |field_i| { | 1946 | for (0..fields_len) |field_i| { |
| 1951 | const field_ty = ty.structFieldType(field_i); | 1947 | const field_ty = ty.structFieldType(field_i, mod); |
| 1952 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or | 1948 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or |
| 1953 | !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 1949 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 1954 | 1950 | ||
| 1955 | defer c_field_i += 1; | 1951 | defer c_field_i += 1; |
| 1956 | fields_pl[c_field_i] = .{ | 1952 | fields_pl[c_field_i] = .{ |
| 1957 | .name = try if (ty.isSimpleTuple()) | 1953 | .name = try if (ty.isSimpleTuple(mod)) |
| 1958 | std.fmt.allocPrintZ(arena, "f{}", .{field_i}) | 1954 | std.fmt.allocPrintZ(arena, "f{}", .{field_i}) |
| 1959 | else | 1955 | else |
| 1960 | arena.dupeZ(u8, switch (zig_ty_tag) { | 1956 | arena.dupeZ(u8, mod.intern_pool.stringToSlice(switch (zig_ty_tag) { |
| 1961 | .Struct => ty.structFieldName(field_i), | 1957 | .Struct => ty.structFieldName(field_i, mod), |
| 1962 | .Union => ty.unionFields().keys()[field_i], | 1958 | .Union => ty.unionFields(mod).keys()[field_i], |
| 1963 | else => unreachable, | 1959 | else => unreachable, |
| 1964 | }), | 1960 | })), |
| 1965 | .type = store.set.typeToIndex(field_ty, target, switch (kind) { | 1961 | .type = store.set.typeToIndex(field_ty, mod, switch (kind) { |
| 1966 | .forward, .forward_parameter => .forward, | 1962 | .forward, .forward_parameter => .forward, |
| 1967 | .complete, .parameter, .payload => .complete, | 1963 | .complete, .parameter, .payload => .complete, |
| 1968 | .global => .global, | 1964 | .global => .global, |
| 1969 | }).?, | 1965 | }).?, |
| 1970 | .alignas = AlignAs.fieldAlign(ty, field_i, target), | 1966 | .alignas = AlignAs.fieldAlign(ty, field_i, mod), |
| 1971 | }; | 1967 | }; |
| 1972 | } | 1968 | } |
| 1973 | 1969 | ||
| ... | @@ -1988,8 +1984,8 @@ pub const CType = extern union { | ... | @@ -1988,8 +1984,8 @@ pub const CType = extern union { |
| 1988 | const unnamed_pl = try arena.create(Payload.Unnamed); | 1984 | const unnamed_pl = try arena.create(Payload.Unnamed); |
| 1989 | unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{ | 1985 | unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{ |
| 1990 | .fields = fields_pl, | 1986 | .fields = fields_pl, |
| 1991 | .owner_decl = ty.getOwnerDecl(), | 1987 | .owner_decl = ty.getOwnerDecl(mod), |
| 1992 | .id = if (ty.unionTagTypeSafety()) |_| 0 else unreachable, | 1988 | .id = if (ty.unionTagTypeSafety(mod)) |_| 0 else unreachable, |
| 1993 | } }; | 1989 | } }; |
| 1994 | return initPayload(unnamed_pl); | 1990 | return initPayload(unnamed_pl); |
| 1995 | }, | 1991 | }, |
| ... | @@ -2004,7 +2000,7 @@ pub const CType = extern union { | ... | @@ -2004,7 +2000,7 @@ pub const CType = extern union { |
| 2004 | const struct_pl = try arena.create(Payload.Aggregate); | 2000 | const struct_pl = try arena.create(Payload.Aggregate); |
| 2005 | struct_pl.* = .{ .base = .{ .tag = t }, .data = .{ | 2001 | struct_pl.* = .{ .base = .{ .tag = t }, .data = .{ |
| 2006 | .fields = fields_pl, | 2002 | .fields = fields_pl, |
| 2007 | .fwd_decl = store.set.typeToIndex(ty, target, .forward).?, | 2003 | .fwd_decl = store.set.typeToIndex(ty, mod, .forward).?, |
| 2008 | } }; | 2004 | } }; |
| 2009 | return initPayload(struct_pl); | 2005 | return initPayload(struct_pl); |
| 2010 | }, | 2006 | }, |
| ... | @@ -2016,7 +2012,7 @@ pub const CType = extern union { | ... | @@ -2016,7 +2012,7 @@ pub const CType = extern union { |
| 2016 | .function, | 2012 | .function, |
| 2017 | .varargs_function, | 2013 | .varargs_function, |
| 2018 | => { | 2014 | => { |
| 2019 | const info = ty.fnInfo(); | 2015 | const info = mod.typeToFunc(ty).?; |
| 2020 | assert(!info.is_generic); | 2016 | assert(!info.is_generic); |
| 2021 | const param_kind: Kind = switch (kind) { | 2017 | const param_kind: Kind = switch (kind) { |
| 2022 | .forward, .forward_parameter => .forward_parameter, | 2018 | .forward, .forward_parameter => .forward_parameter, |
| ... | @@ -2026,21 +2022,21 @@ pub const CType = extern union { | ... | @@ -2026,21 +2022,21 @@ pub const CType = extern union { |
| 2026 | 2022 | ||
| 2027 | var c_params_len: usize = 0; | 2023 | var c_params_len: usize = 0; |
| 2028 | for (info.param_types) |param_type| { | 2024 | for (info.param_types) |param_type| { |
| 2029 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | 2025 | if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 2030 | c_params_len += 1; | 2026 | c_params_len += 1; |
| 2031 | } | 2027 | } |
| 2032 | 2028 | ||
| 2033 | const params_pl = try arena.alloc(Index, c_params_len); | 2029 | const params_pl = try arena.alloc(Index, c_params_len); |
| 2034 | var c_param_i: usize = 0; | 2030 | var c_param_i: usize = 0; |
| 2035 | for (info.param_types) |param_type| { | 2031 | for (info.param_types) |param_type| { |
| 2036 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | 2032 | if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 2037 | params_pl[c_param_i] = store.set.typeToIndex(param_type, target, param_kind).?; | 2033 | params_pl[c_param_i] = store.set.typeToIndex(param_type.toType(), mod, param_kind).?; |
| 2038 | c_param_i += 1; | 2034 | c_param_i += 1; |
| 2039 | } | 2035 | } |
| 2040 | 2036 | ||
| 2041 | const fn_pl = try arena.create(Payload.Function); | 2037 | const fn_pl = try arena.create(Payload.Function); |
| 2042 | fn_pl.* = .{ .base = .{ .tag = t }, .data = .{ | 2038 | fn_pl.* = .{ .base = .{ .tag = t }, .data = .{ |
| 2043 | .return_type = store.set.typeToIndex(info.return_type, target, param_kind).?, | 2039 | .return_type = store.set.typeToIndex(info.return_type.toType(), mod, param_kind).?, |
| 2044 | .param_types = params_pl, | 2040 | .param_types = params_pl, |
| 2045 | } }; | 2041 | } }; |
| 2046 | return initPayload(fn_pl); | 2042 | return initPayload(fn_pl); |
| ... | @@ -2067,33 +2063,33 @@ pub const CType = extern union { | ... | @@ -2067,33 +2063,33 @@ pub const CType = extern union { |
| 2067 | } | 2063 | } |
| 2068 | 2064 | ||
| 2069 | pub fn eql(self: @This(), ty: Type, cty: CType) bool { | 2065 | pub fn eql(self: @This(), ty: Type, cty: CType) bool { |
| 2066 | const mod = self.lookup.getModule(); | ||
| 2070 | switch (self.convert.value) { | 2067 | switch (self.convert.value) { |
| 2071 | .cty => |c| return c.eql(cty), | 2068 | .cty => |c| return c.eql(cty), |
| 2072 | .tag => |t| { | 2069 | .tag => |t| { |
| 2073 | if (t != cty.tag()) return false; | 2070 | if (t != cty.tag()) return false; |
| 2074 | 2071 | ||
| 2075 | const target = self.lookup.getTarget(); | ||
| 2076 | switch (t) { | 2072 | switch (t) { |
| 2077 | .fwd_anon_struct, | 2073 | .fwd_anon_struct, |
| 2078 | .fwd_anon_union, | 2074 | .fwd_anon_union, |
| 2079 | => { | 2075 | => { |
| 2080 | if (!ty.isTupleOrAnonStruct()) return false; | 2076 | if (!ty.isTupleOrAnonStruct(mod)) return false; |
| 2081 | 2077 | ||
| 2082 | var name_buf: [ | 2078 | var name_buf: [ |
| 2083 | std.fmt.count("f{}", .{std.math.maxInt(usize)}) | 2079 | std.fmt.count("f{}", .{std.math.maxInt(usize)}) |
| 2084 | ]u8 = undefined; | 2080 | ]u8 = undefined; |
| 2085 | const c_fields = cty.cast(Payload.Fields).?.data; | 2081 | const c_fields = cty.cast(Payload.Fields).?.data; |
| 2086 | 2082 | ||
| 2087 | const zig_ty_tag = ty.zigTypeTag(); | 2083 | const zig_ty_tag = ty.zigTypeTag(mod); |
| 2088 | var c_field_i: usize = 0; | 2084 | var c_field_i: usize = 0; |
| 2089 | for (0..switch (zig_ty_tag) { | 2085 | for (0..switch (zig_ty_tag) { |
| 2090 | .Struct => ty.structFieldCount(), | 2086 | .Struct => ty.structFieldCount(mod), |
| 2091 | .Union => ty.unionFields().count(), | 2087 | .Union => ty.unionFields(mod).count(), |
| 2092 | else => unreachable, | 2088 | else => unreachable, |
| 2093 | }) |field_i| { | 2089 | }) |field_i| { |
| 2094 | const field_ty = ty.structFieldType(field_i); | 2090 | const field_ty = ty.structFieldType(field_i, mod); |
| 2095 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or | 2091 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or |
| 2096 | !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 2092 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 2097 | 2093 | ||
| 2098 | defer c_field_i += 1; | 2094 | defer c_field_i += 1; |
| 2099 | const c_field = &c_fields[c_field_i]; | 2095 | const c_field = &c_fields[c_field_i]; |
| ... | @@ -2105,15 +2101,16 @@ pub const CType = extern union { | ... | @@ -2105,15 +2101,16 @@ pub const CType = extern union { |
| 2105 | .payload => unreachable, | 2101 | .payload => unreachable, |
| 2106 | }) or !mem.eql( | 2102 | }) or !mem.eql( |
| 2107 | u8, | 2103 | u8, |
| 2108 | if (ty.isSimpleTuple()) | 2104 | if (ty.isSimpleTuple(mod)) |
| 2109 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable | 2105 | std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2110 | else switch (zig_ty_tag) { | 2106 | else |
| 2111 | .Struct => ty.structFieldName(field_i), | 2107 | mod.intern_pool.stringToSlice(switch (zig_ty_tag) { |
| 2112 | .Union => ty.unionFields().keys()[field_i], | 2108 | .Struct => ty.structFieldName(field_i, mod), |
| 2113 | else => unreachable, | 2109 | .Union => ty.unionFields(mod).keys()[field_i], |
| 2114 | }, | 2110 | else => unreachable, |
| 2111 | }), | ||
| 2115 | mem.span(c_field.name), | 2112 | mem.span(c_field.name), |
| 2116 | ) or AlignAs.fieldAlign(ty, field_i, target).@"align" != | 2113 | ) or AlignAs.fieldAlign(ty, field_i, mod).@"align" != |
| 2117 | c_field.alignas.@"align") return false; | 2114 | c_field.alignas.@"align") return false; |
| 2118 | } | 2115 | } |
| 2119 | return true; | 2116 | return true; |
| ... | @@ -2125,9 +2122,9 @@ pub const CType = extern union { | ... | @@ -2125,9 +2122,9 @@ pub const CType = extern union { |
| 2125 | .packed_unnamed_union, | 2122 | .packed_unnamed_union, |
| 2126 | => switch (self.kind) { | 2123 | => switch (self.kind) { |
| 2127 | .forward, .forward_parameter, .complete, .parameter, .global => unreachable, | 2124 | .forward, .forward_parameter, .complete, .parameter, .global => unreachable, |
| 2128 | .payload => if (ty.unionTagTypeSafety()) |_| { | 2125 | .payload => if (ty.unionTagTypeSafety(mod)) |_| { |
| 2129 | const data = cty.cast(Payload.Unnamed).?.data; | 2126 | const data = cty.cast(Payload.Unnamed).?.data; |
| 2130 | return ty.getOwnerDecl() == data.owner_decl and data.id == 0; | 2127 | return ty.getOwnerDecl(mod) == data.owner_decl and data.id == 0; |
| 2131 | } else unreachable, | 2128 | } else unreachable, |
| 2132 | }, | 2129 | }, |
| 2133 | 2130 | ||
| ... | @@ -2146,9 +2143,9 @@ pub const CType = extern union { | ... | @@ -2146,9 +2143,9 @@ pub const CType = extern union { |
| 2146 | .function, | 2143 | .function, |
| 2147 | .varargs_function, | 2144 | .varargs_function, |
| 2148 | => { | 2145 | => { |
| 2149 | if (ty.zigTypeTag() != .Fn) return false; | 2146 | if (ty.zigTypeTag(mod) != .Fn) return false; |
| 2150 | 2147 | ||
| 2151 | const info = ty.fnInfo(); | 2148 | const info = mod.typeToFunc(ty).?; |
| 2152 | assert(!info.is_generic); | 2149 | assert(!info.is_generic); |
| 2153 | const data = cty.cast(Payload.Function).?.data; | 2150 | const data = cty.cast(Payload.Function).?.data; |
| 2154 | const param_kind: Kind = switch (self.kind) { | 2151 | const param_kind: Kind = switch (self.kind) { |
| ... | @@ -2157,18 +2154,18 @@ pub const CType = extern union { | ... | @@ -2157,18 +2154,18 @@ pub const CType = extern union { |
| 2157 | .payload => unreachable, | 2154 | .payload => unreachable, |
| 2158 | }; | 2155 | }; |
| 2159 | 2156 | ||
| 2160 | if (!self.eqlRecurse(info.return_type, data.return_type, param_kind)) | 2157 | if (!self.eqlRecurse(info.return_type.toType(), data.return_type, param_kind)) |
| 2161 | return false; | 2158 | return false; |
| 2162 | 2159 | ||
| 2163 | var c_param_i: usize = 0; | 2160 | var c_param_i: usize = 0; |
| 2164 | for (info.param_types) |param_type| { | 2161 | for (info.param_types) |param_type| { |
| 2165 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | 2162 | if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 2166 | 2163 | ||
| 2167 | if (c_param_i >= data.param_types.len) return false; | 2164 | if (c_param_i >= data.param_types.len) return false; |
| 2168 | const param_cty = data.param_types[c_param_i]; | 2165 | const param_cty = data.param_types[c_param_i]; |
| 2169 | c_param_i += 1; | 2166 | c_param_i += 1; |
| 2170 | 2167 | ||
| 2171 | if (!self.eqlRecurse(param_type, param_cty, param_kind)) | 2168 | if (!self.eqlRecurse(param_type.toType(), param_cty, param_kind)) |
| 2172 | return false; | 2169 | return false; |
| 2173 | } | 2170 | } |
| 2174 | return c_param_i == data.param_types.len; | 2171 | return c_param_i == data.param_types.len; |
| ... | @@ -2202,7 +2199,7 @@ pub const CType = extern union { | ... | @@ -2202,7 +2199,7 @@ pub const CType = extern union { |
| 2202 | .tag => |t| { | 2199 | .tag => |t| { |
| 2203 | autoHash(hasher, t); | 2200 | autoHash(hasher, t); |
| 2204 | 2201 | ||
| 2205 | const target = self.lookup.getTarget(); | 2202 | const mod = self.lookup.getModule(); |
| 2206 | switch (t) { | 2203 | switch (t) { |
| 2207 | .fwd_anon_struct, | 2204 | .fwd_anon_struct, |
| 2208 | .fwd_anon_union, | 2205 | .fwd_anon_union, |
| ... | @@ -2211,15 +2208,15 @@ pub const CType = extern union { | ... | @@ -2211,15 +2208,15 @@ pub const CType = extern union { |
| 2211 | std.fmt.count("f{}", .{std.math.maxInt(usize)}) | 2208 | std.fmt.count("f{}", .{std.math.maxInt(usize)}) |
| 2212 | ]u8 = undefined; | 2209 | ]u8 = undefined; |
| 2213 | 2210 | ||
| 2214 | const zig_ty_tag = ty.zigTypeTag(); | 2211 | const zig_ty_tag = ty.zigTypeTag(mod); |
| 2215 | for (0..switch (ty.zigTypeTag()) { | 2212 | for (0..switch (ty.zigTypeTag(mod)) { |
| 2216 | .Struct => ty.structFieldCount(), | 2213 | .Struct => ty.structFieldCount(mod), |
| 2217 | .Union => ty.unionFields().count(), | 2214 | .Union => ty.unionFields(mod).count(), |
| 2218 | else => unreachable, | 2215 | else => unreachable, |
| 2219 | }) |field_i| { | 2216 | }) |field_i| { |
| 2220 | const field_ty = ty.structFieldType(field_i); | 2217 | const field_ty = ty.structFieldType(field_i, mod); |
| 2221 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or | 2218 | if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or |
| 2222 | !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 2219 | !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 2223 | 2220 | ||
| 2224 | self.updateHasherRecurse(hasher, field_ty, switch (self.kind) { | 2221 | self.updateHasherRecurse(hasher, field_ty, switch (self.kind) { |
| 2225 | .forward, .forward_parameter => .forward, | 2222 | .forward, .forward_parameter => .forward, |
| ... | @@ -2227,14 +2224,15 @@ pub const CType = extern union { | ... | @@ -2227,14 +2224,15 @@ pub const CType = extern union { |
| 2227 | .global => .global, | 2224 | .global => .global, |
| 2228 | .payload => unreachable, | 2225 | .payload => unreachable, |
| 2229 | }); | 2226 | }); |
| 2230 | hasher.update(if (ty.isSimpleTuple()) | 2227 | hasher.update(if (ty.isSimpleTuple(mod)) |
| 2231 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable | 2228 | std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable |
| 2232 | else switch (zig_ty_tag) { | 2229 | else |
| 2233 | .Struct => ty.structFieldName(field_i), | 2230 | mod.intern_pool.stringToSlice(switch (zig_ty_tag) { |
| 2234 | .Union => ty.unionFields().keys()[field_i], | 2231 | .Struct => ty.structFieldName(field_i, mod), |
| 2235 | else => unreachable, | 2232 | .Union => ty.unionFields(mod).keys()[field_i], |
| 2236 | }); | 2233 | else => unreachable, |
| 2237 | autoHash(hasher, AlignAs.fieldAlign(ty, field_i, target).@"align"); | 2234 | })); |
| 2235 | autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align"); | ||
| 2238 | } | 2236 | } |
| 2239 | }, | 2237 | }, |
| 2240 | 2238 | ||
| ... | @@ -2244,8 +2242,8 @@ pub const CType = extern union { | ... | @@ -2244,8 +2242,8 @@ pub const CType = extern union { |
| 2244 | .packed_unnamed_union, | 2242 | .packed_unnamed_union, |
| 2245 | => switch (self.kind) { | 2243 | => switch (self.kind) { |
| 2246 | .forward, .forward_parameter, .complete, .parameter, .global => unreachable, | 2244 | .forward, .forward_parameter, .complete, .parameter, .global => unreachable, |
| 2247 | .payload => if (ty.unionTagTypeSafety()) |_| { | 2245 | .payload => if (ty.unionTagTypeSafety(mod)) |_| { |
| 2248 | autoHash(hasher, ty.getOwnerDecl()); | 2246 | autoHash(hasher, ty.getOwnerDecl(mod)); |
| 2249 | autoHash(hasher, @as(u32, 0)); | 2247 | autoHash(hasher, @as(u32, 0)); |
| 2250 | } else unreachable, | 2248 | } else unreachable, |
| 2251 | }, | 2249 | }, |
| ... | @@ -2261,7 +2259,7 @@ pub const CType = extern union { | ... | @@ -2261,7 +2259,7 @@ pub const CType = extern union { |
| 2261 | .function, | 2259 | .function, |
| 2262 | .varargs_function, | 2260 | .varargs_function, |
| 2263 | => { | 2261 | => { |
| 2264 | const info = ty.fnInfo(); | 2262 | const info = mod.typeToFunc(ty).?; |
| 2265 | assert(!info.is_generic); | 2263 | assert(!info.is_generic); |
| 2266 | const param_kind: Kind = switch (self.kind) { | 2264 | const param_kind: Kind = switch (self.kind) { |
| 2267 | .forward, .forward_parameter => .forward_parameter, | 2265 | .forward, .forward_parameter => .forward_parameter, |
| ... | @@ -2269,10 +2267,10 @@ pub const CType = extern union { | ... | @@ -2269,10 +2267,10 @@ pub const CType = extern union { |
| 2269 | .payload => unreachable, | 2267 | .payload => unreachable, |
| 2270 | }; | 2268 | }; |
| 2271 | 2269 | ||
| 2272 | self.updateHasherRecurse(hasher, info.return_type, param_kind); | 2270 | self.updateHasherRecurse(hasher, info.return_type.toType(), param_kind); |
| 2273 | for (info.param_types) |param_type| { | 2271 | for (info.param_types) |param_type| { |
| 2274 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | 2272 | if (!param_type.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 2275 | self.updateHasherRecurse(hasher, param_type, param_kind); | 2273 | self.updateHasherRecurse(hasher, param_type.toType(), param_kind); |
| 2276 | } | 2274 | } |
| 2277 | }, | 2275 | }, |
| 2278 | 2276 |
src/codegen/llvm.zig+2024-2211| ... | @@ -12,6 +12,7 @@ const link = @import("../link.zig"); | ... | @@ -12,6 +12,7 @@ const link = @import("../link.zig"); |
| 12 | const Compilation = @import("../Compilation.zig"); | 12 | const Compilation = @import("../Compilation.zig"); |
| 13 | const build_options = @import("build_options"); | 13 | const build_options = @import("build_options"); |
| 14 | const Module = @import("../Module.zig"); | 14 | const Module = @import("../Module.zig"); |
| 15 | const InternPool = @import("../InternPool.zig"); | ||
| 15 | const Package = @import("../Package.zig"); | 16 | const Package = @import("../Package.zig"); |
| 16 | const TypedValue = @import("../TypedValue.zig"); | 17 | const TypedValue = @import("../TypedValue.zig"); |
| 17 | const Air = @import("../Air.zig"); | 18 | const Air = @import("../Air.zig"); |
| ... | @@ -361,15 +362,11 @@ pub const Object = struct { | ... | @@ -361,15 +362,11 @@ pub const Object = struct { |
| 361 | decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value), | 362 | decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value), |
| 362 | /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction. | 363 | /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction. |
| 363 | named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value), | 364 | named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, *llvm.Value), |
| 364 | /// Maps Zig types to LLVM types. The table memory itself is backed by the GPA of | 365 | /// Maps Zig types to LLVM types. The table memory is backed by the GPA of |
| 365 | /// the compiler, but the Type/Value memory here is backed by `type_map_arena`. | 366 | /// the compiler. |
| 366 | /// TODO we need to remove entries from this map in response to incremental compilation | 367 | /// TODO when InternPool garbage collection is implemented, this map needs |
| 367 | /// but I think the frontend won't tell us about types that get deleted because | 368 | /// to be garbage collected as well. |
| 368 | /// hasRuntimeBits() is false for types. | ||
| 369 | type_map: TypeMap, | 369 | type_map: TypeMap, |
| 370 | /// The backing memory for `type_map`. Periodically garbage collected after flush(). | ||
| 371 | /// The code for doing the periodical GC is not yet implemented. | ||
| 372 | type_map_arena: std.heap.ArenaAllocator, | ||
| 373 | di_type_map: DITypeMap, | 370 | di_type_map: DITypeMap, |
| 374 | /// The LLVM global table which holds the names corresponding to Zig errors. | 371 | /// The LLVM global table which holds the names corresponding to Zig errors. |
| 375 | /// Note that the values are not added until flushModule, when all errors in | 372 | /// Note that the values are not added until flushModule, when all errors in |
| ... | @@ -380,21 +377,11 @@ pub const Object = struct { | ... | @@ -380,21 +377,11 @@ pub const Object = struct { |
| 380 | /// name collision. | 377 | /// name collision. |
| 381 | extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void), | 378 | extern_collisions: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void), |
| 382 | 379 | ||
| 383 | pub const TypeMap = std.HashMapUnmanaged( | 380 | pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, *llvm.Type); |
| 384 | Type, | ||
| 385 | *llvm.Type, | ||
| 386 | Type.HashContext64, | ||
| 387 | std.hash_map.default_max_load_percentage, | ||
| 388 | ); | ||
| 389 | 381 | ||
| 390 | /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we | 382 | /// This is an ArrayHashMap as opposed to a HashMap because in `flushModule` we |
| 391 | /// want to iterate over it while adding entries to it. | 383 | /// want to iterate over it while adding entries to it. |
| 392 | pub const DITypeMap = std.ArrayHashMapUnmanaged( | 384 | pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr); |
| 393 | Type, | ||
| 394 | AnnotatedDITypePtr, | ||
| 395 | Type.HashContext32, | ||
| 396 | true, | ||
| 397 | ); | ||
| 398 | 385 | ||
| 399 | pub fn create(gpa: Allocator, options: link.Options) !*Object { | 386 | pub fn create(gpa: Allocator, options: link.Options) !*Object { |
| 400 | const obj = try gpa.create(Object); | 387 | const obj = try gpa.create(Object); |
| ... | @@ -542,7 +529,6 @@ pub const Object = struct { | ... | @@ -542,7 +529,6 @@ pub const Object = struct { |
| 542 | .decl_map = .{}, | 529 | .decl_map = .{}, |
| 543 | .named_enum_map = .{}, | 530 | .named_enum_map = .{}, |
| 544 | .type_map = .{}, | 531 | .type_map = .{}, |
| 545 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), | ||
| 546 | .di_type_map = .{}, | 532 | .di_type_map = .{}, |
| 547 | .error_name_table = null, | 533 | .error_name_table = null, |
| 548 | .extern_collisions = .{}, | 534 | .extern_collisions = .{}, |
| ... | @@ -562,7 +548,6 @@ pub const Object = struct { | ... | @@ -562,7 +548,6 @@ pub const Object = struct { |
| 562 | self.decl_map.deinit(gpa); | 548 | self.decl_map.deinit(gpa); |
| 563 | self.named_enum_map.deinit(gpa); | 549 | self.named_enum_map.deinit(gpa); |
| 564 | self.type_map.deinit(gpa); | 550 | self.type_map.deinit(gpa); |
| 565 | self.type_map_arena.deinit(); | ||
| 566 | self.extern_collisions.deinit(gpa); | 551 | self.extern_collisions.deinit(gpa); |
| 567 | self.* = undefined; | 552 | self.* = undefined; |
| 568 | } | 553 | } |
| ... | @@ -597,16 +582,16 @@ pub const Object = struct { | ... | @@ -597,16 +582,16 @@ pub const Object = struct { |
| 597 | llvm_usize_ty, | 582 | llvm_usize_ty, |
| 598 | }; | 583 | }; |
| 599 | const llvm_slice_ty = self.context.structType(&type_fields, type_fields.len, .False); | 584 | const llvm_slice_ty = self.context.structType(&type_fields, type_fields.len, .False); |
| 600 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | 585 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 601 | const slice_alignment = slice_ty.abiAlignment(target); | 586 | const slice_alignment = slice_ty.abiAlignment(mod); |
| 602 | 587 | ||
| 603 | const error_name_list = mod.error_name_list.items; | 588 | const error_name_list = mod.global_error_set.keys(); |
| 604 | const llvm_errors = try mod.gpa.alloc(*llvm.Value, error_name_list.len); | 589 | const llvm_errors = try mod.gpa.alloc(*llvm.Value, error_name_list.len); |
| 605 | defer mod.gpa.free(llvm_errors); | 590 | defer mod.gpa.free(llvm_errors); |
| 606 | 591 | ||
| 607 | llvm_errors[0] = llvm_slice_ty.getUndef(); | 592 | llvm_errors[0] = llvm_slice_ty.getUndef(); |
| 608 | for (llvm_errors[1..], 0..) |*llvm_error, i| { | 593 | for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name_nts| { |
| 609 | const name = error_name_list[1..][i]; | 594 | const name = mod.intern_pool.stringToSlice(name_nts); |
| 610 | const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False); | 595 | const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False); |
| 611 | const str_global = self.llvm_module.addGlobal(str_init.typeOf(), ""); | 596 | const str_global = self.llvm_module.addGlobal(str_init.typeOf(), ""); |
| 612 | str_global.setInitializer(str_init); | 597 | str_global.setInitializer(str_init); |
| ... | @@ -686,7 +671,7 @@ pub const Object = struct { | ... | @@ -686,7 +671,7 @@ pub const Object = struct { |
| 686 | const llvm_global = entry.value_ptr.*; | 671 | const llvm_global = entry.value_ptr.*; |
| 687 | // Same logic as below but for externs instead of exports. | 672 | // Same logic as below but for externs instead of exports. |
| 688 | const decl = mod.declPtr(decl_index); | 673 | const decl = mod.declPtr(decl_index); |
| 689 | const other_global = object.getLlvmGlobal(decl.name) orelse continue; | 674 | const other_global = object.getLlvmGlobal(mod.intern_pool.stringToSlice(decl.name)) orelse continue; |
| 690 | if (other_global == llvm_global) continue; | 675 | if (other_global == llvm_global) continue; |
| 691 | 676 | ||
| 692 | llvm_global.replaceAllUsesWith(other_global); | 677 | llvm_global.replaceAllUsesWith(other_global); |
| ... | @@ -702,12 +687,9 @@ pub const Object = struct { | ... | @@ -702,12 +687,9 @@ pub const Object = struct { |
| 702 | for (export_list.items) |exp| { | 687 | for (export_list.items) |exp| { |
| 703 | // Detect if the LLVM global has already been created as an extern. In such | 688 | // Detect if the LLVM global has already been created as an extern. In such |
| 704 | // case, we need to replace all uses of it with this exported global. | 689 | // case, we need to replace all uses of it with this exported global. |
| 705 | // TODO update std.builtin.ExportOptions to have the name be a | 690 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); |
| 706 | // null-terminated slice. | ||
| 707 | const exp_name_z = try mod.gpa.dupeZ(u8, exp.options.name); | ||
| 708 | defer mod.gpa.free(exp_name_z); | ||
| 709 | 691 | ||
| 710 | const other_global = object.getLlvmGlobal(exp_name_z.ptr) orelse continue; | 692 | const other_global = object.getLlvmGlobal(exp_name.ptr) orelse continue; |
| 711 | if (other_global == llvm_global) continue; | 693 | if (other_global == llvm_global) continue; |
| 712 | 694 | ||
| 713 | other_global.replaceAllUsesWith(llvm_global); | 695 | other_global.replaceAllUsesWith(llvm_global); |
| ... | @@ -880,28 +862,29 @@ pub const Object = struct { | ... | @@ -880,28 +862,29 @@ pub const Object = struct { |
| 880 | 862 | ||
| 881 | pub fn updateFunc( | 863 | pub fn updateFunc( |
| 882 | o: *Object, | 864 | o: *Object, |
| 883 | module: *Module, | 865 | mod: *Module, |
| 884 | func: *Module.Fn, | 866 | func_index: Module.Fn.Index, |
| 885 | air: Air, | 867 | air: Air, |
| 886 | liveness: Liveness, | 868 | liveness: Liveness, |
| 887 | ) !void { | 869 | ) !void { |
| 870 | const func = mod.funcPtr(func_index); | ||
| 888 | const decl_index = func.owner_decl; | 871 | const decl_index = func.owner_decl; |
| 889 | const decl = module.declPtr(decl_index); | 872 | const decl = mod.declPtr(decl_index); |
| 890 | const target = module.getTarget(); | 873 | const target = mod.getTarget(); |
| 891 | 874 | ||
| 892 | var dg: DeclGen = .{ | 875 | var dg: DeclGen = .{ |
| 893 | .context = o.context, | 876 | .context = o.context, |
| 894 | .object = o, | 877 | .object = o, |
| 895 | .module = module, | 878 | .module = mod, |
| 896 | .decl_index = decl_index, | 879 | .decl_index = decl_index, |
| 897 | .decl = decl, | 880 | .decl = decl, |
| 898 | .err_msg = null, | 881 | .err_msg = null, |
| 899 | .gpa = module.gpa, | 882 | .gpa = mod.gpa, |
| 900 | }; | 883 | }; |
| 901 | 884 | ||
| 902 | const llvm_func = try dg.resolveLlvmFunction(decl_index); | 885 | const llvm_func = try dg.resolveLlvmFunction(decl_index); |
| 903 | 886 | ||
| 904 | if (module.align_stack_fns.get(func)) |align_info| { | 887 | if (mod.align_stack_fns.get(func_index)) |align_info| { |
| 905 | dg.addFnAttrInt(llvm_func, "alignstack", align_info.alignment); | 888 | dg.addFnAttrInt(llvm_func, "alignstack", align_info.alignment); |
| 906 | dg.addFnAttr(llvm_func, "noinline"); | 889 | dg.addFnAttr(llvm_func, "noinline"); |
| 907 | } else { | 890 | } else { |
| ... | @@ -922,7 +905,7 @@ pub const Object = struct { | ... | @@ -922,7 +905,7 @@ pub const Object = struct { |
| 922 | } | 905 | } |
| 923 | 906 | ||
| 924 | // TODO: disable this if safety is off for the function scope | 907 | // TODO: disable this if safety is off for the function scope |
| 925 | const ssp_buf_size = module.comp.bin_file.options.stack_protector; | 908 | const ssp_buf_size = mod.comp.bin_file.options.stack_protector; |
| 926 | if (ssp_buf_size != 0) { | 909 | if (ssp_buf_size != 0) { |
| 927 | var buf: [12]u8 = undefined; | 910 | var buf: [12]u8 = undefined; |
| 928 | const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable; | 911 | const arg = std.fmt.bufPrintZ(&buf, "{d}", .{ssp_buf_size}) catch unreachable; |
| ... | @@ -931,15 +914,14 @@ pub const Object = struct { | ... | @@ -931,15 +914,14 @@ pub const Object = struct { |
| 931 | } | 914 | } |
| 932 | 915 | ||
| 933 | // TODO: disable this if safety is off for the function scope | 916 | // TODO: disable this if safety is off for the function scope |
| 934 | if (module.comp.bin_file.options.stack_check) { | 917 | if (mod.comp.bin_file.options.stack_check) { |
| 935 | dg.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack"); | 918 | dg.addFnAttrString(llvm_func, "probe-stack", "__zig_probe_stack"); |
| 936 | } else if (target.os.tag == .uefi) { | 919 | } else if (target.os.tag == .uefi) { |
| 937 | dg.addFnAttrString(llvm_func, "no-stack-arg-probe", ""); | 920 | dg.addFnAttrString(llvm_func, "no-stack-arg-probe", ""); |
| 938 | } | 921 | } |
| 939 | 922 | ||
| 940 | if (decl.@"linksection") |section| { | 923 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| |
| 941 | llvm_func.setSection(section); | 924 | llvm_func.setSection(section); |
| 942 | } | ||
| 943 | 925 | ||
| 944 | // Remove all the basic blocks of a function in order to start over, generating | 926 | // Remove all the basic blocks of a function in order to start over, generating |
| 945 | // LLVM IR from an empty function body. | 927 | // LLVM IR from an empty function body. |
| ... | @@ -953,18 +935,18 @@ pub const Object = struct { | ... | @@ -953,18 +935,18 @@ pub const Object = struct { |
| 953 | builder.positionBuilderAtEnd(entry_block); | 935 | builder.positionBuilderAtEnd(entry_block); |
| 954 | 936 | ||
| 955 | // This gets the LLVM values from the function and stores them in `dg.args`. | 937 | // This gets the LLVM values from the function and stores them in `dg.args`. |
| 956 | const fn_info = decl.ty.fnInfo(); | 938 | const fn_info = mod.typeToFunc(decl.ty).?; |
| 957 | const sret = firstParamSRet(fn_info, target); | 939 | const sret = firstParamSRet(fn_info, mod); |
| 958 | const ret_ptr = if (sret) llvm_func.getParam(0) else null; | 940 | const ret_ptr = if (sret) llvm_func.getParam(0) else null; |
| 959 | const gpa = dg.gpa; | 941 | const gpa = dg.gpa; |
| 960 | 942 | ||
| 961 | if (ccAbiPromoteInt(fn_info.cc, target, fn_info.return_type)) |s| switch (s) { | 943 | if (ccAbiPromoteInt(fn_info.cc, mod, fn_info.return_type.toType())) |s| switch (s) { |
| 962 | .signed => dg.addAttr(llvm_func, 0, "signext"), | 944 | .signed => dg.addAttr(llvm_func, 0, "signext"), |
| 963 | .unsigned => dg.addAttr(llvm_func, 0, "zeroext"), | 945 | .unsigned => dg.addAttr(llvm_func, 0, "zeroext"), |
| 964 | }; | 946 | }; |
| 965 | 947 | ||
| 966 | const err_return_tracing = fn_info.return_type.isError() and | 948 | const err_return_tracing = fn_info.return_type.toType().isError(mod) and |
| 967 | module.comp.bin_file.options.error_return_tracing; | 949 | mod.comp.bin_file.options.error_return_tracing; |
| 968 | 950 | ||
| 969 | const err_ret_trace = if (err_return_tracing) | 951 | const err_ret_trace = if (err_return_tracing) |
| 970 | llvm_func.getParam(@boolToInt(ret_ptr != null)) | 952 | llvm_func.getParam(@boolToInt(ret_ptr != null)) |
| ... | @@ -985,12 +967,12 @@ pub const Object = struct { | ... | @@ -985,12 +967,12 @@ pub const Object = struct { |
| 985 | .byval => { | 967 | .byval => { |
| 986 | assert(!it.byval_attr); | 968 | assert(!it.byval_attr); |
| 987 | const param_index = it.zig_index - 1; | 969 | const param_index = it.zig_index - 1; |
| 988 | const param_ty = fn_info.param_types[param_index]; | 970 | const param_ty = fn_info.param_types[param_index].toType(); |
| 989 | const param = llvm_func.getParam(llvm_arg_i); | 971 | const param = llvm_func.getParam(llvm_arg_i); |
| 990 | try args.ensureUnusedCapacity(1); | 972 | try args.ensureUnusedCapacity(1); |
| 991 | 973 | ||
| 992 | if (isByRef(param_ty)) { | 974 | if (isByRef(param_ty, mod)) { |
| 993 | const alignment = param_ty.abiAlignment(target); | 975 | const alignment = param_ty.abiAlignment(mod); |
| 994 | const param_llvm_ty = param.typeOf(); | 976 | const param_llvm_ty = param.typeOf(); |
| 995 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); | 977 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); |
| 996 | const store_inst = builder.buildStore(param, arg_ptr); | 978 | const store_inst = builder.buildStore(param, arg_ptr); |
| ... | @@ -1004,17 +986,17 @@ pub const Object = struct { | ... | @@ -1004,17 +986,17 @@ pub const Object = struct { |
| 1004 | llvm_arg_i += 1; | 986 | llvm_arg_i += 1; |
| 1005 | }, | 987 | }, |
| 1006 | .byref => { | 988 | .byref => { |
| 1007 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 989 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 1008 | const param_llvm_ty = try dg.lowerType(param_ty); | 990 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1009 | const param = llvm_func.getParam(llvm_arg_i); | 991 | const param = llvm_func.getParam(llvm_arg_i); |
| 1010 | const alignment = param_ty.abiAlignment(target); | 992 | const alignment = param_ty.abiAlignment(mod); |
| 1011 | 993 | ||
| 1012 | dg.addByRefParamAttrs(llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty); | 994 | dg.addByRefParamAttrs(llvm_func, llvm_arg_i, alignment, it.byval_attr, param_llvm_ty); |
| 1013 | llvm_arg_i += 1; | 995 | llvm_arg_i += 1; |
| 1014 | 996 | ||
| 1015 | try args.ensureUnusedCapacity(1); | 997 | try args.ensureUnusedCapacity(1); |
| 1016 | 998 | ||
| 1017 | if (isByRef(param_ty)) { | 999 | if (isByRef(param_ty, mod)) { |
| 1018 | args.appendAssumeCapacity(param); | 1000 | args.appendAssumeCapacity(param); |
| 1019 | } else { | 1001 | } else { |
| 1020 | const load_inst = builder.buildLoad(param_llvm_ty, param, ""); | 1002 | const load_inst = builder.buildLoad(param_llvm_ty, param, ""); |
| ... | @@ -1023,17 +1005,17 @@ pub const Object = struct { | ... | @@ -1023,17 +1005,17 @@ pub const Object = struct { |
| 1023 | } | 1005 | } |
| 1024 | }, | 1006 | }, |
| 1025 | .byref_mut => { | 1007 | .byref_mut => { |
| 1026 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 1008 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 1027 | const param_llvm_ty = try dg.lowerType(param_ty); | 1009 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1028 | const param = llvm_func.getParam(llvm_arg_i); | 1010 | const param = llvm_func.getParam(llvm_arg_i); |
| 1029 | const alignment = param_ty.abiAlignment(target); | 1011 | const alignment = param_ty.abiAlignment(mod); |
| 1030 | 1012 | ||
| 1031 | dg.addArgAttr(llvm_func, llvm_arg_i, "noundef"); | 1013 | dg.addArgAttr(llvm_func, llvm_arg_i, "noundef"); |
| 1032 | llvm_arg_i += 1; | 1014 | llvm_arg_i += 1; |
| 1033 | 1015 | ||
| 1034 | try args.ensureUnusedCapacity(1); | 1016 | try args.ensureUnusedCapacity(1); |
| 1035 | 1017 | ||
| 1036 | if (isByRef(param_ty)) { | 1018 | if (isByRef(param_ty, mod)) { |
| 1037 | args.appendAssumeCapacity(param); | 1019 | args.appendAssumeCapacity(param); |
| 1038 | } else { | 1020 | } else { |
| 1039 | const load_inst = builder.buildLoad(param_llvm_ty, param, ""); | 1021 | const load_inst = builder.buildLoad(param_llvm_ty, param, ""); |
| ... | @@ -1043,15 +1025,15 @@ pub const Object = struct { | ... | @@ -1043,15 +1025,15 @@ pub const Object = struct { |
| 1043 | }, | 1025 | }, |
| 1044 | .abi_sized_int => { | 1026 | .abi_sized_int => { |
| 1045 | assert(!it.byval_attr); | 1027 | assert(!it.byval_attr); |
| 1046 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 1028 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 1047 | const param = llvm_func.getParam(llvm_arg_i); | 1029 | const param = llvm_func.getParam(llvm_arg_i); |
| 1048 | llvm_arg_i += 1; | 1030 | llvm_arg_i += 1; |
| 1049 | 1031 | ||
| 1050 | const param_llvm_ty = try dg.lowerType(param_ty); | 1032 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1051 | const abi_size = @intCast(c_uint, param_ty.abiSize(target)); | 1033 | const abi_size = @intCast(c_uint, param_ty.abiSize(mod)); |
| 1052 | const int_llvm_ty = dg.context.intType(abi_size * 8); | 1034 | const int_llvm_ty = dg.context.intType(abi_size * 8); |
| 1053 | const alignment = @max( | 1035 | const alignment = @max( |
| 1054 | param_ty.abiAlignment(target), | 1036 | param_ty.abiAlignment(mod), |
| 1055 | dg.object.target_data.abiAlignmentOfType(int_llvm_ty), | 1037 | dg.object.target_data.abiAlignmentOfType(int_llvm_ty), |
| 1056 | ); | 1038 | ); |
| 1057 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); | 1039 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); |
| ... | @@ -1060,7 +1042,7 @@ pub const Object = struct { | ... | @@ -1060,7 +1042,7 @@ pub const Object = struct { |
| 1060 | 1042 | ||
| 1061 | try args.ensureUnusedCapacity(1); | 1043 | try args.ensureUnusedCapacity(1); |
| 1062 | 1044 | ||
| 1063 | if (isByRef(param_ty)) { | 1045 | if (isByRef(param_ty, mod)) { |
| 1064 | args.appendAssumeCapacity(arg_ptr); | 1046 | args.appendAssumeCapacity(arg_ptr); |
| 1065 | } else { | 1047 | } else { |
| 1066 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); | 1048 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); |
| ... | @@ -1070,15 +1052,15 @@ pub const Object = struct { | ... | @@ -1070,15 +1052,15 @@ pub const Object = struct { |
| 1070 | }, | 1052 | }, |
| 1071 | .slice => { | 1053 | .slice => { |
| 1072 | assert(!it.byval_attr); | 1054 | assert(!it.byval_attr); |
| 1073 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 1055 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 1074 | const ptr_info = param_ty.ptrInfo().data; | 1056 | const ptr_info = param_ty.ptrInfo(mod); |
| 1075 | 1057 | ||
| 1076 | if (math.cast(u5, it.zig_index - 1)) |i| { | 1058 | if (math.cast(u5, it.zig_index - 1)) |i| { |
| 1077 | if (@truncate(u1, fn_info.noalias_bits >> i) != 0) { | 1059 | if (@truncate(u1, fn_info.noalias_bits >> i) != 0) { |
| 1078 | dg.addArgAttr(llvm_func, llvm_arg_i, "noalias"); | 1060 | dg.addArgAttr(llvm_func, llvm_arg_i, "noalias"); |
| 1079 | } | 1061 | } |
| 1080 | } | 1062 | } |
| 1081 | if (param_ty.zigTypeTag() != .Optional) { | 1063 | if (param_ty.zigTypeTag(mod) != .Optional) { |
| 1082 | dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull"); | 1064 | dg.addArgAttr(llvm_func, llvm_arg_i, "nonnull"); |
| 1083 | } | 1065 | } |
| 1084 | if (!ptr_info.mutable) { | 1066 | if (!ptr_info.mutable) { |
| ... | @@ -1087,7 +1069,7 @@ pub const Object = struct { | ... | @@ -1087,7 +1069,7 @@ pub const Object = struct { |
| 1087 | if (ptr_info.@"align" != 0) { | 1069 | if (ptr_info.@"align" != 0) { |
| 1088 | dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.@"align"); | 1070 | dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", ptr_info.@"align"); |
| 1089 | } else { | 1071 | } else { |
| 1090 | const elem_align = @max(ptr_info.pointee_type.abiAlignment(target), 1); | 1072 | const elem_align = @max(ptr_info.pointee_type.abiAlignment(mod), 1); |
| 1091 | dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align); | 1073 | dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align); |
| 1092 | } | 1074 | } |
| 1093 | const ptr_param = llvm_func.getParam(llvm_arg_i); | 1075 | const ptr_param = llvm_func.getParam(llvm_arg_i); |
| ... | @@ -1103,9 +1085,9 @@ pub const Object = struct { | ... | @@ -1103,9 +1085,9 @@ pub const Object = struct { |
| 1103 | .multiple_llvm_types => { | 1085 | .multiple_llvm_types => { |
| 1104 | assert(!it.byval_attr); | 1086 | assert(!it.byval_attr); |
| 1105 | const field_types = it.llvm_types_buffer[0..it.llvm_types_len]; | 1087 | const field_types = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 1106 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 1088 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 1107 | const param_llvm_ty = try dg.lowerType(param_ty); | 1089 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1108 | const param_alignment = param_ty.abiAlignment(target); | 1090 | const param_alignment = param_ty.abiAlignment(mod); |
| 1109 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, param_alignment, target); | 1091 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, param_alignment, target); |
| 1110 | const llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False); | 1092 | const llvm_ty = dg.context.structType(field_types.ptr, @intCast(c_uint, field_types.len), .False); |
| 1111 | for (field_types, 0..) |_, field_i_usize| { | 1093 | for (field_types, 0..) |_, field_i_usize| { |
| ... | @@ -1117,7 +1099,7 @@ pub const Object = struct { | ... | @@ -1117,7 +1099,7 @@ pub const Object = struct { |
| 1117 | store_inst.setAlignment(target.ptrBitWidth() / 8); | 1099 | store_inst.setAlignment(target.ptrBitWidth() / 8); |
| 1118 | } | 1100 | } |
| 1119 | 1101 | ||
| 1120 | const is_by_ref = isByRef(param_ty); | 1102 | const is_by_ref = isByRef(param_ty, mod); |
| 1121 | const loaded = if (is_by_ref) arg_ptr else l: { | 1103 | const loaded = if (is_by_ref) arg_ptr else l: { |
| 1122 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); | 1104 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); |
| 1123 | load_inst.setAlignment(param_alignment); | 1105 | load_inst.setAlignment(param_alignment); |
| ... | @@ -1134,16 +1116,16 @@ pub const Object = struct { | ... | @@ -1134,16 +1116,16 @@ pub const Object = struct { |
| 1134 | args.appendAssumeCapacity(casted); | 1116 | args.appendAssumeCapacity(casted); |
| 1135 | }, | 1117 | }, |
| 1136 | .float_array => { | 1118 | .float_array => { |
| 1137 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 1119 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 1138 | const param_llvm_ty = try dg.lowerType(param_ty); | 1120 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1139 | const param = llvm_func.getParam(llvm_arg_i); | 1121 | const param = llvm_func.getParam(llvm_arg_i); |
| 1140 | llvm_arg_i += 1; | 1122 | llvm_arg_i += 1; |
| 1141 | 1123 | ||
| 1142 | const alignment = param_ty.abiAlignment(target); | 1124 | const alignment = param_ty.abiAlignment(mod); |
| 1143 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); | 1125 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); |
| 1144 | _ = builder.buildStore(param, arg_ptr); | 1126 | _ = builder.buildStore(param, arg_ptr); |
| 1145 | 1127 | ||
| 1146 | if (isByRef(param_ty)) { | 1128 | if (isByRef(param_ty, mod)) { |
| 1147 | try args.append(arg_ptr); | 1129 | try args.append(arg_ptr); |
| 1148 | } else { | 1130 | } else { |
| 1149 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); | 1131 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); |
| ... | @@ -1152,16 +1134,16 @@ pub const Object = struct { | ... | @@ -1152,16 +1134,16 @@ pub const Object = struct { |
| 1152 | } | 1134 | } |
| 1153 | }, | 1135 | }, |
| 1154 | .i32_array, .i64_array => { | 1136 | .i32_array, .i64_array => { |
| 1155 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 1137 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 1156 | const param_llvm_ty = try dg.lowerType(param_ty); | 1138 | const param_llvm_ty = try dg.lowerType(param_ty); |
| 1157 | const param = llvm_func.getParam(llvm_arg_i); | 1139 | const param = llvm_func.getParam(llvm_arg_i); |
| 1158 | llvm_arg_i += 1; | 1140 | llvm_arg_i += 1; |
| 1159 | 1141 | ||
| 1160 | const alignment = param_ty.abiAlignment(target); | 1142 | const alignment = param_ty.abiAlignment(mod); |
| 1161 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); | 1143 | const arg_ptr = buildAllocaInner(dg.context, builder, llvm_func, false, param_llvm_ty, alignment, target); |
| 1162 | _ = builder.buildStore(param, arg_ptr); | 1144 | _ = builder.buildStore(param, arg_ptr); |
| 1163 | 1145 | ||
| 1164 | if (isByRef(param_ty)) { | 1146 | if (isByRef(param_ty, mod)) { |
| 1165 | try args.append(arg_ptr); | 1147 | try args.append(arg_ptr); |
| 1166 | } else { | 1148 | } else { |
| 1167 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); | 1149 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); |
| ... | @@ -1176,27 +1158,28 @@ pub const Object = struct { | ... | @@ -1176,27 +1158,28 @@ pub const Object = struct { |
| 1176 | var di_scope: ?*llvm.DIScope = null; | 1158 | var di_scope: ?*llvm.DIScope = null; |
| 1177 | 1159 | ||
| 1178 | if (dg.object.di_builder) |dib| { | 1160 | if (dg.object.di_builder) |dib| { |
| 1179 | di_file = try dg.object.getDIFile(gpa, decl.src_namespace.file_scope); | 1161 | di_file = try dg.object.getDIFile(gpa, mod.namespacePtr(decl.src_namespace).file_scope); |
| 1180 | 1162 | ||
| 1181 | const line_number = decl.src_line + 1; | 1163 | const line_number = decl.src_line + 1; |
| 1182 | const is_internal_linkage = decl.val.tag() != .extern_fn and | 1164 | const is_internal_linkage = decl.val.getExternFunc(mod) == null and |
| 1183 | !module.decl_exports.contains(decl_index); | 1165 | !mod.decl_exports.contains(decl_index); |
| 1184 | const noret_bit: c_uint = if (fn_info.return_type.isNoReturn()) | 1166 | const noret_bit: c_uint = if (fn_info.return_type == .noreturn_type) |
| 1185 | llvm.DIFlags.NoReturn | 1167 | llvm.DIFlags.NoReturn |
| 1186 | else | 1168 | else |
| 1187 | 0; | 1169 | 0; |
| 1170 | const decl_di_ty = try o.lowerDebugType(decl.ty, .full); | ||
| 1188 | const subprogram = dib.createFunction( | 1171 | const subprogram = dib.createFunction( |
| 1189 | di_file.?.toScope(), | 1172 | di_file.?.toScope(), |
| 1190 | decl.name, | 1173 | mod.intern_pool.stringToSlice(decl.name), |
| 1191 | llvm_func.getValueName(), | 1174 | llvm_func.getValueName(), |
| 1192 | di_file.?, | 1175 | di_file.?, |
| 1193 | line_number, | 1176 | line_number, |
| 1194 | try o.lowerDebugType(decl.ty, .full), | 1177 | decl_di_ty, |
| 1195 | is_internal_linkage, | 1178 | is_internal_linkage, |
| 1196 | true, // is definition | 1179 | true, // is definition |
| 1197 | line_number + func.lbrace_line, // scope line | 1180 | line_number + func.lbrace_line, // scope line |
| 1198 | llvm.DIFlags.StaticMember | noret_bit, | 1181 | llvm.DIFlags.StaticMember | noret_bit, |
| 1199 | module.comp.bin_file.options.optimize_mode != .Debug, | 1182 | mod.comp.bin_file.options.optimize_mode != .Debug, |
| 1200 | null, // decl_subprogram | 1183 | null, // decl_subprogram |
| 1201 | ); | 1184 | ); |
| 1202 | try dg.object.di_map.put(gpa, decl, subprogram.toNode()); | 1185 | try dg.object.di_map.put(gpa, decl, subprogram.toNode()); |
| ... | @@ -1219,7 +1202,7 @@ pub const Object = struct { | ... | @@ -1219,7 +1202,7 @@ pub const Object = struct { |
| 1219 | .func_inst_table = .{}, | 1202 | .func_inst_table = .{}, |
| 1220 | .llvm_func = llvm_func, | 1203 | .llvm_func = llvm_func, |
| 1221 | .blocks = .{}, | 1204 | .blocks = .{}, |
| 1222 | .single_threaded = module.comp.bin_file.options.single_threaded, | 1205 | .single_threaded = mod.comp.bin_file.options.single_threaded, |
| 1223 | .di_scope = di_scope, | 1206 | .di_scope = di_scope, |
| 1224 | .di_file = di_file, | 1207 | .di_file = di_file, |
| 1225 | .base_line = dg.decl.src_line, | 1208 | .base_line = dg.decl.src_line, |
| ... | @@ -1232,14 +1215,14 @@ pub const Object = struct { | ... | @@ -1232,14 +1215,14 @@ pub const Object = struct { |
| 1232 | fg.genBody(air.getMainBody()) catch |err| switch (err) { | 1215 | fg.genBody(air.getMainBody()) catch |err| switch (err) { |
| 1233 | error.CodegenFail => { | 1216 | error.CodegenFail => { |
| 1234 | decl.analysis = .codegen_failure; | 1217 | decl.analysis = .codegen_failure; |
| 1235 | try module.failed_decls.put(module.gpa, decl_index, dg.err_msg.?); | 1218 | try mod.failed_decls.put(mod.gpa, decl_index, dg.err_msg.?); |
| 1236 | dg.err_msg = null; | 1219 | dg.err_msg = null; |
| 1237 | return; | 1220 | return; |
| 1238 | }, | 1221 | }, |
| 1239 | else => |e| return e, | 1222 | else => |e| return e, |
| 1240 | }; | 1223 | }; |
| 1241 | 1224 | ||
| 1242 | try o.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 1225 | try o.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index)); |
| 1243 | } | 1226 | } |
| 1244 | 1227 | ||
| 1245 | pub fn updateDecl(self: *Object, module: *Module, decl_index: Module.Decl.Index) !void { | 1228 | pub fn updateDecl(self: *Object, module: *Module, decl_index: Module.Decl.Index) !void { |
| ... | @@ -1275,63 +1258,72 @@ pub const Object = struct { | ... | @@ -1275,63 +1258,72 @@ pub const Object = struct { |
| 1275 | 1258 | ||
| 1276 | pub fn updateDeclExports( | 1259 | pub fn updateDeclExports( |
| 1277 | self: *Object, | 1260 | self: *Object, |
| 1278 | module: *Module, | 1261 | mod: *Module, |
| 1279 | decl_index: Module.Decl.Index, | 1262 | decl_index: Module.Decl.Index, |
| 1280 | exports: []const *Module.Export, | 1263 | exports: []const *Module.Export, |
| 1281 | ) !void { | 1264 | ) !void { |
| 1265 | const gpa = mod.gpa; | ||
| 1282 | // If the module does not already have the function, we ignore this function call | 1266 | // If the module does not already have the function, we ignore this function call |
| 1283 | // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. | 1267 | // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. |
| 1284 | const llvm_global = self.decl_map.get(decl_index) orelse return; | 1268 | const llvm_global = self.decl_map.get(decl_index) orelse return; |
| 1285 | const decl = module.declPtr(decl_index); | 1269 | const decl = mod.declPtr(decl_index); |
| 1286 | if (decl.isExtern()) { | 1270 | if (decl.isExtern(mod)) { |
| 1287 | const is_wasm_fn = module.getTarget().isWasm() and try decl.isFunction(); | 1271 | var free_decl_name = false; |
| 1288 | const mangle_name = is_wasm_fn and | 1272 | const decl_name = decl_name: { |
| 1289 | decl.getExternFn().?.lib_name != null and | 1273 | const decl_name = mod.intern_pool.stringToSlice(decl.name); |
| 1290 | !std.mem.eql(u8, std.mem.sliceTo(decl.getExternFn().?.lib_name.?, 0), "c"); | 1274 | |
| 1291 | const decl_name = if (mangle_name) name: { | 1275 | if (mod.getTarget().isWasm() and try decl.isFunction(mod)) { |
| 1292 | const tmp = try std.fmt.allocPrintZ(module.gpa, "{s}|{s}", .{ decl.name, decl.getExternFn().?.lib_name.? }); | 1276 | if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| { |
| 1293 | break :name tmp.ptr; | 1277 | if (!std.mem.eql(u8, lib_name, "c")) { |
| 1294 | } else decl.name; | 1278 | free_decl_name = true; |
| 1295 | defer if (mangle_name) module.gpa.free(std.mem.sliceTo(decl_name, 0)); | 1279 | break :decl_name try std.fmt.allocPrintZ(gpa, "{s}|{s}", .{ |
| 1280 | decl_name, lib_name, | ||
| 1281 | }); | ||
| 1282 | } | ||
| 1283 | } | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | break :decl_name decl_name; | ||
| 1287 | }; | ||
| 1288 | defer if (free_decl_name) gpa.free(decl_name); | ||
| 1296 | 1289 | ||
| 1297 | llvm_global.setValueName(decl_name); | 1290 | llvm_global.setValueName(decl_name); |
| 1298 | if (self.getLlvmGlobal(decl_name)) |other_global| { | 1291 | if (self.getLlvmGlobal(decl_name)) |other_global| { |
| 1299 | if (other_global != llvm_global) { | 1292 | if (other_global != llvm_global) { |
| 1300 | log.debug("updateDeclExports isExtern()=true setValueName({s}) conflict", .{decl.name}); | 1293 | try self.extern_collisions.put(gpa, decl_index, {}); |
| 1301 | try self.extern_collisions.put(module.gpa, decl_index, {}); | ||
| 1302 | } | 1294 | } |
| 1303 | } | 1295 | } |
| 1304 | llvm_global.setUnnamedAddr(.False); | 1296 | llvm_global.setUnnamedAddr(.False); |
| 1305 | llvm_global.setLinkage(.External); | 1297 | llvm_global.setLinkage(.External); |
| 1306 | if (module.wantDllExports()) llvm_global.setDLLStorageClass(.Default); | 1298 | if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.Default); |
| 1307 | if (self.di_map.get(decl)) |di_node| { | 1299 | if (self.di_map.get(decl)) |di_node| { |
| 1308 | if (try decl.isFunction()) { | 1300 | if (try decl.isFunction(mod)) { |
| 1309 | const di_func = @ptrCast(*llvm.DISubprogram, di_node); | 1301 | const di_func = @ptrCast(*llvm.DISubprogram, di_node); |
| 1310 | const linkage_name = llvm.MDString.get(self.context, decl.name, std.mem.len(decl.name)); | 1302 | const linkage_name = llvm.MDString.get(self.context, decl_name.ptr, decl_name.len); |
| 1311 | di_func.replaceLinkageName(linkage_name); | 1303 | di_func.replaceLinkageName(linkage_name); |
| 1312 | } else { | 1304 | } else { |
| 1313 | const di_global = @ptrCast(*llvm.DIGlobalVariable, di_node); | 1305 | const di_global = @ptrCast(*llvm.DIGlobalVariable, di_node); |
| 1314 | const linkage_name = llvm.MDString.get(self.context, decl.name, std.mem.len(decl.name)); | 1306 | const linkage_name = llvm.MDString.get(self.context, decl_name.ptr, decl_name.len); |
| 1315 | di_global.replaceLinkageName(linkage_name); | 1307 | di_global.replaceLinkageName(linkage_name); |
| 1316 | } | 1308 | } |
| 1317 | } | 1309 | } |
| 1318 | if (decl.val.castTag(.variable)) |variable| { | 1310 | if (decl.val.getVariable(mod)) |variable| { |
| 1319 | if (variable.data.is_threadlocal) { | 1311 | if (variable.is_threadlocal) { |
| 1320 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | 1312 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1321 | } else { | 1313 | } else { |
| 1322 | llvm_global.setThreadLocalMode(.NotThreadLocal); | 1314 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| 1323 | } | 1315 | } |
| 1324 | if (variable.data.is_weak_linkage) { | 1316 | if (variable.is_weak_linkage) { |
| 1325 | llvm_global.setLinkage(.ExternalWeak); | 1317 | llvm_global.setLinkage(.ExternalWeak); |
| 1326 | } | 1318 | } |
| 1327 | } | 1319 | } |
| 1328 | } else if (exports.len != 0) { | 1320 | } else if (exports.len != 0) { |
| 1329 | const exp_name = exports[0].options.name; | 1321 | const exp_name = mod.intern_pool.stringToSlice(exports[0].opts.name); |
| 1330 | llvm_global.setValueName2(exp_name.ptr, exp_name.len); | 1322 | llvm_global.setValueName2(exp_name.ptr, exp_name.len); |
| 1331 | llvm_global.setUnnamedAddr(.False); | 1323 | llvm_global.setUnnamedAddr(.False); |
| 1332 | if (module.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport); | 1324 | if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport); |
| 1333 | if (self.di_map.get(decl)) |di_node| { | 1325 | if (self.di_map.get(decl)) |di_node| { |
| 1334 | if (try decl.isFunction()) { | 1326 | if (try decl.isFunction(mod)) { |
| 1335 | const di_func = @ptrCast(*llvm.DISubprogram, di_node); | 1327 | const di_func = @ptrCast(*llvm.DISubprogram, di_node); |
| 1336 | const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len); | 1328 | const linkage_name = llvm.MDString.get(self.context, exp_name.ptr, exp_name.len); |
| 1337 | di_func.replaceLinkageName(linkage_name); | 1329 | di_func.replaceLinkageName(linkage_name); |
| ... | @@ -1341,37 +1333,34 @@ pub const Object = struct { | ... | @@ -1341,37 +1333,34 @@ pub const Object = struct { |
| 1341 | di_global.replaceLinkageName(linkage_name); | 1333 | di_global.replaceLinkageName(linkage_name); |
| 1342 | } | 1334 | } |
| 1343 | } | 1335 | } |
| 1344 | switch (exports[0].options.linkage) { | 1336 | switch (exports[0].opts.linkage) { |
| 1345 | .Internal => unreachable, | 1337 | .Internal => unreachable, |
| 1346 | .Strong => llvm_global.setLinkage(.External), | 1338 | .Strong => llvm_global.setLinkage(.External), |
| 1347 | .Weak => llvm_global.setLinkage(.WeakODR), | 1339 | .Weak => llvm_global.setLinkage(.WeakODR), |
| 1348 | .LinkOnce => llvm_global.setLinkage(.LinkOnceODR), | 1340 | .LinkOnce => llvm_global.setLinkage(.LinkOnceODR), |
| 1349 | } | 1341 | } |
| 1350 | switch (exports[0].options.visibility) { | 1342 | switch (exports[0].opts.visibility) { |
| 1351 | .default => llvm_global.setVisibility(.Default), | 1343 | .default => llvm_global.setVisibility(.Default), |
| 1352 | .hidden => llvm_global.setVisibility(.Hidden), | 1344 | .hidden => llvm_global.setVisibility(.Hidden), |
| 1353 | .protected => llvm_global.setVisibility(.Protected), | 1345 | .protected => llvm_global.setVisibility(.Protected), |
| 1354 | } | 1346 | } |
| 1355 | if (exports[0].options.section) |section| { | 1347 | if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section| { |
| 1356 | const section_z = try module.gpa.dupeZ(u8, section); | 1348 | llvm_global.setSection(section); |
| 1357 | defer module.gpa.free(section_z); | ||
| 1358 | llvm_global.setSection(section_z); | ||
| 1359 | } | 1349 | } |
| 1360 | if (decl.val.castTag(.variable)) |variable| { | 1350 | if (decl.val.getVariable(mod)) |variable| { |
| 1361 | if (variable.data.is_threadlocal) { | 1351 | if (variable.is_threadlocal) { |
| 1362 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | 1352 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1363 | } | 1353 | } |
| 1364 | } | 1354 | } |
| 1365 | 1355 | ||
| 1366 | // If a Decl is exported more than one time (which is rare), | 1356 | // If a Decl is exported more than one time (which is rare), |
| 1367 | // we add aliases for all but the first export. | 1357 | // we add aliases for all but the first export. |
| 1368 | // TODO LLVM C API does not support deleting aliases. We need to | 1358 | // TODO LLVM C API does not support deleting aliases. |
| 1369 | // patch it to support this or figure out how to wrap the C++ API ourselves. | 1359 | // The planned solution to this is https://github.com/ziglang/zig/issues/13265 |
| 1370 | // Until then we iterate over existing aliases and make them point | 1360 | // Until then we iterate over existing aliases and make them point |
| 1371 | // to the correct decl, or otherwise add a new alias. Old aliases are leaked. | 1361 | // to the correct decl, or otherwise add a new alias. Old aliases are leaked. |
| 1372 | for (exports[1..]) |exp| { | 1362 | for (exports[1..]) |exp| { |
| 1373 | const exp_name_z = try module.gpa.dupeZ(u8, exp.options.name); | 1363 | const exp_name_z = mod.intern_pool.stringToSlice(exp.opts.name); |
| 1374 | defer module.gpa.free(exp_name_z); | ||
| 1375 | 1364 | ||
| 1376 | if (self.llvm_module.getNamedGlobalAlias(exp_name_z.ptr, exp_name_z.len)) |alias| { | 1365 | if (self.llvm_module.getNamedGlobalAlias(exp_name_z.ptr, exp_name_z.len)) |alias| { |
| 1377 | alias.setAliasee(llvm_global); | 1366 | alias.setAliasee(llvm_global); |
| ... | @@ -1385,15 +1374,14 @@ pub const Object = struct { | ... | @@ -1385,15 +1374,14 @@ pub const Object = struct { |
| 1385 | } | 1374 | } |
| 1386 | } | 1375 | } |
| 1387 | } else { | 1376 | } else { |
| 1388 | const fqn = try decl.getFullyQualifiedName(module); | 1377 | const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1389 | defer module.gpa.free(fqn); | ||
| 1390 | llvm_global.setValueName2(fqn.ptr, fqn.len); | 1378 | llvm_global.setValueName2(fqn.ptr, fqn.len); |
| 1391 | llvm_global.setLinkage(.Internal); | 1379 | llvm_global.setLinkage(.Internal); |
| 1392 | if (module.wantDllExports()) llvm_global.setDLLStorageClass(.Default); | 1380 | if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.Default); |
| 1393 | llvm_global.setUnnamedAddr(.True); | 1381 | llvm_global.setUnnamedAddr(.True); |
| 1394 | if (decl.val.castTag(.variable)) |variable| { | 1382 | if (decl.val.getVariable(mod)) |variable| { |
| 1395 | const single_threaded = module.comp.bin_file.options.single_threaded; | 1383 | const single_threaded = mod.comp.bin_file.options.single_threaded; |
| 1396 | if (variable.data.is_threadlocal and !single_threaded) { | 1384 | if (variable.is_threadlocal and !single_threaded) { |
| 1397 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | 1385 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1398 | } else { | 1386 | } else { |
| 1399 | llvm_global.setThreadLocalMode(.NotThreadLocal); | 1387 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| ... | @@ -1444,7 +1432,7 @@ pub const Object = struct { | ... | @@ -1444,7 +1432,7 @@ pub const Object = struct { |
| 1444 | const gpa = o.gpa; | 1432 | const gpa = o.gpa; |
| 1445 | // Be careful not to reference this `gop` variable after any recursive calls | 1433 | // Be careful not to reference this `gop` variable after any recursive calls |
| 1446 | // to `lowerDebugType`. | 1434 | // to `lowerDebugType`. |
| 1447 | const gop = try o.di_type_map.getOrPutContext(gpa, ty, .{ .mod = o.module }); | 1435 | const gop = try o.di_type_map.getOrPut(gpa, ty.toIntern()); |
| 1448 | if (gop.found_existing) { | 1436 | if (gop.found_existing) { |
| 1449 | const annotated = gop.value_ptr.*; | 1437 | const annotated = gop.value_ptr.*; |
| 1450 | const di_type = annotated.toDIType(); | 1438 | const di_type = annotated.toDIType(); |
| ... | @@ -1457,10 +1445,7 @@ pub const Object = struct { | ... | @@ -1457,10 +1445,7 @@ pub const Object = struct { |
| 1457 | }; | 1445 | }; |
| 1458 | return o.lowerDebugTypeImpl(entry, resolve, di_type); | 1446 | return o.lowerDebugTypeImpl(entry, resolve, di_type); |
| 1459 | } | 1447 | } |
| 1460 | errdefer assert(o.di_type_map.orderedRemoveContext(ty, .{ .mod = o.module })); | 1448 | errdefer assert(o.di_type_map.orderedRemove(ty.toIntern())); |
| 1461 | // The Type memory is ephemeral; since we want to store a longer-lived | ||
| 1462 | // reference, we need to copy it here. | ||
| 1463 | gop.key_ptr.* = try ty.copy(o.type_map_arena.allocator()); | ||
| 1464 | const entry: Object.DITypeMap.Entry = .{ | 1449 | const entry: Object.DITypeMap.Entry = .{ |
| 1465 | .key_ptr = gop.key_ptr, | 1450 | .key_ptr = gop.key_ptr, |
| 1466 | .value_ptr = gop.value_ptr, | 1451 | .value_ptr = gop.value_ptr, |
| ... | @@ -1475,18 +1460,19 @@ pub const Object = struct { | ... | @@ -1475,18 +1460,19 @@ pub const Object = struct { |
| 1475 | resolve: DebugResolveStatus, | 1460 | resolve: DebugResolveStatus, |
| 1476 | opt_fwd_decl: ?*llvm.DIType, | 1461 | opt_fwd_decl: ?*llvm.DIType, |
| 1477 | ) Allocator.Error!*llvm.DIType { | 1462 | ) Allocator.Error!*llvm.DIType { |
| 1478 | const ty = gop.key_ptr.*; | 1463 | const ty = gop.key_ptr.toType(); |
| 1479 | const gpa = o.gpa; | 1464 | const gpa = o.gpa; |
| 1480 | const target = o.target; | 1465 | const target = o.target; |
| 1481 | const dib = o.di_builder.?; | 1466 | const dib = o.di_builder.?; |
| 1482 | switch (ty.zigTypeTag()) { | 1467 | const mod = o.module; |
| 1468 | switch (ty.zigTypeTag(mod)) { | ||
| 1483 | .Void, .NoReturn => { | 1469 | .Void, .NoReturn => { |
| 1484 | const di_type = dib.createBasicType("void", 0, DW.ATE.signed); | 1470 | const di_type = dib.createBasicType("void", 0, DW.ATE.signed); |
| 1485 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); | 1471 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); |
| 1486 | return di_type; | 1472 | return di_type; |
| 1487 | }, | 1473 | }, |
| 1488 | .Int => { | 1474 | .Int => { |
| 1489 | const info = ty.intInfo(target); | 1475 | const info = ty.intInfo(mod); |
| 1490 | assert(info.bits != 0); | 1476 | assert(info.bits != 0); |
| 1491 | const name = try ty.nameAlloc(gpa, o.module); | 1477 | const name = try ty.nameAlloc(gpa, o.module); |
| 1492 | defer gpa.free(name); | 1478 | defer gpa.free(name); |
| ... | @@ -1494,49 +1480,41 @@ pub const Object = struct { | ... | @@ -1494,49 +1480,41 @@ pub const Object = struct { |
| 1494 | .signed => DW.ATE.signed, | 1480 | .signed => DW.ATE.signed, |
| 1495 | .unsigned => DW.ATE.unsigned, | 1481 | .unsigned => DW.ATE.unsigned, |
| 1496 | }; | 1482 | }; |
| 1497 | const di_bits = ty.abiSize(target) * 8; // lldb cannot handle non-byte sized types | 1483 | const di_bits = ty.abiSize(mod) * 8; // lldb cannot handle non-byte sized types |
| 1498 | const di_type = dib.createBasicType(name, di_bits, dwarf_encoding); | 1484 | const di_type = dib.createBasicType(name, di_bits, dwarf_encoding); |
| 1499 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); | 1485 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type); |
| 1500 | return di_type; | 1486 | return di_type; |
| 1501 | }, | 1487 | }, |
| 1502 | .Enum => { | 1488 | .Enum => { |
| 1503 | const owner_decl_index = ty.getOwnerDecl(); | 1489 | const owner_decl_index = ty.getOwnerDecl(mod); |
| 1504 | const owner_decl = o.module.declPtr(owner_decl_index); | 1490 | const owner_decl = o.module.declPtr(owner_decl_index); |
| 1505 | 1491 | ||
| 1506 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | 1492 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1507 | const enum_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); | 1493 | const enum_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); |
| 1508 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | 1494 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 1509 | // means we can't use `gop` anymore. | 1495 | // means we can't use `gop` anymore. |
| 1510 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(enum_di_ty), .{ .mod = o.module }); | 1496 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(enum_di_ty)); |
| 1511 | return enum_di_ty; | 1497 | return enum_di_ty; |
| 1512 | } | 1498 | } |
| 1513 | 1499 | ||
| 1514 | const field_names = ty.enumFields().keys(); | 1500 | const ip = &mod.intern_pool; |
| 1501 | const enum_type = ip.indexToKey(ty.toIntern()).enum_type; | ||
| 1515 | 1502 | ||
| 1516 | const enumerators = try gpa.alloc(*llvm.DIEnumerator, field_names.len); | 1503 | const enumerators = try gpa.alloc(*llvm.DIEnumerator, enum_type.names.len); |
| 1517 | defer gpa.free(enumerators); | 1504 | defer gpa.free(enumerators); |
| 1518 | 1505 | ||
| 1519 | var buf_field_index: Value.Payload.U32 = .{ | 1506 | const int_ty = enum_type.tag_ty.toType(); |
| 1520 | .base = .{ .tag = .enum_field_index }, | 1507 | const int_info = ty.intInfo(mod); |
| 1521 | .data = undefined, | ||
| 1522 | }; | ||
| 1523 | const field_index_val = Value.initPayload(&buf_field_index.base); | ||
| 1524 | |||
| 1525 | var buffer: Type.Payload.Bits = undefined; | ||
| 1526 | const int_ty = ty.intTagType(&buffer); | ||
| 1527 | const int_info = ty.intInfo(target); | ||
| 1528 | assert(int_info.bits != 0); | 1508 | assert(int_info.bits != 0); |
| 1529 | 1509 | ||
| 1530 | for (field_names, 0..) |field_name, i| { | 1510 | for (enum_type.names, 0..) |field_name_ip, i| { |
| 1531 | const field_name_z = try gpa.dupeZ(u8, field_name); | 1511 | const field_name_z = ip.stringToSlice(field_name_ip); |
| 1532 | defer gpa.free(field_name_z); | ||
| 1533 | |||
| 1534 | buf_field_index.data = @intCast(u32, i); | ||
| 1535 | var buf_u64: Value.Payload.U64 = undefined; | ||
| 1536 | const field_int_val = field_index_val.enumToInt(ty, &buf_u64); | ||
| 1537 | 1512 | ||
| 1538 | var bigint_space: Value.BigIntSpace = undefined; | 1513 | var bigint_space: Value.BigIntSpace = undefined; |
| 1539 | const bigint = field_int_val.toBigInt(&bigint_space, target); | 1514 | const bigint = if (enum_type.values.len != 0) |
| 1515 | enum_type.values[i].toValue().toBigInt(&bigint_space, mod) | ||
| 1516 | else | ||
| 1517 | std.math.big.int.Mutable.init(&bigint_space.limbs, i).toConst(); | ||
| 1540 | 1518 | ||
| 1541 | if (bigint.limbs.len == 1) { | 1519 | if (bigint.limbs.len == 1) { |
| 1542 | enumerators[i] = dib.createEnumerator(field_name_z, bigint.limbs[0], int_info.signedness == .unsigned); | 1520 | enumerators[i] = dib.createEnumerator(field_name_z, bigint.limbs[0], int_info.signedness == .unsigned); |
| ... | @@ -1555,7 +1533,7 @@ pub const Object = struct { | ... | @@ -1555,7 +1533,7 @@ pub const Object = struct { |
| 1555 | @panic("TODO implement bigint debug enumerators to llvm int for 32-bit compiler builds"); | 1533 | @panic("TODO implement bigint debug enumerators to llvm int for 32-bit compiler builds"); |
| 1556 | } | 1534 | } |
| 1557 | 1535 | ||
| 1558 | const di_file = try o.getDIFile(gpa, owner_decl.src_namespace.file_scope); | 1536 | const di_file = try o.getDIFile(gpa, mod.namespacePtr(owner_decl.src_namespace).file_scope); |
| 1559 | const di_scope = try o.namespaceToDebugScope(owner_decl.src_namespace); | 1537 | const di_scope = try o.namespaceToDebugScope(owner_decl.src_namespace); |
| 1560 | 1538 | ||
| 1561 | const name = try ty.nameAlloc(gpa, o.module); | 1539 | const name = try ty.nameAlloc(gpa, o.module); |
| ... | @@ -1566,15 +1544,15 @@ pub const Object = struct { | ... | @@ -1566,15 +1544,15 @@ pub const Object = struct { |
| 1566 | name, | 1544 | name, |
| 1567 | di_file, | 1545 | di_file, |
| 1568 | owner_decl.src_node + 1, | 1546 | owner_decl.src_node + 1, |
| 1569 | ty.abiSize(target) * 8, | 1547 | ty.abiSize(mod) * 8, |
| 1570 | ty.abiAlignment(target) * 8, | 1548 | ty.abiAlignment(mod) * 8, |
| 1571 | enumerators.ptr, | 1549 | enumerators.ptr, |
| 1572 | @intCast(c_int, enumerators.len), | 1550 | @intCast(c_int, enumerators.len), |
| 1573 | try o.lowerDebugType(int_ty, .full), | 1551 | try o.lowerDebugType(int_ty, .full), |
| 1574 | "", | 1552 | "", |
| 1575 | ); | 1553 | ); |
| 1576 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 1554 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1577 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(enum_di_ty), .{ .mod = o.module }); | 1555 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(enum_di_ty)); |
| 1578 | return enum_di_ty; | 1556 | return enum_di_ty; |
| 1579 | }, | 1557 | }, |
| 1580 | .Float => { | 1558 | .Float => { |
| ... | @@ -1593,49 +1571,40 @@ pub const Object = struct { | ... | @@ -1593,49 +1571,40 @@ pub const Object = struct { |
| 1593 | }, | 1571 | }, |
| 1594 | .Pointer => { | 1572 | .Pointer => { |
| 1595 | // Normalize everything that the debug info does not represent. | 1573 | // Normalize everything that the debug info does not represent. |
| 1596 | const ptr_info = ty.ptrInfo().data; | 1574 | const ptr_info = Type.ptrInfoIp(&mod.intern_pool, ty.toIntern()); |
| 1597 | 1575 | ||
| 1598 | if (ptr_info.sentinel != null or | 1576 | if (ptr_info.sentinel != .none or |
| 1599 | ptr_info.@"addrspace" != .generic or | 1577 | ptr_info.flags.address_space != .generic or |
| 1600 | ptr_info.bit_offset != 0 or | 1578 | ptr_info.packed_offset.bit_offset != 0 or |
| 1601 | ptr_info.host_size != 0 or | 1579 | ptr_info.packed_offset.host_size != 0 or |
| 1602 | ptr_info.vector_index != .none or | 1580 | ptr_info.flags.vector_index != .none or |
| 1603 | ptr_info.@"allowzero" or | 1581 | ptr_info.flags.is_allowzero or |
| 1604 | !ptr_info.mutable or | 1582 | ptr_info.flags.is_const or |
| 1605 | ptr_info.@"volatile" or | 1583 | ptr_info.flags.is_volatile or |
| 1606 | ptr_info.size == .Many or ptr_info.size == .C or | 1584 | ptr_info.flags.size == .Many or ptr_info.flags.size == .C or |
| 1607 | !ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) | 1585 | !ptr_info.child.toType().hasRuntimeBitsIgnoreComptime(mod)) |
| 1608 | { | 1586 | { |
| 1609 | var payload: Type.Payload.Pointer = .{ | 1587 | const bland_ptr_ty = try mod.ptrType(.{ |
| 1610 | .data = .{ | 1588 | .child = if (!ptr_info.child.toType().hasRuntimeBitsIgnoreComptime(mod)) |
| 1611 | .pointee_type = ptr_info.pointee_type, | 1589 | .anyopaque_type |
| 1612 | .sentinel = null, | 1590 | else |
| 1613 | .@"align" = ptr_info.@"align", | 1591 | ptr_info.child, |
| 1614 | .@"addrspace" = .generic, | 1592 | .flags = .{ |
| 1615 | .bit_offset = 0, | 1593 | .alignment = ptr_info.flags.alignment, |
| 1616 | .host_size = 0, | 1594 | .size = switch (ptr_info.flags.size) { |
| 1617 | .@"allowzero" = false, | ||
| 1618 | .mutable = true, | ||
| 1619 | .@"volatile" = false, | ||
| 1620 | .size = switch (ptr_info.size) { | ||
| 1621 | .Many, .C, .One => .One, | 1595 | .Many, .C, .One => .One, |
| 1622 | .Slice => .Slice, | 1596 | .Slice => .Slice, |
| 1623 | }, | 1597 | }, |
| 1624 | }, | 1598 | }, |
| 1625 | }; | 1599 | }); |
| 1626 | if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) { | ||
| 1627 | payload.data.pointee_type = Type.anyopaque; | ||
| 1628 | } | ||
| 1629 | const bland_ptr_ty = Type.initPayload(&payload.base); | ||
| 1630 | const ptr_di_ty = try o.lowerDebugType(bland_ptr_ty, resolve); | 1600 | const ptr_di_ty = try o.lowerDebugType(bland_ptr_ty, resolve); |
| 1631 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 1601 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1632 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.init(ptr_di_ty, resolve), .{ .mod = o.module }); | 1602 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.init(ptr_di_ty, resolve)); |
| 1633 | return ptr_di_ty; | 1603 | return ptr_di_ty; |
| 1634 | } | 1604 | } |
| 1635 | 1605 | ||
| 1636 | if (ty.isSlice()) { | 1606 | if (ty.isSlice(mod)) { |
| 1637 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1607 | const ptr_ty = ty.slicePtrFieldType(mod); |
| 1638 | const ptr_ty = ty.slicePtrFieldType(&buf); | ||
| 1639 | const len_ty = Type.usize; | 1608 | const len_ty = Type.usize; |
| 1640 | 1609 | ||
| 1641 | const name = try ty.nameAlloc(gpa, o.module); | 1610 | const name = try ty.nameAlloc(gpa, o.module); |
| ... | @@ -1657,10 +1626,10 @@ pub const Object = struct { | ... | @@ -1657,10 +1626,10 @@ pub const Object = struct { |
| 1657 | break :blk fwd_decl; | 1626 | break :blk fwd_decl; |
| 1658 | }; | 1627 | }; |
| 1659 | 1628 | ||
| 1660 | const ptr_size = ptr_ty.abiSize(target); | 1629 | const ptr_size = ptr_ty.abiSize(mod); |
| 1661 | const ptr_align = ptr_ty.abiAlignment(target); | 1630 | const ptr_align = ptr_ty.abiAlignment(mod); |
| 1662 | const len_size = len_ty.abiSize(target); | 1631 | const len_size = len_ty.abiSize(mod); |
| 1663 | const len_align = len_ty.abiAlignment(target); | 1632 | const len_align = len_ty.abiAlignment(mod); |
| 1664 | 1633 | ||
| 1665 | var offset: u64 = 0; | 1634 | var offset: u64 = 0; |
| 1666 | offset += ptr_size; | 1635 | offset += ptr_size; |
| ... | @@ -1697,8 +1666,8 @@ pub const Object = struct { | ... | @@ -1697,8 +1666,8 @@ pub const Object = struct { |
| 1697 | name.ptr, | 1666 | name.ptr, |
| 1698 | di_file, | 1667 | di_file, |
| 1699 | line, | 1668 | line, |
| 1700 | ty.abiSize(target) * 8, // size in bits | 1669 | ty.abiSize(mod) * 8, // size in bits |
| 1701 | ty.abiAlignment(target) * 8, // align in bits | 1670 | ty.abiAlignment(mod) * 8, // align in bits |
| 1702 | 0, // flags | 1671 | 0, // flags |
| 1703 | null, // derived from | 1672 | null, // derived from |
| 1704 | &fields, | 1673 | &fields, |
| ... | @@ -1709,65 +1678,65 @@ pub const Object = struct { | ... | @@ -1709,65 +1678,65 @@ pub const Object = struct { |
| 1709 | ); | 1678 | ); |
| 1710 | dib.replaceTemporary(fwd_decl, full_di_ty); | 1679 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 1711 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 1680 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1712 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | 1681 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); |
| 1713 | return full_di_ty; | 1682 | return full_di_ty; |
| 1714 | } | 1683 | } |
| 1715 | 1684 | ||
| 1716 | const elem_di_ty = try o.lowerDebugType(ptr_info.pointee_type, .fwd); | 1685 | const elem_di_ty = try o.lowerDebugType(ptr_info.child.toType(), .fwd); |
| 1717 | const name = try ty.nameAlloc(gpa, o.module); | 1686 | const name = try ty.nameAlloc(gpa, o.module); |
| 1718 | defer gpa.free(name); | 1687 | defer gpa.free(name); |
| 1719 | const ptr_di_ty = dib.createPointerType( | 1688 | const ptr_di_ty = dib.createPointerType( |
| 1720 | elem_di_ty, | 1689 | elem_di_ty, |
| 1721 | target.ptrBitWidth(), | 1690 | target.ptrBitWidth(), |
| 1722 | ty.ptrAlignment(target) * 8, | 1691 | ty.ptrAlignment(mod) * 8, |
| 1723 | name, | 1692 | name, |
| 1724 | ); | 1693 | ); |
| 1725 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 1694 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1726 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(ptr_di_ty), .{ .mod = o.module }); | 1695 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(ptr_di_ty)); |
| 1727 | return ptr_di_ty; | 1696 | return ptr_di_ty; |
| 1728 | }, | 1697 | }, |
| 1729 | .Opaque => { | 1698 | .Opaque => { |
| 1730 | if (ty.tag() == .anyopaque) { | 1699 | if (ty.toIntern() == .anyopaque_type) { |
| 1731 | const di_ty = dib.createBasicType("anyopaque", 0, DW.ATE.signed); | 1700 | const di_ty = dib.createBasicType("anyopaque", 0, DW.ATE.signed); |
| 1732 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); | 1701 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); |
| 1733 | return di_ty; | 1702 | return di_ty; |
| 1734 | } | 1703 | } |
| 1735 | const name = try ty.nameAlloc(gpa, o.module); | 1704 | const name = try ty.nameAlloc(gpa, o.module); |
| 1736 | defer gpa.free(name); | 1705 | defer gpa.free(name); |
| 1737 | const owner_decl_index = ty.getOwnerDecl(); | 1706 | const owner_decl_index = ty.getOwnerDecl(mod); |
| 1738 | const owner_decl = o.module.declPtr(owner_decl_index); | 1707 | const owner_decl = o.module.declPtr(owner_decl_index); |
| 1739 | const opaque_di_ty = dib.createForwardDeclType( | 1708 | const opaque_di_ty = dib.createForwardDeclType( |
| 1740 | DW.TAG.structure_type, | 1709 | DW.TAG.structure_type, |
| 1741 | name, | 1710 | name, |
| 1742 | try o.namespaceToDebugScope(owner_decl.src_namespace), | 1711 | try o.namespaceToDebugScope(owner_decl.src_namespace), |
| 1743 | try o.getDIFile(gpa, owner_decl.src_namespace.file_scope), | 1712 | try o.getDIFile(gpa, mod.namespacePtr(owner_decl.src_namespace).file_scope), |
| 1744 | owner_decl.src_node + 1, | 1713 | owner_decl.src_node + 1, |
| 1745 | ); | 1714 | ); |
| 1746 | // The recursive call to `lowerDebugType` va `namespaceToDebugScope` | 1715 | // The recursive call to `lowerDebugType` va `namespaceToDebugScope` |
| 1747 | // means we can't use `gop` anymore. | 1716 | // means we can't use `gop` anymore. |
| 1748 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(opaque_di_ty), .{ .mod = o.module }); | 1717 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(opaque_di_ty)); |
| 1749 | return opaque_di_ty; | 1718 | return opaque_di_ty; |
| 1750 | }, | 1719 | }, |
| 1751 | .Array => { | 1720 | .Array => { |
| 1752 | const array_di_ty = dib.createArrayType( | 1721 | const array_di_ty = dib.createArrayType( |
| 1753 | ty.abiSize(target) * 8, | 1722 | ty.abiSize(mod) * 8, |
| 1754 | ty.abiAlignment(target) * 8, | 1723 | ty.abiAlignment(mod) * 8, |
| 1755 | try o.lowerDebugType(ty.childType(), .full), | 1724 | try o.lowerDebugType(ty.childType(mod), .full), |
| 1756 | @intCast(c_int, ty.arrayLen()), | 1725 | @intCast(c_int, ty.arrayLen(mod)), |
| 1757 | ); | 1726 | ); |
| 1758 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 1727 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1759 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(array_di_ty), .{ .mod = o.module }); | 1728 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(array_di_ty)); |
| 1760 | return array_di_ty; | 1729 | return array_di_ty; |
| 1761 | }, | 1730 | }, |
| 1762 | .Vector => { | 1731 | .Vector => { |
| 1763 | const elem_ty = ty.elemType2(); | 1732 | const elem_ty = ty.elemType2(mod); |
| 1764 | // Vector elements cannot be padded since that would make | 1733 | // Vector elements cannot be padded since that would make |
| 1765 | // @bitSizOf(elem) * len > @bitSizOf(vec). | 1734 | // @bitSizOf(elem) * len > @bitSizOf(vec). |
| 1766 | // Neither gdb nor lldb seem to be able to display non-byte sized | 1735 | // Neither gdb nor lldb seem to be able to display non-byte sized |
| 1767 | // vectors properly. | 1736 | // vectors properly. |
| 1768 | const elem_di_type = switch (elem_ty.zigTypeTag()) { | 1737 | const elem_di_type = switch (elem_ty.zigTypeTag(mod)) { |
| 1769 | .Int => blk: { | 1738 | .Int => blk: { |
| 1770 | const info = elem_ty.intInfo(target); | 1739 | const info = elem_ty.intInfo(mod); |
| 1771 | assert(info.bits != 0); | 1740 | assert(info.bits != 0); |
| 1772 | const name = try ty.nameAlloc(gpa, o.module); | 1741 | const name = try ty.nameAlloc(gpa, o.module); |
| 1773 | defer gpa.free(name); | 1742 | defer gpa.free(name); |
| ... | @@ -1778,34 +1747,33 @@ pub const Object = struct { | ... | @@ -1778,34 +1747,33 @@ pub const Object = struct { |
| 1778 | break :blk dib.createBasicType(name, info.bits, dwarf_encoding); | 1747 | break :blk dib.createBasicType(name, info.bits, dwarf_encoding); |
| 1779 | }, | 1748 | }, |
| 1780 | .Bool => dib.createBasicType("bool", 1, DW.ATE.boolean), | 1749 | .Bool => dib.createBasicType("bool", 1, DW.ATE.boolean), |
| 1781 | else => try o.lowerDebugType(ty.childType(), .full), | 1750 | else => try o.lowerDebugType(ty.childType(mod), .full), |
| 1782 | }; | 1751 | }; |
| 1783 | 1752 | ||
| 1784 | const vector_di_ty = dib.createVectorType( | 1753 | const vector_di_ty = dib.createVectorType( |
| 1785 | ty.abiSize(target) * 8, | 1754 | ty.abiSize(mod) * 8, |
| 1786 | ty.abiAlignment(target) * 8, | 1755 | ty.abiAlignment(mod) * 8, |
| 1787 | elem_di_type, | 1756 | elem_di_type, |
| 1788 | ty.vectorLen(), | 1757 | ty.vectorLen(mod), |
| 1789 | ); | 1758 | ); |
| 1790 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 1759 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1791 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(vector_di_ty), .{ .mod = o.module }); | 1760 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(vector_di_ty)); |
| 1792 | return vector_di_ty; | 1761 | return vector_di_ty; |
| 1793 | }, | 1762 | }, |
| 1794 | .Optional => { | 1763 | .Optional => { |
| 1795 | const name = try ty.nameAlloc(gpa, o.module); | 1764 | const name = try ty.nameAlloc(gpa, o.module); |
| 1796 | defer gpa.free(name); | 1765 | defer gpa.free(name); |
| 1797 | var buf: Type.Payload.ElemType = undefined; | 1766 | const child_ty = ty.optionalChild(mod); |
| 1798 | const child_ty = ty.optionalChild(&buf); | 1767 | if (!child_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1799 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 1800 | const di_bits = 8; // lldb cannot handle non-byte sized types | 1768 | const di_bits = 8; // lldb cannot handle non-byte sized types |
| 1801 | const di_ty = dib.createBasicType(name, di_bits, DW.ATE.boolean); | 1769 | const di_ty = dib.createBasicType(name, di_bits, DW.ATE.boolean); |
| 1802 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); | 1770 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); |
| 1803 | return di_ty; | 1771 | return di_ty; |
| 1804 | } | 1772 | } |
| 1805 | if (ty.optionalReprIsPayload()) { | 1773 | if (ty.optionalReprIsPayload(mod)) { |
| 1806 | const ptr_di_ty = try o.lowerDebugType(child_ty, resolve); | 1774 | const ptr_di_ty = try o.lowerDebugType(child_ty, resolve); |
| 1807 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 1775 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1808 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.init(ptr_di_ty, resolve), .{ .mod = o.module }); | 1776 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.init(ptr_di_ty, resolve)); |
| 1809 | return ptr_di_ty; | 1777 | return ptr_di_ty; |
| 1810 | } | 1778 | } |
| 1811 | 1779 | ||
| ... | @@ -1826,10 +1794,10 @@ pub const Object = struct { | ... | @@ -1826,10 +1794,10 @@ pub const Object = struct { |
| 1826 | }; | 1794 | }; |
| 1827 | 1795 | ||
| 1828 | const non_null_ty = Type.u8; | 1796 | const non_null_ty = Type.u8; |
| 1829 | const payload_size = child_ty.abiSize(target); | 1797 | const payload_size = child_ty.abiSize(mod); |
| 1830 | const payload_align = child_ty.abiAlignment(target); | 1798 | const payload_align = child_ty.abiAlignment(mod); |
| 1831 | const non_null_size = non_null_ty.abiSize(target); | 1799 | const non_null_size = non_null_ty.abiSize(mod); |
| 1832 | const non_null_align = non_null_ty.abiAlignment(target); | 1800 | const non_null_align = non_null_ty.abiAlignment(mod); |
| 1833 | 1801 | ||
| 1834 | var offset: u64 = 0; | 1802 | var offset: u64 = 0; |
| 1835 | offset += payload_size; | 1803 | offset += payload_size; |
| ... | @@ -1866,8 +1834,8 @@ pub const Object = struct { | ... | @@ -1866,8 +1834,8 @@ pub const Object = struct { |
| 1866 | name.ptr, | 1834 | name.ptr, |
| 1867 | di_file, | 1835 | di_file, |
| 1868 | line, | 1836 | line, |
| 1869 | ty.abiSize(target) * 8, // size in bits | 1837 | ty.abiSize(mod) * 8, // size in bits |
| 1870 | ty.abiAlignment(target) * 8, // align in bits | 1838 | ty.abiAlignment(mod) * 8, // align in bits |
| 1871 | 0, // flags | 1839 | 0, // flags |
| 1872 | null, // derived from | 1840 | null, // derived from |
| 1873 | &fields, | 1841 | &fields, |
| ... | @@ -1878,15 +1846,15 @@ pub const Object = struct { | ... | @@ -1878,15 +1846,15 @@ pub const Object = struct { |
| 1878 | ); | 1846 | ); |
| 1879 | dib.replaceTemporary(fwd_decl, full_di_ty); | 1847 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 1880 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 1848 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1881 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | 1849 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); |
| 1882 | return full_di_ty; | 1850 | return full_di_ty; |
| 1883 | }, | 1851 | }, |
| 1884 | .ErrorUnion => { | 1852 | .ErrorUnion => { |
| 1885 | const payload_ty = ty.errorUnionPayload(); | 1853 | const payload_ty = ty.errorUnionPayload(mod); |
| 1886 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 1854 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1887 | const err_set_di_ty = try o.lowerDebugType(Type.anyerror, .full); | 1855 | const err_set_di_ty = try o.lowerDebugType(Type.anyerror, .full); |
| 1888 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 1856 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1889 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(err_set_di_ty), .{ .mod = o.module }); | 1857 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(err_set_di_ty)); |
| 1890 | return err_set_di_ty; | 1858 | return err_set_di_ty; |
| 1891 | } | 1859 | } |
| 1892 | const name = try ty.nameAlloc(gpa, o.module); | 1860 | const name = try ty.nameAlloc(gpa, o.module); |
| ... | @@ -1907,10 +1875,10 @@ pub const Object = struct { | ... | @@ -1907,10 +1875,10 @@ pub const Object = struct { |
| 1907 | break :blk fwd_decl; | 1875 | break :blk fwd_decl; |
| 1908 | }; | 1876 | }; |
| 1909 | 1877 | ||
| 1910 | const error_size = Type.anyerror.abiSize(target); | 1878 | const error_size = Type.anyerror.abiSize(mod); |
| 1911 | const error_align = Type.anyerror.abiAlignment(target); | 1879 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1912 | const payload_size = payload_ty.abiSize(target); | 1880 | const payload_size = payload_ty.abiSize(mod); |
| 1913 | const payload_align = payload_ty.abiAlignment(target); | 1881 | const payload_align = payload_ty.abiAlignment(mod); |
| 1914 | 1882 | ||
| 1915 | var error_index: u32 = undefined; | 1883 | var error_index: u32 = undefined; |
| 1916 | var payload_index: u32 = undefined; | 1884 | var payload_index: u32 = undefined; |
| ... | @@ -1957,8 +1925,8 @@ pub const Object = struct { | ... | @@ -1957,8 +1925,8 @@ pub const Object = struct { |
| 1957 | name.ptr, | 1925 | name.ptr, |
| 1958 | di_file, | 1926 | di_file, |
| 1959 | line, | 1927 | line, |
| 1960 | ty.abiSize(target) * 8, // size in bits | 1928 | ty.abiSize(mod) * 8, // size in bits |
| 1961 | ty.abiAlignment(target) * 8, // align in bits | 1929 | ty.abiAlignment(mod) * 8, // align in bits |
| 1962 | 0, // flags | 1930 | 0, // flags |
| 1963 | null, // derived from | 1931 | null, // derived from |
| 1964 | &fields, | 1932 | &fields, |
| ... | @@ -1969,7 +1937,7 @@ pub const Object = struct { | ... | @@ -1969,7 +1937,7 @@ pub const Object = struct { |
| 1969 | ); | 1937 | ); |
| 1970 | dib.replaceTemporary(fwd_decl, full_di_ty); | 1938 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 1971 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 1939 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1972 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | 1940 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); |
| 1973 | return full_di_ty; | 1941 | return full_di_ty; |
| 1974 | }, | 1942 | }, |
| 1975 | .ErrorSet => { | 1943 | .ErrorSet => { |
| ... | @@ -1984,16 +1952,15 @@ pub const Object = struct { | ... | @@ -1984,16 +1952,15 @@ pub const Object = struct { |
| 1984 | const name = try ty.nameAlloc(gpa, o.module); | 1952 | const name = try ty.nameAlloc(gpa, o.module); |
| 1985 | defer gpa.free(name); | 1953 | defer gpa.free(name); |
| 1986 | 1954 | ||
| 1987 | if (ty.castTag(.@"struct")) |payload| { | 1955 | if (mod.typeToStruct(ty)) |struct_obj| { |
| 1988 | const struct_obj = payload.data; | ||
| 1989 | if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { | 1956 | if (struct_obj.layout == .Packed and struct_obj.haveFieldTypes()) { |
| 1990 | assert(struct_obj.haveLayout()); | 1957 | assert(struct_obj.haveLayout()); |
| 1991 | const info = struct_obj.backing_int_ty.intInfo(target); | 1958 | const info = struct_obj.backing_int_ty.intInfo(mod); |
| 1992 | const dwarf_encoding: c_uint = switch (info.signedness) { | 1959 | const dwarf_encoding: c_uint = switch (info.signedness) { |
| 1993 | .signed => DW.ATE.signed, | 1960 | .signed => DW.ATE.signed, |
| 1994 | .unsigned => DW.ATE.unsigned, | 1961 | .unsigned => DW.ATE.unsigned, |
| 1995 | }; | 1962 | }; |
| 1996 | const di_bits = ty.abiSize(target) * 8; // lldb cannot handle non-byte sized types | 1963 | const di_bits = ty.abiSize(mod) * 8; // lldb cannot handle non-byte sized types |
| 1997 | const di_ty = dib.createBasicType(name, di_bits, dwarf_encoding); | 1964 | const di_ty = dib.createBasicType(name, di_bits, dwarf_encoding); |
| 1998 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); | 1965 | gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty); |
| 1999 | return di_ty; | 1966 | return di_ty; |
| ... | @@ -2013,98 +1980,98 @@ pub const Object = struct { | ... | @@ -2013,98 +1980,98 @@ pub const Object = struct { |
| 2013 | break :blk fwd_decl; | 1980 | break :blk fwd_decl; |
| 2014 | }; | 1981 | }; |
| 2015 | 1982 | ||
| 2016 | if (ty.isSimpleTupleOrAnonStruct()) { | 1983 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 2017 | const tuple = ty.tupleFields(); | 1984 | .anon_struct_type => |tuple| { |
| 2018 | 1985 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | |
| 2019 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | 1986 | defer di_fields.deinit(gpa); |
| 2020 | defer di_fields.deinit(gpa); | 1987 | |
| 2021 | 1988 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 2022 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); | 1989 | |
| 2023 | 1990 | comptime assert(struct_layout_version == 2); | |
| 2024 | comptime assert(struct_layout_version == 2); | 1991 | var offset: u64 = 0; |
| 2025 | var offset: u64 = 0; | 1992 | |
| 2026 | 1993 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 2027 | for (tuple.types, 0..) |field_ty, i| { | 1994 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; |
| 2028 | const field_val = tuple.values[i]; | 1995 | |
| 2029 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; | 1996 | const field_size = field_ty.toType().abiSize(mod); |
| 2030 | 1997 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 2031 | const field_size = field_ty.abiSize(target); | 1998 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 2032 | const field_align = field_ty.abiAlignment(target); | 1999 | offset = field_offset + field_size; |
| 2033 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 2000 | |
| 2034 | offset = field_offset + field_size; | 2001 | const field_name = if (tuple.names.len != 0) |
| 2035 | 2002 | mod.intern_pool.stringToSlice(tuple.names[i]) | |
| 2036 | const field_name = if (ty.castTag(.anon_struct)) |payload| | 2003 | else |
| 2037 | try gpa.dupeZ(u8, payload.data.names[i]) | 2004 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); |
| 2038 | else | 2005 | defer if (tuple.names.len == 0) gpa.free(field_name); |
| 2039 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); | 2006 | |
| 2040 | defer gpa.free(field_name); | 2007 | try di_fields.append(gpa, dib.createMemberType( |
| 2008 | fwd_decl.toScope(), | ||
| 2009 | field_name, | ||
| 2010 | null, // file | ||
| 2011 | 0, // line | ||
| 2012 | field_size * 8, // size in bits | ||
| 2013 | field_align * 8, // align in bits | ||
| 2014 | field_offset * 8, // offset in bits | ||
| 2015 | 0, // flags | ||
| 2016 | try o.lowerDebugType(field_ty.toType(), .full), | ||
| 2017 | )); | ||
| 2018 | } | ||
| 2041 | 2019 | ||
| 2042 | try di_fields.append(gpa, dib.createMemberType( | 2020 | const full_di_ty = dib.createStructType( |
| 2043 | fwd_decl.toScope(), | 2021 | compile_unit_scope, |
| 2044 | field_name, | 2022 | name.ptr, |
| 2045 | null, // file | 2023 | null, // file |
| 2046 | 0, // line | 2024 | 0, // line |
| 2047 | field_size * 8, // size in bits | 2025 | ty.abiSize(mod) * 8, // size in bits |
| 2048 | field_align * 8, // align in bits | 2026 | ty.abiAlignment(mod) * 8, // align in bits |
| 2049 | field_offset * 8, // offset in bits | ||
| 2050 | 0, // flags | 2027 | 0, // flags |
| 2051 | try o.lowerDebugType(field_ty, .full), | 2028 | null, // derived from |
| 2052 | )); | 2029 | di_fields.items.ptr, |
| 2053 | } | 2030 | @intCast(c_int, di_fields.items.len), |
| 2054 | 2031 | 0, // run time lang | |
| 2055 | const full_di_ty = dib.createStructType( | 2032 | null, // vtable holder |
| 2056 | compile_unit_scope, | 2033 | "", // unique id |
| 2057 | name.ptr, | 2034 | ); |
| 2058 | null, // file | 2035 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 2059 | 0, // line | 2036 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2060 | ty.abiSize(target) * 8, // size in bits | 2037 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); |
| 2061 | ty.abiAlignment(target) * 8, // align in bits | 2038 | return full_di_ty; |
| 2062 | 0, // flags | 2039 | }, |
| 2063 | null, // derived from | 2040 | .struct_type => |struct_type| s: { |
| 2064 | di_fields.items.ptr, | 2041 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s; |
| 2065 | @intCast(c_int, di_fields.items.len), | 2042 | |
| 2066 | 0, // run time lang | 2043 | if (!struct_obj.haveFieldTypes()) { |
| 2067 | null, // vtable holder | 2044 | // This can happen if a struct type makes it all the way to |
| 2068 | "", // unique id | 2045 | // flush() without ever being instantiated or referenced (even |
| 2069 | ); | 2046 | // via pointer). The only reason we are hearing about it now is |
| 2070 | dib.replaceTemporary(fwd_decl, full_di_ty); | 2047 | // that it is being used as a namespace to put other debug types |
| 2071 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2048 | // into. Therefore we can satisfy this by making an empty namespace, |
| 2072 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | 2049 | // rather than changing the frontend to unnecessarily resolve the |
| 2073 | return full_di_ty; | 2050 | // struct field types. |
| 2074 | } | 2051 | const owner_decl_index = ty.getOwnerDecl(mod); |
| 2075 | 2052 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); | |
| 2076 | if (ty.castTag(.@"struct")) |payload| { | 2053 | dib.replaceTemporary(fwd_decl, struct_di_ty); |
| 2077 | const struct_obj = payload.data; | 2054 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 2078 | if (!struct_obj.haveFieldTypes()) { | 2055 | // means we can't use `gop` anymore. |
| 2079 | // This can happen if a struct type makes it all the way to | 2056 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(struct_di_ty)); |
| 2080 | // flush() without ever being instantiated or referenced (even | 2057 | return struct_di_ty; |
| 2081 | // via pointer). The only reason we are hearing about it now is | 2058 | } |
| 2082 | // that it is being used as a namespace to put other debug types | 2059 | }, |
| 2083 | // into. Therefore we can satisfy this by making an empty namespace, | 2060 | else => {}, |
| 2084 | // rather than changing the frontend to unnecessarily resolve the | ||
| 2085 | // struct field types. | ||
| 2086 | const owner_decl_index = ty.getOwnerDecl(); | ||
| 2087 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); | ||
| 2088 | dib.replaceTemporary(fwd_decl, struct_di_ty); | ||
| 2089 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | ||
| 2090 | // means we can't use `gop` anymore. | ||
| 2091 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty), .{ .mod = o.module }); | ||
| 2092 | return struct_di_ty; | ||
| 2093 | } | ||
| 2094 | } | 2061 | } |
| 2095 | 2062 | ||
| 2096 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | 2063 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2097 | const owner_decl_index = ty.getOwnerDecl(); | 2064 | const owner_decl_index = ty.getOwnerDecl(mod); |
| 2098 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); | 2065 | const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); |
| 2099 | dib.replaceTemporary(fwd_decl, struct_di_ty); | 2066 | dib.replaceTemporary(fwd_decl, struct_di_ty); |
| 2100 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | 2067 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 2101 | // means we can't use `gop` anymore. | 2068 | // means we can't use `gop` anymore. |
| 2102 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(struct_di_ty), .{ .mod = o.module }); | 2069 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(struct_di_ty)); |
| 2103 | return struct_di_ty; | 2070 | return struct_di_ty; |
| 2104 | } | 2071 | } |
| 2105 | 2072 | ||
| 2106 | const fields = ty.structFields(); | 2073 | const fields = ty.structFields(mod); |
| 2107 | const layout = ty.containerLayout(); | 2074 | const layout = ty.containerLayout(mod); |
| 2108 | 2075 | ||
| 2109 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; | 2076 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; |
| 2110 | defer di_fields.deinit(gpa); | 2077 | defer di_fields.deinit(gpa); |
| ... | @@ -2114,16 +2081,15 @@ pub const Object = struct { | ... | @@ -2114,16 +2081,15 @@ pub const Object = struct { |
| 2114 | comptime assert(struct_layout_version == 2); | 2081 | comptime assert(struct_layout_version == 2); |
| 2115 | var offset: u64 = 0; | 2082 | var offset: u64 = 0; |
| 2116 | 2083 | ||
| 2117 | var it = ty.castTag(.@"struct").?.data.runtimeFieldIterator(); | 2084 | var it = mod.typeToStruct(ty).?.runtimeFieldIterator(mod); |
| 2118 | while (it.next()) |field_and_index| { | 2085 | while (it.next()) |field_and_index| { |
| 2119 | const field = field_and_index.field; | 2086 | const field = field_and_index.field; |
| 2120 | const field_size = field.ty.abiSize(target); | 2087 | const field_size = field.ty.abiSize(mod); |
| 2121 | const field_align = field.alignment(target, layout); | 2088 | const field_align = field.alignment(mod, layout); |
| 2122 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 2089 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 2123 | offset = field_offset + field_size; | 2090 | offset = field_offset + field_size; |
| 2124 | 2091 | ||
| 2125 | const field_name = try gpa.dupeZ(u8, fields.keys()[field_and_index.index]); | 2092 | const field_name = mod.intern_pool.stringToSlice(fields.keys()[field_and_index.index]); |
| 2126 | defer gpa.free(field_name); | ||
| 2127 | 2093 | ||
| 2128 | try di_fields.append(gpa, dib.createMemberType( | 2094 | try di_fields.append(gpa, dib.createMemberType( |
| 2129 | fwd_decl.toScope(), | 2095 | fwd_decl.toScope(), |
| ... | @@ -2143,8 +2109,8 @@ pub const Object = struct { | ... | @@ -2143,8 +2109,8 @@ pub const Object = struct { |
| 2143 | name.ptr, | 2109 | name.ptr, |
| 2144 | null, // file | 2110 | null, // file |
| 2145 | 0, // line | 2111 | 0, // line |
| 2146 | ty.abiSize(target) * 8, // size in bits | 2112 | ty.abiSize(mod) * 8, // size in bits |
| 2147 | ty.abiAlignment(target) * 8, // align in bits | 2113 | ty.abiAlignment(mod) * 8, // align in bits |
| 2148 | 0, // flags | 2114 | 0, // flags |
| 2149 | null, // derived from | 2115 | null, // derived from |
| 2150 | di_fields.items.ptr, | 2116 | di_fields.items.ptr, |
| ... | @@ -2155,12 +2121,12 @@ pub const Object = struct { | ... | @@ -2155,12 +2121,12 @@ pub const Object = struct { |
| 2155 | ); | 2121 | ); |
| 2156 | dib.replaceTemporary(fwd_decl, full_di_ty); | 2122 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 2157 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2123 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2158 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | 2124 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); |
| 2159 | return full_di_ty; | 2125 | return full_di_ty; |
| 2160 | }, | 2126 | }, |
| 2161 | .Union => { | 2127 | .Union => { |
| 2162 | const compile_unit_scope = o.di_compile_unit.?.toScope(); | 2128 | const compile_unit_scope = o.di_compile_unit.?.toScope(); |
| 2163 | const owner_decl_index = ty.getOwnerDecl(); | 2129 | const owner_decl_index = ty.getOwnerDecl(mod); |
| 2164 | 2130 | ||
| 2165 | const name = try ty.nameAlloc(gpa, o.module); | 2131 | const name = try ty.nameAlloc(gpa, o.module); |
| 2166 | defer gpa.free(name); | 2132 | defer gpa.free(name); |
| ... | @@ -2178,17 +2144,17 @@ pub const Object = struct { | ... | @@ -2178,17 +2144,17 @@ pub const Object = struct { |
| 2178 | break :blk fwd_decl; | 2144 | break :blk fwd_decl; |
| 2179 | }; | 2145 | }; |
| 2180 | 2146 | ||
| 2181 | const union_obj = ty.cast(Type.Payload.Union).?.data; | 2147 | const union_obj = mod.typeToUnion(ty).?; |
| 2182 | if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime()) { | 2148 | if (!union_obj.haveFieldTypes() or !ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2183 | const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); | 2149 | const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index); |
| 2184 | dib.replaceTemporary(fwd_decl, union_di_ty); | 2150 | dib.replaceTemporary(fwd_decl, union_di_ty); |
| 2185 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | 2151 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 2186 | // means we can't use `gop` anymore. | 2152 | // means we can't use `gop` anymore. |
| 2187 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .mod = o.module }); | 2153 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(union_di_ty)); |
| 2188 | return union_di_ty; | 2154 | return union_di_ty; |
| 2189 | } | 2155 | } |
| 2190 | 2156 | ||
| 2191 | const layout = ty.unionGetLayout(target); | 2157 | const layout = ty.unionGetLayout(mod); |
| 2192 | 2158 | ||
| 2193 | if (layout.payload_size == 0) { | 2159 | if (layout.payload_size == 0) { |
| 2194 | const tag_di_ty = try o.lowerDebugType(union_obj.tag_ty, .full); | 2160 | const tag_di_ty = try o.lowerDebugType(union_obj.tag_ty, .full); |
| ... | @@ -2198,8 +2164,8 @@ pub const Object = struct { | ... | @@ -2198,8 +2164,8 @@ pub const Object = struct { |
| 2198 | name.ptr, | 2164 | name.ptr, |
| 2199 | null, // file | 2165 | null, // file |
| 2200 | 0, // line | 2166 | 0, // line |
| 2201 | ty.abiSize(target) * 8, // size in bits | 2167 | ty.abiSize(mod) * 8, // size in bits |
| 2202 | ty.abiAlignment(target) * 8, // align in bits | 2168 | ty.abiAlignment(mod) * 8, // align in bits |
| 2203 | 0, // flags | 2169 | 0, // flags |
| 2204 | null, // derived from | 2170 | null, // derived from |
| 2205 | &di_fields, | 2171 | &di_fields, |
| ... | @@ -2211,7 +2177,7 @@ pub const Object = struct { | ... | @@ -2211,7 +2177,7 @@ pub const Object = struct { |
| 2211 | dib.replaceTemporary(fwd_decl, full_di_ty); | 2177 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 2212 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` | 2178 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 2213 | // means we can't use `gop` anymore. | 2179 | // means we can't use `gop` anymore. |
| 2214 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | 2180 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); |
| 2215 | return full_di_ty; | 2181 | return full_di_ty; |
| 2216 | } | 2182 | } |
| 2217 | 2183 | ||
| ... | @@ -2225,24 +2191,22 @@ pub const Object = struct { | ... | @@ -2225,24 +2191,22 @@ pub const Object = struct { |
| 2225 | const field_name = kv.key_ptr.*; | 2191 | const field_name = kv.key_ptr.*; |
| 2226 | const field = kv.value_ptr.*; | 2192 | const field = kv.value_ptr.*; |
| 2227 | 2193 | ||
| 2228 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 2194 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 2229 | |||
| 2230 | const field_size = field.ty.abiSize(target); | ||
| 2231 | const field_align = field.normalAlignment(target); | ||
| 2232 | 2195 | ||
| 2233 | const field_name_copy = try gpa.dupeZ(u8, field_name); | 2196 | const field_size = field.ty.abiSize(mod); |
| 2234 | defer gpa.free(field_name_copy); | 2197 | const field_align = field.normalAlignment(mod); |
| 2235 | 2198 | ||
| 2199 | const field_di_ty = try o.lowerDebugType(field.ty, .full); | ||
| 2236 | di_fields.appendAssumeCapacity(dib.createMemberType( | 2200 | di_fields.appendAssumeCapacity(dib.createMemberType( |
| 2237 | fwd_decl.toScope(), | 2201 | fwd_decl.toScope(), |
| 2238 | field_name_copy, | 2202 | mod.intern_pool.stringToSlice(field_name), |
| 2239 | null, // file | 2203 | null, // file |
| 2240 | 0, // line | 2204 | 0, // line |
| 2241 | field_size * 8, // size in bits | 2205 | field_size * 8, // size in bits |
| 2242 | field_align * 8, // align in bits | 2206 | field_align * 8, // align in bits |
| 2243 | 0, // offset in bits | 2207 | 0, // offset in bits |
| 2244 | 0, // flags | 2208 | 0, // flags |
| 2245 | try o.lowerDebugType(field.ty, .full), | 2209 | field_di_ty, |
| 2246 | )); | 2210 | )); |
| 2247 | } | 2211 | } |
| 2248 | 2212 | ||
| ... | @@ -2258,8 +2222,8 @@ pub const Object = struct { | ... | @@ -2258,8 +2222,8 @@ pub const Object = struct { |
| 2258 | union_name.ptr, | 2222 | union_name.ptr, |
| 2259 | null, // file | 2223 | null, // file |
| 2260 | 0, // line | 2224 | 0, // line |
| 2261 | ty.abiSize(target) * 8, // size in bits | 2225 | ty.abiSize(mod) * 8, // size in bits |
| 2262 | ty.abiAlignment(target) * 8, // align in bits | 2226 | ty.abiAlignment(mod) * 8, // align in bits |
| 2263 | 0, // flags | 2227 | 0, // flags |
| 2264 | di_fields.items.ptr, | 2228 | di_fields.items.ptr, |
| 2265 | @intCast(c_int, di_fields.items.len), | 2229 | @intCast(c_int, di_fields.items.len), |
| ... | @@ -2270,7 +2234,7 @@ pub const Object = struct { | ... | @@ -2270,7 +2234,7 @@ pub const Object = struct { |
| 2270 | if (layout.tag_size == 0) { | 2234 | if (layout.tag_size == 0) { |
| 2271 | dib.replaceTemporary(fwd_decl, union_di_ty); | 2235 | dib.replaceTemporary(fwd_decl, union_di_ty); |
| 2272 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2236 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2273 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(union_di_ty), .{ .mod = o.module }); | 2237 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(union_di_ty)); |
| 2274 | return union_di_ty; | 2238 | return union_di_ty; |
| 2275 | } | 2239 | } |
| 2276 | 2240 | ||
| ... | @@ -2319,8 +2283,8 @@ pub const Object = struct { | ... | @@ -2319,8 +2283,8 @@ pub const Object = struct { |
| 2319 | name.ptr, | 2283 | name.ptr, |
| 2320 | null, // file | 2284 | null, // file |
| 2321 | 0, // line | 2285 | 0, // line |
| 2322 | ty.abiSize(target) * 8, // size in bits | 2286 | ty.abiSize(mod) * 8, // size in bits |
| 2323 | ty.abiAlignment(target) * 8, // align in bits | 2287 | ty.abiAlignment(mod) * 8, // align in bits |
| 2324 | 0, // flags | 2288 | 0, // flags |
| 2325 | null, // derived from | 2289 | null, // derived from |
| 2326 | &full_di_fields, | 2290 | &full_di_fields, |
| ... | @@ -2331,53 +2295,42 @@ pub const Object = struct { | ... | @@ -2331,53 +2295,42 @@ pub const Object = struct { |
| 2331 | ); | 2295 | ); |
| 2332 | dib.replaceTemporary(fwd_decl, full_di_ty); | 2296 | dib.replaceTemporary(fwd_decl, full_di_ty); |
| 2333 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2297 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2334 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(full_di_ty), .{ .mod = o.module }); | 2298 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty)); |
| 2335 | return full_di_ty; | 2299 | return full_di_ty; |
| 2336 | }, | 2300 | }, |
| 2337 | .Fn => { | 2301 | .Fn => { |
| 2338 | const fn_info = ty.fnInfo(); | 2302 | const fn_info = mod.typeToFunc(ty).?; |
| 2339 | 2303 | ||
| 2340 | var param_di_types = std.ArrayList(*llvm.DIType).init(gpa); | 2304 | var param_di_types = std.ArrayList(*llvm.DIType).init(gpa); |
| 2341 | defer param_di_types.deinit(); | 2305 | defer param_di_types.deinit(); |
| 2342 | 2306 | ||
| 2343 | // Return type goes first. | 2307 | // Return type goes first. |
| 2344 | if (fn_info.return_type.hasRuntimeBitsIgnoreComptime()) { | 2308 | if (fn_info.return_type.toType().hasRuntimeBitsIgnoreComptime(mod)) { |
| 2345 | const sret = firstParamSRet(fn_info, target); | 2309 | const sret = firstParamSRet(fn_info, mod); |
| 2346 | const di_ret_ty = if (sret) Type.void else fn_info.return_type; | 2310 | const di_ret_ty = if (sret) Type.void else fn_info.return_type.toType(); |
| 2347 | try param_di_types.append(try o.lowerDebugType(di_ret_ty, .full)); | 2311 | try param_di_types.append(try o.lowerDebugType(di_ret_ty, .full)); |
| 2348 | 2312 | ||
| 2349 | if (sret) { | 2313 | if (sret) { |
| 2350 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 2314 | const ptr_ty = try mod.singleMutPtrType(fn_info.return_type.toType()); |
| 2351 | .base = .{ .tag = .single_mut_pointer }, | ||
| 2352 | .data = fn_info.return_type, | ||
| 2353 | }; | ||
| 2354 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 2355 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); | 2315 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); |
| 2356 | } | 2316 | } |
| 2357 | } else { | 2317 | } else { |
| 2358 | try param_di_types.append(try o.lowerDebugType(Type.void, .full)); | 2318 | try param_di_types.append(try o.lowerDebugType(Type.void, .full)); |
| 2359 | } | 2319 | } |
| 2360 | 2320 | ||
| 2361 | if (fn_info.return_type.isError() and | 2321 | if (fn_info.return_type.toType().isError(mod) and |
| 2362 | o.module.comp.bin_file.options.error_return_tracing) | 2322 | o.module.comp.bin_file.options.error_return_tracing) |
| 2363 | { | 2323 | { |
| 2364 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 2324 | const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); |
| 2365 | .base = .{ .tag = .single_mut_pointer }, | ||
| 2366 | .data = o.getStackTraceType(), | ||
| 2367 | }; | ||
| 2368 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 2369 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); | 2325 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); |
| 2370 | } | 2326 | } |
| 2371 | 2327 | ||
| 2372 | for (fn_info.param_types) |param_ty| { | 2328 | for (0..mod.typeToFunc(ty).?.param_types.len) |i| { |
| 2373 | if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; | 2329 | const param_ty = mod.typeToFunc(ty).?.param_types[i].toType(); |
| 2330 | if (!param_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | ||
| 2374 | 2331 | ||
| 2375 | if (isByRef(param_ty)) { | 2332 | if (isByRef(param_ty, mod)) { |
| 2376 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 2333 | const ptr_ty = try mod.singleMutPtrType(param_ty); |
| 2377 | .base = .{ .tag = .single_mut_pointer }, | ||
| 2378 | .data = param_ty, | ||
| 2379 | }; | ||
| 2380 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 2381 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); | 2334 | try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); |
| 2382 | } else { | 2335 | } else { |
| 2383 | try param_di_types.append(try o.lowerDebugType(param_ty, .full)); | 2336 | try param_di_types.append(try o.lowerDebugType(param_ty, .full)); |
| ... | @@ -2390,7 +2343,7 @@ pub const Object = struct { | ... | @@ -2390,7 +2343,7 @@ pub const Object = struct { |
| 2390 | 0, | 2343 | 0, |
| 2391 | ); | 2344 | ); |
| 2392 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. | 2345 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2393 | try o.di_type_map.putContext(gpa, ty, AnnotatedDITypePtr.initFull(fn_di_ty), .{ .mod = o.module }); | 2346 | try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(fn_di_ty)); |
| 2394 | return fn_di_ty; | 2347 | return fn_di_ty; |
| 2395 | }, | 2348 | }, |
| 2396 | .ComptimeInt => unreachable, | 2349 | .ComptimeInt => unreachable, |
| ... | @@ -2405,8 +2358,10 @@ pub const Object = struct { | ... | @@ -2405,8 +2358,10 @@ pub const Object = struct { |
| 2405 | } | 2358 | } |
| 2406 | } | 2359 | } |
| 2407 | 2360 | ||
| 2408 | fn namespaceToDebugScope(o: *Object, namespace: *const Module.Namespace) !*llvm.DIScope { | 2361 | fn namespaceToDebugScope(o: *Object, namespace_index: Module.Namespace.Index) !*llvm.DIScope { |
| 2409 | if (namespace.parent == null) { | 2362 | const mod = o.module; |
| 2363 | const namespace = mod.namespacePtr(namespace_index); | ||
| 2364 | if (namespace.parent == .none) { | ||
| 2410 | const di_file = try o.getDIFile(o.gpa, namespace.file_scope); | 2365 | const di_file = try o.getDIFile(o.gpa, namespace.file_scope); |
| 2411 | return di_file.toScope(); | 2366 | return di_file.toScope(); |
| 2412 | } | 2367 | } |
| ... | @@ -2418,12 +2373,14 @@ pub const Object = struct { | ... | @@ -2418,12 +2373,14 @@ pub const Object = struct { |
| 2418 | /// Assertion `!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"' | 2373 | /// Assertion `!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"' |
| 2419 | /// when targeting CodeView (Windows). | 2374 | /// when targeting CodeView (Windows). |
| 2420 | fn makeEmptyNamespaceDIType(o: *Object, decl_index: Module.Decl.Index) !*llvm.DIType { | 2375 | fn makeEmptyNamespaceDIType(o: *Object, decl_index: Module.Decl.Index) !*llvm.DIType { |
| 2421 | const decl = o.module.declPtr(decl_index); | 2376 | const mod = o.module; |
| 2377 | const decl = mod.declPtr(decl_index); | ||
| 2422 | const fields: [0]*llvm.DIType = .{}; | 2378 | const fields: [0]*llvm.DIType = .{}; |
| 2379 | const di_scope = try o.namespaceToDebugScope(decl.src_namespace); | ||
| 2423 | return o.di_builder.?.createStructType( | 2380 | return o.di_builder.?.createStructType( |
| 2424 | try o.namespaceToDebugScope(decl.src_namespace), | 2381 | di_scope, |
| 2425 | decl.name, // TODO use fully qualified name | 2382 | mod.intern_pool.stringToSlice(decl.name), // TODO use fully qualified name |
| 2426 | try o.getDIFile(o.gpa, decl.src_namespace.file_scope), | 2383 | try o.getDIFile(o.gpa, mod.namespacePtr(decl.src_namespace).file_scope), |
| 2427 | decl.src_line + 1, | 2384 | decl.src_line + 1, |
| 2428 | 0, // size in bits | 2385 | 0, // size in bits |
| 2429 | 0, // align in bits | 2386 | 0, // align in bits |
| ... | @@ -2437,28 +2394,28 @@ pub const Object = struct { | ... | @@ -2437,28 +2394,28 @@ pub const Object = struct { |
| 2437 | ); | 2394 | ); |
| 2438 | } | 2395 | } |
| 2439 | 2396 | ||
| 2440 | fn getStackTraceType(o: *Object) Type { | 2397 | fn getStackTraceType(o: *Object) Allocator.Error!Type { |
| 2441 | const mod = o.module; | 2398 | const mod = o.module; |
| 2442 | 2399 | ||
| 2443 | const std_pkg = mod.main_pkg.table.get("std").?; | 2400 | const std_pkg = mod.main_pkg.table.get("std").?; |
| 2444 | const std_file = (mod.importPkg(std_pkg) catch unreachable).file; | 2401 | const std_file = (mod.importPkg(std_pkg) catch unreachable).file; |
| 2445 | 2402 | ||
| 2446 | const builtin_str: []const u8 = "builtin"; | 2403 | const builtin_str = try mod.intern_pool.getOrPutString(mod.gpa, "builtin"); |
| 2447 | const std_namespace = mod.declPtr(std_file.root_decl.unwrap().?).src_namespace; | 2404 | const std_namespace = mod.namespacePtr(mod.declPtr(std_file.root_decl.unwrap().?).src_namespace); |
| 2448 | const builtin_decl = std_namespace.decls | 2405 | const builtin_decl = std_namespace.decls |
| 2449 | .getKeyAdapted(builtin_str, Module.DeclAdapter{ .mod = mod }).?; | 2406 | .getKeyAdapted(builtin_str, Module.DeclAdapter{ .mod = mod }).?; |
| 2450 | 2407 | ||
| 2451 | const stack_trace_str: []const u8 = "StackTrace"; | 2408 | const stack_trace_str = try mod.intern_pool.getOrPutString(mod.gpa, "StackTrace"); |
| 2452 | // buffer is only used for int_type, `builtin` is a struct. | 2409 | // buffer is only used for int_type, `builtin` is a struct. |
| 2453 | const builtin_ty = mod.declPtr(builtin_decl).val.toType(undefined); | 2410 | const builtin_ty = mod.declPtr(builtin_decl).val.toType(); |
| 2454 | const builtin_namespace = builtin_ty.getNamespace().?; | 2411 | const builtin_namespace = builtin_ty.getNamespace(mod).?; |
| 2455 | const stack_trace_decl_index = builtin_namespace.decls | 2412 | const stack_trace_decl_index = builtin_namespace.decls |
| 2456 | .getKeyAdapted(stack_trace_str, Module.DeclAdapter{ .mod = mod }).?; | 2413 | .getKeyAdapted(stack_trace_str, Module.DeclAdapter{ .mod = mod }).?; |
| 2457 | const stack_trace_decl = mod.declPtr(stack_trace_decl_index); | 2414 | const stack_trace_decl = mod.declPtr(stack_trace_decl_index); |
| 2458 | 2415 | ||
| 2459 | // Sema should have ensured that StackTrace was analyzed. | 2416 | // Sema should have ensured that StackTrace was analyzed. |
| 2460 | assert(stack_trace_decl.has_tv); | 2417 | assert(stack_trace_decl.has_tv); |
| 2461 | return stack_trace_decl.val.toType(undefined); | 2418 | return stack_trace_decl.val.toType(); |
| 2462 | } | 2419 | } |
| 2463 | }; | 2420 | }; |
| 2464 | 2421 | ||
| ... | @@ -2474,7 +2431,8 @@ pub const DeclGen = struct { | ... | @@ -2474,7 +2431,8 @@ pub const DeclGen = struct { |
| 2474 | fn todo(self: *DeclGen, comptime format: []const u8, args: anytype) Error { | 2431 | fn todo(self: *DeclGen, comptime format: []const u8, args: anytype) Error { |
| 2475 | @setCold(true); | 2432 | @setCold(true); |
| 2476 | assert(self.err_msg == null); | 2433 | assert(self.err_msg == null); |
| 2477 | const src_loc = LazySrcLoc.nodeOffset(0).toSrcLoc(self.decl); | 2434 | const mod = self.module; |
| 2435 | const src_loc = LazySrcLoc.nodeOffset(0).toSrcLoc(self.decl, mod); | ||
| 2478 | self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, "TODO (LLVM): " ++ format, args); | 2436 | self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, "TODO (LLVM): " ++ format, args); |
| 2479 | return error.CodegenFail; | 2437 | return error.CodegenFail; |
| 2480 | } | 2438 | } |
| ... | @@ -2484,31 +2442,27 @@ pub const DeclGen = struct { | ... | @@ -2484,31 +2442,27 @@ pub const DeclGen = struct { |
| 2484 | } | 2442 | } |
| 2485 | 2443 | ||
| 2486 | fn genDecl(dg: *DeclGen) !void { | 2444 | fn genDecl(dg: *DeclGen) !void { |
| 2445 | const mod = dg.module; | ||
| 2487 | const decl = dg.decl; | 2446 | const decl = dg.decl; |
| 2488 | const decl_index = dg.decl_index; | 2447 | const decl_index = dg.decl_index; |
| 2489 | assert(decl.has_tv); | 2448 | assert(decl.has_tv); |
| 2490 | 2449 | ||
| 2491 | log.debug("gen: {s} type: {}, value: {}", .{ | 2450 | if (decl.val.getExternFunc(mod)) |extern_func| { |
| 2492 | decl.name, decl.ty.fmtDebug(), decl.val.fmtDebug(), | 2451 | _ = try dg.resolveLlvmFunction(extern_func.decl); |
| 2493 | }); | ||
| 2494 | assert(decl.val.tag() != .function); | ||
| 2495 | if (decl.val.castTag(.extern_fn)) |extern_fn| { | ||
| 2496 | _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl); | ||
| 2497 | } else { | 2452 | } else { |
| 2498 | const target = dg.module.getTarget(); | 2453 | const target = mod.getTarget(); |
| 2499 | var global = try dg.resolveGlobalDecl(decl_index); | 2454 | var global = try dg.resolveGlobalDecl(decl_index); |
| 2500 | global.setAlignment(decl.getAlignment(target)); | 2455 | global.setAlignment(decl.getAlignment(mod)); |
| 2501 | if (decl.@"linksection") |section| global.setSection(section); | 2456 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| global.setSection(s); |
| 2502 | assert(decl.has_tv); | 2457 | assert(decl.has_tv); |
| 2503 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { | 2458 | const init_val = if (decl.val.getVariable(mod)) |variable| init_val: { |
| 2504 | const variable = payload.data; | ||
| 2505 | break :init_val variable.init; | 2459 | break :init_val variable.init; |
| 2506 | } else init_val: { | 2460 | } else init_val: { |
| 2507 | global.setGlobalConstant(.True); | 2461 | global.setGlobalConstant(.True); |
| 2508 | break :init_val decl.val; | 2462 | break :init_val decl.val.toIntern(); |
| 2509 | }; | 2463 | }; |
| 2510 | if (init_val.tag() != .unreachable_value) { | 2464 | if (init_val != .none) { |
| 2511 | const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val }); | 2465 | const llvm_init = try dg.lowerValue(.{ .ty = decl.ty, .val = init_val.toValue() }); |
| 2512 | if (global.globalGetValueType() == llvm_init.typeOf()) { | 2466 | if (global.globalGetValueType() == llvm_init.typeOf()) { |
| 2513 | global.setInitializer(llvm_init); | 2467 | global.setInitializer(llvm_init); |
| 2514 | } else { | 2468 | } else { |
| ... | @@ -2533,7 +2487,8 @@ pub const DeclGen = struct { | ... | @@ -2533,7 +2487,8 @@ pub const DeclGen = struct { |
| 2533 | new_global.setLinkage(global.getLinkage()); | 2487 | new_global.setLinkage(global.getLinkage()); |
| 2534 | new_global.setUnnamedAddr(global.getUnnamedAddress()); | 2488 | new_global.setUnnamedAddr(global.getUnnamedAddress()); |
| 2535 | new_global.setAlignment(global.getAlignment()); | 2489 | new_global.setAlignment(global.getAlignment()); |
| 2536 | if (decl.@"linksection") |section| new_global.setSection(section); | 2490 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| |
| 2491 | new_global.setSection(s); | ||
| 2537 | new_global.setInitializer(llvm_init); | 2492 | new_global.setInitializer(llvm_init); |
| 2538 | // TODO: How should this work then the address space of a global changed? | 2493 | // TODO: How should this work then the address space of a global changed? |
| 2539 | global.replaceAllUsesWith(new_global); | 2494 | global.replaceAllUsesWith(new_global); |
| ... | @@ -2545,13 +2500,13 @@ pub const DeclGen = struct { | ... | @@ -2545,13 +2500,13 @@ pub const DeclGen = struct { |
| 2545 | } | 2500 | } |
| 2546 | 2501 | ||
| 2547 | if (dg.object.di_builder) |dib| { | 2502 | if (dg.object.di_builder) |dib| { |
| 2548 | const di_file = try dg.object.getDIFile(dg.gpa, decl.src_namespace.file_scope); | 2503 | const di_file = try dg.object.getDIFile(dg.gpa, mod.namespacePtr(decl.src_namespace).file_scope); |
| 2549 | 2504 | ||
| 2550 | const line_number = decl.src_line + 1; | 2505 | const line_number = decl.src_line + 1; |
| 2551 | const is_internal_linkage = !dg.module.decl_exports.contains(decl_index); | 2506 | const is_internal_linkage = !dg.module.decl_exports.contains(decl_index); |
| 2552 | const di_global = dib.createGlobalVariableExpression( | 2507 | const di_global = dib.createGlobalVariableExpression( |
| 2553 | di_file.toScope(), | 2508 | di_file.toScope(), |
| 2554 | decl.name, | 2509 | mod.intern_pool.stringToSlice(decl.name), |
| 2555 | global.getValueName(), | 2510 | global.getValueName(), |
| 2556 | di_file, | 2511 | di_file, |
| 2557 | line_number, | 2512 | line_number, |
| ... | @@ -2560,7 +2515,7 @@ pub const DeclGen = struct { | ... | @@ -2560,7 +2515,7 @@ pub const DeclGen = struct { |
| 2560 | ); | 2515 | ); |
| 2561 | 2516 | ||
| 2562 | try dg.object.di_map.put(dg.gpa, dg.decl, di_global.getVariable().toNode()); | 2517 | try dg.object.di_map.put(dg.gpa, dg.decl, di_global.getVariable().toNode()); |
| 2563 | if (!is_internal_linkage or decl.isExtern()) global.attachMetaData(di_global); | 2518 | if (!is_internal_linkage or decl.isExtern(mod)) global.attachMetaData(di_global); |
| 2564 | } | 2519 | } |
| 2565 | } | 2520 | } |
| 2566 | } | 2521 | } |
| ... | @@ -2569,36 +2524,35 @@ pub const DeclGen = struct { | ... | @@ -2569,36 +2524,35 @@ pub const DeclGen = struct { |
| 2569 | /// Note that this can be called before the function's semantic analysis has | 2524 | /// Note that this can be called before the function's semantic analysis has |
| 2570 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. | 2525 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. |
| 2571 | fn resolveLlvmFunction(dg: *DeclGen, decl_index: Module.Decl.Index) !*llvm.Value { | 2526 | fn resolveLlvmFunction(dg: *DeclGen, decl_index: Module.Decl.Index) !*llvm.Value { |
| 2572 | const decl = dg.module.declPtr(decl_index); | 2527 | const mod = dg.module; |
| 2528 | const decl = mod.declPtr(decl_index); | ||
| 2573 | const zig_fn_type = decl.ty; | 2529 | const zig_fn_type = decl.ty; |
| 2574 | const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl_index); | 2530 | const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl_index); |
| 2575 | if (gop.found_existing) return gop.value_ptr.*; | 2531 | if (gop.found_existing) return gop.value_ptr.*; |
| 2576 | 2532 | ||
| 2577 | assert(decl.has_tv); | 2533 | assert(decl.has_tv); |
| 2578 | const fn_info = zig_fn_type.fnInfo(); | 2534 | const fn_info = mod.typeToFunc(zig_fn_type).?; |
| 2579 | const target = dg.module.getTarget(); | 2535 | const target = mod.getTarget(); |
| 2580 | const sret = firstParamSRet(fn_info, target); | 2536 | const sret = firstParamSRet(fn_info, mod); |
| 2581 | 2537 | ||
| 2582 | const fn_type = try dg.lowerType(zig_fn_type); | 2538 | const fn_type = try dg.lowerType(zig_fn_type); |
| 2583 | 2539 | ||
| 2584 | const fqn = try decl.getFullyQualifiedName(dg.module); | 2540 | const fqn = try decl.getFullyQualifiedName(mod); |
| 2585 | defer dg.gpa.free(fqn); | ||
| 2586 | 2541 | ||
| 2587 | const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); | 2542 | const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); |
| 2588 | const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace); | 2543 | const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(mod.intern_pool.stringToSlice(fqn), fn_type, llvm_addrspace); |
| 2589 | gop.value_ptr.* = llvm_fn; | 2544 | gop.value_ptr.* = llvm_fn; |
| 2590 | 2545 | ||
| 2591 | const is_extern = decl.isExtern(); | 2546 | const is_extern = decl.isExtern(mod); |
| 2592 | if (!is_extern) { | 2547 | if (!is_extern) { |
| 2593 | llvm_fn.setLinkage(.Internal); | 2548 | llvm_fn.setLinkage(.Internal); |
| 2594 | llvm_fn.setUnnamedAddr(.True); | 2549 | llvm_fn.setUnnamedAddr(.True); |
| 2595 | } else { | 2550 | } else { |
| 2596 | if (dg.module.getTarget().isWasm()) { | 2551 | if (target.isWasm()) { |
| 2597 | dg.addFnAttrString(llvm_fn, "wasm-import-name", std.mem.sliceTo(decl.name, 0)); | 2552 | dg.addFnAttrString(llvm_fn, "wasm-import-name", mod.intern_pool.stringToSlice(decl.name)); |
| 2598 | if (decl.getExternFn().?.lib_name) |lib_name| { | 2553 | if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| { |
| 2599 | const module_name = std.mem.sliceTo(lib_name, 0); | 2554 | if (!std.mem.eql(u8, lib_name, "c")) { |
| 2600 | if (!std.mem.eql(u8, module_name, "c")) { | 2555 | dg.addFnAttrString(llvm_fn, "wasm-import-module", lib_name); |
| 2601 | dg.addFnAttrString(llvm_fn, "wasm-import-module", module_name); | ||
| 2602 | } | 2556 | } |
| 2603 | } | 2557 | } |
| 2604 | } | 2558 | } |
| ... | @@ -2608,12 +2562,12 @@ pub const DeclGen = struct { | ... | @@ -2608,12 +2562,12 @@ pub const DeclGen = struct { |
| 2608 | dg.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0 | 2562 | dg.addArgAttr(llvm_fn, 0, "nonnull"); // Sret pointers must not be address 0 |
| 2609 | dg.addArgAttr(llvm_fn, 0, "noalias"); | 2563 | dg.addArgAttr(llvm_fn, 0, "noalias"); |
| 2610 | 2564 | ||
| 2611 | const raw_llvm_ret_ty = try dg.lowerType(fn_info.return_type); | 2565 | const raw_llvm_ret_ty = try dg.lowerType(fn_info.return_type.toType()); |
| 2612 | llvm_fn.addSretAttr(raw_llvm_ret_ty); | 2566 | llvm_fn.addSretAttr(raw_llvm_ret_ty); |
| 2613 | } | 2567 | } |
| 2614 | 2568 | ||
| 2615 | const err_return_tracing = fn_info.return_type.isError() and | 2569 | const err_return_tracing = fn_info.return_type.toType().isError(mod) and |
| 2616 | dg.module.comp.bin_file.options.error_return_tracing; | 2570 | mod.comp.bin_file.options.error_return_tracing; |
| 2617 | 2571 | ||
| 2618 | if (err_return_tracing) { | 2572 | if (err_return_tracing) { |
| 2619 | dg.addArgAttr(llvm_fn, @boolToInt(sret), "nonnull"); | 2573 | dg.addArgAttr(llvm_fn, @boolToInt(sret), "nonnull"); |
| ... | @@ -2635,14 +2589,14 @@ pub const DeclGen = struct { | ... | @@ -2635,14 +2589,14 @@ pub const DeclGen = struct { |
| 2635 | }, | 2589 | }, |
| 2636 | } | 2590 | } |
| 2637 | 2591 | ||
| 2638 | if (fn_info.alignment != 0) { | 2592 | if (fn_info.alignment.toByteUnitsOptional()) |a| { |
| 2639 | llvm_fn.setAlignment(fn_info.alignment); | 2593 | llvm_fn.setAlignment(@intCast(c_uint, a)); |
| 2640 | } | 2594 | } |
| 2641 | 2595 | ||
| 2642 | // Function attributes that are independent of analysis results of the function body. | 2596 | // Function attributes that are independent of analysis results of the function body. |
| 2643 | dg.addCommonFnAttributes(llvm_fn); | 2597 | dg.addCommonFnAttributes(llvm_fn); |
| 2644 | 2598 | ||
| 2645 | if (fn_info.return_type.isNoReturn()) { | 2599 | if (fn_info.return_type == .noreturn_type) { |
| 2646 | dg.addFnAttr(llvm_fn, "noreturn"); | 2600 | dg.addFnAttr(llvm_fn, "noreturn"); |
| 2647 | } | 2601 | } |
| 2648 | 2602 | ||
| ... | @@ -2655,15 +2609,15 @@ pub const DeclGen = struct { | ... | @@ -2655,15 +2609,15 @@ pub const DeclGen = struct { |
| 2655 | while (it.next()) |lowering| switch (lowering) { | 2609 | while (it.next()) |lowering| switch (lowering) { |
| 2656 | .byval => { | 2610 | .byval => { |
| 2657 | const param_index = it.zig_index - 1; | 2611 | const param_index = it.zig_index - 1; |
| 2658 | const param_ty = fn_info.param_types[param_index]; | 2612 | const param_ty = fn_info.param_types[param_index].toType(); |
| 2659 | if (!isByRef(param_ty)) { | 2613 | if (!isByRef(param_ty, mod)) { |
| 2660 | dg.addByValParamAttrs(llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1); | 2614 | dg.addByValParamAttrs(llvm_fn, param_ty, param_index, fn_info, it.llvm_index - 1); |
| 2661 | } | 2615 | } |
| 2662 | }, | 2616 | }, |
| 2663 | .byref => { | 2617 | .byref => { |
| 2664 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 2618 | const param_ty = fn_info.param_types[it.zig_index - 1]; |
| 2665 | const param_llvm_ty = try dg.lowerType(param_ty); | 2619 | const param_llvm_ty = try dg.lowerType(param_ty.toType()); |
| 2666 | const alignment = param_ty.abiAlignment(target); | 2620 | const alignment = param_ty.toType().abiAlignment(mod); |
| 2667 | dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); | 2621 | dg.addByRefParamAttrs(llvm_fn, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); |
| 2668 | }, | 2622 | }, |
| 2669 | .byref_mut => { | 2623 | .byref_mut => { |
| ... | @@ -2735,35 +2689,35 @@ pub const DeclGen = struct { | ... | @@ -2735,35 +2689,35 @@ pub const DeclGen = struct { |
| 2735 | if (gop.found_existing) return gop.value_ptr.*; | 2689 | if (gop.found_existing) return gop.value_ptr.*; |
| 2736 | errdefer assert(dg.object.decl_map.remove(decl_index)); | 2690 | errdefer assert(dg.object.decl_map.remove(decl_index)); |
| 2737 | 2691 | ||
| 2738 | const decl = dg.module.declPtr(decl_index); | 2692 | const mod = dg.module; |
| 2739 | const fqn = try decl.getFullyQualifiedName(dg.module); | 2693 | const decl = mod.declPtr(decl_index); |
| 2740 | defer dg.gpa.free(fqn); | 2694 | const fqn = try decl.getFullyQualifiedName(mod); |
| 2741 | 2695 | ||
| 2742 | const target = dg.module.getTarget(); | 2696 | const target = mod.getTarget(); |
| 2743 | 2697 | ||
| 2744 | const llvm_type = try dg.lowerType(decl.ty); | 2698 | const llvm_type = try dg.lowerType(decl.ty); |
| 2745 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | 2699 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); |
| 2746 | 2700 | ||
| 2747 | const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace( | 2701 | const llvm_global = dg.object.llvm_module.addGlobalInAddressSpace( |
| 2748 | llvm_type, | 2702 | llvm_type, |
| 2749 | fqn, | 2703 | mod.intern_pool.stringToSlice(fqn), |
| 2750 | llvm_actual_addrspace, | 2704 | llvm_actual_addrspace, |
| 2751 | ); | 2705 | ); |
| 2752 | gop.value_ptr.* = llvm_global; | 2706 | gop.value_ptr.* = llvm_global; |
| 2753 | 2707 | ||
| 2754 | // This is needed for declarations created by `@extern`. | 2708 | // This is needed for declarations created by `@extern`. |
| 2755 | if (decl.isExtern()) { | 2709 | if (decl.isExtern(mod)) { |
| 2756 | llvm_global.setValueName(decl.name); | 2710 | llvm_global.setValueName(mod.intern_pool.stringToSlice(decl.name)); |
| 2757 | llvm_global.setUnnamedAddr(.False); | 2711 | llvm_global.setUnnamedAddr(.False); |
| 2758 | llvm_global.setLinkage(.External); | 2712 | llvm_global.setLinkage(.External); |
| 2759 | if (decl.val.castTag(.variable)) |variable| { | 2713 | if (decl.val.getVariable(mod)) |variable| { |
| 2760 | const single_threaded = dg.module.comp.bin_file.options.single_threaded; | 2714 | const single_threaded = mod.comp.bin_file.options.single_threaded; |
| 2761 | if (variable.data.is_threadlocal and !single_threaded) { | 2715 | if (variable.is_threadlocal and !single_threaded) { |
| 2762 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); | 2716 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 2763 | } else { | 2717 | } else { |
| 2764 | llvm_global.setThreadLocalMode(.NotThreadLocal); | 2718 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| 2765 | } | 2719 | } |
| 2766 | if (variable.data.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak); | 2720 | if (variable.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak); |
| 2767 | } | 2721 | } |
| 2768 | } else { | 2722 | } else { |
| 2769 | llvm_global.setLinkage(.Internal); | 2723 | llvm_global.setLinkage(.Internal); |
| ... | @@ -2784,12 +2738,13 @@ pub const DeclGen = struct { | ... | @@ -2784,12 +2738,13 @@ pub const DeclGen = struct { |
| 2784 | 2738 | ||
| 2785 | fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*llvm.Type { | 2739 | fn lowerType(dg: *DeclGen, t: Type) Allocator.Error!*llvm.Type { |
| 2786 | const llvm_ty = try lowerTypeInner(dg, t); | 2740 | const llvm_ty = try lowerTypeInner(dg, t); |
| 2741 | const mod = dg.module; | ||
| 2787 | if (std.debug.runtime_safety and false) check: { | 2742 | if (std.debug.runtime_safety and false) check: { |
| 2788 | if (t.zigTypeTag() == .Opaque) break :check; | 2743 | if (t.zigTypeTag(mod) == .Opaque) break :check; |
| 2789 | if (!t.hasRuntimeBits()) break :check; | 2744 | if (!t.hasRuntimeBits(mod)) break :check; |
| 2790 | if (!llvm_ty.isSized().toBool()) break :check; | 2745 | if (!llvm_ty.isSized().toBool()) break :check; |
| 2791 | 2746 | ||
| 2792 | const zig_size = t.abiSize(dg.module.getTarget()); | 2747 | const zig_size = t.abiSize(mod); |
| 2793 | const llvm_size = dg.object.target_data.abiSizeOfType(llvm_ty); | 2748 | const llvm_size = dg.object.target_data.abiSizeOfType(llvm_ty); |
| 2794 | if (llvm_size != zig_size) { | 2749 | if (llvm_size != zig_size) { |
| 2795 | log.err("when lowering {}, Zig ABI size = {d} but LLVM ABI size = {d}", .{ | 2750 | log.err("when lowering {}, Zig ABI size = {d} but LLVM ABI size = {d}", .{ |
| ... | @@ -2802,18 +2757,18 @@ pub const DeclGen = struct { | ... | @@ -2802,18 +2757,18 @@ pub const DeclGen = struct { |
| 2802 | 2757 | ||
| 2803 | fn lowerTypeInner(dg: *DeclGen, t: Type) Allocator.Error!*llvm.Type { | 2758 | fn lowerTypeInner(dg: *DeclGen, t: Type) Allocator.Error!*llvm.Type { |
| 2804 | const gpa = dg.gpa; | 2759 | const gpa = dg.gpa; |
| 2805 | const target = dg.module.getTarget(); | 2760 | const mod = dg.module; |
| 2806 | switch (t.zigTypeTag()) { | 2761 | const target = mod.getTarget(); |
| 2762 | switch (t.zigTypeTag(mod)) { | ||
| 2807 | .Void, .NoReturn => return dg.context.voidType(), | 2763 | .Void, .NoReturn => return dg.context.voidType(), |
| 2808 | .Int => { | 2764 | .Int => { |
| 2809 | const info = t.intInfo(target); | 2765 | const info = t.intInfo(mod); |
| 2810 | assert(info.bits != 0); | 2766 | assert(info.bits != 0); |
| 2811 | return dg.context.intType(info.bits); | 2767 | return dg.context.intType(info.bits); |
| 2812 | }, | 2768 | }, |
| 2813 | .Enum => { | 2769 | .Enum => { |
| 2814 | var buffer: Type.Payload.Bits = undefined; | 2770 | const int_ty = t.intTagType(mod); |
| 2815 | const int_ty = t.intTagType(&buffer); | 2771 | const bit_count = int_ty.intInfo(mod).bits; |
| 2816 | const bit_count = int_ty.intInfo(target).bits; | ||
| 2817 | assert(bit_count != 0); | 2772 | assert(bit_count != 0); |
| 2818 | return dg.context.intType(bit_count); | 2773 | return dg.context.intType(bit_count); |
| 2819 | }, | 2774 | }, |
| ... | @@ -2827,9 +2782,8 @@ pub const DeclGen = struct { | ... | @@ -2827,9 +2782,8 @@ pub const DeclGen = struct { |
| 2827 | }, | 2782 | }, |
| 2828 | .Bool => return dg.context.intType(1), | 2783 | .Bool => return dg.context.intType(1), |
| 2829 | .Pointer => { | 2784 | .Pointer => { |
| 2830 | if (t.isSlice()) { | 2785 | if (t.isSlice(mod)) { |
| 2831 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 2786 | const ptr_type = t.slicePtrFieldType(mod); |
| 2832 | const ptr_type = t.slicePtrFieldType(&buf); | ||
| 2833 | 2787 | ||
| 2834 | const fields: [2]*llvm.Type = .{ | 2788 | const fields: [2]*llvm.Type = .{ |
| 2835 | try dg.lowerType(ptr_type), | 2789 | try dg.lowerType(ptr_type), |
| ... | @@ -2837,49 +2791,41 @@ pub const DeclGen = struct { | ... | @@ -2837,49 +2791,41 @@ pub const DeclGen = struct { |
| 2837 | }; | 2791 | }; |
| 2838 | return dg.context.structType(&fields, fields.len, .False); | 2792 | return dg.context.structType(&fields, fields.len, .False); |
| 2839 | } | 2793 | } |
| 2840 | const ptr_info = t.ptrInfo().data; | 2794 | const ptr_info = t.ptrInfo(mod); |
| 2841 | const llvm_addrspace = toLlvmAddressSpace(ptr_info.@"addrspace", target); | 2795 | const llvm_addrspace = toLlvmAddressSpace(ptr_info.@"addrspace", target); |
| 2842 | return dg.context.pointerType(llvm_addrspace); | 2796 | return dg.context.pointerType(llvm_addrspace); |
| 2843 | }, | 2797 | }, |
| 2844 | .Opaque => switch (t.tag()) { | 2798 | .Opaque => { |
| 2845 | .@"opaque" => { | 2799 | if (t.toIntern() == .anyopaque_type) return dg.context.intType(8); |
| 2846 | const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = dg.module }); | ||
| 2847 | if (gop.found_existing) return gop.value_ptr.*; | ||
| 2848 | 2800 | ||
| 2849 | // The Type memory is ephemeral; since we want to store a longer-lived | 2801 | const gop = try dg.object.type_map.getOrPut(gpa, t.toIntern()); |
| 2850 | // reference, we need to copy it here. | 2802 | if (gop.found_existing) return gop.value_ptr.*; |
| 2851 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); | ||
| 2852 | 2803 | ||
| 2853 | const opaque_obj = t.castTag(.@"opaque").?.data; | 2804 | const opaque_type = mod.intern_pool.indexToKey(t.toIntern()).opaque_type; |
| 2854 | const name = try opaque_obj.getFullyQualifiedName(dg.module); | 2805 | const name = mod.intern_pool.stringToSlice(try mod.opaqueFullyQualifiedName(opaque_type)); |
| 2855 | defer gpa.free(name); | ||
| 2856 | 2806 | ||
| 2857 | const llvm_struct_ty = dg.context.structCreateNamed(name); | 2807 | const llvm_struct_ty = dg.context.structCreateNamed(name); |
| 2858 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | 2808 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| 2859 | return llvm_struct_ty; | 2809 | return llvm_struct_ty; |
| 2860 | }, | ||
| 2861 | .anyopaque => return dg.context.intType(8), | ||
| 2862 | else => unreachable, | ||
| 2863 | }, | 2810 | }, |
| 2864 | .Array => { | 2811 | .Array => { |
| 2865 | const elem_ty = t.childType(); | 2812 | const elem_ty = t.childType(mod); |
| 2866 | assert(elem_ty.onePossibleValue() == null); | 2813 | if (std.debug.runtime_safety) assert((try elem_ty.onePossibleValue(mod)) == null); |
| 2867 | const elem_llvm_ty = try dg.lowerType(elem_ty); | 2814 | const elem_llvm_ty = try dg.lowerType(elem_ty); |
| 2868 | const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null); | 2815 | const total_len = t.arrayLen(mod) + @boolToInt(t.sentinel(mod) != null); |
| 2869 | return elem_llvm_ty.arrayType(@intCast(c_uint, total_len)); | 2816 | return elem_llvm_ty.arrayType(@intCast(c_uint, total_len)); |
| 2870 | }, | 2817 | }, |
| 2871 | .Vector => { | 2818 | .Vector => { |
| 2872 | const elem_type = try dg.lowerType(t.childType()); | 2819 | const elem_type = try dg.lowerType(t.childType(mod)); |
| 2873 | return elem_type.vectorType(t.vectorLen()); | 2820 | return elem_type.vectorType(t.vectorLen(mod)); |
| 2874 | }, | 2821 | }, |
| 2875 | .Optional => { | 2822 | .Optional => { |
| 2876 | var buf: Type.Payload.ElemType = undefined; | 2823 | const child_ty = t.optionalChild(mod); |
| 2877 | const child_ty = t.optionalChild(&buf); | 2824 | if (!child_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2878 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 2879 | return dg.context.intType(8); | 2825 | return dg.context.intType(8); |
| 2880 | } | 2826 | } |
| 2881 | const payload_llvm_ty = try dg.lowerType(child_ty); | 2827 | const payload_llvm_ty = try dg.lowerType(child_ty); |
| 2882 | if (t.optionalReprIsPayload()) { | 2828 | if (t.optionalReprIsPayload(mod)) { |
| 2883 | return payload_llvm_ty; | 2829 | return payload_llvm_ty; |
| 2884 | } | 2830 | } |
| 2885 | 2831 | ||
| ... | @@ -2887,8 +2833,8 @@ pub const DeclGen = struct { | ... | @@ -2887,8 +2833,8 @@ pub const DeclGen = struct { |
| 2887 | var fields_buf: [3]*llvm.Type = .{ | 2833 | var fields_buf: [3]*llvm.Type = .{ |
| 2888 | payload_llvm_ty, dg.context.intType(8), undefined, | 2834 | payload_llvm_ty, dg.context.intType(8), undefined, |
| 2889 | }; | 2835 | }; |
| 2890 | const offset = child_ty.abiSize(target) + 1; | 2836 | const offset = child_ty.abiSize(mod) + 1; |
| 2891 | const abi_size = t.abiSize(target); | 2837 | const abi_size = t.abiSize(mod); |
| 2892 | const padding = @intCast(c_uint, abi_size - offset); | 2838 | const padding = @intCast(c_uint, abi_size - offset); |
| 2893 | if (padding == 0) { | 2839 | if (padding == 0) { |
| 2894 | return dg.context.structType(&fields_buf, 2, .False); | 2840 | return dg.context.structType(&fields_buf, 2, .False); |
| ... | @@ -2897,18 +2843,18 @@ pub const DeclGen = struct { | ... | @@ -2897,18 +2843,18 @@ pub const DeclGen = struct { |
| 2897 | return dg.context.structType(&fields_buf, 3, .False); | 2843 | return dg.context.structType(&fields_buf, 3, .False); |
| 2898 | }, | 2844 | }, |
| 2899 | .ErrorUnion => { | 2845 | .ErrorUnion => { |
| 2900 | const payload_ty = t.errorUnionPayload(); | 2846 | const payload_ty = t.errorUnionPayload(mod); |
| 2901 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 2847 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2902 | return try dg.lowerType(Type.anyerror); | 2848 | return try dg.lowerType(Type.anyerror); |
| 2903 | } | 2849 | } |
| 2904 | const llvm_error_type = try dg.lowerType(Type.anyerror); | 2850 | const llvm_error_type = try dg.lowerType(Type.anyerror); |
| 2905 | const llvm_payload_type = try dg.lowerType(payload_ty); | 2851 | const llvm_payload_type = try dg.lowerType(payload_ty); |
| 2906 | 2852 | ||
| 2907 | const payload_align = payload_ty.abiAlignment(target); | 2853 | const payload_align = payload_ty.abiAlignment(mod); |
| 2908 | const error_align = Type.anyerror.abiAlignment(target); | 2854 | const error_align = Type.anyerror.abiAlignment(mod); |
| 2909 | 2855 | ||
| 2910 | const payload_size = payload_ty.abiSize(target); | 2856 | const payload_size = payload_ty.abiSize(mod); |
| 2911 | const error_size = Type.anyerror.abiSize(target); | 2857 | const error_size = Type.anyerror.abiSize(mod); |
| 2912 | 2858 | ||
| 2913 | var fields_buf: [3]*llvm.Type = undefined; | 2859 | var fields_buf: [3]*llvm.Type = undefined; |
| 2914 | if (error_align > payload_align) { | 2860 | if (error_align > payload_align) { |
| ... | @@ -2941,66 +2887,64 @@ pub const DeclGen = struct { | ... | @@ -2941,66 +2887,64 @@ pub const DeclGen = struct { |
| 2941 | }, | 2887 | }, |
| 2942 | .ErrorSet => return dg.context.intType(16), | 2888 | .ErrorSet => return dg.context.intType(16), |
| 2943 | .Struct => { | 2889 | .Struct => { |
| 2944 | const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = dg.module }); | 2890 | const gop = try dg.object.type_map.getOrPut(gpa, t.toIntern()); |
| 2945 | if (gop.found_existing) return gop.value_ptr.*; | 2891 | if (gop.found_existing) return gop.value_ptr.*; |
| 2946 | 2892 | ||
| 2947 | // The Type memory is ephemeral; since we want to store a longer-lived | 2893 | const struct_type = switch (mod.intern_pool.indexToKey(t.toIntern())) { |
| 2948 | // reference, we need to copy it here. | 2894 | .anon_struct_type => |tuple| { |
| 2949 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); | 2895 | const llvm_struct_ty = dg.context.structCreateNamed(""); |
| 2896 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | ||
| 2950 | 2897 | ||
| 2951 | if (t.isSimpleTupleOrAnonStruct()) { | 2898 | var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{}; |
| 2952 | const tuple = t.tupleFields(); | 2899 | defer llvm_field_types.deinit(gpa); |
| 2953 | const llvm_struct_ty = dg.context.structCreateNamed(""); | ||
| 2954 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | ||
| 2955 | 2900 | ||
| 2956 | var llvm_field_types: std.ArrayListUnmanaged(*llvm.Type) = .{}; | 2901 | try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len); |
| 2957 | defer llvm_field_types.deinit(gpa); | ||
| 2958 | 2902 | ||
| 2959 | try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len); | 2903 | comptime assert(struct_layout_version == 2); |
| 2904 | var offset: u64 = 0; | ||
| 2905 | var big_align: u32 = 0; | ||
| 2960 | 2906 | ||
| 2961 | comptime assert(struct_layout_version == 2); | 2907 | for (tuple.types, tuple.values) |field_ty, field_val| { |
| 2962 | var offset: u64 = 0; | 2908 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; |
| 2963 | var big_align: u32 = 0; | ||
| 2964 | 2909 | ||
| 2965 | for (tuple.types, 0..) |field_ty, i| { | 2910 | const field_align = field_ty.toType().abiAlignment(mod); |
| 2966 | const field_val = tuple.values[i]; | 2911 | big_align = @max(big_align, field_align); |
| 2967 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; | 2912 | const prev_offset = offset; |
| 2913 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | ||
| 2968 | 2914 | ||
| 2969 | const field_align = field_ty.abiAlignment(target); | 2915 | const padding_len = offset - prev_offset; |
| 2970 | big_align = @max(big_align, field_align); | 2916 | if (padding_len > 0) { |
| 2971 | const prev_offset = offset; | 2917 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 2972 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 2918 | try llvm_field_types.append(gpa, llvm_array_ty); |
| 2919 | } | ||
| 2920 | const field_llvm_ty = try dg.lowerType(field_ty.toType()); | ||
| 2921 | try llvm_field_types.append(gpa, field_llvm_ty); | ||
| 2973 | 2922 | ||
| 2974 | const padding_len = offset - prev_offset; | 2923 | offset += field_ty.toType().abiSize(mod); |
| 2975 | if (padding_len > 0) { | ||
| 2976 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | ||
| 2977 | try llvm_field_types.append(gpa, llvm_array_ty); | ||
| 2978 | } | 2924 | } |
| 2979 | const field_llvm_ty = try dg.lowerType(field_ty); | 2925 | { |
| 2980 | try llvm_field_types.append(gpa, field_llvm_ty); | 2926 | const prev_offset = offset; |
| 2981 | 2927 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 2982 | offset += field_ty.abiSize(target); | 2928 | const padding_len = offset - prev_offset; |
| 2983 | } | 2929 | if (padding_len > 0) { |
| 2984 | { | 2930 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 2985 | const prev_offset = offset; | 2931 | try llvm_field_types.append(gpa, llvm_array_ty); |
| 2986 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | 2932 | } |
| 2987 | const padding_len = offset - prev_offset; | ||
| 2988 | if (padding_len > 0) { | ||
| 2989 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | ||
| 2990 | try llvm_field_types.append(gpa, llvm_array_ty); | ||
| 2991 | } | 2933 | } |
| 2992 | } | ||
| 2993 | 2934 | ||
| 2994 | llvm_struct_ty.structSetBody( | 2935 | llvm_struct_ty.structSetBody( |
| 2995 | llvm_field_types.items.ptr, | 2936 | llvm_field_types.items.ptr, |
| 2996 | @intCast(c_uint, llvm_field_types.items.len), | 2937 | @intCast(c_uint, llvm_field_types.items.len), |
| 2997 | .False, | 2938 | .False, |
| 2998 | ); | 2939 | ); |
| 2999 | 2940 | ||
| 3000 | return llvm_struct_ty; | 2941 | return llvm_struct_ty; |
| 3001 | } | 2942 | }, |
| 2943 | .struct_type => |struct_type| struct_type, | ||
| 2944 | else => unreachable, | ||
| 2945 | }; | ||
| 3002 | 2946 | ||
| 3003 | const struct_obj = t.castTag(.@"struct").?.data; | 2947 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 3004 | 2948 | ||
| 3005 | if (struct_obj.layout == .Packed) { | 2949 | if (struct_obj.layout == .Packed) { |
| 3006 | assert(struct_obj.haveLayout()); | 2950 | assert(struct_obj.haveLayout()); |
| ... | @@ -3009,8 +2953,7 @@ pub const DeclGen = struct { | ... | @@ -3009,8 +2953,7 @@ pub const DeclGen = struct { |
| 3009 | return int_llvm_ty; | 2953 | return int_llvm_ty; |
| 3010 | } | 2954 | } |
| 3011 | 2955 | ||
| 3012 | const name = try struct_obj.getFullyQualifiedName(dg.module); | 2956 | const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(mod)); |
| 3013 | defer gpa.free(name); | ||
| 3014 | 2957 | ||
| 3015 | const llvm_struct_ty = dg.context.structCreateNamed(name); | 2958 | const llvm_struct_ty = dg.context.structCreateNamed(name); |
| 3016 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls | 2959 | gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| ... | @@ -3027,11 +2970,11 @@ pub const DeclGen = struct { | ... | @@ -3027,11 +2970,11 @@ pub const DeclGen = struct { |
| 3027 | var big_align: u32 = 1; | 2970 | var big_align: u32 = 1; |
| 3028 | var any_underaligned_fields = false; | 2971 | var any_underaligned_fields = false; |
| 3029 | 2972 | ||
| 3030 | var it = struct_obj.runtimeFieldIterator(); | 2973 | var it = struct_obj.runtimeFieldIterator(mod); |
| 3031 | while (it.next()) |field_and_index| { | 2974 | while (it.next()) |field_and_index| { |
| 3032 | const field = field_and_index.field; | 2975 | const field = field_and_index.field; |
| 3033 | const field_align = field.alignment(target, struct_obj.layout); | 2976 | const field_align = field.alignment(mod, struct_obj.layout); |
| 3034 | const field_ty_align = field.ty.abiAlignment(target); | 2977 | const field_ty_align = field.ty.abiAlignment(mod); |
| 3035 | any_underaligned_fields = any_underaligned_fields or | 2978 | any_underaligned_fields = any_underaligned_fields or |
| 3036 | field_align < field_ty_align; | 2979 | field_align < field_ty_align; |
| 3037 | big_align = @max(big_align, field_align); | 2980 | big_align = @max(big_align, field_align); |
| ... | @@ -3046,7 +2989,7 @@ pub const DeclGen = struct { | ... | @@ -3046,7 +2989,7 @@ pub const DeclGen = struct { |
| 3046 | const field_llvm_ty = try dg.lowerType(field.ty); | 2989 | const field_llvm_ty = try dg.lowerType(field.ty); |
| 3047 | try llvm_field_types.append(gpa, field_llvm_ty); | 2990 | try llvm_field_types.append(gpa, field_llvm_ty); |
| 3048 | 2991 | ||
| 3049 | offset += field.ty.abiSize(target); | 2992 | offset += field.ty.abiSize(mod); |
| 3050 | } | 2993 | } |
| 3051 | { | 2994 | { |
| 3052 | const prev_offset = offset; | 2995 | const prev_offset = offset; |
| ... | @@ -3067,18 +3010,14 @@ pub const DeclGen = struct { | ... | @@ -3067,18 +3010,14 @@ pub const DeclGen = struct { |
| 3067 | return llvm_struct_ty; | 3010 | return llvm_struct_ty; |
| 3068 | }, | 3011 | }, |
| 3069 | .Union => { | 3012 | .Union => { |
| 3070 | const gop = try dg.object.type_map.getOrPutContext(gpa, t, .{ .mod = dg.module }); | 3013 | const gop = try dg.object.type_map.getOrPut(gpa, t.toIntern()); |
| 3071 | if (gop.found_existing) return gop.value_ptr.*; | 3014 | if (gop.found_existing) return gop.value_ptr.*; |
| 3072 | 3015 | ||
| 3073 | // The Type memory is ephemeral; since we want to store a longer-lived | 3016 | const layout = t.unionGetLayout(mod); |
| 3074 | // reference, we need to copy it here. | 3017 | const union_obj = mod.typeToUnion(t).?; |
| 3075 | gop.key_ptr.* = try t.copy(dg.object.type_map_arena.allocator()); | ||
| 3076 | |||
| 3077 | const layout = t.unionGetLayout(target); | ||
| 3078 | const union_obj = t.cast(Type.Payload.Union).?.data; | ||
| 3079 | 3018 | ||
| 3080 | if (union_obj.layout == .Packed) { | 3019 | if (union_obj.layout == .Packed) { |
| 3081 | const bitsize = @intCast(c_uint, t.bitSize(target)); | 3020 | const bitsize = @intCast(c_uint, t.bitSize(mod)); |
| 3082 | const int_llvm_ty = dg.context.intType(bitsize); | 3021 | const int_llvm_ty = dg.context.intType(bitsize); |
| 3083 | gop.value_ptr.* = int_llvm_ty; | 3022 | gop.value_ptr.* = int_llvm_ty; |
| 3084 | return int_llvm_ty; | 3023 | return int_llvm_ty; |
| ... | @@ -3090,8 +3029,7 @@ pub const DeclGen = struct { | ... | @@ -3090,8 +3029,7 @@ pub const DeclGen = struct { |
| 3090 | return enum_tag_llvm_ty; | 3029 | return enum_tag_llvm_ty; |
| 3091 | } | 3030 | } |
| 3092 | 3031 | ||
| 3093 | const name = try union_obj.getFullyQualifiedName(dg.module); | 3032 | const name = mod.intern_pool.stringToSlice(try union_obj.getFullyQualifiedName(mod)); |
| 3094 | defer gpa.free(name); | ||
| 3095 | 3033 | ||
| 3096 | const llvm_union_ty = dg.context.structCreateNamed(name); | 3034 | const llvm_union_ty = dg.context.structCreateNamed(name); |
| 3097 | gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls | 3035 | gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls |
| ... | @@ -3155,25 +3093,21 @@ pub const DeclGen = struct { | ... | @@ -3155,25 +3093,21 @@ pub const DeclGen = struct { |
| 3155 | } | 3093 | } |
| 3156 | 3094 | ||
| 3157 | fn lowerTypeFn(dg: *DeclGen, fn_ty: Type) Allocator.Error!*llvm.Type { | 3095 | fn lowerTypeFn(dg: *DeclGen, fn_ty: Type) Allocator.Error!*llvm.Type { |
| 3158 | const target = dg.module.getTarget(); | 3096 | const mod = dg.module; |
| 3159 | const fn_info = fn_ty.fnInfo(); | 3097 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 3160 | const llvm_ret_ty = try lowerFnRetTy(dg, fn_info); | 3098 | const llvm_ret_ty = try lowerFnRetTy(dg, fn_info); |
| 3161 | 3099 | ||
| 3162 | var llvm_params = std.ArrayList(*llvm.Type).init(dg.gpa); | 3100 | var llvm_params = std.ArrayList(*llvm.Type).init(dg.gpa); |
| 3163 | defer llvm_params.deinit(); | 3101 | defer llvm_params.deinit(); |
| 3164 | 3102 | ||
| 3165 | if (firstParamSRet(fn_info, target)) { | 3103 | if (firstParamSRet(fn_info, mod)) { |
| 3166 | try llvm_params.append(dg.context.pointerType(0)); | 3104 | try llvm_params.append(dg.context.pointerType(0)); |
| 3167 | } | 3105 | } |
| 3168 | 3106 | ||
| 3169 | if (fn_info.return_type.isError() and | 3107 | if (fn_info.return_type.toType().isError(mod) and |
| 3170 | dg.module.comp.bin_file.options.error_return_tracing) | 3108 | mod.comp.bin_file.options.error_return_tracing) |
| 3171 | { | 3109 | { |
| 3172 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 3110 | const ptr_ty = try mod.singleMutPtrType(try dg.object.getStackTraceType()); |
| 3173 | .base = .{ .tag = .single_mut_pointer }, | ||
| 3174 | .data = dg.object.getStackTraceType(), | ||
| 3175 | }; | ||
| 3176 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 3177 | try llvm_params.append(try dg.lowerType(ptr_ty)); | 3111 | try llvm_params.append(try dg.lowerType(ptr_ty)); |
| 3178 | } | 3112 | } |
| 3179 | 3113 | ||
| ... | @@ -3181,25 +3115,23 @@ pub const DeclGen = struct { | ... | @@ -3181,25 +3115,23 @@ pub const DeclGen = struct { |
| 3181 | while (it.next()) |lowering| switch (lowering) { | 3115 | while (it.next()) |lowering| switch (lowering) { |
| 3182 | .no_bits => continue, | 3116 | .no_bits => continue, |
| 3183 | .byval => { | 3117 | .byval => { |
| 3184 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 3118 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 3185 | try llvm_params.append(try dg.lowerType(param_ty)); | 3119 | try llvm_params.append(try dg.lowerType(param_ty)); |
| 3186 | }, | 3120 | }, |
| 3187 | .byref, .byref_mut => { | 3121 | .byref, .byref_mut => { |
| 3188 | try llvm_params.append(dg.context.pointerType(0)); | 3122 | try llvm_params.append(dg.context.pointerType(0)); |
| 3189 | }, | 3123 | }, |
| 3190 | .abi_sized_int => { | 3124 | .abi_sized_int => { |
| 3191 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 3125 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 3192 | const abi_size = @intCast(c_uint, param_ty.abiSize(target)); | 3126 | const abi_size = @intCast(c_uint, param_ty.abiSize(mod)); |
| 3193 | try llvm_params.append(dg.context.intType(abi_size * 8)); | 3127 | try llvm_params.append(dg.context.intType(abi_size * 8)); |
| 3194 | }, | 3128 | }, |
| 3195 | .slice => { | 3129 | .slice => { |
| 3196 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 3130 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 3197 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 3131 | const ptr_ty = if (param_ty.zigTypeTag(mod) == .Optional) |
| 3198 | var opt_buf: Type.Payload.ElemType = undefined; | 3132 | param_ty.optionalChild(mod).slicePtrFieldType(mod) |
| 3199 | const ptr_ty = if (param_ty.zigTypeTag() == .Optional) | ||
| 3200 | param_ty.optionalChild(&opt_buf).slicePtrFieldType(&buf) | ||
| 3201 | else | 3133 | else |
| 3202 | param_ty.slicePtrFieldType(&buf); | 3134 | param_ty.slicePtrFieldType(mod); |
| 3203 | const ptr_llvm_ty = try dg.lowerType(ptr_ty); | 3135 | const ptr_llvm_ty = try dg.lowerType(ptr_ty); |
| 3204 | const len_llvm_ty = try dg.lowerType(Type.usize); | 3136 | const len_llvm_ty = try dg.lowerType(Type.usize); |
| 3205 | 3137 | ||
| ... | @@ -3214,8 +3146,8 @@ pub const DeclGen = struct { | ... | @@ -3214,8 +3146,8 @@ pub const DeclGen = struct { |
| 3214 | try llvm_params.append(dg.context.intType(16)); | 3146 | try llvm_params.append(dg.context.intType(16)); |
| 3215 | }, | 3147 | }, |
| 3216 | .float_array => |count| { | 3148 | .float_array => |count| { |
| 3217 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 3149 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 3218 | const float_ty = try dg.lowerType(aarch64_c_abi.getFloatArrayType(param_ty).?); | 3150 | const float_ty = try dg.lowerType(aarch64_c_abi.getFloatArrayType(param_ty, mod).?); |
| 3219 | const field_count = @intCast(c_uint, count); | 3151 | const field_count = @intCast(c_uint, count); |
| 3220 | const arr_ty = float_ty.arrayType(field_count); | 3152 | const arr_ty = float_ty.arrayType(field_count); |
| 3221 | try llvm_params.append(arr_ty); | 3153 | try llvm_params.append(arr_ty); |
| ... | @@ -3239,11 +3171,12 @@ pub const DeclGen = struct { | ... | @@ -3239,11 +3171,12 @@ pub const DeclGen = struct { |
| 3239 | /// being a zero bit type, but it should still be lowered as an i8 in such case. | 3171 | /// being a zero bit type, but it should still be lowered as an i8 in such case. |
| 3240 | /// There are other similar cases handled here as well. | 3172 | /// There are other similar cases handled here as well. |
| 3241 | fn lowerPtrElemTy(dg: *DeclGen, elem_ty: Type) Allocator.Error!*llvm.Type { | 3173 | fn lowerPtrElemTy(dg: *DeclGen, elem_ty: Type) Allocator.Error!*llvm.Type { |
| 3242 | const lower_elem_ty = switch (elem_ty.zigTypeTag()) { | 3174 | const mod = dg.module; |
| 3175 | const lower_elem_ty = switch (elem_ty.zigTypeTag(mod)) { | ||
| 3243 | .Opaque => true, | 3176 | .Opaque => true, |
| 3244 | .Fn => !elem_ty.fnInfo().is_generic, | 3177 | .Fn => !mod.typeToFunc(elem_ty).?.is_generic, |
| 3245 | .Array => elem_ty.childType().hasRuntimeBitsIgnoreComptime(), | 3178 | .Array => elem_ty.childType(mod).hasRuntimeBitsIgnoreComptime(mod), |
| 3246 | else => elem_ty.hasRuntimeBitsIgnoreComptime(), | 3179 | else => elem_ty.hasRuntimeBitsIgnoreComptime(mod), |
| 3247 | }; | 3180 | }; |
| 3248 | const llvm_elem_ty = if (lower_elem_ty) | 3181 | const llvm_elem_ty = if (lower_elem_ty) |
| 3249 | try dg.lowerType(elem_ty) | 3182 | try dg.lowerType(elem_ty) |
| ... | @@ -3254,59 +3187,132 @@ pub const DeclGen = struct { | ... | @@ -3254,59 +3187,132 @@ pub const DeclGen = struct { |
| 3254 | } | 3187 | } |
| 3255 | 3188 | ||
| 3256 | fn lowerValue(dg: *DeclGen, arg_tv: TypedValue) Error!*llvm.Value { | 3189 | fn lowerValue(dg: *DeclGen, arg_tv: TypedValue) Error!*llvm.Value { |
| 3190 | const mod = dg.module; | ||
| 3191 | const target = mod.getTarget(); | ||
| 3257 | var tv = arg_tv; | 3192 | var tv = arg_tv; |
| 3258 | if (tv.val.castTag(.runtime_value)) |rt| { | 3193 | switch (mod.intern_pool.indexToKey(tv.val.toIntern())) { |
| 3259 | tv.val = rt.data; | 3194 | .runtime_value => |rt| tv.val = rt.val.toValue(), |
| 3195 | else => {}, | ||
| 3260 | } | 3196 | } |
| 3261 | if (tv.val.isUndef()) { | 3197 | if (tv.val.isUndefDeep(mod)) { |
| 3262 | const llvm_type = try dg.lowerType(tv.ty); | 3198 | const llvm_type = try dg.lowerType(tv.ty); |
| 3263 | return llvm_type.getUndef(); | 3199 | return llvm_type.getUndef(); |
| 3264 | } | 3200 | } |
| 3265 | const target = dg.module.getTarget(); | ||
| 3266 | 3201 | ||
| 3267 | switch (tv.ty.zigTypeTag()) { | 3202 | const val_key = mod.intern_pool.indexToKey(tv.val.toIntern()); |
| 3268 | .Bool => { | 3203 | switch (val_key) { |
| 3269 | const llvm_type = try dg.lowerType(tv.ty); | 3204 | .int_type, |
| 3270 | return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(); | 3205 | .ptr_type, |
| 3271 | }, | 3206 | .array_type, |
| 3272 | // TODO this duplicates code with Pointer but they should share the handling | 3207 | .vector_type, |
| 3273 | // of the tv.val.tag() and then Int should do extra constPtrToInt on top | 3208 | .opt_type, |
| 3274 | .Int => switch (tv.val.tag()) { | 3209 | .anyframe_type, |
| 3275 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index), | 3210 | .error_union_type, |
| 3276 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), | 3211 | .simple_type, |
| 3277 | else => { | 3212 | .struct_type, |
| 3278 | var bigint_space: Value.BigIntSpace = undefined; | 3213 | .anon_struct_type, |
| 3279 | const bigint = tv.val.toBigInt(&bigint_space, target); | 3214 | .union_type, |
| 3280 | const int_info = tv.ty.intInfo(target); | 3215 | .opaque_type, |
| 3281 | assert(int_info.bits != 0); | 3216 | .enum_type, |
| 3282 | const llvm_type = dg.context.intType(int_info.bits); | 3217 | .func_type, |
| 3283 | 3218 | .error_set_type, | |
| 3284 | const unsigned_val = v: { | 3219 | .inferred_error_set_type, |
| 3285 | if (bigint.limbs.len == 1) { | 3220 | => unreachable, // types, not values |
| 3286 | break :v llvm_type.constInt(bigint.limbs[0], .False); | 3221 | |
| 3287 | } | 3222 | .undef, .runtime_value => unreachable, // handled above |
| 3288 | if (@sizeOf(usize) == @sizeOf(u64)) { | 3223 | .simple_value => |simple_value| switch (simple_value) { |
| 3289 | break :v llvm_type.constIntOfArbitraryPrecision( | 3224 | .undefined, |
| 3290 | @intCast(c_uint, bigint.limbs.len), | 3225 | .void, |
| 3291 | bigint.limbs.ptr, | 3226 | .null, |
| 3292 | ); | 3227 | .empty_struct, |
| 3293 | } | 3228 | .@"unreachable", |
| 3294 | @panic("TODO implement bigint to llvm int for 32-bit compiler builds"); | 3229 | .generic_poison, |
| 3295 | }; | 3230 | => unreachable, // non-runtime values |
| 3296 | if (!bigint.positive) { | 3231 | .false, .true => { |
| 3297 | return llvm.constNeg(unsigned_val); | 3232 | const llvm_type = try dg.lowerType(tv.ty); |
| 3298 | } | 3233 | return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(); |
| 3299 | return unsigned_val; | ||
| 3300 | }, | 3234 | }, |
| 3301 | }, | 3235 | }, |
| 3302 | .Enum => { | 3236 | .variable, |
| 3303 | var int_buffer: Value.Payload.U64 = undefined; | 3237 | .enum_literal, |
| 3304 | const int_val = tv.enumToInt(&int_buffer); | 3238 | .empty_enum_value, |
| 3239 | => unreachable, // non-runtime values | ||
| 3240 | .extern_func, .func => { | ||
| 3241 | const fn_decl_index = switch (val_key) { | ||
| 3242 | .extern_func => |extern_func| extern_func.decl, | ||
| 3243 | .func => |func| mod.funcPtr(func.index).owner_decl, | ||
| 3244 | else => unreachable, | ||
| 3245 | }; | ||
| 3246 | const fn_decl = dg.module.declPtr(fn_decl_index); | ||
| 3247 | try dg.module.markDeclAlive(fn_decl); | ||
| 3248 | return dg.resolveLlvmFunction(fn_decl_index); | ||
| 3249 | }, | ||
| 3250 | .int => { | ||
| 3251 | var bigint_space: Value.BigIntSpace = undefined; | ||
| 3252 | const bigint = tv.val.toBigInt(&bigint_space, mod); | ||
| 3253 | return lowerBigInt(dg, tv.ty, bigint); | ||
| 3254 | }, | ||
| 3255 | .err => |err| { | ||
| 3256 | const llvm_ty = try dg.lowerType(Type.anyerror); | ||
| 3257 | const int = try mod.getErrorValue(err.name); | ||
| 3258 | return llvm_ty.constInt(int, .False); | ||
| 3259 | }, | ||
| 3260 | .error_union => |error_union| { | ||
| 3261 | const err_tv: TypedValue = switch (error_union.val) { | ||
| 3262 | .err_name => |err_name| .{ | ||
| 3263 | .ty = tv.ty.errorUnionSet(mod), | ||
| 3264 | .val = (try mod.intern(.{ .err = .{ | ||
| 3265 | .ty = tv.ty.errorUnionSet(mod).toIntern(), | ||
| 3266 | .name = err_name, | ||
| 3267 | } })).toValue(), | ||
| 3268 | }, | ||
| 3269 | .payload => .{ | ||
| 3270 | .ty = Type.err_int, | ||
| 3271 | .val = try mod.intValue(Type.err_int, 0), | ||
| 3272 | }, | ||
| 3273 | }; | ||
| 3274 | const payload_type = tv.ty.errorUnionPayload(mod); | ||
| 3275 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { | ||
| 3276 | // We use the error type directly as the type. | ||
| 3277 | return dg.lowerValue(err_tv); | ||
| 3278 | } | ||
| 3279 | |||
| 3280 | const payload_align = payload_type.abiAlignment(mod); | ||
| 3281 | const error_align = err_tv.ty.abiAlignment(mod); | ||
| 3282 | const llvm_error_value = try dg.lowerValue(err_tv); | ||
| 3283 | const llvm_payload_value = try dg.lowerValue(.{ | ||
| 3284 | .ty = payload_type, | ||
| 3285 | .val = switch (error_union.val) { | ||
| 3286 | .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }), | ||
| 3287 | .payload => |payload| payload, | ||
| 3288 | }.toValue(), | ||
| 3289 | }); | ||
| 3290 | var fields_buf: [3]*llvm.Value = undefined; | ||
| 3291 | |||
| 3292 | const llvm_ty = try dg.lowerType(tv.ty); | ||
| 3293 | const llvm_field_count = llvm_ty.countStructElementTypes(); | ||
| 3294 | if (llvm_field_count > 2) { | ||
| 3295 | assert(llvm_field_count == 3); | ||
| 3296 | fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef(); | ||
| 3297 | } | ||
| 3298 | |||
| 3299 | if (error_align > payload_align) { | ||
| 3300 | fields_buf[0] = llvm_error_value; | ||
| 3301 | fields_buf[1] = llvm_payload_value; | ||
| 3302 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); | ||
| 3303 | } else { | ||
| 3304 | fields_buf[0] = llvm_payload_value; | ||
| 3305 | fields_buf[1] = llvm_error_value; | ||
| 3306 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); | ||
| 3307 | } | ||
| 3308 | }, | ||
| 3309 | .enum_tag => { | ||
| 3310 | const int_val = try tv.enumToInt(mod); | ||
| 3305 | 3311 | ||
| 3306 | var bigint_space: Value.BigIntSpace = undefined; | 3312 | var bigint_space: Value.BigIntSpace = undefined; |
| 3307 | const bigint = int_val.toBigInt(&bigint_space, target); | 3313 | const bigint = int_val.toBigInt(&bigint_space, mod); |
| 3308 | 3314 | ||
| 3309 | const int_info = tv.ty.intInfo(target); | 3315 | const int_info = tv.ty.intInfo(mod); |
| 3310 | const llvm_type = dg.context.intType(int_info.bits); | 3316 | const llvm_type = dg.context.intType(int_info.bits); |
| 3311 | 3317 | ||
| 3312 | const unsigned_val = v: { | 3318 | const unsigned_val = v: { |
| ... | @@ -3326,29 +3332,29 @@ pub const DeclGen = struct { | ... | @@ -3326,29 +3332,29 @@ pub const DeclGen = struct { |
| 3326 | } | 3332 | } |
| 3327 | return unsigned_val; | 3333 | return unsigned_val; |
| 3328 | }, | 3334 | }, |
| 3329 | .Float => { | 3335 | .float => { |
| 3330 | const llvm_ty = try dg.lowerType(tv.ty); | 3336 | const llvm_ty = try dg.lowerType(tv.ty); |
| 3331 | switch (tv.ty.floatBits(target)) { | 3337 | switch (tv.ty.floatBits(target)) { |
| 3332 | 16 => { | 3338 | 16 => { |
| 3333 | const repr = @bitCast(u16, tv.val.toFloat(f16)); | 3339 | const repr = @bitCast(u16, tv.val.toFloat(f16, mod)); |
| 3334 | const llvm_i16 = dg.context.intType(16); | 3340 | const llvm_i16 = dg.context.intType(16); |
| 3335 | const int = llvm_i16.constInt(repr, .False); | 3341 | const int = llvm_i16.constInt(repr, .False); |
| 3336 | return int.constBitCast(llvm_ty); | 3342 | return int.constBitCast(llvm_ty); |
| 3337 | }, | 3343 | }, |
| 3338 | 32 => { | 3344 | 32 => { |
| 3339 | const repr = @bitCast(u32, tv.val.toFloat(f32)); | 3345 | const repr = @bitCast(u32, tv.val.toFloat(f32, mod)); |
| 3340 | const llvm_i32 = dg.context.intType(32); | 3346 | const llvm_i32 = dg.context.intType(32); |
| 3341 | const int = llvm_i32.constInt(repr, .False); | 3347 | const int = llvm_i32.constInt(repr, .False); |
| 3342 | return int.constBitCast(llvm_ty); | 3348 | return int.constBitCast(llvm_ty); |
| 3343 | }, | 3349 | }, |
| 3344 | 64 => { | 3350 | 64 => { |
| 3345 | const repr = @bitCast(u64, tv.val.toFloat(f64)); | 3351 | const repr = @bitCast(u64, tv.val.toFloat(f64, mod)); |
| 3346 | const llvm_i64 = dg.context.intType(64); | 3352 | const llvm_i64 = dg.context.intType(64); |
| 3347 | const int = llvm_i64.constInt(repr, .False); | 3353 | const int = llvm_i64.constInt(repr, .False); |
| 3348 | return int.constBitCast(llvm_ty); | 3354 | return int.constBitCast(llvm_ty); |
| 3349 | }, | 3355 | }, |
| 3350 | 80 => { | 3356 | 80 => { |
| 3351 | const float = tv.val.toFloat(f80); | 3357 | const float = tv.val.toFloat(f80, mod); |
| 3352 | const repr = std.math.break_f80(float); | 3358 | const repr = std.math.break_f80(float); |
| 3353 | const llvm_i80 = dg.context.intType(80); | 3359 | const llvm_i80 = dg.context.intType(80); |
| 3354 | var x = llvm_i80.constInt(repr.exp, .False); | 3360 | var x = llvm_i80.constInt(repr.exp, .False); |
| ... | @@ -3361,7 +3367,7 @@ pub const DeclGen = struct { | ... | @@ -3361,7 +3367,7 @@ pub const DeclGen = struct { |
| 3361 | } | 3367 | } |
| 3362 | }, | 3368 | }, |
| 3363 | 128 => { | 3369 | 128 => { |
| 3364 | var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128)); | 3370 | var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128, mod)); |
| 3365 | // LLVM seems to require that the lower half of the f128 be placed first | 3371 | // LLVM seems to require that the lower half of the f128 be placed first |
| 3366 | // in the buffer. | 3372 | // in the buffer. |
| 3367 | if (native_endian == .Big) { | 3373 | if (native_endian == .Big) { |
| ... | @@ -3373,204 +3379,60 @@ pub const DeclGen = struct { | ... | @@ -3373,204 +3379,60 @@ pub const DeclGen = struct { |
| 3373 | else => unreachable, | 3379 | else => unreachable, |
| 3374 | } | 3380 | } |
| 3375 | }, | 3381 | }, |
| 3376 | .Pointer => switch (tv.val.tag()) { | 3382 | .ptr => |ptr| { |
| 3377 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index), | 3383 | const ptr_tv: TypedValue = switch (ptr.len) { |
| 3378 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), | 3384 | .none => tv, |
| 3379 | .variable => { | 3385 | else => .{ .ty = tv.ty.slicePtrFieldType(mod), .val = tv.val.slicePtr(mod) }, |
| 3380 | const decl_index = tv.val.castTag(.variable).?.data.owner_decl; | 3386 | }; |
| 3381 | const decl = dg.module.declPtr(decl_index); | 3387 | const llvm_ptr_val = switch (ptr.addr) { |
| 3382 | dg.module.markDeclAlive(decl); | 3388 | .decl => |decl| try dg.lowerDeclRefValue(ptr_tv, decl), |
| 3383 | 3389 | .mut_decl => |mut_decl| try dg.lowerDeclRefValue(ptr_tv, mut_decl.decl), | |
| 3384 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); | 3390 | .int => |int| try dg.lowerIntAsPtr(int.toValue()), |
| 3385 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | 3391 | .eu_payload, |
| 3386 | 3392 | .opt_payload, | |
| 3387 | const val = try dg.resolveGlobalDecl(decl_index); | 3393 | .elem, |
| 3388 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) | 3394 | .field, |
| 3389 | val.constAddrSpaceCast(dg.context.pointerType(llvm_wanted_addrspace)) | 3395 | => try dg.lowerParentPtr(ptr_tv.val, ptr_tv.ty.ptrInfo(mod).bit_offset % 8 == 0), |
| 3390 | else | 3396 | .comptime_field => unreachable, |
| 3391 | val; | 3397 | }; |
| 3392 | return addrspace_casted_ptr; | 3398 | switch (ptr.len) { |
| 3393 | }, | 3399 | .none => return llvm_ptr_val, |
| 3394 | .slice => { | 3400 | else => { |
| 3395 | const slice = tv.val.castTag(.slice).?.data; | 3401 | const fields: [2]*llvm.Value = .{ |
| 3396 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 3402 | llvm_ptr_val, |
| 3397 | const fields: [2]*llvm.Value = .{ | 3403 | try dg.lowerValue(.{ .ty = Type.usize, .val = ptr.len.toValue() }), |
| 3398 | try dg.lowerValue(.{ | 3404 | }; |
| 3399 | .ty = tv.ty.slicePtrFieldType(&buf), | 3405 | return dg.context.constStruct(&fields, fields.len, .False); |
| 3400 | .val = slice.ptr, | 3406 | }, |
| 3401 | }), | 3407 | } |
| 3402 | try dg.lowerValue(.{ | ||
| 3403 | .ty = Type.usize, | ||
| 3404 | .val = slice.len, | ||
| 3405 | }), | ||
| 3406 | }; | ||
| 3407 | return dg.context.constStruct(&fields, fields.len, .False); | ||
| 3408 | }, | ||
| 3409 | .int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => { | ||
| 3410 | const llvm_usize = try dg.lowerType(Type.usize); | ||
| 3411 | const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(target), .False); | ||
| 3412 | return llvm_int.constIntToPtr(try dg.lowerType(tv.ty)); | ||
| 3413 | }, | ||
| 3414 | .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => { | ||
| 3415 | return dg.lowerParentPtr(tv.val, tv.ty.ptrInfo().data.bit_offset % 8 == 0); | ||
| 3416 | }, | ||
| 3417 | .null_value, .zero => { | ||
| 3418 | const llvm_type = try dg.lowerType(tv.ty); | ||
| 3419 | return llvm_type.constNull(); | ||
| 3420 | }, | ||
| 3421 | .opt_payload => { | ||
| 3422 | const payload = tv.val.castTag(.opt_payload).?.data; | ||
| 3423 | return dg.lowerParentPtr(payload, tv.ty.ptrInfo().data.bit_offset % 8 == 0); | ||
| 3424 | }, | ||
| 3425 | else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ | ||
| 3426 | tv.ty.fmtDebug(), tag, | ||
| 3427 | }), | ||
| 3428 | }, | ||
| 3429 | .Array => switch (tv.val.tag()) { | ||
| 3430 | .bytes => { | ||
| 3431 | const bytes = tv.val.castTag(.bytes).?.data; | ||
| 3432 | return dg.context.constString( | ||
| 3433 | bytes.ptr, | ||
| 3434 | @intCast(c_uint, tv.ty.arrayLenIncludingSentinel()), | ||
| 3435 | .True, // Don't null terminate. Bytes has the sentinel, if any. | ||
| 3436 | ); | ||
| 3437 | }, | ||
| 3438 | .str_lit => { | ||
| 3439 | const str_lit = tv.val.castTag(.str_lit).?.data; | ||
| 3440 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | ||
| 3441 | if (tv.ty.sentinel()) |sent_val| { | ||
| 3442 | const byte = @intCast(u8, sent_val.toUnsignedInt(target)); | ||
| 3443 | if (byte == 0 and bytes.len > 0) { | ||
| 3444 | return dg.context.constString( | ||
| 3445 | bytes.ptr, | ||
| 3446 | @intCast(c_uint, bytes.len), | ||
| 3447 | .False, // Yes, null terminate. | ||
| 3448 | ); | ||
| 3449 | } | ||
| 3450 | var array = std.ArrayList(u8).init(dg.gpa); | ||
| 3451 | defer array.deinit(); | ||
| 3452 | try array.ensureUnusedCapacity(bytes.len + 1); | ||
| 3453 | array.appendSliceAssumeCapacity(bytes); | ||
| 3454 | array.appendAssumeCapacity(byte); | ||
| 3455 | return dg.context.constString( | ||
| 3456 | array.items.ptr, | ||
| 3457 | @intCast(c_uint, array.items.len), | ||
| 3458 | .True, // Don't null terminate. | ||
| 3459 | ); | ||
| 3460 | } else { | ||
| 3461 | return dg.context.constString( | ||
| 3462 | bytes.ptr, | ||
| 3463 | @intCast(c_uint, bytes.len), | ||
| 3464 | .True, // Don't null terminate. `bytes` has the sentinel, if any. | ||
| 3465 | ); | ||
| 3466 | } | ||
| 3467 | }, | ||
| 3468 | .aggregate => { | ||
| 3469 | const elem_vals = tv.val.castTag(.aggregate).?.data; | ||
| 3470 | const elem_ty = tv.ty.elemType(); | ||
| 3471 | const gpa = dg.gpa; | ||
| 3472 | const len = @intCast(usize, tv.ty.arrayLenIncludingSentinel()); | ||
| 3473 | const llvm_elems = try gpa.alloc(*llvm.Value, len); | ||
| 3474 | defer gpa.free(llvm_elems); | ||
| 3475 | var need_unnamed = false; | ||
| 3476 | for (elem_vals[0..len], 0..) |elem_val, i| { | ||
| 3477 | llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val }); | ||
| 3478 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); | ||
| 3479 | } | ||
| 3480 | if (need_unnamed) { | ||
| 3481 | return dg.context.constStruct( | ||
| 3482 | llvm_elems.ptr, | ||
| 3483 | @intCast(c_uint, llvm_elems.len), | ||
| 3484 | .True, | ||
| 3485 | ); | ||
| 3486 | } else { | ||
| 3487 | const llvm_elem_ty = try dg.lowerType(elem_ty); | ||
| 3488 | return llvm_elem_ty.constArray( | ||
| 3489 | llvm_elems.ptr, | ||
| 3490 | @intCast(c_uint, llvm_elems.len), | ||
| 3491 | ); | ||
| 3492 | } | ||
| 3493 | }, | ||
| 3494 | .repeated => { | ||
| 3495 | const val = tv.val.castTag(.repeated).?.data; | ||
| 3496 | const elem_ty = tv.ty.elemType(); | ||
| 3497 | const sentinel = tv.ty.sentinel(); | ||
| 3498 | const len = @intCast(usize, tv.ty.arrayLen()); | ||
| 3499 | const len_including_sent = len + @boolToInt(sentinel != null); | ||
| 3500 | const gpa = dg.gpa; | ||
| 3501 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); | ||
| 3502 | defer gpa.free(llvm_elems); | ||
| 3503 | |||
| 3504 | var need_unnamed = false; | ||
| 3505 | if (len != 0) { | ||
| 3506 | for (llvm_elems[0..len]) |*elem| { | ||
| 3507 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val }); | ||
| 3508 | } | ||
| 3509 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); | ||
| 3510 | } | ||
| 3511 | |||
| 3512 | if (sentinel) |sent| { | ||
| 3513 | llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent }); | ||
| 3514 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); | ||
| 3515 | } | ||
| 3516 | |||
| 3517 | if (need_unnamed) { | ||
| 3518 | return dg.context.constStruct( | ||
| 3519 | llvm_elems.ptr, | ||
| 3520 | @intCast(c_uint, llvm_elems.len), | ||
| 3521 | .True, | ||
| 3522 | ); | ||
| 3523 | } else { | ||
| 3524 | const llvm_elem_ty = try dg.lowerType(elem_ty); | ||
| 3525 | return llvm_elem_ty.constArray( | ||
| 3526 | llvm_elems.ptr, | ||
| 3527 | @intCast(c_uint, llvm_elems.len), | ||
| 3528 | ); | ||
| 3529 | } | ||
| 3530 | }, | ||
| 3531 | .empty_array_sentinel => { | ||
| 3532 | const elem_ty = tv.ty.elemType(); | ||
| 3533 | const sent_val = tv.ty.sentinel().?; | ||
| 3534 | const sentinel = try dg.lowerValue(.{ .ty = elem_ty, .val = sent_val }); | ||
| 3535 | const llvm_elems: [1]*llvm.Value = .{sentinel}; | ||
| 3536 | const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]); | ||
| 3537 | if (need_unnamed) { | ||
| 3538 | return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True); | ||
| 3539 | } else { | ||
| 3540 | const llvm_elem_ty = try dg.lowerType(elem_ty); | ||
| 3541 | return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); | ||
| 3542 | } | ||
| 3543 | }, | ||
| 3544 | else => unreachable, | ||
| 3545 | }, | 3408 | }, |
| 3546 | .Optional => { | 3409 | .opt => |opt| { |
| 3547 | comptime assert(optional_layout_version == 3); | 3410 | comptime assert(optional_layout_version == 3); |
| 3548 | var buf: Type.Payload.ElemType = undefined; | 3411 | const payload_ty = tv.ty.optionalChild(mod); |
| 3549 | const payload_ty = tv.ty.optionalChild(&buf); | ||
| 3550 | 3412 | ||
| 3551 | const llvm_i8 = dg.context.intType(8); | 3413 | const llvm_i8 = dg.context.intType(8); |
| 3552 | const is_pl = !tv.val.isNull(); | 3414 | const non_null_bit = switch (opt.val) { |
| 3553 | const non_null_bit = if (is_pl) llvm_i8.constInt(1, .False) else llvm_i8.constNull(); | 3415 | .none => llvm_i8.constNull(), |
| 3554 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3416 | else => llvm_i8.constInt(1, .False), |
| 3417 | }; | ||
| 3418 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | ||
| 3555 | return non_null_bit; | 3419 | return non_null_bit; |
| 3556 | } | 3420 | } |
| 3557 | const llvm_ty = try dg.lowerType(tv.ty); | 3421 | const llvm_ty = try dg.lowerType(tv.ty); |
| 3558 | if (tv.ty.optionalReprIsPayload()) { | 3422 | if (tv.ty.optionalReprIsPayload(mod)) return switch (opt.val) { |
| 3559 | if (tv.val.castTag(.opt_payload)) |payload| { | 3423 | .none => llvm_ty.constNull(), |
| 3560 | return dg.lowerValue(.{ .ty = payload_ty, .val = payload.data }); | 3424 | else => |payload| dg.lowerValue(.{ .ty = payload_ty, .val = payload.toValue() }), |
| 3561 | } else if (is_pl) { | 3425 | }; |
| 3562 | return dg.lowerValue(.{ .ty = payload_ty, .val = tv.val }); | 3426 | assert(payload_ty.zigTypeTag(mod) != .Fn); |
| 3563 | } else { | ||
| 3564 | return llvm_ty.constNull(); | ||
| 3565 | } | ||
| 3566 | } | ||
| 3567 | assert(payload_ty.zigTypeTag() != .Fn); | ||
| 3568 | 3427 | ||
| 3569 | const llvm_field_count = llvm_ty.countStructElementTypes(); | 3428 | const llvm_field_count = llvm_ty.countStructElementTypes(); |
| 3570 | var fields_buf: [3]*llvm.Value = undefined; | 3429 | var fields_buf: [3]*llvm.Value = undefined; |
| 3571 | fields_buf[0] = try dg.lowerValue(.{ | 3430 | fields_buf[0] = try dg.lowerValue(.{ |
| 3572 | .ty = payload_ty, | 3431 | .ty = payload_ty, |
| 3573 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.initTag(.undef), | 3432 | .val = switch (opt.val) { |
| 3433 | .none => try mod.intern(.{ .undef = payload_ty.toIntern() }), | ||
| 3434 | else => |payload| payload, | ||
| 3435 | }.toValue(), | ||
| 3574 | }); | 3436 | }); |
| 3575 | fields_buf[1] = non_null_bit; | 3437 | fields_buf[1] = non_null_bit; |
| 3576 | if (llvm_field_count > 2) { | 3438 | if (llvm_field_count > 2) { |
| ... | @@ -3579,76 +3441,100 @@ pub const DeclGen = struct { | ... | @@ -3579,76 +3441,100 @@ pub const DeclGen = struct { |
| 3579 | } | 3441 | } |
| 3580 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); | 3442 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); |
| 3581 | }, | 3443 | }, |
| 3582 | .Fn => { | 3444 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(tv.ty.toIntern())) { |
| 3583 | const fn_decl_index = switch (tv.val.tag()) { | 3445 | .array_type => switch (aggregate.storage) { |
| 3584 | .extern_fn => tv.val.castTag(.extern_fn).?.data.owner_decl, | 3446 | .bytes => |bytes| return dg.context.constString( |
| 3585 | .function => tv.val.castTag(.function).?.data.owner_decl, | 3447 | bytes.ptr, |
| 3586 | else => unreachable, | 3448 | @intCast(c_uint, tv.ty.arrayLenIncludingSentinel(mod)), |
| 3587 | }; | 3449 | .True, // Don't null terminate. Bytes has the sentinel, if any. |
| 3588 | const fn_decl = dg.module.declPtr(fn_decl_index); | 3450 | ), |
| 3589 | dg.module.markDeclAlive(fn_decl); | 3451 | .elems => |elem_vals| { |
| 3590 | return dg.resolveLlvmFunction(fn_decl_index); | 3452 | const elem_ty = tv.ty.childType(mod); |
| 3591 | }, | 3453 | const gpa = dg.gpa; |
| 3592 | .ErrorSet => { | 3454 | const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len); |
| 3593 | const llvm_ty = try dg.lowerType(Type.anyerror); | 3455 | defer gpa.free(llvm_elems); |
| 3594 | switch (tv.val.tag()) { | 3456 | var need_unnamed = false; |
| 3595 | .@"error" => { | 3457 | for (elem_vals, 0..) |elem_val, i| { |
| 3596 | const err_name = tv.val.castTag(.@"error").?.data.name; | 3458 | llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() }); |
| 3597 | const kv = try dg.module.getErrorValue(err_name); | 3459 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); |
| 3598 | return llvm_ty.constInt(kv.value, .False); | 3460 | } |
| 3599 | }, | 3461 | if (need_unnamed) { |
| 3600 | else => { | 3462 | return dg.context.constStruct( |
| 3601 | // In this case we are rendering an error union which has a 0 bits payload. | 3463 | llvm_elems.ptr, |
| 3602 | return llvm_ty.constNull(); | 3464 | @intCast(c_uint, llvm_elems.len), |
| 3465 | .True, | ||
| 3466 | ); | ||
| 3467 | } else { | ||
| 3468 | const llvm_elem_ty = try dg.lowerType(elem_ty); | ||
| 3469 | return llvm_elem_ty.constArray( | ||
| 3470 | llvm_elems.ptr, | ||
| 3471 | @intCast(c_uint, llvm_elems.len), | ||
| 3472 | ); | ||
| 3473 | } | ||
| 3603 | }, | 3474 | }, |
| 3604 | } | 3475 | .repeated_elem => |val| { |
| 3605 | }, | 3476 | const elem_ty = tv.ty.childType(mod); |
| 3606 | .ErrorUnion => { | 3477 | const sentinel = tv.ty.sentinel(mod); |
| 3607 | const payload_type = tv.ty.errorUnionPayload(); | 3478 | const len = @intCast(usize, tv.ty.arrayLen(mod)); |
| 3608 | const is_pl = tv.val.errorUnionIsPayload(); | 3479 | const len_including_sent = len + @boolToInt(sentinel != null); |
| 3609 | 3480 | const gpa = dg.gpa; | |
| 3610 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | 3481 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); |
| 3611 | // We use the error type directly as the type. | 3482 | defer gpa.free(llvm_elems); |
| 3612 | const err_val = if (!is_pl) tv.val else Value.initTag(.zero); | 3483 | |
| 3613 | return dg.lowerValue(.{ .ty = Type.anyerror, .val = err_val }); | 3484 | var need_unnamed = false; |
| 3614 | } | 3485 | if (len != 0) { |
| 3615 | 3486 | for (llvm_elems[0..len]) |*elem| { | |
| 3616 | const payload_align = payload_type.abiAlignment(target); | 3487 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val.toValue() }); |
| 3617 | const error_align = Type.anyerror.abiAlignment(target); | 3488 | } |
| 3618 | const llvm_error_value = try dg.lowerValue(.{ | 3489 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); |
| 3619 | .ty = Type.anyerror, | 3490 | } |
| 3620 | .val = if (is_pl) Value.initTag(.zero) else tv.val, | ||
| 3621 | }); | ||
| 3622 | const llvm_payload_value = try dg.lowerValue(.{ | ||
| 3623 | .ty = payload_type, | ||
| 3624 | .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), | ||
| 3625 | }); | ||
| 3626 | var fields_buf: [3]*llvm.Value = undefined; | ||
| 3627 | 3491 | ||
| 3628 | const llvm_ty = try dg.lowerType(tv.ty); | 3492 | if (sentinel) |sent| { |
| 3629 | const llvm_field_count = llvm_ty.countStructElementTypes(); | 3493 | llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent }); |
| 3630 | if (llvm_field_count > 2) { | 3494 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); |
| 3631 | assert(llvm_field_count == 3); | 3495 | } |
| 3632 | fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef(); | ||
| 3633 | } | ||
| 3634 | 3496 | ||
| 3635 | if (error_align > payload_align) { | 3497 | if (need_unnamed) { |
| 3636 | fields_buf[0] = llvm_error_value; | 3498 | return dg.context.constStruct( |
| 3637 | fields_buf[1] = llvm_payload_value; | 3499 | llvm_elems.ptr, |
| 3638 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); | 3500 | @intCast(c_uint, llvm_elems.len), |
| 3639 | } else { | 3501 | .True, |
| 3640 | fields_buf[0] = llvm_payload_value; | 3502 | ); |
| 3641 | fields_buf[1] = llvm_error_value; | 3503 | } else { |
| 3642 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); | 3504 | const llvm_elem_ty = try dg.lowerType(elem_ty); |
| 3643 | } | 3505 | return llvm_elem_ty.constArray( |
| 3644 | }, | 3506 | llvm_elems.ptr, |
| 3645 | .Struct => { | 3507 | @intCast(c_uint, llvm_elems.len), |
| 3646 | const llvm_struct_ty = try dg.lowerType(tv.ty); | 3508 | ); |
| 3647 | const field_vals = tv.val.castTag(.aggregate).?.data; | 3509 | } |
| 3648 | const gpa = dg.gpa; | 3510 | }, |
| 3511 | }, | ||
| 3512 | .vector_type => |vector_type| { | ||
| 3513 | const elem_ty = vector_type.child.toType(); | ||
| 3514 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_type.len); | ||
| 3515 | defer dg.gpa.free(llvm_elems); | ||
| 3516 | const llvm_i8 = dg.context.intType(8); | ||
| 3517 | for (llvm_elems, 0..) |*llvm_elem, i| { | ||
| 3518 | llvm_elem.* = switch (aggregate.storage) { | ||
| 3519 | .bytes => |bytes| llvm_i8.constInt(bytes[i], .False), | ||
| 3520 | .elems => |elems| try dg.lowerValue(.{ | ||
| 3521 | .ty = elem_ty, | ||
| 3522 | .val = elems[i].toValue(), | ||
| 3523 | }), | ||
| 3524 | .repeated_elem => |elem| try dg.lowerValue(.{ | ||
| 3525 | .ty = elem_ty, | ||
| 3526 | .val = elem.toValue(), | ||
| 3527 | }), | ||
| 3528 | }; | ||
| 3529 | } | ||
| 3530 | return llvm.constVector( | ||
| 3531 | llvm_elems.ptr, | ||
| 3532 | @intCast(c_uint, llvm_elems.len), | ||
| 3533 | ); | ||
| 3534 | }, | ||
| 3535 | .anon_struct_type => |tuple| { | ||
| 3536 | const gpa = dg.gpa; | ||
| 3649 | 3537 | ||
| 3650 | if (tv.ty.isSimpleTupleOrAnonStruct()) { | ||
| 3651 | const tuple = tv.ty.tupleFields(); | ||
| 3652 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; | 3538 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; |
| 3653 | defer llvm_fields.deinit(gpa); | 3539 | defer llvm_fields.deinit(gpa); |
| 3654 | 3540 | ||
| ... | @@ -3659,11 +3545,11 @@ pub const DeclGen = struct { | ... | @@ -3659,11 +3545,11 @@ pub const DeclGen = struct { |
| 3659 | var big_align: u32 = 0; | 3545 | var big_align: u32 = 0; |
| 3660 | var need_unnamed = false; | 3546 | var need_unnamed = false; |
| 3661 | 3547 | ||
| 3662 | for (tuple.types, 0..) |field_ty, i| { | 3548 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { |
| 3663 | if (tuple.values[i].tag() != .unreachable_value) continue; | 3549 | if (field_val != .none) continue; |
| 3664 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; | 3550 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3665 | 3551 | ||
| 3666 | const field_align = field_ty.abiAlignment(target); | 3552 | const field_align = field_ty.toType().abiAlignment(mod); |
| 3667 | big_align = @max(big_align, field_align); | 3553 | big_align = @max(big_align, field_align); |
| 3668 | const prev_offset = offset; | 3554 | const prev_offset = offset; |
| 3669 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 3555 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| ... | @@ -3677,15 +3563,15 @@ pub const DeclGen = struct { | ... | @@ -3677,15 +3563,15 @@ pub const DeclGen = struct { |
| 3677 | } | 3563 | } |
| 3678 | 3564 | ||
| 3679 | const field_llvm_val = try dg.lowerValue(.{ | 3565 | const field_llvm_val = try dg.lowerValue(.{ |
| 3680 | .ty = field_ty, | 3566 | .ty = field_ty.toType(), |
| 3681 | .val = field_vals[i], | 3567 | .val = try tv.val.fieldValue(mod, i), |
| 3682 | }); | 3568 | }); |
| 3683 | 3569 | ||
| 3684 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field_llvm_val); | 3570 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty.toType(), field_llvm_val); |
| 3685 | 3571 | ||
| 3686 | llvm_fields.appendAssumeCapacity(field_llvm_val); | 3572 | llvm_fields.appendAssumeCapacity(field_llvm_val); |
| 3687 | 3573 | ||
| 3688 | offset += field_ty.abiSize(target); | 3574 | offset += field_ty.toType().abiSize(mod); |
| 3689 | } | 3575 | } |
| 3690 | { | 3576 | { |
| 3691 | const prev_offset = offset; | 3577 | const prev_offset = offset; |
| ... | @@ -3704,132 +3590,142 @@ pub const DeclGen = struct { | ... | @@ -3704,132 +3590,142 @@ pub const DeclGen = struct { |
| 3704 | .False, | 3590 | .False, |
| 3705 | ); | 3591 | ); |
| 3706 | } else { | 3592 | } else { |
| 3593 | const llvm_struct_ty = try dg.lowerType(tv.ty); | ||
| 3707 | return llvm_struct_ty.constNamedStruct( | 3594 | return llvm_struct_ty.constNamedStruct( |
| 3708 | llvm_fields.items.ptr, | 3595 | llvm_fields.items.ptr, |
| 3709 | @intCast(c_uint, llvm_fields.items.len), | 3596 | @intCast(c_uint, llvm_fields.items.len), |
| 3710 | ); | 3597 | ); |
| 3711 | } | 3598 | } |
| 3712 | } | 3599 | }, |
| 3713 | 3600 | .struct_type => |struct_type| { | |
| 3714 | const struct_obj = tv.ty.castTag(.@"struct").?.data; | 3601 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 3715 | 3602 | const llvm_struct_ty = try dg.lowerType(tv.ty); | |
| 3716 | if (struct_obj.layout == .Packed) { | 3603 | const gpa = dg.gpa; |
| 3717 | assert(struct_obj.haveLayout()); | ||
| 3718 | const big_bits = struct_obj.backing_int_ty.bitSize(target); | ||
| 3719 | const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits)); | ||
| 3720 | const fields = struct_obj.fields.values(); | ||
| 3721 | comptime assert(Type.packed_struct_layout_version == 2); | ||
| 3722 | var running_int: *llvm.Value = int_llvm_ty.constNull(); | ||
| 3723 | var running_bits: u16 = 0; | ||
| 3724 | for (field_vals, 0..) |field_val, i| { | ||
| 3725 | const field = fields[i]; | ||
| 3726 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; | ||
| 3727 | 3604 | ||
| 3728 | const non_int_val = try dg.lowerValue(.{ | 3605 | if (struct_obj.layout == .Packed) { |
| 3729 | .ty = field.ty, | 3606 | assert(struct_obj.haveLayout()); |
| 3730 | .val = field_val, | 3607 | const big_bits = struct_obj.backing_int_ty.bitSize(mod); |
| 3731 | }); | 3608 | const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits)); |
| 3732 | const ty_bit_size = @intCast(u16, field.ty.bitSize(target)); | 3609 | const fields = struct_obj.fields.values(); |
| 3733 | const small_int_ty = dg.context.intType(ty_bit_size); | 3610 | comptime assert(Type.packed_struct_layout_version == 2); |
| 3734 | const small_int_val = if (field.ty.isPtrAtRuntime()) | 3611 | var running_int: *llvm.Value = int_llvm_ty.constNull(); |
| 3735 | non_int_val.constPtrToInt(small_int_ty) | 3612 | var running_bits: u16 = 0; |
| 3736 | else | 3613 | for (fields, 0..) |field, i| { |
| 3737 | non_int_val.constBitCast(small_int_ty); | 3614 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3738 | const shift_rhs = int_llvm_ty.constInt(running_bits, .False); | 3615 | |
| 3739 | // If the field is as large as the entire packed struct, this | 3616 | const non_int_val = try dg.lowerValue(.{ |
| 3740 | // zext would go from, e.g. i16 to i16. This is legal with | 3617 | .ty = field.ty, |
| 3741 | // constZExtOrBitCast but not legal with constZExt. | 3618 | .val = try tv.val.fieldValue(mod, i), |
| 3742 | const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty); | 3619 | }); |
| 3743 | const shifted = extended_int_val.constShl(shift_rhs); | 3620 | const ty_bit_size = @intCast(u16, field.ty.bitSize(mod)); |
| 3744 | running_int = running_int.constOr(shifted); | 3621 | const small_int_ty = dg.context.intType(ty_bit_size); |
| 3745 | running_bits += ty_bit_size; | 3622 | const small_int_val = if (field.ty.isPtrAtRuntime(mod)) |
| 3623 | non_int_val.constPtrToInt(small_int_ty) | ||
| 3624 | else | ||
| 3625 | non_int_val.constBitCast(small_int_ty); | ||
| 3626 | const shift_rhs = int_llvm_ty.constInt(running_bits, .False); | ||
| 3627 | // If the field is as large as the entire packed struct, this | ||
| 3628 | // zext would go from, e.g. i16 to i16. This is legal with | ||
| 3629 | // constZExtOrBitCast but not legal with constZExt. | ||
| 3630 | const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty); | ||
| 3631 | const shifted = extended_int_val.constShl(shift_rhs); | ||
| 3632 | running_int = running_int.constOr(shifted); | ||
| 3633 | running_bits += ty_bit_size; | ||
| 3634 | } | ||
| 3635 | return running_int; | ||
| 3746 | } | 3636 | } |
| 3747 | return running_int; | ||
| 3748 | } | ||
| 3749 | 3637 | ||
| 3750 | const llvm_field_count = llvm_struct_ty.countStructElementTypes(); | 3638 | const llvm_field_count = llvm_struct_ty.countStructElementTypes(); |
| 3751 | var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count); | 3639 | var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count); |
| 3752 | defer llvm_fields.deinit(gpa); | 3640 | defer llvm_fields.deinit(gpa); |
| 3753 | 3641 | ||
| 3754 | comptime assert(struct_layout_version == 2); | 3642 | comptime assert(struct_layout_version == 2); |
| 3755 | var offset: u64 = 0; | 3643 | var offset: u64 = 0; |
| 3756 | var big_align: u32 = 0; | 3644 | var big_align: u32 = 0; |
| 3757 | var need_unnamed = false; | 3645 | var need_unnamed = false; |
| 3758 | 3646 | ||
| 3759 | var it = struct_obj.runtimeFieldIterator(); | 3647 | var it = struct_obj.runtimeFieldIterator(mod); |
| 3760 | while (it.next()) |field_and_index| { | 3648 | while (it.next()) |field_and_index| { |
| 3761 | const field = field_and_index.field; | 3649 | const field = field_and_index.field; |
| 3762 | const field_align = field.alignment(target, struct_obj.layout); | 3650 | const field_align = field.alignment(mod, struct_obj.layout); |
| 3763 | big_align = @max(big_align, field_align); | 3651 | big_align = @max(big_align, field_align); |
| 3764 | const prev_offset = offset; | 3652 | const prev_offset = offset; |
| 3765 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 3653 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 3766 | 3654 | ||
| 3767 | const padding_len = offset - prev_offset; | 3655 | const padding_len = offset - prev_offset; |
| 3768 | if (padding_len > 0) { | 3656 | if (padding_len > 0) { |
| 3769 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 3657 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 3770 | // TODO make this and all other padding elsewhere in debug | 3658 | // TODO make this and all other padding elsewhere in debug |
| 3771 | // builds be 0xaa not undef. | 3659 | // builds be 0xaa not undef. |
| 3772 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | 3660 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); |
| 3773 | } | 3661 | } |
| 3774 | 3662 | ||
| 3775 | const field_llvm_val = try dg.lowerValue(.{ | 3663 | const field_llvm_val = try dg.lowerValue(.{ |
| 3776 | .ty = field.ty, | 3664 | .ty = field.ty, |
| 3777 | .val = field_vals[field_and_index.index], | 3665 | .val = try tv.val.fieldValue(mod, field_and_index.index), |
| 3778 | }); | 3666 | }); |
| 3779 | 3667 | ||
| 3780 | need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val); | 3668 | need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val); |
| 3781 | 3669 | ||
| 3782 | llvm_fields.appendAssumeCapacity(field_llvm_val); | 3670 | llvm_fields.appendAssumeCapacity(field_llvm_val); |
| 3783 | 3671 | ||
| 3784 | offset += field.ty.abiSize(target); | 3672 | offset += field.ty.abiSize(mod); |
| 3785 | } | 3673 | } |
| 3786 | { | 3674 | { |
| 3787 | const prev_offset = offset; | 3675 | const prev_offset = offset; |
| 3788 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | 3676 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| 3789 | const padding_len = offset - prev_offset; | 3677 | const padding_len = offset - prev_offset; |
| 3790 | if (padding_len > 0) { | 3678 | if (padding_len > 0) { |
| 3791 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | 3679 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 3792 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | 3680 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); |
| 3681 | } | ||
| 3793 | } | 3682 | } |
| 3794 | } | ||
| 3795 | 3683 | ||
| 3796 | if (need_unnamed) { | 3684 | if (need_unnamed) { |
| 3797 | return dg.context.constStruct( | 3685 | return dg.context.constStruct( |
| 3798 | llvm_fields.items.ptr, | 3686 | llvm_fields.items.ptr, |
| 3799 | @intCast(c_uint, llvm_fields.items.len), | 3687 | @intCast(c_uint, llvm_fields.items.len), |
| 3800 | .False, | 3688 | .False, |
| 3801 | ); | 3689 | ); |
| 3802 | } else { | 3690 | } else { |
| 3803 | return llvm_struct_ty.constNamedStruct( | 3691 | return llvm_struct_ty.constNamedStruct( |
| 3804 | llvm_fields.items.ptr, | 3692 | llvm_fields.items.ptr, |
| 3805 | @intCast(c_uint, llvm_fields.items.len), | 3693 | @intCast(c_uint, llvm_fields.items.len), |
| 3806 | ); | 3694 | ); |
| 3807 | } | 3695 | } |
| 3696 | }, | ||
| 3697 | else => unreachable, | ||
| 3808 | }, | 3698 | }, |
| 3809 | .Union => { | 3699 | .un => { |
| 3810 | const llvm_union_ty = try dg.lowerType(tv.ty); | 3700 | const llvm_union_ty = try dg.lowerType(tv.ty); |
| 3811 | const tag_and_val = tv.val.castTag(.@"union").?.data; | 3701 | const tag_and_val: Value.Payload.Union.Data = switch (tv.val.toIntern()) { |
| 3702 | .none => tv.val.castTag(.@"union").?.data, | ||
| 3703 | else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) { | ||
| 3704 | .un => |un| .{ .tag = un.tag.toValue(), .val = un.val.toValue() }, | ||
| 3705 | else => unreachable, | ||
| 3706 | }, | ||
| 3707 | }; | ||
| 3812 | 3708 | ||
| 3813 | const layout = tv.ty.unionGetLayout(target); | 3709 | const layout = tv.ty.unionGetLayout(mod); |
| 3814 | 3710 | ||
| 3815 | if (layout.payload_size == 0) { | 3711 | if (layout.payload_size == 0) { |
| 3816 | return lowerValue(dg, .{ | 3712 | return lowerValue(dg, .{ |
| 3817 | .ty = tv.ty.unionTagTypeSafety().?, | 3713 | .ty = tv.ty.unionTagTypeSafety(mod).?, |
| 3818 | .val = tag_and_val.tag, | 3714 | .val = tag_and_val.tag, |
| 3819 | }); | 3715 | }); |
| 3820 | } | 3716 | } |
| 3821 | const union_obj = tv.ty.cast(Type.Payload.Union).?.data; | 3717 | const union_obj = mod.typeToUnion(tv.ty).?; |
| 3822 | const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?; | 3718 | const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?; |
| 3823 | assert(union_obj.haveFieldTypes()); | 3719 | assert(union_obj.haveFieldTypes()); |
| 3824 | 3720 | ||
| 3825 | const field_ty = union_obj.fields.values()[field_index].ty; | 3721 | const field_ty = union_obj.fields.values()[field_index].ty; |
| 3826 | if (union_obj.layout == .Packed) { | 3722 | if (union_obj.layout == .Packed) { |
| 3827 | if (!field_ty.hasRuntimeBits()) | 3723 | if (!field_ty.hasRuntimeBits(mod)) |
| 3828 | return llvm_union_ty.constNull(); | 3724 | return llvm_union_ty.constNull(); |
| 3829 | const non_int_val = try lowerValue(dg, .{ .ty = field_ty, .val = tag_and_val.val }); | 3725 | const non_int_val = try lowerValue(dg, .{ .ty = field_ty, .val = tag_and_val.val }); |
| 3830 | const ty_bit_size = @intCast(u16, field_ty.bitSize(target)); | 3726 | const ty_bit_size = @intCast(u16, field_ty.bitSize(mod)); |
| 3831 | const small_int_ty = dg.context.intType(ty_bit_size); | 3727 | const small_int_ty = dg.context.intType(ty_bit_size); |
| 3832 | const small_int_val = if (field_ty.isPtrAtRuntime()) | 3728 | const small_int_val = if (field_ty.isPtrAtRuntime(mod)) |
| 3833 | non_int_val.constPtrToInt(small_int_ty) | 3729 | non_int_val.constPtrToInt(small_int_ty) |
| 3834 | else | 3730 | else |
| 3835 | non_int_val.constBitCast(small_int_ty); | 3731 | non_int_val.constBitCast(small_int_ty); |
| ... | @@ -3842,13 +3738,13 @@ pub const DeclGen = struct { | ... | @@ -3842,13 +3738,13 @@ pub const DeclGen = struct { |
| 3842 | // must pointer cast to the expected type before accessing the union. | 3738 | // must pointer cast to the expected type before accessing the union. |
| 3843 | var need_unnamed: bool = layout.most_aligned_field != field_index; | 3739 | var need_unnamed: bool = layout.most_aligned_field != field_index; |
| 3844 | const payload = p: { | 3740 | const payload = p: { |
| 3845 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) { | 3741 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3846 | const padding_len = @intCast(c_uint, layout.payload_size); | 3742 | const padding_len = @intCast(c_uint, layout.payload_size); |
| 3847 | break :p dg.context.intType(8).arrayType(padding_len).getUndef(); | 3743 | break :p dg.context.intType(8).arrayType(padding_len).getUndef(); |
| 3848 | } | 3744 | } |
| 3849 | const field = try lowerValue(dg, .{ .ty = field_ty, .val = tag_and_val.val }); | 3745 | const field = try lowerValue(dg, .{ .ty = field_ty, .val = tag_and_val.val }); |
| 3850 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field); | 3746 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field); |
| 3851 | const field_size = field_ty.abiSize(target); | 3747 | const field_size = field_ty.abiSize(mod); |
| 3852 | if (field_size == layout.payload_size) { | 3748 | if (field_size == layout.payload_size) { |
| 3853 | break :p field; | 3749 | break :p field; |
| 3854 | } | 3750 | } |
| ... | @@ -3868,7 +3764,7 @@ pub const DeclGen = struct { | ... | @@ -3868,7 +3764,7 @@ pub const DeclGen = struct { |
| 3868 | } | 3764 | } |
| 3869 | } | 3765 | } |
| 3870 | const llvm_tag_value = try lowerValue(dg, .{ | 3766 | const llvm_tag_value = try lowerValue(dg, .{ |
| 3871 | .ty = tv.ty.unionTagTypeSafety().?, | 3767 | .ty = tv.ty.unionTagTypeSafety(mod).?, |
| 3872 | .val = tag_and_val.tag, | 3768 | .val = tag_and_val.tag, |
| 3873 | }); | 3769 | }); |
| 3874 | var fields: [3]*llvm.Value = undefined; | 3770 | var fields: [3]*llvm.Value = undefined; |
| ... | @@ -3888,107 +3784,45 @@ pub const DeclGen = struct { | ... | @@ -3888,107 +3784,45 @@ pub const DeclGen = struct { |
| 3888 | return llvm_union_ty.constNamedStruct(&fields, fields_len); | 3784 | return llvm_union_ty.constNamedStruct(&fields, fields_len); |
| 3889 | } | 3785 | } |
| 3890 | }, | 3786 | }, |
| 3891 | .Vector => switch (tv.val.tag()) { | 3787 | .memoized_call => unreachable, |
| 3892 | .bytes => { | 3788 | } |
| 3893 | // Note, sentinel is not stored even if the type has a sentinel. | 3789 | } |
| 3894 | const bytes = tv.val.castTag(.bytes).?.data; | ||
| 3895 | const vector_len = @intCast(usize, tv.ty.arrayLen()); | ||
| 3896 | assert(vector_len == bytes.len or vector_len + 1 == bytes.len); | ||
| 3897 | |||
| 3898 | const elem_ty = tv.ty.elemType(); | ||
| 3899 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_len); | ||
| 3900 | defer dg.gpa.free(llvm_elems); | ||
| 3901 | for (llvm_elems, 0..) |*elem, i| { | ||
| 3902 | var byte_payload: Value.Payload.U64 = .{ | ||
| 3903 | .base = .{ .tag = .int_u64 }, | ||
| 3904 | .data = bytes[i], | ||
| 3905 | }; | ||
| 3906 | |||
| 3907 | elem.* = try dg.lowerValue(.{ | ||
| 3908 | .ty = elem_ty, | ||
| 3909 | .val = Value.initPayload(&byte_payload.base), | ||
| 3910 | }); | ||
| 3911 | } | ||
| 3912 | return llvm.constVector( | ||
| 3913 | llvm_elems.ptr, | ||
| 3914 | @intCast(c_uint, llvm_elems.len), | ||
| 3915 | ); | ||
| 3916 | }, | ||
| 3917 | .aggregate => { | ||
| 3918 | // Note, sentinel is not stored even if the type has a sentinel. | ||
| 3919 | // The value includes the sentinel in those cases. | ||
| 3920 | const elem_vals = tv.val.castTag(.aggregate).?.data; | ||
| 3921 | const vector_len = @intCast(usize, tv.ty.arrayLen()); | ||
| 3922 | assert(vector_len == elem_vals.len or vector_len + 1 == elem_vals.len); | ||
| 3923 | const elem_ty = tv.ty.elemType(); | ||
| 3924 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_len); | ||
| 3925 | defer dg.gpa.free(llvm_elems); | ||
| 3926 | for (llvm_elems, 0..) |*elem, i| { | ||
| 3927 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_vals[i] }); | ||
| 3928 | } | ||
| 3929 | return llvm.constVector( | ||
| 3930 | llvm_elems.ptr, | ||
| 3931 | @intCast(c_uint, llvm_elems.len), | ||
| 3932 | ); | ||
| 3933 | }, | ||
| 3934 | .repeated => { | ||
| 3935 | // Note, sentinel is not stored even if the type has a sentinel. | ||
| 3936 | const val = tv.val.castTag(.repeated).?.data; | ||
| 3937 | const elem_ty = tv.ty.elemType(); | ||
| 3938 | const len = @intCast(usize, tv.ty.arrayLen()); | ||
| 3939 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, len); | ||
| 3940 | defer dg.gpa.free(llvm_elems); | ||
| 3941 | for (llvm_elems) |*elem| { | ||
| 3942 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val }); | ||
| 3943 | } | ||
| 3944 | return llvm.constVector( | ||
| 3945 | llvm_elems.ptr, | ||
| 3946 | @intCast(c_uint, llvm_elems.len), | ||
| 3947 | ); | ||
| 3948 | }, | ||
| 3949 | .str_lit => { | ||
| 3950 | // Note, sentinel is not stored | ||
| 3951 | const str_lit = tv.val.castTag(.str_lit).?.data; | ||
| 3952 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | ||
| 3953 | const vector_len = @intCast(usize, tv.ty.arrayLen()); | ||
| 3954 | assert(vector_len == bytes.len); | ||
| 3955 | |||
| 3956 | const elem_ty = tv.ty.elemType(); | ||
| 3957 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_len); | ||
| 3958 | defer dg.gpa.free(llvm_elems); | ||
| 3959 | for (llvm_elems, 0..) |*elem, i| { | ||
| 3960 | var byte_payload: Value.Payload.U64 = .{ | ||
| 3961 | .base = .{ .tag = .int_u64 }, | ||
| 3962 | .data = bytes[i], | ||
| 3963 | }; | ||
| 3964 | 3790 | ||
| 3965 | elem.* = try dg.lowerValue(.{ | 3791 | fn lowerIntAsPtr(dg: *DeclGen, val: Value) Error!*llvm.Value { |
| 3966 | .ty = elem_ty, | 3792 | switch (dg.module.intern_pool.indexToKey(val.toIntern())) { |
| 3967 | .val = Value.initPayload(&byte_payload.base), | 3793 | .undef => return dg.context.pointerType(0).getUndef(), |
| 3968 | }); | 3794 | .int => { |
| 3969 | } | 3795 | var bigint_space: Value.BigIntSpace = undefined; |
| 3970 | return llvm.constVector( | 3796 | const bigint = val.toBigInt(&bigint_space, dg.module); |
| 3971 | llvm_elems.ptr, | 3797 | const llvm_int = lowerBigInt(dg, Type.usize, bigint); |
| 3972 | @intCast(c_uint, llvm_elems.len), | 3798 | return llvm_int.constIntToPtr(dg.context.pointerType(0)); |
| 3973 | ); | ||
| 3974 | }, | ||
| 3975 | else => unreachable, | ||
| 3976 | }, | 3799 | }, |
| 3800 | else => unreachable, | ||
| 3801 | } | ||
| 3802 | } | ||
| 3977 | 3803 | ||
| 3978 | .ComptimeInt => unreachable, | 3804 | fn lowerBigInt(dg: *DeclGen, ty: Type, bigint: std.math.big.int.Const) *llvm.Value { |
| 3979 | .ComptimeFloat => unreachable, | 3805 | const mod = dg.module; |
| 3980 | .Type => unreachable, | 3806 | const int_info = ty.intInfo(mod); |
| 3981 | .EnumLiteral => unreachable, | 3807 | assert(int_info.bits != 0); |
| 3982 | .Void => unreachable, | 3808 | const llvm_type = dg.context.intType(int_info.bits); |
| 3983 | .NoReturn => unreachable, | ||
| 3984 | .Undefined => unreachable, | ||
| 3985 | .Null => unreachable, | ||
| 3986 | .Opaque => unreachable, | ||
| 3987 | 3809 | ||
| 3988 | .Frame, | 3810 | const unsigned_val = v: { |
| 3989 | .AnyFrame, | 3811 | if (bigint.limbs.len == 1) { |
| 3990 | => return dg.todo("implement const of type '{}'", .{tv.ty.fmtDebug()}), | 3812 | break :v llvm_type.constInt(bigint.limbs[0], .False); |
| 3813 | } | ||
| 3814 | if (@sizeOf(usize) == @sizeOf(u64)) { | ||
| 3815 | break :v llvm_type.constIntOfArbitraryPrecision( | ||
| 3816 | @intCast(c_uint, bigint.limbs.len), | ||
| 3817 | bigint.limbs.ptr, | ||
| 3818 | ); | ||
| 3819 | } | ||
| 3820 | @panic("TODO implement bigint to llvm int for 32-bit compiler builds"); | ||
| 3821 | }; | ||
| 3822 | if (!bigint.positive) { | ||
| 3823 | return llvm.constNeg(unsigned_val); | ||
| 3991 | } | 3824 | } |
| 3825 | return unsigned_val; | ||
| 3992 | } | 3826 | } |
| 3993 | 3827 | ||
| 3994 | const ParentPtr = struct { | 3828 | const ParentPtr = struct { |
| ... | @@ -4001,57 +3835,86 @@ pub const DeclGen = struct { | ... | @@ -4001,57 +3835,86 @@ pub const DeclGen = struct { |
| 4001 | ptr_val: Value, | 3835 | ptr_val: Value, |
| 4002 | decl_index: Module.Decl.Index, | 3836 | decl_index: Module.Decl.Index, |
| 4003 | ) Error!*llvm.Value { | 3837 | ) Error!*llvm.Value { |
| 4004 | const decl = dg.module.declPtr(decl_index); | 3838 | const mod = dg.module; |
| 4005 | dg.module.markDeclAlive(decl); | 3839 | const decl = mod.declPtr(decl_index); |
| 4006 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 3840 | try mod.markDeclAlive(decl); |
| 4007 | .base = .{ .tag = .single_mut_pointer }, | 3841 | const ptr_ty = try mod.singleMutPtrType(decl.ty); |
| 4008 | .data = decl.ty, | ||
| 4009 | }; | ||
| 4010 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 4011 | return try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index); | 3842 | return try dg.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index); |
| 4012 | } | 3843 | } |
| 4013 | 3844 | ||
| 4014 | fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, byte_aligned: bool) Error!*llvm.Value { | 3845 | fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, byte_aligned: bool) Error!*llvm.Value { |
| 4015 | const target = dg.module.getTarget(); | 3846 | const mod = dg.module; |
| 4016 | switch (ptr_val.tag()) { | 3847 | const target = mod.getTarget(); |
| 4017 | .decl_ref_mut => { | 3848 | return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { |
| 4018 | const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl_index; | 3849 | .decl => |decl| dg.lowerParentPtrDecl(ptr_val, decl), |
| 4019 | return dg.lowerParentPtrDecl(ptr_val, decl); | 3850 | .mut_decl => |mut_decl| dg.lowerParentPtrDecl(ptr_val, mut_decl.decl), |
| 4020 | }, | 3851 | .int => |int| dg.lowerIntAsPtr(int.toValue()), |
| 4021 | .decl_ref => { | 3852 | .eu_payload => |eu_ptr| { |
| 4022 | const decl = ptr_val.castTag(.decl_ref).?.data; | 3853 | const parent_llvm_ptr = try dg.lowerParentPtr(eu_ptr.toValue(), true); |
| 4023 | return dg.lowerParentPtrDecl(ptr_val, decl); | 3854 | |
| 4024 | }, | 3855 | const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod); |
| 4025 | .variable => { | 3856 | const payload_ty = eu_ty.errorUnionPayload(mod); |
| 4026 | const decl = ptr_val.castTag(.variable).?.data.owner_decl; | 3857 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 4027 | return dg.lowerParentPtrDecl(ptr_val, decl); | 3858 | // In this case, we represent pointer to error union the same as pointer |
| 3859 | // to the payload. | ||
| 3860 | return parent_llvm_ptr; | ||
| 3861 | } | ||
| 3862 | |||
| 3863 | const payload_offset: u8 = if (payload_ty.abiAlignment(mod) > Type.anyerror.abiSize(mod)) 2 else 1; | ||
| 3864 | const llvm_u32 = dg.context.intType(32); | ||
| 3865 | const indices: [2]*llvm.Value = .{ | ||
| 3866 | llvm_u32.constInt(0, .False), | ||
| 3867 | llvm_u32.constInt(payload_offset, .False), | ||
| 3868 | }; | ||
| 3869 | const eu_llvm_ty = try dg.lowerType(eu_ty); | ||
| 3870 | return eu_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4028 | }, | 3871 | }, |
| 4029 | .int_i64 => { | 3872 | .opt_payload => |opt_ptr| { |
| 4030 | const int = ptr_val.castTag(.int_i64).?.data; | 3873 | const parent_llvm_ptr = try dg.lowerParentPtr(opt_ptr.toValue(), true); |
| 4031 | const llvm_usize = try dg.lowerType(Type.usize); | 3874 | |
| 4032 | const llvm_int = llvm_usize.constInt(@bitCast(u64, int), .False); | 3875 | const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod); |
| 4033 | return llvm_int.constIntToPtr(dg.context.pointerType(0)); | 3876 | const payload_ty = opt_ty.optionalChild(mod); |
| 3877 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or | ||
| 3878 | payload_ty.optionalReprIsPayload(mod)) | ||
| 3879 | { | ||
| 3880 | // In this case, we represent pointer to optional the same as pointer | ||
| 3881 | // to the payload. | ||
| 3882 | return parent_llvm_ptr; | ||
| 3883 | } | ||
| 3884 | |||
| 3885 | const llvm_u32 = dg.context.intType(32); | ||
| 3886 | const indices: [2]*llvm.Value = .{ | ||
| 3887 | llvm_u32.constInt(0, .False), | ||
| 3888 | llvm_u32.constInt(0, .False), | ||
| 3889 | }; | ||
| 3890 | const opt_llvm_ty = try dg.lowerType(opt_ty); | ||
| 3891 | return opt_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4034 | }, | 3892 | }, |
| 4035 | .int_u64 => { | 3893 | .comptime_field => unreachable, |
| 4036 | const int = ptr_val.castTag(.int_u64).?.data; | 3894 | .elem => |elem_ptr| { |
| 3895 | const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.base.toValue(), true); | ||
| 3896 | |||
| 4037 | const llvm_usize = try dg.lowerType(Type.usize); | 3897 | const llvm_usize = try dg.lowerType(Type.usize); |
| 4038 | const llvm_int = llvm_usize.constInt(int, .False); | 3898 | const indices: [1]*llvm.Value = .{ |
| 4039 | return llvm_int.constIntToPtr(dg.context.pointerType(0)); | 3899 | llvm_usize.constInt(elem_ptr.index, .False), |
| 3900 | }; | ||
| 3901 | const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod); | ||
| 3902 | const elem_llvm_ty = try dg.lowerType(elem_ty); | ||
| 3903 | return elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4040 | }, | 3904 | }, |
| 4041 | .field_ptr => { | 3905 | .field => |field_ptr| { |
| 4042 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | 3906 | const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.base.toValue(), byte_aligned); |
| 4043 | const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.container_ptr, byte_aligned); | 3907 | const parent_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); |
| 4044 | const parent_ty = field_ptr.container_ty; | ||
| 4045 | 3908 | ||
| 4046 | const field_index = @intCast(u32, field_ptr.field_index); | 3909 | const field_index = @intCast(u32, field_ptr.index); |
| 4047 | const llvm_u32 = dg.context.intType(32); | 3910 | const llvm_u32 = dg.context.intType(32); |
| 4048 | switch (parent_ty.zigTypeTag()) { | 3911 | switch (parent_ty.zigTypeTag(mod)) { |
| 4049 | .Union => { | 3912 | .Union => { |
| 4050 | if (parent_ty.containerLayout() == .Packed) { | 3913 | if (parent_ty.containerLayout(mod) == .Packed) { |
| 4051 | return parent_llvm_ptr; | 3914 | return parent_llvm_ptr; |
| 4052 | } | 3915 | } |
| 4053 | 3916 | ||
| 4054 | const layout = parent_ty.unionGetLayout(target); | 3917 | const layout = parent_ty.unionGetLayout(mod); |
| 4055 | if (layout.payload_size == 0) { | 3918 | if (layout.payload_size == 0) { |
| 4056 | // In this case a pointer to the union and a pointer to any | 3919 | // In this case a pointer to the union and a pointer to any |
| 4057 | // (void) payload is the same. | 3920 | // (void) payload is the same. |
| ... | @@ -4069,16 +3932,16 @@ pub const DeclGen = struct { | ... | @@ -4069,16 +3932,16 @@ pub const DeclGen = struct { |
| 4069 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | 3932 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4070 | }, | 3933 | }, |
| 4071 | .Struct => { | 3934 | .Struct => { |
| 4072 | if (parent_ty.containerLayout() == .Packed) { | 3935 | if (parent_ty.containerLayout(mod) == .Packed) { |
| 4073 | if (!byte_aligned) return parent_llvm_ptr; | 3936 | if (!byte_aligned) return parent_llvm_ptr; |
| 4074 | const llvm_usize = dg.context.intType(target.ptrBitWidth()); | 3937 | const llvm_usize = dg.context.intType(target.ptrBitWidth()); |
| 4075 | const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); | 3938 | const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); |
| 4076 | // count bits of fields before this one | 3939 | // count bits of fields before this one |
| 4077 | const prev_bits = b: { | 3940 | const prev_bits = b: { |
| 4078 | var b: usize = 0; | 3941 | var b: usize = 0; |
| 4079 | for (parent_ty.structFields().values()[0..field_index]) |field| { | 3942 | for (parent_ty.structFields(mod).values()[0..field_index]) |field| { |
| 4080 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 3943 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 4081 | b += @intCast(usize, field.ty.bitSize(target)); | 3944 | b += @intCast(usize, field.ty.bitSize(mod)); |
| 4082 | } | 3945 | } |
| 4083 | break :b b; | 3946 | break :b b; |
| 4084 | }; | 3947 | }; |
| ... | @@ -4088,23 +3951,21 @@ pub const DeclGen = struct { | ... | @@ -4088,23 +3951,21 @@ pub const DeclGen = struct { |
| 4088 | return field_addr.constIntToPtr(final_llvm_ty); | 3951 | return field_addr.constIntToPtr(final_llvm_ty); |
| 4089 | } | 3952 | } |
| 4090 | 3953 | ||
| 4091 | var ty_buf: Type.Payload.Pointer = undefined; | ||
| 4092 | |||
| 4093 | const parent_llvm_ty = try dg.lowerType(parent_ty); | 3954 | const parent_llvm_ty = try dg.lowerType(parent_ty); |
| 4094 | if (llvmFieldIndex(parent_ty, field_index, target, &ty_buf)) |llvm_field_index| { | 3955 | if (llvmField(parent_ty, field_index, mod)) |llvm_field| { |
| 4095 | const indices: [2]*llvm.Value = .{ | 3956 | const indices: [2]*llvm.Value = .{ |
| 4096 | llvm_u32.constInt(0, .False), | 3957 | llvm_u32.constInt(0, .False), |
| 4097 | llvm_u32.constInt(llvm_field_index, .False), | 3958 | llvm_u32.constInt(llvm_field.index, .False), |
| 4098 | }; | 3959 | }; |
| 4099 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | 3960 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4100 | } else { | 3961 | } else { |
| 4101 | const llvm_index = llvm_u32.constInt(@boolToInt(parent_ty.hasRuntimeBitsIgnoreComptime()), .False); | 3962 | const llvm_index = llvm_u32.constInt(@boolToInt(parent_ty.hasRuntimeBitsIgnoreComptime(mod)), .False); |
| 4102 | const indices: [1]*llvm.Value = .{llvm_index}; | 3963 | const indices: [1]*llvm.Value = .{llvm_index}; |
| 4103 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | 3964 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4104 | } | 3965 | } |
| 4105 | }, | 3966 | }, |
| 4106 | .Pointer => { | 3967 | .Pointer => { |
| 4107 | assert(parent_ty.isSlice()); | 3968 | assert(parent_ty.isSlice(mod)); |
| 4108 | const indices: [2]*llvm.Value = .{ | 3969 | const indices: [2]*llvm.Value = .{ |
| 4109 | llvm_u32.constInt(0, .False), | 3970 | llvm_u32.constInt(0, .False), |
| 4110 | llvm_u32.constInt(field_index, .False), | 3971 | llvm_u32.constInt(field_index, .False), |
| ... | @@ -4115,61 +3976,7 @@ pub const DeclGen = struct { | ... | @@ -4115,61 +3976,7 @@ pub const DeclGen = struct { |
| 4115 | else => unreachable, | 3976 | else => unreachable, |
| 4116 | } | 3977 | } |
| 4117 | }, | 3978 | }, |
| 4118 | .elem_ptr => { | 3979 | }; |
| 4119 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | ||
| 4120 | const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr, true); | ||
| 4121 | |||
| 4122 | const llvm_usize = try dg.lowerType(Type.usize); | ||
| 4123 | const indices: [1]*llvm.Value = .{ | ||
| 4124 | llvm_usize.constInt(elem_ptr.index, .False), | ||
| 4125 | }; | ||
| 4126 | const elem_llvm_ty = try dg.lowerType(elem_ptr.elem_ty); | ||
| 4127 | return elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4128 | }, | ||
| 4129 | .opt_payload_ptr => { | ||
| 4130 | const opt_payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; | ||
| 4131 | const parent_llvm_ptr = try dg.lowerParentPtr(opt_payload_ptr.container_ptr, true); | ||
| 4132 | var buf: Type.Payload.ElemType = undefined; | ||
| 4133 | |||
| 4134 | const payload_ty = opt_payload_ptr.container_ty.optionalChild(&buf); | ||
| 4135 | if (!payload_ty.hasRuntimeBitsIgnoreComptime() or | ||
| 4136 | payload_ty.optionalReprIsPayload()) | ||
| 4137 | { | ||
| 4138 | // In this case, we represent pointer to optional the same as pointer | ||
| 4139 | // to the payload. | ||
| 4140 | return parent_llvm_ptr; | ||
| 4141 | } | ||
| 4142 | |||
| 4143 | const llvm_u32 = dg.context.intType(32); | ||
| 4144 | const indices: [2]*llvm.Value = .{ | ||
| 4145 | llvm_u32.constInt(0, .False), | ||
| 4146 | llvm_u32.constInt(0, .False), | ||
| 4147 | }; | ||
| 4148 | const opt_llvm_ty = try dg.lowerType(opt_payload_ptr.container_ty); | ||
| 4149 | return opt_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4150 | }, | ||
| 4151 | .eu_payload_ptr => { | ||
| 4152 | const eu_payload_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; | ||
| 4153 | const parent_llvm_ptr = try dg.lowerParentPtr(eu_payload_ptr.container_ptr, true); | ||
| 4154 | |||
| 4155 | const payload_ty = eu_payload_ptr.container_ty.errorUnionPayload(); | ||
| 4156 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 4157 | // In this case, we represent pointer to error union the same as pointer | ||
| 4158 | // to the payload. | ||
| 4159 | return parent_llvm_ptr; | ||
| 4160 | } | ||
| 4161 | |||
| 4162 | const payload_offset: u8 = if (payload_ty.abiAlignment(target) > Type.anyerror.abiSize(target)) 2 else 1; | ||
| 4163 | const llvm_u32 = dg.context.intType(32); | ||
| 4164 | const indices: [2]*llvm.Value = .{ | ||
| 4165 | llvm_u32.constInt(0, .False), | ||
| 4166 | llvm_u32.constInt(payload_offset, .False), | ||
| 4167 | }; | ||
| 4168 | const eu_llvm_ty = try dg.lowerType(eu_payload_ptr.container_ty); | ||
| 4169 | return eu_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | ||
| 4170 | }, | ||
| 4171 | else => unreachable, | ||
| 4172 | } | ||
| 4173 | } | 3980 | } |
| 4174 | 3981 | ||
| 4175 | fn lowerDeclRefValue( | 3982 | fn lowerDeclRefValue( |
| ... | @@ -4177,57 +3984,39 @@ pub const DeclGen = struct { | ... | @@ -4177,57 +3984,39 @@ pub const DeclGen = struct { |
| 4177 | tv: TypedValue, | 3984 | tv: TypedValue, |
| 4178 | decl_index: Module.Decl.Index, | 3985 | decl_index: Module.Decl.Index, |
| 4179 | ) Error!*llvm.Value { | 3986 | ) Error!*llvm.Value { |
| 4180 | if (tv.ty.isSlice()) { | 3987 | const mod = self.module; |
| 4181 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 4182 | const ptr_ty = tv.ty.slicePtrFieldType(&buf); | ||
| 4183 | var slice_len: Value.Payload.U64 = .{ | ||
| 4184 | .base = .{ .tag = .int_u64 }, | ||
| 4185 | .data = tv.val.sliceLen(self.module), | ||
| 4186 | }; | ||
| 4187 | const fields: [2]*llvm.Value = .{ | ||
| 4188 | try self.lowerValue(.{ | ||
| 4189 | .ty = ptr_ty, | ||
| 4190 | .val = tv.val, | ||
| 4191 | }), | ||
| 4192 | try self.lowerValue(.{ | ||
| 4193 | .ty = Type.usize, | ||
| 4194 | .val = Value.initPayload(&slice_len.base), | ||
| 4195 | }), | ||
| 4196 | }; | ||
| 4197 | return self.context.constStruct(&fields, fields.len, .False); | ||
| 4198 | } | ||
| 4199 | 3988 | ||
| 4200 | // In the case of something like: | 3989 | // In the case of something like: |
| 4201 | // fn foo() void {} | 3990 | // fn foo() void {} |
| 4202 | // const bar = foo; | 3991 | // const bar = foo; |
| 4203 | // ... &bar; | 3992 | // ... &bar; |
| 4204 | // `bar` is just an alias and we actually want to lower a reference to `foo`. | 3993 | // `bar` is just an alias and we actually want to lower a reference to `foo`. |
| 4205 | const decl = self.module.declPtr(decl_index); | 3994 | const decl = mod.declPtr(decl_index); |
| 4206 | if (decl.val.castTag(.function)) |func| { | 3995 | if (decl.val.getFunction(mod)) |func| { |
| 4207 | if (func.data.owner_decl != decl_index) { | 3996 | if (func.owner_decl != decl_index) { |
| 4208 | return self.lowerDeclRefValue(tv, func.data.owner_decl); | 3997 | return self.lowerDeclRefValue(tv, func.owner_decl); |
| 4209 | } | 3998 | } |
| 4210 | } else if (decl.val.castTag(.extern_fn)) |func| { | 3999 | } else if (decl.val.getExternFunc(mod)) |func| { |
| 4211 | if (func.data.owner_decl != decl_index) { | 4000 | if (func.decl != decl_index) { |
| 4212 | return self.lowerDeclRefValue(tv, func.data.owner_decl); | 4001 | return self.lowerDeclRefValue(tv, func.decl); |
| 4213 | } | 4002 | } |
| 4214 | } | 4003 | } |
| 4215 | 4004 | ||
| 4216 | const is_fn_body = decl.ty.zigTypeTag() == .Fn; | 4005 | const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn; |
| 4217 | if ((!is_fn_body and !decl.ty.hasRuntimeBits()) or | 4006 | if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or |
| 4218 | (is_fn_body and decl.ty.fnInfo().is_generic)) | 4007 | (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic)) |
| 4219 | { | 4008 | { |
| 4220 | return self.lowerPtrToVoid(tv.ty); | 4009 | return self.lowerPtrToVoid(tv.ty); |
| 4221 | } | 4010 | } |
| 4222 | 4011 | ||
| 4223 | self.module.markDeclAlive(decl); | 4012 | try mod.markDeclAlive(decl); |
| 4224 | 4013 | ||
| 4225 | const llvm_decl_val = if (is_fn_body) | 4014 | const llvm_decl_val = if (is_fn_body) |
| 4226 | try self.resolveLlvmFunction(decl_index) | 4015 | try self.resolveLlvmFunction(decl_index) |
| 4227 | else | 4016 | else |
| 4228 | try self.resolveGlobalDecl(decl_index); | 4017 | try self.resolveGlobalDecl(decl_index); |
| 4229 | 4018 | ||
| 4230 | const target = self.module.getTarget(); | 4019 | const target = mod.getTarget(); |
| 4231 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); | 4020 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); |
| 4232 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | 4021 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); |
| 4233 | const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) blk: { | 4022 | const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) blk: { |
| ... | @@ -4236,7 +4025,7 @@ pub const DeclGen = struct { | ... | @@ -4236,7 +4025,7 @@ pub const DeclGen = struct { |
| 4236 | } else llvm_decl_val; | 4025 | } else llvm_decl_val; |
| 4237 | 4026 | ||
| 4238 | const llvm_type = try self.lowerType(tv.ty); | 4027 | const llvm_type = try self.lowerType(tv.ty); |
| 4239 | if (tv.ty.zigTypeTag() == .Int) { | 4028 | if (tv.ty.zigTypeTag(mod) == .Int) { |
| 4240 | return llvm_val.constPtrToInt(llvm_type); | 4029 | return llvm_val.constPtrToInt(llvm_type); |
| 4241 | } else { | 4030 | } else { |
| 4242 | return llvm_val.constBitCast(llvm_type); | 4031 | return llvm_val.constBitCast(llvm_type); |
| ... | @@ -4244,7 +4033,8 @@ pub const DeclGen = struct { | ... | @@ -4244,7 +4033,8 @@ pub const DeclGen = struct { |
| 4244 | } | 4033 | } |
| 4245 | 4034 | ||
| 4246 | fn lowerPtrToVoid(dg: *DeclGen, ptr_ty: Type) !*llvm.Value { | 4035 | fn lowerPtrToVoid(dg: *DeclGen, ptr_ty: Type) !*llvm.Value { |
| 4247 | const alignment = ptr_ty.ptrInfo().data.@"align"; | 4036 | const mod = dg.module; |
| 4037 | const alignment = ptr_ty.ptrInfo(mod).@"align"; | ||
| 4248 | // Even though we are pointing at something which has zero bits (e.g. `void`), | 4038 | // Even though we are pointing at something which has zero bits (e.g. `void`), |
| 4249 | // Pointers are defined to have bits. So we must return something here. | 4039 | // Pointers are defined to have bits. So we must return something here. |
| 4250 | // The value cannot be undefined, because we use the `nonnull` annotation | 4040 | // The value cannot be undefined, because we use the `nonnull` annotation |
| ... | @@ -4338,21 +4128,20 @@ pub const DeclGen = struct { | ... | @@ -4338,21 +4128,20 @@ pub const DeclGen = struct { |
| 4338 | /// RMW exchange of floating-point values is bitcasted to same-sized integer | 4128 | /// RMW exchange of floating-point values is bitcasted to same-sized integer |
| 4339 | /// types to work around a LLVM deficiency when targeting ARM/AArch64. | 4129 | /// types to work around a LLVM deficiency when targeting ARM/AArch64. |
| 4340 | fn getAtomicAbiType(dg: *DeclGen, ty: Type, is_rmw_xchg: bool) ?*llvm.Type { | 4130 | fn getAtomicAbiType(dg: *DeclGen, ty: Type, is_rmw_xchg: bool) ?*llvm.Type { |
| 4341 | const target = dg.module.getTarget(); | 4131 | const mod = dg.module; |
| 4342 | var buffer: Type.Payload.Bits = undefined; | 4132 | const int_ty = switch (ty.zigTypeTag(mod)) { |
| 4343 | const int_ty = switch (ty.zigTypeTag()) { | ||
| 4344 | .Int => ty, | 4133 | .Int => ty, |
| 4345 | .Enum => ty.intTagType(&buffer), | 4134 | .Enum => ty.intTagType(mod), |
| 4346 | .Float => { | 4135 | .Float => { |
| 4347 | if (!is_rmw_xchg) return null; | 4136 | if (!is_rmw_xchg) return null; |
| 4348 | return dg.context.intType(@intCast(c_uint, ty.abiSize(target) * 8)); | 4137 | return dg.context.intType(@intCast(c_uint, ty.abiSize(mod) * 8)); |
| 4349 | }, | 4138 | }, |
| 4350 | .Bool => return dg.context.intType(8), | 4139 | .Bool => return dg.context.intType(8), |
| 4351 | else => return null, | 4140 | else => return null, |
| 4352 | }; | 4141 | }; |
| 4353 | const bit_count = int_ty.intInfo(target).bits; | 4142 | const bit_count = int_ty.intInfo(mod).bits; |
| 4354 | if (!std.math.isPowerOfTwo(bit_count) or (bit_count % 8) != 0) { | 4143 | if (!std.math.isPowerOfTwo(bit_count) or (bit_count % 8) != 0) { |
| 4355 | return dg.context.intType(@intCast(c_uint, int_ty.abiSize(target) * 8)); | 4144 | return dg.context.intType(@intCast(c_uint, int_ty.abiSize(mod) * 8)); |
| 4356 | } else { | 4145 | } else { |
| 4357 | return null; | 4146 | return null; |
| 4358 | } | 4147 | } |
| ... | @@ -4363,18 +4152,18 @@ pub const DeclGen = struct { | ... | @@ -4363,18 +4152,18 @@ pub const DeclGen = struct { |
| 4363 | llvm_fn: *llvm.Value, | 4152 | llvm_fn: *llvm.Value, |
| 4364 | param_ty: Type, | 4153 | param_ty: Type, |
| 4365 | param_index: u32, | 4154 | param_index: u32, |
| 4366 | fn_info: Type.Payload.Function.Data, | 4155 | fn_info: InternPool.Key.FuncType, |
| 4367 | llvm_arg_i: u32, | 4156 | llvm_arg_i: u32, |
| 4368 | ) void { | 4157 | ) void { |
| 4369 | const target = dg.module.getTarget(); | 4158 | const mod = dg.module; |
| 4370 | if (param_ty.isPtrAtRuntime()) { | 4159 | if (param_ty.isPtrAtRuntime(mod)) { |
| 4371 | const ptr_info = param_ty.ptrInfo().data; | 4160 | const ptr_info = param_ty.ptrInfo(mod); |
| 4372 | if (math.cast(u5, param_index)) |i| { | 4161 | if (math.cast(u5, param_index)) |i| { |
| 4373 | if (@truncate(u1, fn_info.noalias_bits >> i) != 0) { | 4162 | if (@truncate(u1, fn_info.noalias_bits >> i) != 0) { |
| 4374 | dg.addArgAttr(llvm_fn, llvm_arg_i, "noalias"); | 4163 | dg.addArgAttr(llvm_fn, llvm_arg_i, "noalias"); |
| 4375 | } | 4164 | } |
| 4376 | } | 4165 | } |
| 4377 | if (!param_ty.isPtrLikeOptional() and !ptr_info.@"allowzero") { | 4166 | if (!param_ty.isPtrLikeOptional(mod) and !ptr_info.@"allowzero") { |
| 4378 | dg.addArgAttr(llvm_fn, llvm_arg_i, "nonnull"); | 4167 | dg.addArgAttr(llvm_fn, llvm_arg_i, "nonnull"); |
| 4379 | } | 4168 | } |
| 4380 | if (!ptr_info.mutable) { | 4169 | if (!ptr_info.mutable) { |
| ... | @@ -4383,13 +4172,10 @@ pub const DeclGen = struct { | ... | @@ -4383,13 +4172,10 @@ pub const DeclGen = struct { |
| 4383 | if (ptr_info.@"align" != 0) { | 4172 | if (ptr_info.@"align" != 0) { |
| 4384 | dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", ptr_info.@"align"); | 4173 | dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", ptr_info.@"align"); |
| 4385 | } else { | 4174 | } else { |
| 4386 | const elem_align = @max( | 4175 | const elem_align = @max(ptr_info.pointee_type.abiAlignment(mod), 1); |
| 4387 | ptr_info.pointee_type.abiAlignment(target), | ||
| 4388 | 1, | ||
| 4389 | ); | ||
| 4390 | dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align); | 4176 | dg.addArgAttrInt(llvm_fn, llvm_arg_i, "align", elem_align); |
| 4391 | } | 4177 | } |
| 4392 | } else if (ccAbiPromoteInt(fn_info.cc, target, param_ty)) |s| switch (s) { | 4178 | } else if (ccAbiPromoteInt(fn_info.cc, mod, param_ty)) |s| switch (s) { |
| 4393 | .signed => dg.addArgAttr(llvm_fn, llvm_arg_i, "signext"), | 4179 | .signed => dg.addArgAttr(llvm_fn, llvm_arg_i, "signext"), |
| 4394 | .unsigned => dg.addArgAttr(llvm_fn, llvm_arg_i, "zeroext"), | 4180 | .unsigned => dg.addArgAttr(llvm_fn, llvm_arg_i, "zeroext"), |
| 4395 | }; | 4181 | }; |
| ... | @@ -4490,21 +4276,23 @@ pub const FuncGen = struct { | ... | @@ -4490,21 +4276,23 @@ pub const FuncGen = struct { |
| 4490 | const gop = try self.func_inst_table.getOrPut(self.dg.gpa, inst); | 4276 | const gop = try self.func_inst_table.getOrPut(self.dg.gpa, inst); |
| 4491 | if (gop.found_existing) return gop.value_ptr.*; | 4277 | if (gop.found_existing) return gop.value_ptr.*; |
| 4492 | 4278 | ||
| 4279 | const mod = self.dg.module; | ||
| 4493 | const llvm_val = try self.resolveValue(.{ | 4280 | const llvm_val = try self.resolveValue(.{ |
| 4494 | .ty = self.air.typeOf(inst), | 4281 | .ty = self.typeOf(inst), |
| 4495 | .val = self.air.value(inst).?, | 4282 | .val = (try self.air.value(inst, mod)).?, |
| 4496 | }); | 4283 | }); |
| 4497 | gop.value_ptr.* = llvm_val; | 4284 | gop.value_ptr.* = llvm_val; |
| 4498 | return llvm_val; | 4285 | return llvm_val; |
| 4499 | } | 4286 | } |
| 4500 | 4287 | ||
| 4501 | fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value { | 4288 | fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value { |
| 4289 | const mod = self.dg.module; | ||
| 4502 | const llvm_val = try self.dg.lowerValue(tv); | 4290 | const llvm_val = try self.dg.lowerValue(tv); |
| 4503 | if (!isByRef(tv.ty)) return llvm_val; | 4291 | if (!isByRef(tv.ty, mod)) return llvm_val; |
| 4504 | 4292 | ||
| 4505 | // We have an LLVM value but we need to create a global constant and | 4293 | // We have an LLVM value but we need to create a global constant and |
| 4506 | // set the value as its initializer, and then return a pointer to the global. | 4294 | // set the value as its initializer, and then return a pointer to the global. |
| 4507 | const target = self.dg.module.getTarget(); | 4295 | const target = mod.getTarget(); |
| 4508 | const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target); | 4296 | const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target); |
| 4509 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target); | 4297 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target); |
| 4510 | const global = self.dg.object.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", llvm_actual_addrspace); | 4298 | const global = self.dg.object.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", llvm_actual_addrspace); |
| ... | @@ -4512,7 +4300,7 @@ pub const FuncGen = struct { | ... | @@ -4512,7 +4300,7 @@ pub const FuncGen = struct { |
| 4512 | global.setLinkage(.Private); | 4300 | global.setLinkage(.Private); |
| 4513 | global.setGlobalConstant(.True); | 4301 | global.setGlobalConstant(.True); |
| 4514 | global.setUnnamedAddr(.True); | 4302 | global.setUnnamedAddr(.True); |
| 4515 | global.setAlignment(tv.ty.abiAlignment(target)); | 4303 | global.setAlignment(tv.ty.abiAlignment(mod)); |
| 4516 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) | 4304 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) |
| 4517 | global.constAddrSpaceCast(self.context.pointerType(llvm_wanted_addrspace)) | 4305 | global.constAddrSpaceCast(self.context.pointerType(llvm_wanted_addrspace)) |
| 4518 | else | 4306 | else |
| ... | @@ -4521,11 +4309,12 @@ pub const FuncGen = struct { | ... | @@ -4521,11 +4309,12 @@ pub const FuncGen = struct { |
| 4521 | } | 4309 | } |
| 4522 | 4310 | ||
| 4523 | fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void { | 4311 | fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void { |
| 4312 | const mod = self.dg.module; | ||
| 4313 | const ip = &mod.intern_pool; | ||
| 4524 | const air_tags = self.air.instructions.items(.tag); | 4314 | const air_tags = self.air.instructions.items(.tag); |
| 4525 | for (body, 0..) |inst, i| { | 4315 | for (body, 0..) |inst, i| { |
| 4526 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) { | 4316 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) |
| 4527 | continue; | 4317 | continue; |
| 4528 | } | ||
| 4529 | 4318 | ||
| 4530 | const opt_value: ?*llvm.Value = switch (air_tags[inst]) { | 4319 | const opt_value: ?*llvm.Value = switch (air_tags[inst]) { |
| 4531 | // zig fmt: off | 4320 | // zig fmt: off |
| ... | @@ -4742,8 +4531,8 @@ pub const FuncGen = struct { | ... | @@ -4742,8 +4531,8 @@ pub const FuncGen = struct { |
| 4742 | 4531 | ||
| 4743 | .vector_store_elem => try self.airVectorStoreElem(inst), | 4532 | .vector_store_elem => try self.airVectorStoreElem(inst), |
| 4744 | 4533 | ||
| 4745 | .constant => unreachable, | 4534 | .inferred_alloc, .inferred_alloc_comptime, .interned => unreachable, |
| 4746 | .const_ty => unreachable, | 4535 | |
| 4747 | .unreach => self.airUnreach(inst), | 4536 | .unreach => self.airUnreach(inst), |
| 4748 | .dbg_stmt => self.airDbgStmt(inst), | 4537 | .dbg_stmt => self.airDbgStmt(inst), |
| 4749 | .dbg_inline_begin => try self.airDbgInlineBegin(inst), | 4538 | .dbg_inline_begin => try self.airDbgInlineBegin(inst), |
| ... | @@ -4774,29 +4563,30 @@ pub const FuncGen = struct { | ... | @@ -4774,29 +4563,30 @@ pub const FuncGen = struct { |
| 4774 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 4563 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 4775 | const extra = self.air.extraData(Air.Call, pl_op.payload); | 4564 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 4776 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); | 4565 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); |
| 4777 | const callee_ty = self.air.typeOf(pl_op.operand); | 4566 | const mod = self.dg.module; |
| 4778 | const zig_fn_ty = switch (callee_ty.zigTypeTag()) { | 4567 | const callee_ty = self.typeOf(pl_op.operand); |
| 4568 | const zig_fn_ty = switch (callee_ty.zigTypeTag(mod)) { | ||
| 4779 | .Fn => callee_ty, | 4569 | .Fn => callee_ty, |
| 4780 | .Pointer => callee_ty.childType(), | 4570 | .Pointer => callee_ty.childType(mod), |
| 4781 | else => unreachable, | 4571 | else => unreachable, |
| 4782 | }; | 4572 | }; |
| 4783 | const fn_info = zig_fn_ty.fnInfo(); | 4573 | const fn_info = mod.typeToFunc(zig_fn_ty).?; |
| 4784 | const return_type = fn_info.return_type; | 4574 | const return_type = fn_info.return_type.toType(); |
| 4785 | const llvm_fn = try self.resolveInst(pl_op.operand); | 4575 | const llvm_fn = try self.resolveInst(pl_op.operand); |
| 4786 | const target = self.dg.module.getTarget(); | 4576 | const target = mod.getTarget(); |
| 4787 | const sret = firstParamSRet(fn_info, target); | 4577 | const sret = firstParamSRet(fn_info, mod); |
| 4788 | 4578 | ||
| 4789 | var llvm_args = std.ArrayList(*llvm.Value).init(self.gpa); | 4579 | var llvm_args = std.ArrayList(*llvm.Value).init(self.gpa); |
| 4790 | defer llvm_args.deinit(); | 4580 | defer llvm_args.deinit(); |
| 4791 | 4581 | ||
| 4792 | const ret_ptr = if (!sret) null else blk: { | 4582 | const ret_ptr = if (!sret) null else blk: { |
| 4793 | const llvm_ret_ty = try self.dg.lowerType(return_type); | 4583 | const llvm_ret_ty = try self.dg.lowerType(return_type); |
| 4794 | const ret_ptr = self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(target)); | 4584 | const ret_ptr = self.buildAlloca(llvm_ret_ty, return_type.abiAlignment(mod)); |
| 4795 | try llvm_args.append(ret_ptr); | 4585 | try llvm_args.append(ret_ptr); |
| 4796 | break :blk ret_ptr; | 4586 | break :blk ret_ptr; |
| 4797 | }; | 4587 | }; |
| 4798 | 4588 | ||
| 4799 | const err_return_tracing = fn_info.return_type.isError() and | 4589 | const err_return_tracing = return_type.isError(mod) and |
| 4800 | self.dg.module.comp.bin_file.options.error_return_tracing; | 4590 | self.dg.module.comp.bin_file.options.error_return_tracing; |
| 4801 | if (err_return_tracing) { | 4591 | if (err_return_tracing) { |
| 4802 | try llvm_args.append(self.err_ret_trace.?); | 4592 | try llvm_args.append(self.err_ret_trace.?); |
| ... | @@ -4807,11 +4597,11 @@ pub const FuncGen = struct { | ... | @@ -4807,11 +4597,11 @@ pub const FuncGen = struct { |
| 4807 | .no_bits => continue, | 4597 | .no_bits => continue, |
| 4808 | .byval => { | 4598 | .byval => { |
| 4809 | const arg = args[it.zig_index - 1]; | 4599 | const arg = args[it.zig_index - 1]; |
| 4810 | const param_ty = self.air.typeOf(arg); | 4600 | const param_ty = self.typeOf(arg); |
| 4811 | const llvm_arg = try self.resolveInst(arg); | 4601 | const llvm_arg = try self.resolveInst(arg); |
| 4812 | const llvm_param_ty = try self.dg.lowerType(param_ty); | 4602 | const llvm_param_ty = try self.dg.lowerType(param_ty); |
| 4813 | if (isByRef(param_ty)) { | 4603 | if (isByRef(param_ty, mod)) { |
| 4814 | const alignment = param_ty.abiAlignment(target); | 4604 | const alignment = param_ty.abiAlignment(mod); |
| 4815 | const load_inst = self.builder.buildLoad(llvm_param_ty, llvm_arg, ""); | 4605 | const load_inst = self.builder.buildLoad(llvm_param_ty, llvm_arg, ""); |
| 4816 | load_inst.setAlignment(alignment); | 4606 | load_inst.setAlignment(alignment); |
| 4817 | try llvm_args.append(load_inst); | 4607 | try llvm_args.append(load_inst); |
| ... | @@ -4821,12 +4611,12 @@ pub const FuncGen = struct { | ... | @@ -4821,12 +4611,12 @@ pub const FuncGen = struct { |
| 4821 | }, | 4611 | }, |
| 4822 | .byref => { | 4612 | .byref => { |
| 4823 | const arg = args[it.zig_index - 1]; | 4613 | const arg = args[it.zig_index - 1]; |
| 4824 | const param_ty = self.air.typeOf(arg); | 4614 | const param_ty = self.typeOf(arg); |
| 4825 | const llvm_arg = try self.resolveInst(arg); | 4615 | const llvm_arg = try self.resolveInst(arg); |
| 4826 | if (isByRef(param_ty)) { | 4616 | if (isByRef(param_ty, mod)) { |
| 4827 | try llvm_args.append(llvm_arg); | 4617 | try llvm_args.append(llvm_arg); |
| 4828 | } else { | 4618 | } else { |
| 4829 | const alignment = param_ty.abiAlignment(target); | 4619 | const alignment = param_ty.abiAlignment(mod); |
| 4830 | const param_llvm_ty = llvm_arg.typeOf(); | 4620 | const param_llvm_ty = llvm_arg.typeOf(); |
| 4831 | const arg_ptr = self.buildAlloca(param_llvm_ty, alignment); | 4621 | const arg_ptr = self.buildAlloca(param_llvm_ty, alignment); |
| 4832 | const store_inst = self.builder.buildStore(llvm_arg, arg_ptr); | 4622 | const store_inst = self.builder.buildStore(llvm_arg, arg_ptr); |
| ... | @@ -4836,13 +4626,13 @@ pub const FuncGen = struct { | ... | @@ -4836,13 +4626,13 @@ pub const FuncGen = struct { |
| 4836 | }, | 4626 | }, |
| 4837 | .byref_mut => { | 4627 | .byref_mut => { |
| 4838 | const arg = args[it.zig_index - 1]; | 4628 | const arg = args[it.zig_index - 1]; |
| 4839 | const param_ty = self.air.typeOf(arg); | 4629 | const param_ty = self.typeOf(arg); |
| 4840 | const llvm_arg = try self.resolveInst(arg); | 4630 | const llvm_arg = try self.resolveInst(arg); |
| 4841 | 4631 | ||
| 4842 | const alignment = param_ty.abiAlignment(target); | 4632 | const alignment = param_ty.abiAlignment(mod); |
| 4843 | const param_llvm_ty = try self.dg.lowerType(param_ty); | 4633 | const param_llvm_ty = try self.dg.lowerType(param_ty); |
| 4844 | const arg_ptr = self.buildAlloca(param_llvm_ty, alignment); | 4634 | const arg_ptr = self.buildAlloca(param_llvm_ty, alignment); |
| 4845 | if (isByRef(param_ty)) { | 4635 | if (isByRef(param_ty, mod)) { |
| 4846 | const load_inst = self.builder.buildLoad(param_llvm_ty, llvm_arg, ""); | 4636 | const load_inst = self.builder.buildLoad(param_llvm_ty, llvm_arg, ""); |
| 4847 | load_inst.setAlignment(alignment); | 4637 | load_inst.setAlignment(alignment); |
| 4848 | 4638 | ||
| ... | @@ -4857,13 +4647,13 @@ pub const FuncGen = struct { | ... | @@ -4857,13 +4647,13 @@ pub const FuncGen = struct { |
| 4857 | }, | 4647 | }, |
| 4858 | .abi_sized_int => { | 4648 | .abi_sized_int => { |
| 4859 | const arg = args[it.zig_index - 1]; | 4649 | const arg = args[it.zig_index - 1]; |
| 4860 | const param_ty = self.air.typeOf(arg); | 4650 | const param_ty = self.typeOf(arg); |
| 4861 | const llvm_arg = try self.resolveInst(arg); | 4651 | const llvm_arg = try self.resolveInst(arg); |
| 4862 | const abi_size = @intCast(c_uint, param_ty.abiSize(target)); | 4652 | const abi_size = @intCast(c_uint, param_ty.abiSize(mod)); |
| 4863 | const int_llvm_ty = self.context.intType(abi_size * 8); | 4653 | const int_llvm_ty = self.context.intType(abi_size * 8); |
| 4864 | 4654 | ||
| 4865 | if (isByRef(param_ty)) { | 4655 | if (isByRef(param_ty, mod)) { |
| 4866 | const alignment = param_ty.abiAlignment(target); | 4656 | const alignment = param_ty.abiAlignment(mod); |
| 4867 | const load_inst = self.builder.buildLoad(int_llvm_ty, llvm_arg, ""); | 4657 | const load_inst = self.builder.buildLoad(int_llvm_ty, llvm_arg, ""); |
| 4868 | load_inst.setAlignment(alignment); | 4658 | load_inst.setAlignment(alignment); |
| 4869 | try llvm_args.append(load_inst); | 4659 | try llvm_args.append(load_inst); |
| ... | @@ -4871,7 +4661,7 @@ pub const FuncGen = struct { | ... | @@ -4871,7 +4661,7 @@ pub const FuncGen = struct { |
| 4871 | // LLVM does not allow bitcasting structs so we must allocate | 4661 | // LLVM does not allow bitcasting structs so we must allocate |
| 4872 | // a local, store as one type, and then load as another type. | 4662 | // a local, store as one type, and then load as another type. |
| 4873 | const alignment = @max( | 4663 | const alignment = @max( |
| 4874 | param_ty.abiAlignment(target), | 4664 | param_ty.abiAlignment(mod), |
| 4875 | self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty), | 4665 | self.dg.object.target_data.abiAlignmentOfType(int_llvm_ty), |
| 4876 | ); | 4666 | ); |
| 4877 | const int_ptr = self.buildAlloca(int_llvm_ty, alignment); | 4667 | const int_ptr = self.buildAlloca(int_llvm_ty, alignment); |
| ... | @@ -4893,14 +4683,14 @@ pub const FuncGen = struct { | ... | @@ -4893,14 +4683,14 @@ pub const FuncGen = struct { |
| 4893 | }, | 4683 | }, |
| 4894 | .multiple_llvm_types => { | 4684 | .multiple_llvm_types => { |
| 4895 | const arg = args[it.zig_index - 1]; | 4685 | const arg = args[it.zig_index - 1]; |
| 4896 | const param_ty = self.air.typeOf(arg); | 4686 | const param_ty = self.typeOf(arg); |
| 4897 | const llvm_types = it.llvm_types_buffer[0..it.llvm_types_len]; | 4687 | const llvm_types = it.llvm_types_buffer[0..it.llvm_types_len]; |
| 4898 | const llvm_arg = try self.resolveInst(arg); | 4688 | const llvm_arg = try self.resolveInst(arg); |
| 4899 | const is_by_ref = isByRef(param_ty); | 4689 | const is_by_ref = isByRef(param_ty, mod); |
| 4900 | const arg_ptr = if (is_by_ref) llvm_arg else p: { | 4690 | const arg_ptr = if (is_by_ref) llvm_arg else p: { |
| 4901 | const p = self.buildAlloca(llvm_arg.typeOf(), null); | 4691 | const p = self.buildAlloca(llvm_arg.typeOf(), null); |
| 4902 | const store_inst = self.builder.buildStore(llvm_arg, p); | 4692 | const store_inst = self.builder.buildStore(llvm_arg, p); |
| 4903 | store_inst.setAlignment(param_ty.abiAlignment(target)); | 4693 | store_inst.setAlignment(param_ty.abiAlignment(mod)); |
| 4904 | break :p p; | 4694 | break :p p; |
| 4905 | }; | 4695 | }; |
| 4906 | 4696 | ||
| ... | @@ -4922,19 +4712,19 @@ pub const FuncGen = struct { | ... | @@ -4922,19 +4712,19 @@ pub const FuncGen = struct { |
| 4922 | }, | 4712 | }, |
| 4923 | .float_array => |count| { | 4713 | .float_array => |count| { |
| 4924 | const arg = args[it.zig_index - 1]; | 4714 | const arg = args[it.zig_index - 1]; |
| 4925 | const arg_ty = self.air.typeOf(arg); | 4715 | const arg_ty = self.typeOf(arg); |
| 4926 | var llvm_arg = try self.resolveInst(arg); | 4716 | var llvm_arg = try self.resolveInst(arg); |
| 4927 | if (!isByRef(arg_ty)) { | 4717 | if (!isByRef(arg_ty, mod)) { |
| 4928 | const p = self.buildAlloca(llvm_arg.typeOf(), null); | 4718 | const p = self.buildAlloca(llvm_arg.typeOf(), null); |
| 4929 | const store_inst = self.builder.buildStore(llvm_arg, p); | 4719 | const store_inst = self.builder.buildStore(llvm_arg, p); |
| 4930 | store_inst.setAlignment(arg_ty.abiAlignment(target)); | 4720 | store_inst.setAlignment(arg_ty.abiAlignment(mod)); |
| 4931 | llvm_arg = store_inst; | 4721 | llvm_arg = store_inst; |
| 4932 | } | 4722 | } |
| 4933 | 4723 | ||
| 4934 | const float_ty = try self.dg.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty).?); | 4724 | const float_ty = try self.dg.lowerType(aarch64_c_abi.getFloatArrayType(arg_ty, mod).?); |
| 4935 | const array_llvm_ty = float_ty.arrayType(count); | 4725 | const array_llvm_ty = float_ty.arrayType(count); |
| 4936 | 4726 | ||
| 4937 | const alignment = arg_ty.abiAlignment(target); | 4727 | const alignment = arg_ty.abiAlignment(mod); |
| 4938 | const load_inst = self.builder.buildLoad(array_llvm_ty, llvm_arg, ""); | 4728 | const load_inst = self.builder.buildLoad(array_llvm_ty, llvm_arg, ""); |
| 4939 | load_inst.setAlignment(alignment); | 4729 | load_inst.setAlignment(alignment); |
| 4940 | try llvm_args.append(load_inst); | 4730 | try llvm_args.append(load_inst); |
| ... | @@ -4942,17 +4732,17 @@ pub const FuncGen = struct { | ... | @@ -4942,17 +4732,17 @@ pub const FuncGen = struct { |
| 4942 | .i32_array, .i64_array => |arr_len| { | 4732 | .i32_array, .i64_array => |arr_len| { |
| 4943 | const elem_size: u8 = if (lowering == .i32_array) 32 else 64; | 4733 | const elem_size: u8 = if (lowering == .i32_array) 32 else 64; |
| 4944 | const arg = args[it.zig_index - 1]; | 4734 | const arg = args[it.zig_index - 1]; |
| 4945 | const arg_ty = self.air.typeOf(arg); | 4735 | const arg_ty = self.typeOf(arg); |
| 4946 | var llvm_arg = try self.resolveInst(arg); | 4736 | var llvm_arg = try self.resolveInst(arg); |
| 4947 | if (!isByRef(arg_ty)) { | 4737 | if (!isByRef(arg_ty, mod)) { |
| 4948 | const p = self.buildAlloca(llvm_arg.typeOf(), null); | 4738 | const p = self.buildAlloca(llvm_arg.typeOf(), null); |
| 4949 | const store_inst = self.builder.buildStore(llvm_arg, p); | 4739 | const store_inst = self.builder.buildStore(llvm_arg, p); |
| 4950 | store_inst.setAlignment(arg_ty.abiAlignment(target)); | 4740 | store_inst.setAlignment(arg_ty.abiAlignment(mod)); |
| 4951 | llvm_arg = store_inst; | 4741 | llvm_arg = store_inst; |
| 4952 | } | 4742 | } |
| 4953 | 4743 | ||
| 4954 | const array_llvm_ty = self.context.intType(elem_size).arrayType(arr_len); | 4744 | const array_llvm_ty = self.context.intType(elem_size).arrayType(arr_len); |
| 4955 | const alignment = arg_ty.abiAlignment(target); | 4745 | const alignment = arg_ty.abiAlignment(mod); |
| 4956 | const load_inst = self.builder.buildLoad(array_llvm_ty, llvm_arg, ""); | 4746 | const load_inst = self.builder.buildLoad(array_llvm_ty, llvm_arg, ""); |
| 4957 | load_inst.setAlignment(alignment); | 4747 | load_inst.setAlignment(alignment); |
| 4958 | try llvm_args.append(load_inst); | 4748 | try llvm_args.append(load_inst); |
| ... | @@ -4969,7 +4759,7 @@ pub const FuncGen = struct { | ... | @@ -4969,7 +4759,7 @@ pub const FuncGen = struct { |
| 4969 | "", | 4759 | "", |
| 4970 | ); | 4760 | ); |
| 4971 | 4761 | ||
| 4972 | if (callee_ty.zigTypeTag() == .Pointer) { | 4762 | if (callee_ty.zigTypeTag(mod) == .Pointer) { |
| 4973 | // Add argument attributes for function pointer calls. | 4763 | // Add argument attributes for function pointer calls. |
| 4974 | it = iterateParamTypes(self.dg, fn_info); | 4764 | it = iterateParamTypes(self.dg, fn_info); |
| 4975 | it.llvm_index += @boolToInt(sret); | 4765 | it.llvm_index += @boolToInt(sret); |
| ... | @@ -4977,16 +4767,16 @@ pub const FuncGen = struct { | ... | @@ -4977,16 +4767,16 @@ pub const FuncGen = struct { |
| 4977 | while (it.next()) |lowering| switch (lowering) { | 4767 | while (it.next()) |lowering| switch (lowering) { |
| 4978 | .byval => { | 4768 | .byval => { |
| 4979 | const param_index = it.zig_index - 1; | 4769 | const param_index = it.zig_index - 1; |
| 4980 | const param_ty = fn_info.param_types[param_index]; | 4770 | const param_ty = fn_info.param_types[param_index].toType(); |
| 4981 | if (!isByRef(param_ty)) { | 4771 | if (!isByRef(param_ty, mod)) { |
| 4982 | self.dg.addByValParamAttrs(call, param_ty, param_index, fn_info, it.llvm_index - 1); | 4772 | self.dg.addByValParamAttrs(call, param_ty, param_index, fn_info, it.llvm_index - 1); |
| 4983 | } | 4773 | } |
| 4984 | }, | 4774 | }, |
| 4985 | .byref => { | 4775 | .byref => { |
| 4986 | const param_index = it.zig_index - 1; | 4776 | const param_index = it.zig_index - 1; |
| 4987 | const param_ty = fn_info.param_types[param_index]; | 4777 | const param_ty = fn_info.param_types[param_index].toType(); |
| 4988 | const param_llvm_ty = try self.dg.lowerType(param_ty); | 4778 | const param_llvm_ty = try self.dg.lowerType(param_ty); |
| 4989 | const alignment = param_ty.abiAlignment(target); | 4779 | const alignment = param_ty.abiAlignment(mod); |
| 4990 | self.dg.addByRefParamAttrs(call, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); | 4780 | self.dg.addByRefParamAttrs(call, it.llvm_index - 1, alignment, it.byval_attr, param_llvm_ty); |
| 4991 | }, | 4781 | }, |
| 4992 | .byref_mut => { | 4782 | .byref_mut => { |
| ... | @@ -5004,8 +4794,8 @@ pub const FuncGen = struct { | ... | @@ -5004,8 +4794,8 @@ pub const FuncGen = struct { |
| 5004 | 4794 | ||
| 5005 | .slice => { | 4795 | .slice => { |
| 5006 | assert(!it.byval_attr); | 4796 | assert(!it.byval_attr); |
| 5007 | const param_ty = fn_info.param_types[it.zig_index - 1]; | 4797 | const param_ty = fn_info.param_types[it.zig_index - 1].toType(); |
| 5008 | const ptr_info = param_ty.ptrInfo().data; | 4798 | const ptr_info = param_ty.ptrInfo(mod); |
| 5009 | const llvm_arg_i = it.llvm_index - 2; | 4799 | const llvm_arg_i = it.llvm_index - 2; |
| 5010 | 4800 | ||
| 5011 | if (math.cast(u5, it.zig_index - 1)) |i| { | 4801 | if (math.cast(u5, it.zig_index - 1)) |i| { |
| ... | @@ -5013,7 +4803,7 @@ pub const FuncGen = struct { | ... | @@ -5013,7 +4803,7 @@ pub const FuncGen = struct { |
| 5013 | self.dg.addArgAttr(call, llvm_arg_i, "noalias"); | 4803 | self.dg.addArgAttr(call, llvm_arg_i, "noalias"); |
| 5014 | } | 4804 | } |
| 5015 | } | 4805 | } |
| 5016 | if (param_ty.zigTypeTag() != .Optional) { | 4806 | if (param_ty.zigTypeTag(mod) != .Optional) { |
| 5017 | self.dg.addArgAttr(call, llvm_arg_i, "nonnull"); | 4807 | self.dg.addArgAttr(call, llvm_arg_i, "nonnull"); |
| 5018 | } | 4808 | } |
| 5019 | if (!ptr_info.mutable) { | 4809 | if (!ptr_info.mutable) { |
| ... | @@ -5022,18 +4812,18 @@ pub const FuncGen = struct { | ... | @@ -5022,18 +4812,18 @@ pub const FuncGen = struct { |
| 5022 | if (ptr_info.@"align" != 0) { | 4812 | if (ptr_info.@"align" != 0) { |
| 5023 | self.dg.addArgAttrInt(call, llvm_arg_i, "align", ptr_info.@"align"); | 4813 | self.dg.addArgAttrInt(call, llvm_arg_i, "align", ptr_info.@"align"); |
| 5024 | } else { | 4814 | } else { |
| 5025 | const elem_align = @max(ptr_info.pointee_type.abiAlignment(target), 1); | 4815 | const elem_align = @max(ptr_info.pointee_type.abiAlignment(mod), 1); |
| 5026 | self.dg.addArgAttrInt(call, llvm_arg_i, "align", elem_align); | 4816 | self.dg.addArgAttrInt(call, llvm_arg_i, "align", elem_align); |
| 5027 | } | 4817 | } |
| 5028 | }, | 4818 | }, |
| 5029 | }; | 4819 | }; |
| 5030 | } | 4820 | } |
| 5031 | 4821 | ||
| 5032 | if (return_type.isNoReturn() and attr != .AlwaysTail) { | 4822 | if (fn_info.return_type == .noreturn_type and attr != .AlwaysTail) { |
| 5033 | return null; | 4823 | return null; |
| 5034 | } | 4824 | } |
| 5035 | 4825 | ||
| 5036 | if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime()) { | 4826 | if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime(mod)) { |
| 5037 | return null; | 4827 | return null; |
| 5038 | } | 4828 | } |
| 5039 | 4829 | ||
| ... | @@ -5041,12 +4831,12 @@ pub const FuncGen = struct { | ... | @@ -5041,12 +4831,12 @@ pub const FuncGen = struct { |
| 5041 | 4831 | ||
| 5042 | if (ret_ptr) |rp| { | 4832 | if (ret_ptr) |rp| { |
| 5043 | call.setCallSret(llvm_ret_ty); | 4833 | call.setCallSret(llvm_ret_ty); |
| 5044 | if (isByRef(return_type)) { | 4834 | if (isByRef(return_type, mod)) { |
| 5045 | return rp; | 4835 | return rp; |
| 5046 | } else { | 4836 | } else { |
| 5047 | // our by-ref status disagrees with sret so we must load. | 4837 | // our by-ref status disagrees with sret so we must load. |
| 5048 | const loaded = self.builder.buildLoad(llvm_ret_ty, rp, ""); | 4838 | const loaded = self.builder.buildLoad(llvm_ret_ty, rp, ""); |
| 5049 | loaded.setAlignment(return_type.abiAlignment(target)); | 4839 | loaded.setAlignment(return_type.abiAlignment(mod)); |
| 5050 | return loaded; | 4840 | return loaded; |
| 5051 | } | 4841 | } |
| 5052 | } | 4842 | } |
| ... | @@ -5061,7 +4851,7 @@ pub const FuncGen = struct { | ... | @@ -5061,7 +4851,7 @@ pub const FuncGen = struct { |
| 5061 | const rp = self.buildAlloca(llvm_ret_ty, alignment); | 4851 | const rp = self.buildAlloca(llvm_ret_ty, alignment); |
| 5062 | const store_inst = self.builder.buildStore(call, rp); | 4852 | const store_inst = self.builder.buildStore(call, rp); |
| 5063 | store_inst.setAlignment(alignment); | 4853 | store_inst.setAlignment(alignment); |
| 5064 | if (isByRef(return_type)) { | 4854 | if (isByRef(return_type, mod)) { |
| 5065 | return rp; | 4855 | return rp; |
| 5066 | } else { | 4856 | } else { |
| 5067 | const load_inst = self.builder.buildLoad(llvm_ret_ty, rp, ""); | 4857 | const load_inst = self.builder.buildLoad(llvm_ret_ty, rp, ""); |
| ... | @@ -5070,10 +4860,10 @@ pub const FuncGen = struct { | ... | @@ -5070,10 +4860,10 @@ pub const FuncGen = struct { |
| 5070 | } | 4860 | } |
| 5071 | } | 4861 | } |
| 5072 | 4862 | ||
| 5073 | if (isByRef(return_type)) { | 4863 | if (isByRef(return_type, mod)) { |
| 5074 | // our by-ref status disagrees with sret so we must allocate, store, | 4864 | // our by-ref status disagrees with sret so we must allocate, store, |
| 5075 | // and return the allocation pointer. | 4865 | // and return the allocation pointer. |
| 5076 | const alignment = return_type.abiAlignment(target); | 4866 | const alignment = return_type.abiAlignment(mod); |
| 5077 | const rp = self.buildAlloca(llvm_ret_ty, alignment); | 4867 | const rp = self.buildAlloca(llvm_ret_ty, alignment); |
| 5078 | const store_inst = self.builder.buildStore(call, rp); | 4868 | const store_inst = self.builder.buildStore(call, rp); |
| 5079 | store_inst.setAlignment(alignment); | 4869 | store_inst.setAlignment(alignment); |
| ... | @@ -5084,22 +4874,19 @@ pub const FuncGen = struct { | ... | @@ -5084,22 +4874,19 @@ pub const FuncGen = struct { |
| 5084 | } | 4874 | } |
| 5085 | 4875 | ||
| 5086 | fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 4876 | fn airRet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 4877 | const mod = self.dg.module; | ||
| 5087 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4878 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5088 | const ret_ty = self.air.typeOf(un_op); | 4879 | const ret_ty = self.typeOf(un_op); |
| 5089 | if (self.ret_ptr) |ret_ptr| { | 4880 | if (self.ret_ptr) |ret_ptr| { |
| 5090 | const operand = try self.resolveInst(un_op); | 4881 | const operand = try self.resolveInst(un_op); |
| 5091 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 4882 | const ptr_ty = try mod.singleMutPtrType(ret_ty); |
| 5092 | .base = .{ .tag = .single_mut_pointer }, | ||
| 5093 | .data = ret_ty, | ||
| 5094 | }; | ||
| 5095 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 5096 | try self.store(ret_ptr, ptr_ty, operand, .NotAtomic); | 4883 | try self.store(ret_ptr, ptr_ty, operand, .NotAtomic); |
| 5097 | _ = self.builder.buildRetVoid(); | 4884 | _ = self.builder.buildRetVoid(); |
| 5098 | return null; | 4885 | return null; |
| 5099 | } | 4886 | } |
| 5100 | const fn_info = self.dg.decl.ty.fnInfo(); | 4887 | const fn_info = mod.typeToFunc(self.dg.decl.ty).?; |
| 5101 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | 4888 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 5102 | if (fn_info.return_type.isError()) { | 4889 | if (fn_info.return_type.toType().isError(mod)) { |
| 5103 | // Functions with an empty error set are emitted with an error code | 4890 | // Functions with an empty error set are emitted with an error code |
| 5104 | // return type and return zero so they can be function pointers coerced | 4891 | // return type and return zero so they can be function pointers coerced |
| 5105 | // to functions that return anyerror. | 4892 | // to functions that return anyerror. |
| ... | @@ -5113,10 +4900,9 @@ pub const FuncGen = struct { | ... | @@ -5113,10 +4900,9 @@ pub const FuncGen = struct { |
| 5113 | 4900 | ||
| 5114 | const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info); | 4901 | const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info); |
| 5115 | const operand = try self.resolveInst(un_op); | 4902 | const operand = try self.resolveInst(un_op); |
| 5116 | const target = self.dg.module.getTarget(); | 4903 | const alignment = ret_ty.abiAlignment(mod); |
| 5117 | const alignment = ret_ty.abiAlignment(target); | ||
| 5118 | 4904 | ||
| 5119 | if (isByRef(ret_ty)) { | 4905 | if (isByRef(ret_ty, mod)) { |
| 5120 | // operand is a pointer however self.ret_ptr is null so that means | 4906 | // operand is a pointer however self.ret_ptr is null so that means |
| 5121 | // we need to return a value. | 4907 | // we need to return a value. |
| 5122 | const load_inst = self.builder.buildLoad(abi_ret_ty, operand, ""); | 4908 | const load_inst = self.builder.buildLoad(abi_ret_ty, operand, ""); |
| ... | @@ -5141,12 +4927,13 @@ pub const FuncGen = struct { | ... | @@ -5141,12 +4927,13 @@ pub const FuncGen = struct { |
| 5141 | } | 4927 | } |
| 5142 | 4928 | ||
| 5143 | fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 4929 | fn airRetLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 4930 | const mod = self.dg.module; | ||
| 5144 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4931 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5145 | const ptr_ty = self.air.typeOf(un_op); | 4932 | const ptr_ty = self.typeOf(un_op); |
| 5146 | const ret_ty = ptr_ty.childType(); | 4933 | const ret_ty = ptr_ty.childType(mod); |
| 5147 | const fn_info = self.dg.decl.ty.fnInfo(); | 4934 | const fn_info = mod.typeToFunc(self.dg.decl.ty).?; |
| 5148 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | 4935 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 5149 | if (fn_info.return_type.isError()) { | 4936 | if (fn_info.return_type.toType().isError(mod)) { |
| 5150 | // Functions with an empty error set are emitted with an error code | 4937 | // Functions with an empty error set are emitted with an error code |
| 5151 | // return type and return zero so they can be function pointers coerced | 4938 | // return type and return zero so they can be function pointers coerced |
| 5152 | // to functions that return anyerror. | 4939 | // to functions that return anyerror. |
| ... | @@ -5162,10 +4949,9 @@ pub const FuncGen = struct { | ... | @@ -5162,10 +4949,9 @@ pub const FuncGen = struct { |
| 5162 | return null; | 4949 | return null; |
| 5163 | } | 4950 | } |
| 5164 | const ptr = try self.resolveInst(un_op); | 4951 | const ptr = try self.resolveInst(un_op); |
| 5165 | const target = self.dg.module.getTarget(); | ||
| 5166 | const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info); | 4952 | const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info); |
| 5167 | const loaded = self.builder.buildLoad(abi_ret_ty, ptr, ""); | 4953 | const loaded = self.builder.buildLoad(abi_ret_ty, ptr, ""); |
| 5168 | loaded.setAlignment(ret_ty.abiAlignment(target)); | 4954 | loaded.setAlignment(ret_ty.abiAlignment(mod)); |
| 5169 | _ = self.builder.buildRet(loaded); | 4955 | _ = self.builder.buildRet(loaded); |
| 5170 | return null; | 4956 | return null; |
| 5171 | } | 4957 | } |
| ... | @@ -5184,9 +4970,9 @@ pub const FuncGen = struct { | ... | @@ -5184,9 +4970,9 @@ pub const FuncGen = struct { |
| 5184 | const src_list = try self.resolveInst(ty_op.operand); | 4970 | const src_list = try self.resolveInst(ty_op.operand); |
| 5185 | const va_list_ty = self.air.getRefType(ty_op.ty); | 4971 | const va_list_ty = self.air.getRefType(ty_op.ty); |
| 5186 | const llvm_va_list_ty = try self.dg.lowerType(va_list_ty); | 4972 | const llvm_va_list_ty = try self.dg.lowerType(va_list_ty); |
| 4973 | const mod = self.dg.module; | ||
| 5187 | 4974 | ||
| 5188 | const target = self.dg.module.getTarget(); | 4975 | const result_alignment = va_list_ty.abiAlignment(mod); |
| 5189 | const result_alignment = va_list_ty.abiAlignment(target); | ||
| 5190 | const dest_list = self.buildAlloca(llvm_va_list_ty, result_alignment); | 4976 | const dest_list = self.buildAlloca(llvm_va_list_ty, result_alignment); |
| 5191 | 4977 | ||
| 5192 | const llvm_fn_name = "llvm.va_copy"; | 4978 | const llvm_fn_name = "llvm.va_copy"; |
| ... | @@ -5202,7 +4988,7 @@ pub const FuncGen = struct { | ... | @@ -5202,7 +4988,7 @@ pub const FuncGen = struct { |
| 5202 | const args: [2]*llvm.Value = .{ dest_list, src_list }; | 4988 | const args: [2]*llvm.Value = .{ dest_list, src_list }; |
| 5203 | _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); | 4989 | _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); |
| 5204 | 4990 | ||
| 5205 | if (isByRef(va_list_ty)) { | 4991 | if (isByRef(va_list_ty, mod)) { |
| 5206 | return dest_list; | 4992 | return dest_list; |
| 5207 | } else { | 4993 | } else { |
| 5208 | const loaded = self.builder.buildLoad(llvm_va_list_ty, dest_list, ""); | 4994 | const loaded = self.builder.buildLoad(llvm_va_list_ty, dest_list, ""); |
| ... | @@ -5227,11 +5013,11 @@ pub const FuncGen = struct { | ... | @@ -5227,11 +5013,11 @@ pub const FuncGen = struct { |
| 5227 | } | 5013 | } |
| 5228 | 5014 | ||
| 5229 | fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5015 | fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5230 | const va_list_ty = self.air.typeOfIndex(inst); | 5016 | const mod = self.dg.module; |
| 5017 | const va_list_ty = self.typeOfIndex(inst); | ||
| 5231 | const llvm_va_list_ty = try self.dg.lowerType(va_list_ty); | 5018 | const llvm_va_list_ty = try self.dg.lowerType(va_list_ty); |
| 5232 | 5019 | ||
| 5233 | const target = self.dg.module.getTarget(); | 5020 | const result_alignment = va_list_ty.abiAlignment(mod); |
| 5234 | const result_alignment = va_list_ty.abiAlignment(target); | ||
| 5235 | const list = self.buildAlloca(llvm_va_list_ty, result_alignment); | 5021 | const list = self.buildAlloca(llvm_va_list_ty, result_alignment); |
| 5236 | 5022 | ||
| 5237 | const llvm_fn_name = "llvm.va_start"; | 5023 | const llvm_fn_name = "llvm.va_start"; |
| ... | @@ -5243,7 +5029,7 @@ pub const FuncGen = struct { | ... | @@ -5243,7 +5029,7 @@ pub const FuncGen = struct { |
| 5243 | const args: [1]*llvm.Value = .{list}; | 5029 | const args: [1]*llvm.Value = .{list}; |
| 5244 | _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); | 5030 | _ = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &args, args.len, .Fast, .Auto, ""); |
| 5245 | 5031 | ||
| 5246 | if (isByRef(va_list_ty)) { | 5032 | if (isByRef(va_list_ty, mod)) { |
| 5247 | return list; | 5033 | return list; |
| 5248 | } else { | 5034 | } else { |
| 5249 | const loaded = self.builder.buildLoad(llvm_va_list_ty, list, ""); | 5035 | const loaded = self.builder.buildLoad(llvm_va_list_ty, list, ""); |
| ... | @@ -5258,7 +5044,7 @@ pub const FuncGen = struct { | ... | @@ -5258,7 +5044,7 @@ pub const FuncGen = struct { |
| 5258 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 5044 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5259 | const lhs = try self.resolveInst(bin_op.lhs); | 5045 | const lhs = try self.resolveInst(bin_op.lhs); |
| 5260 | const rhs = try self.resolveInst(bin_op.rhs); | 5046 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5261 | const operand_ty = self.air.typeOf(bin_op.lhs); | 5047 | const operand_ty = self.typeOf(bin_op.lhs); |
| 5262 | 5048 | ||
| 5263 | return self.cmp(lhs, rhs, operand_ty, op); | 5049 | return self.cmp(lhs, rhs, operand_ty, op); |
| 5264 | } | 5050 | } |
| ... | @@ -5271,7 +5057,7 @@ pub const FuncGen = struct { | ... | @@ -5271,7 +5057,7 @@ pub const FuncGen = struct { |
| 5271 | 5057 | ||
| 5272 | const lhs = try self.resolveInst(extra.lhs); | 5058 | const lhs = try self.resolveInst(extra.lhs); |
| 5273 | const rhs = try self.resolveInst(extra.rhs); | 5059 | const rhs = try self.resolveInst(extra.rhs); |
| 5274 | const vec_ty = self.air.typeOf(extra.lhs); | 5060 | const vec_ty = self.typeOf(extra.lhs); |
| 5275 | const cmp_op = extra.compareOperator(); | 5061 | const cmp_op = extra.compareOperator(); |
| 5276 | 5062 | ||
| 5277 | return self.cmp(lhs, rhs, vec_ty, cmp_op); | 5063 | return self.cmp(lhs, rhs, vec_ty, cmp_op); |
| ... | @@ -5292,23 +5078,21 @@ pub const FuncGen = struct { | ... | @@ -5292,23 +5078,21 @@ pub const FuncGen = struct { |
| 5292 | operand_ty: Type, | 5078 | operand_ty: Type, |
| 5293 | op: math.CompareOperator, | 5079 | op: math.CompareOperator, |
| 5294 | ) Allocator.Error!*llvm.Value { | 5080 | ) Allocator.Error!*llvm.Value { |
| 5295 | var int_buffer: Type.Payload.Bits = undefined; | 5081 | const mod = self.dg.module; |
| 5296 | var opt_buffer: Type.Payload.ElemType = undefined; | 5082 | const scalar_ty = operand_ty.scalarType(mod); |
| 5297 | 5083 | const int_ty = switch (scalar_ty.zigTypeTag(mod)) { | |
| 5298 | const scalar_ty = operand_ty.scalarType(); | 5084 | .Enum => scalar_ty.intTagType(mod), |
| 5299 | const int_ty = switch (scalar_ty.zigTypeTag()) { | ||
| 5300 | .Enum => scalar_ty.intTagType(&int_buffer), | ||
| 5301 | .Int, .Bool, .Pointer, .ErrorSet => scalar_ty, | 5085 | .Int, .Bool, .Pointer, .ErrorSet => scalar_ty, |
| 5302 | .Optional => blk: { | 5086 | .Optional => blk: { |
| 5303 | const payload_ty = operand_ty.optionalChild(&opt_buffer); | 5087 | const payload_ty = operand_ty.optionalChild(mod); |
| 5304 | if (!payload_ty.hasRuntimeBitsIgnoreComptime() or | 5088 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or |
| 5305 | operand_ty.optionalReprIsPayload()) | 5089 | operand_ty.optionalReprIsPayload(mod)) |
| 5306 | { | 5090 | { |
| 5307 | break :blk operand_ty; | 5091 | break :blk operand_ty; |
| 5308 | } | 5092 | } |
| 5309 | // We need to emit instructions to check for equality/inequality | 5093 | // We need to emit instructions to check for equality/inequality |
| 5310 | // of optionals that are not pointers. | 5094 | // of optionals that are not pointers. |
| 5311 | const is_by_ref = isByRef(scalar_ty); | 5095 | const is_by_ref = isByRef(scalar_ty, mod); |
| 5312 | const opt_llvm_ty = try self.dg.lowerType(scalar_ty); | 5096 | const opt_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 5313 | const lhs_non_null = self.optIsNonNull(opt_llvm_ty, lhs, is_by_ref); | 5097 | const lhs_non_null = self.optIsNonNull(opt_llvm_ty, lhs, is_by_ref); |
| 5314 | const rhs_non_null = self.optIsNonNull(opt_llvm_ty, rhs, is_by_ref); | 5098 | const rhs_non_null = self.optIsNonNull(opt_llvm_ty, rhs, is_by_ref); |
| ... | @@ -5375,7 +5159,7 @@ pub const FuncGen = struct { | ... | @@ -5375,7 +5159,7 @@ pub const FuncGen = struct { |
| 5375 | .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }), | 5159 | .Float => return self.buildFloatCmp(op, operand_ty, .{ lhs, rhs }), |
| 5376 | else => unreachable, | 5160 | else => unreachable, |
| 5377 | }; | 5161 | }; |
| 5378 | const is_signed = int_ty.isSignedInt(); | 5162 | const is_signed = int_ty.isSignedInt(mod); |
| 5379 | const operation: llvm.IntPredicate = switch (op) { | 5163 | const operation: llvm.IntPredicate = switch (op) { |
| 5380 | .eq => .EQ, | 5164 | .eq => .EQ, |
| 5381 | .neq => .NE, | 5165 | .neq => .NE, |
| ... | @@ -5388,13 +5172,14 @@ pub const FuncGen = struct { | ... | @@ -5388,13 +5172,14 @@ pub const FuncGen = struct { |
| 5388 | } | 5172 | } |
| 5389 | 5173 | ||
| 5390 | fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5174 | fn airBlock(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5175 | const mod = self.dg.module; | ||
| 5391 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5176 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5392 | const extra = self.air.extraData(Air.Block, ty_pl.payload); | 5177 | const extra = self.air.extraData(Air.Block, ty_pl.payload); |
| 5393 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 5178 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 5394 | const inst_ty = self.air.typeOfIndex(inst); | 5179 | const inst_ty = self.typeOfIndex(inst); |
| 5395 | const parent_bb = self.context.createBasicBlock("Block"); | 5180 | const parent_bb = self.context.createBasicBlock("Block"); |
| 5396 | 5181 | ||
| 5397 | if (inst_ty.isNoReturn()) { | 5182 | if (inst_ty.isNoReturn(mod)) { |
| 5398 | try self.genBody(body); | 5183 | try self.genBody(body); |
| 5399 | return null; | 5184 | return null; |
| 5400 | } | 5185 | } |
| ... | @@ -5414,8 +5199,8 @@ pub const FuncGen = struct { | ... | @@ -5414,8 +5199,8 @@ pub const FuncGen = struct { |
| 5414 | self.builder.positionBuilderAtEnd(parent_bb); | 5199 | self.builder.positionBuilderAtEnd(parent_bb); |
| 5415 | 5200 | ||
| 5416 | // Create a phi node only if the block returns a value. | 5201 | // Create a phi node only if the block returns a value. |
| 5417 | const is_body = inst_ty.zigTypeTag() == .Fn; | 5202 | const is_body = inst_ty.zigTypeTag(mod) == .Fn; |
| 5418 | if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime()) return null; | 5203 | if (!is_body and !inst_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; |
| 5419 | 5204 | ||
| 5420 | const raw_llvm_ty = try self.dg.lowerType(inst_ty); | 5205 | const raw_llvm_ty = try self.dg.lowerType(inst_ty); |
| 5421 | 5206 | ||
| ... | @@ -5424,7 +5209,7 @@ pub const FuncGen = struct { | ... | @@ -5424,7 +5209,7 @@ pub const FuncGen = struct { |
| 5424 | // a pointer to it. LLVM IR allows the call instruction to use function bodies instead | 5209 | // a pointer to it. LLVM IR allows the call instruction to use function bodies instead |
| 5425 | // of function pointers, however the phi makes it a runtime value and therefore | 5210 | // of function pointers, however the phi makes it a runtime value and therefore |
| 5426 | // the LLVM type has to be wrapped in a pointer. | 5211 | // the LLVM type has to be wrapped in a pointer. |
| 5427 | if (is_body or isByRef(inst_ty)) { | 5212 | if (is_body or isByRef(inst_ty, mod)) { |
| 5428 | break :ty self.context.pointerType(0); | 5213 | break :ty self.context.pointerType(0); |
| 5429 | } | 5214 | } |
| 5430 | break :ty raw_llvm_ty; | 5215 | break :ty raw_llvm_ty; |
| ... | @@ -5444,8 +5229,9 @@ pub const FuncGen = struct { | ... | @@ -5444,8 +5229,9 @@ pub const FuncGen = struct { |
| 5444 | const block = self.blocks.get(branch.block_inst).?; | 5229 | const block = self.blocks.get(branch.block_inst).?; |
| 5445 | 5230 | ||
| 5446 | // Add the values to the lists only if the break provides a value. | 5231 | // Add the values to the lists only if the break provides a value. |
| 5447 | const operand_ty = self.air.typeOf(branch.operand); | 5232 | const operand_ty = self.typeOf(branch.operand); |
| 5448 | if (operand_ty.hasRuntimeBitsIgnoreComptime() or operand_ty.zigTypeTag() == .Fn) { | 5233 | const mod = self.dg.module; |
| 5234 | if (operand_ty.hasRuntimeBitsIgnoreComptime(mod) or operand_ty.zigTypeTag(mod) == .Fn) { | ||
| 5449 | const val = try self.resolveInst(branch.operand); | 5235 | const val = try self.resolveInst(branch.operand); |
| 5450 | 5236 | ||
| 5451 | // For the phi node, we need the basic blocks and the values of the | 5237 | // For the phi node, we need the basic blocks and the values of the |
| ... | @@ -5481,24 +5267,26 @@ pub const FuncGen = struct { | ... | @@ -5481,24 +5267,26 @@ pub const FuncGen = struct { |
| 5481 | } | 5267 | } |
| 5482 | 5268 | ||
| 5483 | fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { | 5269 | fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5270 | const mod = self.dg.module; | ||
| 5484 | const inst = body_tail[0]; | 5271 | const inst = body_tail[0]; |
| 5485 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 5272 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 5486 | const err_union = try self.resolveInst(pl_op.operand); | 5273 | const err_union = try self.resolveInst(pl_op.operand); |
| 5487 | const extra = self.air.extraData(Air.Try, pl_op.payload); | 5274 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 5488 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 5275 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 5489 | const err_union_ty = self.air.typeOf(pl_op.operand); | 5276 | const err_union_ty = self.typeOf(pl_op.operand); |
| 5490 | const payload_ty = self.air.typeOfIndex(inst); | 5277 | const payload_ty = self.typeOfIndex(inst); |
| 5491 | const can_elide_load = if (isByRef(payload_ty)) self.canElideLoad(body_tail) else false; | 5278 | const can_elide_load = if (isByRef(payload_ty, mod)) self.canElideLoad(body_tail) else false; |
| 5492 | const is_unused = self.liveness.isUnused(inst); | 5279 | const is_unused = self.liveness.isUnused(inst); |
| 5493 | return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused); | 5280 | return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused); |
| 5494 | } | 5281 | } |
| 5495 | 5282 | ||
| 5496 | fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5283 | fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5284 | const mod = self.dg.module; | ||
| 5497 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5285 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5498 | const extra = self.air.extraData(Air.TryPtr, ty_pl.payload); | 5286 | const extra = self.air.extraData(Air.TryPtr, ty_pl.payload); |
| 5499 | const err_union_ptr = try self.resolveInst(extra.data.ptr); | 5287 | const err_union_ptr = try self.resolveInst(extra.data.ptr); |
| 5500 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 5288 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 5501 | const err_union_ty = self.air.typeOf(extra.data.ptr).childType(); | 5289 | const err_union_ty = self.typeOf(extra.data.ptr).childType(mod); |
| 5502 | const is_unused = self.liveness.isUnused(inst); | 5290 | const is_unused = self.liveness.isUnused(inst); |
| 5503 | return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, is_unused); | 5291 | return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, is_unused); |
| 5504 | } | 5292 | } |
| ... | @@ -5512,12 +5300,12 @@ pub const FuncGen = struct { | ... | @@ -5512,12 +5300,12 @@ pub const FuncGen = struct { |
| 5512 | can_elide_load: bool, | 5300 | can_elide_load: bool, |
| 5513 | is_unused: bool, | 5301 | is_unused: bool, |
| 5514 | ) !?*llvm.Value { | 5302 | ) !?*llvm.Value { |
| 5515 | const payload_ty = err_union_ty.errorUnionPayload(); | 5303 | const mod = fg.dg.module; |
| 5516 | const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(); | 5304 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 5517 | const target = fg.dg.module.getTarget(); | 5305 | const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod); |
| 5518 | const err_union_llvm_ty = try fg.dg.lowerType(err_union_ty); | 5306 | const err_union_llvm_ty = try fg.dg.lowerType(err_union_ty); |
| 5519 | 5307 | ||
| 5520 | if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 5308 | if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 5521 | const is_err = err: { | 5309 | const is_err = err: { |
| 5522 | const err_set_ty = try fg.dg.lowerType(Type.anyerror); | 5310 | const err_set_ty = try fg.dg.lowerType(Type.anyerror); |
| 5523 | const zero = err_set_ty.constNull(); | 5311 | const zero = err_set_ty.constNull(); |
| ... | @@ -5529,8 +5317,8 @@ pub const FuncGen = struct { | ... | @@ -5529,8 +5317,8 @@ pub const FuncGen = struct { |
| 5529 | err_union; | 5317 | err_union; |
| 5530 | break :err fg.builder.buildICmp(.NE, loaded, zero, ""); | 5318 | break :err fg.builder.buildICmp(.NE, loaded, zero, ""); |
| 5531 | } | 5319 | } |
| 5532 | const err_field_index = errUnionErrorOffset(payload_ty, target); | 5320 | const err_field_index = errUnionErrorOffset(payload_ty, mod); |
| 5533 | if (operand_is_ptr or isByRef(err_union_ty)) { | 5321 | if (operand_is_ptr or isByRef(err_union_ty, mod)) { |
| 5534 | const err_field_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, err_field_index, ""); | 5322 | const err_field_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, err_field_index, ""); |
| 5535 | // TODO add alignment to this load | 5323 | // TODO add alignment to this load |
| 5536 | const loaded = fg.builder.buildLoad(err_set_ty, err_field_ptr, ""); | 5324 | const loaded = fg.builder.buildLoad(err_set_ty, err_field_ptr, ""); |
| ... | @@ -5555,30 +5343,31 @@ pub const FuncGen = struct { | ... | @@ -5555,30 +5343,31 @@ pub const FuncGen = struct { |
| 5555 | if (!payload_has_bits) { | 5343 | if (!payload_has_bits) { |
| 5556 | return if (operand_is_ptr) err_union else null; | 5344 | return if (operand_is_ptr) err_union else null; |
| 5557 | } | 5345 | } |
| 5558 | const offset = errUnionPayloadOffset(payload_ty, target); | 5346 | const offset = errUnionPayloadOffset(payload_ty, mod); |
| 5559 | if (operand_is_ptr) { | 5347 | if (operand_is_ptr) { |
| 5560 | return fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, ""); | 5348 | return fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, ""); |
| 5561 | } else if (isByRef(err_union_ty)) { | 5349 | } else if (isByRef(err_union_ty, mod)) { |
| 5562 | const payload_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, ""); | 5350 | const payload_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, ""); |
| 5563 | if (isByRef(payload_ty)) { | 5351 | if (isByRef(payload_ty, mod)) { |
| 5564 | if (can_elide_load) | 5352 | if (can_elide_load) |
| 5565 | return payload_ptr; | 5353 | return payload_ptr; |
| 5566 | 5354 | ||
| 5567 | return fg.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(target), false); | 5355 | return fg.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(mod), false); |
| 5568 | } | 5356 | } |
| 5569 | const load_inst = fg.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, ""); | 5357 | const load_inst = fg.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, ""); |
| 5570 | load_inst.setAlignment(payload_ty.abiAlignment(target)); | 5358 | load_inst.setAlignment(payload_ty.abiAlignment(mod)); |
| 5571 | return load_inst; | 5359 | return load_inst; |
| 5572 | } | 5360 | } |
| 5573 | return fg.builder.buildExtractValue(err_union, offset, ""); | 5361 | return fg.builder.buildExtractValue(err_union, offset, ""); |
| 5574 | } | 5362 | } |
| 5575 | 5363 | ||
| 5576 | fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5364 | fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5365 | const mod = self.dg.module; | ||
| 5577 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 5366 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 5578 | const cond = try self.resolveInst(pl_op.operand); | 5367 | const cond = try self.resolveInst(pl_op.operand); |
| 5579 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); | 5368 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 5580 | const else_block = self.context.appendBasicBlock(self.llvm_func, "Else"); | 5369 | const else_block = self.context.appendBasicBlock(self.llvm_func, "Else"); |
| 5581 | const target = self.dg.module.getTarget(); | 5370 | const target = mod.getTarget(); |
| 5582 | const llvm_usize = self.context.intType(target.ptrBitWidth()); | 5371 | const llvm_usize = self.context.intType(target.ptrBitWidth()); |
| 5583 | const cond_int = if (cond.typeOf().getTypeKind() == .Pointer) | 5372 | const cond_int = if (cond.typeOf().getTypeKind() == .Pointer) |
| 5584 | self.builder.buildPtrToInt(cond, llvm_usize, "") | 5373 | self.builder.buildPtrToInt(cond, llvm_usize, "") |
| ... | @@ -5623,6 +5412,7 @@ pub const FuncGen = struct { | ... | @@ -5623,6 +5412,7 @@ pub const FuncGen = struct { |
| 5623 | } | 5412 | } |
| 5624 | 5413 | ||
| 5625 | fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5414 | fn airLoop(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5415 | const mod = self.dg.module; | ||
| 5626 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5416 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5627 | const loop = self.air.extraData(Air.Block, ty_pl.payload); | 5417 | const loop = self.air.extraData(Air.Block, ty_pl.payload); |
| 5628 | const body = self.air.extra[loop.end..][0..loop.data.body_len]; | 5418 | const body = self.air.extra[loop.end..][0..loop.data.body_len]; |
| ... | @@ -5638,21 +5428,22 @@ pub const FuncGen = struct { | ... | @@ -5638,21 +5428,22 @@ pub const FuncGen = struct { |
| 5638 | // would have been emitted already. Also the main loop in genBody can | 5428 | // would have been emitted already. Also the main loop in genBody can |
| 5639 | // be while(true) instead of for(body), which will eliminate 1 branch on | 5429 | // be while(true) instead of for(body), which will eliminate 1 branch on |
| 5640 | // a hot path. | 5430 | // a hot path. |
| 5641 | if (body.len == 0 or !self.air.typeOfIndex(body[body.len - 1]).isNoReturn()) { | 5431 | if (body.len == 0 or !self.typeOfIndex(body[body.len - 1]).isNoReturn(mod)) { |
| 5642 | _ = self.builder.buildBr(loop_block); | 5432 | _ = self.builder.buildBr(loop_block); |
| 5643 | } | 5433 | } |
| 5644 | return null; | 5434 | return null; |
| 5645 | } | 5435 | } |
| 5646 | 5436 | ||
| 5647 | fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5437 | fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5438 | const mod = self.dg.module; | ||
| 5648 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5439 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5649 | const operand_ty = self.air.typeOf(ty_op.operand); | 5440 | const operand_ty = self.typeOf(ty_op.operand); |
| 5650 | const array_ty = operand_ty.childType(); | 5441 | const array_ty = operand_ty.childType(mod); |
| 5651 | const llvm_usize = try self.dg.lowerType(Type.usize); | 5442 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| 5652 | const len = llvm_usize.constInt(array_ty.arrayLen(), .False); | 5443 | const len = llvm_usize.constInt(array_ty.arrayLen(mod), .False); |
| 5653 | const slice_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); | 5444 | const slice_llvm_ty = try self.dg.lowerType(self.typeOfIndex(inst)); |
| 5654 | const operand = try self.resolveInst(ty_op.operand); | 5445 | const operand = try self.resolveInst(ty_op.operand); |
| 5655 | if (!array_ty.hasRuntimeBitsIgnoreComptime()) { | 5446 | if (!array_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 5656 | const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), operand, 0, ""); | 5447 | const partial = self.builder.buildInsertValue(slice_llvm_ty.getUndef(), operand, 0, ""); |
| 5657 | return self.builder.buildInsertValue(partial, len, 1, ""); | 5448 | return self.builder.buildInsertValue(partial, len, 1, ""); |
| 5658 | } | 5449 | } |
| ... | @@ -5666,30 +5457,31 @@ pub const FuncGen = struct { | ... | @@ -5666,30 +5457,31 @@ pub const FuncGen = struct { |
| 5666 | } | 5457 | } |
| 5667 | 5458 | ||
| 5668 | fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5459 | fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5460 | const mod = self.dg.module; | ||
| 5669 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5461 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5670 | 5462 | ||
| 5671 | const operand = try self.resolveInst(ty_op.operand); | 5463 | const operand = try self.resolveInst(ty_op.operand); |
| 5672 | const operand_ty = self.air.typeOf(ty_op.operand); | 5464 | const operand_ty = self.typeOf(ty_op.operand); |
| 5673 | const operand_scalar_ty = operand_ty.scalarType(); | 5465 | const operand_scalar_ty = operand_ty.scalarType(mod); |
| 5674 | 5466 | ||
| 5675 | const dest_ty = self.air.typeOfIndex(inst); | 5467 | const dest_ty = self.typeOfIndex(inst); |
| 5676 | const dest_scalar_ty = dest_ty.scalarType(); | 5468 | const dest_scalar_ty = dest_ty.scalarType(mod); |
| 5677 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); | 5469 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); |
| 5678 | const target = self.dg.module.getTarget(); | 5470 | const target = mod.getTarget(); |
| 5679 | 5471 | ||
| 5680 | if (intrinsicsAllowed(dest_scalar_ty, target)) { | 5472 | if (intrinsicsAllowed(dest_scalar_ty, target)) { |
| 5681 | if (operand_scalar_ty.isSignedInt()) { | 5473 | if (operand_scalar_ty.isSignedInt(mod)) { |
| 5682 | return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); | 5474 | return self.builder.buildSIToFP(operand, dest_llvm_ty, ""); |
| 5683 | } else { | 5475 | } else { |
| 5684 | return self.builder.buildUIToFP(operand, dest_llvm_ty, ""); | 5476 | return self.builder.buildUIToFP(operand, dest_llvm_ty, ""); |
| 5685 | } | 5477 | } |
| 5686 | } | 5478 | } |
| 5687 | 5479 | ||
| 5688 | const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(target)); | 5480 | const operand_bits = @intCast(u16, operand_scalar_ty.bitSize(mod)); |
| 5689 | const rt_int_bits = compilerRtIntBits(operand_bits); | 5481 | const rt_int_bits = compilerRtIntBits(operand_bits); |
| 5690 | const rt_int_ty = self.context.intType(rt_int_bits); | 5482 | const rt_int_ty = self.context.intType(rt_int_bits); |
| 5691 | var extended = e: { | 5483 | var extended = e: { |
| 5692 | if (operand_scalar_ty.isSignedInt()) { | 5484 | if (operand_scalar_ty.isSignedInt(mod)) { |
| 5693 | break :e self.builder.buildSExtOrBitCast(operand, rt_int_ty, ""); | 5485 | break :e self.builder.buildSExtOrBitCast(operand, rt_int_ty, ""); |
| 5694 | } else { | 5486 | } else { |
| 5695 | break :e self.builder.buildZExtOrBitCast(operand, rt_int_ty, ""); | 5487 | break :e self.builder.buildZExtOrBitCast(operand, rt_int_ty, ""); |
| ... | @@ -5698,7 +5490,7 @@ pub const FuncGen = struct { | ... | @@ -5698,7 +5490,7 @@ pub const FuncGen = struct { |
| 5698 | const dest_bits = dest_scalar_ty.floatBits(target); | 5490 | const dest_bits = dest_scalar_ty.floatBits(target); |
| 5699 | const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits); | 5491 | const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits); |
| 5700 | const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits); | 5492 | const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits); |
| 5701 | const sign_prefix = if (operand_scalar_ty.isSignedInt()) "" else "un"; | 5493 | const sign_prefix = if (operand_scalar_ty.isSignedInt(mod)) "" else "un"; |
| 5702 | var fn_name_buf: [64]u8 = undefined; | 5494 | var fn_name_buf: [64]u8 = undefined; |
| 5703 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__float{s}{s}i{s}f", .{ | 5495 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__float{s}{s}i{s}f", .{ |
| 5704 | sign_prefix, | 5496 | sign_prefix, |
| ... | @@ -5724,27 +5516,28 @@ pub const FuncGen = struct { | ... | @@ -5724,27 +5516,28 @@ pub const FuncGen = struct { |
| 5724 | fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { | 5516 | fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 5725 | self.builder.setFastMath(want_fast_math); | 5517 | self.builder.setFastMath(want_fast_math); |
| 5726 | 5518 | ||
| 5727 | const target = self.dg.module.getTarget(); | 5519 | const mod = self.dg.module; |
| 5520 | const target = mod.getTarget(); | ||
| 5728 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5521 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5729 | 5522 | ||
| 5730 | const operand = try self.resolveInst(ty_op.operand); | 5523 | const operand = try self.resolveInst(ty_op.operand); |
| 5731 | const operand_ty = self.air.typeOf(ty_op.operand); | 5524 | const operand_ty = self.typeOf(ty_op.operand); |
| 5732 | const operand_scalar_ty = operand_ty.scalarType(); | 5525 | const operand_scalar_ty = operand_ty.scalarType(mod); |
| 5733 | 5526 | ||
| 5734 | const dest_ty = self.air.typeOfIndex(inst); | 5527 | const dest_ty = self.typeOfIndex(inst); |
| 5735 | const dest_scalar_ty = dest_ty.scalarType(); | 5528 | const dest_scalar_ty = dest_ty.scalarType(mod); |
| 5736 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); | 5529 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); |
| 5737 | 5530 | ||
| 5738 | if (intrinsicsAllowed(operand_scalar_ty, target)) { | 5531 | if (intrinsicsAllowed(operand_scalar_ty, target)) { |
| 5739 | // TODO set fast math flag | 5532 | // TODO set fast math flag |
| 5740 | if (dest_scalar_ty.isSignedInt()) { | 5533 | if (dest_scalar_ty.isSignedInt(mod)) { |
| 5741 | return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); | 5534 | return self.builder.buildFPToSI(operand, dest_llvm_ty, ""); |
| 5742 | } else { | 5535 | } else { |
| 5743 | return self.builder.buildFPToUI(operand, dest_llvm_ty, ""); | 5536 | return self.builder.buildFPToUI(operand, dest_llvm_ty, ""); |
| 5744 | } | 5537 | } |
| 5745 | } | 5538 | } |
| 5746 | 5539 | ||
| 5747 | const rt_int_bits = compilerRtIntBits(@intCast(u16, dest_scalar_ty.bitSize(target))); | 5540 | const rt_int_bits = compilerRtIntBits(@intCast(u16, dest_scalar_ty.bitSize(mod))); |
| 5748 | const ret_ty = self.context.intType(rt_int_bits); | 5541 | const ret_ty = self.context.intType(rt_int_bits); |
| 5749 | const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: { | 5542 | const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: { |
| 5750 | // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard | 5543 | // On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard |
| ... | @@ -5756,7 +5549,7 @@ pub const FuncGen = struct { | ... | @@ -5756,7 +5549,7 @@ pub const FuncGen = struct { |
| 5756 | const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); | 5549 | const compiler_rt_operand_abbrev = compilerRtFloatAbbrev(operand_bits); |
| 5757 | 5550 | ||
| 5758 | const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits); | 5551 | const compiler_rt_dest_abbrev = compilerRtIntAbbrev(rt_int_bits); |
| 5759 | const sign_prefix = if (dest_scalar_ty.isSignedInt()) "" else "uns"; | 5552 | const sign_prefix = if (dest_scalar_ty.isSignedInt(mod)) "" else "uns"; |
| 5760 | 5553 | ||
| 5761 | var fn_name_buf: [64]u8 = undefined; | 5554 | var fn_name_buf: [64]u8 = undefined; |
| 5762 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}{s}f{s}i", .{ | 5555 | const fn_name = std.fmt.bufPrintZ(&fn_name_buf, "__fix{s}{s}f{s}i", .{ |
| ... | @@ -5778,7 +5571,8 @@ pub const FuncGen = struct { | ... | @@ -5778,7 +5571,8 @@ pub const FuncGen = struct { |
| 5778 | } | 5571 | } |
| 5779 | 5572 | ||
| 5780 | fn sliceOrArrayPtr(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value { | 5573 | fn sliceOrArrayPtr(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value { |
| 5781 | if (ty.isSlice()) { | 5574 | const mod = fg.dg.module; |
| 5575 | if (ty.isSlice(mod)) { | ||
| 5782 | return fg.builder.buildExtractValue(ptr, 0, ""); | 5576 | return fg.builder.buildExtractValue(ptr, 0, ""); |
| 5783 | } else { | 5577 | } else { |
| 5784 | return ptr; | 5578 | return ptr; |
| ... | @@ -5786,22 +5580,23 @@ pub const FuncGen = struct { | ... | @@ -5786,22 +5580,23 @@ pub const FuncGen = struct { |
| 5786 | } | 5580 | } |
| 5787 | 5581 | ||
| 5788 | fn sliceOrArrayLenInBytes(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value { | 5582 | fn sliceOrArrayLenInBytes(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value { |
| 5789 | const target = fg.dg.module.getTarget(); | 5583 | const mod = fg.dg.module; |
| 5584 | const target = mod.getTarget(); | ||
| 5790 | const llvm_usize_ty = fg.context.intType(target.ptrBitWidth()); | 5585 | const llvm_usize_ty = fg.context.intType(target.ptrBitWidth()); |
| 5791 | switch (ty.ptrSize()) { | 5586 | switch (ty.ptrSize(mod)) { |
| 5792 | .Slice => { | 5587 | .Slice => { |
| 5793 | const len = fg.builder.buildExtractValue(ptr, 1, ""); | 5588 | const len = fg.builder.buildExtractValue(ptr, 1, ""); |
| 5794 | const elem_ty = ty.childType(); | 5589 | const elem_ty = ty.childType(mod); |
| 5795 | const abi_size = elem_ty.abiSize(target); | 5590 | const abi_size = elem_ty.abiSize(mod); |
| 5796 | if (abi_size == 1) return len; | 5591 | if (abi_size == 1) return len; |
| 5797 | const abi_size_llvm_val = llvm_usize_ty.constInt(abi_size, .False); | 5592 | const abi_size_llvm_val = llvm_usize_ty.constInt(abi_size, .False); |
| 5798 | return fg.builder.buildMul(len, abi_size_llvm_val, ""); | 5593 | return fg.builder.buildMul(len, abi_size_llvm_val, ""); |
| 5799 | }, | 5594 | }, |
| 5800 | .One => { | 5595 | .One => { |
| 5801 | const array_ty = ty.childType(); | 5596 | const array_ty = ty.childType(mod); |
| 5802 | const elem_ty = array_ty.childType(); | 5597 | const elem_ty = array_ty.childType(mod); |
| 5803 | const abi_size = elem_ty.abiSize(target); | 5598 | const abi_size = elem_ty.abiSize(mod); |
| 5804 | return llvm_usize_ty.constInt(array_ty.arrayLen() * abi_size, .False); | 5599 | return llvm_usize_ty.constInt(array_ty.arrayLen(mod) * abi_size, .False); |
| 5805 | }, | 5600 | }, |
| 5806 | .Many, .C => unreachable, | 5601 | .Many, .C => unreachable, |
| 5807 | } | 5602 | } |
| ... | @@ -5814,67 +5609,69 @@ pub const FuncGen = struct { | ... | @@ -5814,67 +5609,69 @@ pub const FuncGen = struct { |
| 5814 | } | 5609 | } |
| 5815 | 5610 | ||
| 5816 | fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value { | 5611 | fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value { |
| 5612 | const mod = self.dg.module; | ||
| 5817 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5613 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5818 | const slice_ptr = try self.resolveInst(ty_op.operand); | 5614 | const slice_ptr = try self.resolveInst(ty_op.operand); |
| 5819 | const slice_ptr_ty = self.air.typeOf(ty_op.operand); | 5615 | const slice_ptr_ty = self.typeOf(ty_op.operand); |
| 5820 | const slice_llvm_ty = try self.dg.lowerPtrElemTy(slice_ptr_ty.childType()); | 5616 | const slice_llvm_ty = try self.dg.lowerPtrElemTy(slice_ptr_ty.childType(mod)); |
| 5821 | 5617 | ||
| 5822 | return self.builder.buildStructGEP(slice_llvm_ty, slice_ptr, index, ""); | 5618 | return self.builder.buildStructGEP(slice_llvm_ty, slice_ptr, index, ""); |
| 5823 | } | 5619 | } |
| 5824 | 5620 | ||
| 5825 | fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { | 5621 | fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5622 | const mod = self.dg.module; | ||
| 5826 | const inst = body_tail[0]; | 5623 | const inst = body_tail[0]; |
| 5827 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 5624 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5828 | const slice_ty = self.air.typeOf(bin_op.lhs); | 5625 | const slice_ty = self.typeOf(bin_op.lhs); |
| 5829 | const slice = try self.resolveInst(bin_op.lhs); | 5626 | const slice = try self.resolveInst(bin_op.lhs); |
| 5830 | const index = try self.resolveInst(bin_op.rhs); | 5627 | const index = try self.resolveInst(bin_op.rhs); |
| 5831 | const elem_ty = slice_ty.childType(); | 5628 | const elem_ty = slice_ty.childType(mod); |
| 5832 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); | 5629 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); |
| 5833 | const base_ptr = self.builder.buildExtractValue(slice, 0, ""); | 5630 | const base_ptr = self.builder.buildExtractValue(slice, 0, ""); |
| 5834 | const indices: [1]*llvm.Value = .{index}; | 5631 | const indices: [1]*llvm.Value = .{index}; |
| 5835 | const ptr = self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 5632 | const ptr = self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| 5836 | if (isByRef(elem_ty)) { | 5633 | if (isByRef(elem_ty, mod)) { |
| 5837 | if (self.canElideLoad(body_tail)) | 5634 | if (self.canElideLoad(body_tail)) |
| 5838 | return ptr; | 5635 | return ptr; |
| 5839 | 5636 | ||
| 5840 | const target = self.dg.module.getTarget(); | 5637 | return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(mod), false); |
| 5841 | return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(target), false); | ||
| 5842 | } | 5638 | } |
| 5843 | 5639 | ||
| 5844 | return self.load(ptr, slice_ty); | 5640 | return self.load(ptr, slice_ty); |
| 5845 | } | 5641 | } |
| 5846 | 5642 | ||
| 5847 | fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5643 | fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5644 | const mod = self.dg.module; | ||
| 5848 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5645 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5849 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 5646 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 5850 | const slice_ty = self.air.typeOf(bin_op.lhs); | 5647 | const slice_ty = self.typeOf(bin_op.lhs); |
| 5851 | 5648 | ||
| 5852 | const slice = try self.resolveInst(bin_op.lhs); | 5649 | const slice = try self.resolveInst(bin_op.lhs); |
| 5853 | const index = try self.resolveInst(bin_op.rhs); | 5650 | const index = try self.resolveInst(bin_op.rhs); |
| 5854 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(slice_ty.childType()); | 5651 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(slice_ty.childType(mod)); |
| 5855 | const base_ptr = self.builder.buildExtractValue(slice, 0, ""); | 5652 | const base_ptr = self.builder.buildExtractValue(slice, 0, ""); |
| 5856 | const indices: [1]*llvm.Value = .{index}; | 5653 | const indices: [1]*llvm.Value = .{index}; |
| 5857 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 5654 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| 5858 | } | 5655 | } |
| 5859 | 5656 | ||
| 5860 | fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { | 5657 | fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5658 | const mod = self.dg.module; | ||
| 5861 | const inst = body_tail[0]; | 5659 | const inst = body_tail[0]; |
| 5862 | 5660 | ||
| 5863 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 5661 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5864 | const array_ty = self.air.typeOf(bin_op.lhs); | 5662 | const array_ty = self.typeOf(bin_op.lhs); |
| 5865 | const array_llvm_val = try self.resolveInst(bin_op.lhs); | 5663 | const array_llvm_val = try self.resolveInst(bin_op.lhs); |
| 5866 | const rhs = try self.resolveInst(bin_op.rhs); | 5664 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5867 | const array_llvm_ty = try self.dg.lowerType(array_ty); | 5665 | const array_llvm_ty = try self.dg.lowerType(array_ty); |
| 5868 | const elem_ty = array_ty.childType(); | 5666 | const elem_ty = array_ty.childType(mod); |
| 5869 | if (isByRef(array_ty)) { | 5667 | if (isByRef(array_ty, mod)) { |
| 5870 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs }; | 5668 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs }; |
| 5871 | if (isByRef(elem_ty)) { | 5669 | if (isByRef(elem_ty, mod)) { |
| 5872 | const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, ""); | 5670 | const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, ""); |
| 5873 | if (canElideLoad(self, body_tail)) | 5671 | if (canElideLoad(self, body_tail)) |
| 5874 | return elem_ptr; | 5672 | return elem_ptr; |
| 5875 | 5673 | ||
| 5876 | const target = self.dg.module.getTarget(); | 5674 | return self.loadByRef(elem_ptr, elem_ty, elem_ty.abiAlignment(mod), false); |
| 5877 | return self.loadByRef(elem_ptr, elem_ty, elem_ty.abiAlignment(target), false); | ||
| 5878 | } else { | 5675 | } else { |
| 5879 | const lhs_index = Air.refToIndex(bin_op.lhs).?; | 5676 | const lhs_index = Air.refToIndex(bin_op.lhs).?; |
| 5880 | const elem_llvm_ty = try self.dg.lowerType(elem_ty); | 5677 | const elem_llvm_ty = try self.dg.lowerType(elem_ty); |
| ... | @@ -5901,15 +5698,16 @@ pub const FuncGen = struct { | ... | @@ -5901,15 +5698,16 @@ pub const FuncGen = struct { |
| 5901 | } | 5698 | } |
| 5902 | 5699 | ||
| 5903 | fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { | 5700 | fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5701 | const mod = self.dg.module; | ||
| 5904 | const inst = body_tail[0]; | 5702 | const inst = body_tail[0]; |
| 5905 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 5703 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 5906 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 5704 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 5907 | const elem_ty = ptr_ty.childType(); | 5705 | const elem_ty = ptr_ty.childType(mod); |
| 5908 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); | 5706 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); |
| 5909 | const base_ptr = try self.resolveInst(bin_op.lhs); | 5707 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 5910 | const rhs = try self.resolveInst(bin_op.rhs); | 5708 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5911 | // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch | 5709 | // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch |
| 5912 | const ptr = if (ptr_ty.isSinglePointer()) ptr: { | 5710 | const ptr = if (ptr_ty.isSinglePointer(mod)) ptr: { |
| 5913 | // If this is a single-item pointer to an array, we need another index in the GEP. | 5711 | // If this is a single-item pointer to an array, we need another index in the GEP. |
| 5914 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs }; | 5712 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs }; |
| 5915 | break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 5713 | break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| ... | @@ -5917,32 +5715,32 @@ pub const FuncGen = struct { | ... | @@ -5917,32 +5715,32 @@ pub const FuncGen = struct { |
| 5917 | const indices: [1]*llvm.Value = .{rhs}; | 5715 | const indices: [1]*llvm.Value = .{rhs}; |
| 5918 | break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 5716 | break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| 5919 | }; | 5717 | }; |
| 5920 | if (isByRef(elem_ty)) { | 5718 | if (isByRef(elem_ty, mod)) { |
| 5921 | if (self.canElideLoad(body_tail)) | 5719 | if (self.canElideLoad(body_tail)) |
| 5922 | return ptr; | 5720 | return ptr; |
| 5923 | 5721 | ||
| 5924 | const target = self.dg.module.getTarget(); | 5722 | return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(mod), false); |
| 5925 | return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(target), false); | ||
| 5926 | } | 5723 | } |
| 5927 | 5724 | ||
| 5928 | return self.load(ptr, ptr_ty); | 5725 | return self.load(ptr, ptr_ty); |
| 5929 | } | 5726 | } |
| 5930 | 5727 | ||
| 5931 | fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5728 | fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5729 | const mod = self.dg.module; | ||
| 5932 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5730 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5933 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 5731 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 5934 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 5732 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 5935 | const elem_ty = ptr_ty.childType(); | 5733 | const elem_ty = ptr_ty.childType(mod); |
| 5936 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty); | 5734 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return self.dg.lowerPtrToVoid(ptr_ty); |
| 5937 | 5735 | ||
| 5938 | const base_ptr = try self.resolveInst(bin_op.lhs); | 5736 | const base_ptr = try self.resolveInst(bin_op.lhs); |
| 5939 | const rhs = try self.resolveInst(bin_op.rhs); | 5737 | const rhs = try self.resolveInst(bin_op.rhs); |
| 5940 | 5738 | ||
| 5941 | const elem_ptr = self.air.getRefType(ty_pl.ty); | 5739 | const elem_ptr = self.air.getRefType(ty_pl.ty); |
| 5942 | if (elem_ptr.ptrInfo().data.vector_index != .none) return base_ptr; | 5740 | if (elem_ptr.ptrInfo(mod).vector_index != .none) return base_ptr; |
| 5943 | 5741 | ||
| 5944 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); | 5742 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty); |
| 5945 | if (ptr_ty.isSinglePointer()) { | 5743 | if (ptr_ty.isSinglePointer(mod)) { |
| 5946 | // If this is a single-item pointer to an array, we need another index in the GEP. | 5744 | // If this is a single-item pointer to an array, we need another index in the GEP. |
| 5947 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs }; | 5745 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), rhs }; |
| 5948 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 5746 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); |
| ... | @@ -5956,7 +5754,7 @@ pub const FuncGen = struct { | ... | @@ -5956,7 +5754,7 @@ pub const FuncGen = struct { |
| 5956 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5754 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5957 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; | 5755 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 5958 | const struct_ptr = try self.resolveInst(struct_field.struct_operand); | 5756 | const struct_ptr = try self.resolveInst(struct_field.struct_operand); |
| 5959 | const struct_ptr_ty = self.air.typeOf(struct_field.struct_operand); | 5757 | const struct_ptr_ty = self.typeOf(struct_field.struct_operand); |
| 5960 | return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, struct_field.field_index); | 5758 | return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, struct_field.field_index); |
| 5961 | } | 5759 | } |
| 5962 | 5760 | ||
| ... | @@ -5967,41 +5765,41 @@ pub const FuncGen = struct { | ... | @@ -5967,41 +5765,41 @@ pub const FuncGen = struct { |
| 5967 | ) !?*llvm.Value { | 5765 | ) !?*llvm.Value { |
| 5968 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5766 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5969 | const struct_ptr = try self.resolveInst(ty_op.operand); | 5767 | const struct_ptr = try self.resolveInst(ty_op.operand); |
| 5970 | const struct_ptr_ty = self.air.typeOf(ty_op.operand); | 5768 | const struct_ptr_ty = self.typeOf(ty_op.operand); |
| 5971 | return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index); | 5769 | return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index); |
| 5972 | } | 5770 | } |
| 5973 | 5771 | ||
| 5974 | fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { | 5772 | fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 5773 | const mod = self.dg.module; | ||
| 5975 | const inst = body_tail[0]; | 5774 | const inst = body_tail[0]; |
| 5976 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5775 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 5977 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; | 5776 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 5978 | const struct_ty = self.air.typeOf(struct_field.struct_operand); | 5777 | const struct_ty = self.typeOf(struct_field.struct_operand); |
| 5979 | const struct_llvm_val = try self.resolveInst(struct_field.struct_operand); | 5778 | const struct_llvm_val = try self.resolveInst(struct_field.struct_operand); |
| 5980 | const field_index = struct_field.field_index; | 5779 | const field_index = struct_field.field_index; |
| 5981 | const field_ty = struct_ty.structFieldType(field_index); | 5780 | const field_ty = struct_ty.structFieldType(field_index, mod); |
| 5982 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) { | 5781 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 5983 | return null; | 5782 | return null; |
| 5984 | } | 5783 | } |
| 5985 | const target = self.dg.module.getTarget(); | ||
| 5986 | 5784 | ||
| 5987 | if (!isByRef(struct_ty)) { | 5785 | if (!isByRef(struct_ty, mod)) { |
| 5988 | assert(!isByRef(field_ty)); | 5786 | assert(!isByRef(field_ty, mod)); |
| 5989 | switch (struct_ty.zigTypeTag()) { | 5787 | switch (struct_ty.zigTypeTag(mod)) { |
| 5990 | .Struct => switch (struct_ty.containerLayout()) { | 5788 | .Struct => switch (struct_ty.containerLayout(mod)) { |
| 5991 | .Packed => { | 5789 | .Packed => { |
| 5992 | const struct_obj = struct_ty.castTag(.@"struct").?.data; | 5790 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| 5993 | const bit_offset = struct_obj.packedFieldBitOffset(target, field_index); | 5791 | const bit_offset = struct_obj.packedFieldBitOffset(mod, field_index); |
| 5994 | const containing_int = struct_llvm_val; | 5792 | const containing_int = struct_llvm_val; |
| 5995 | const shift_amt = containing_int.typeOf().constInt(bit_offset, .False); | 5793 | const shift_amt = containing_int.typeOf().constInt(bit_offset, .False); |
| 5996 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt, ""); | 5794 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt, ""); |
| 5997 | const elem_llvm_ty = try self.dg.lowerType(field_ty); | 5795 | const elem_llvm_ty = try self.dg.lowerType(field_ty); |
| 5998 | if (field_ty.zigTypeTag() == .Float or field_ty.zigTypeTag() == .Vector) { | 5796 | if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) { |
| 5999 | const elem_bits = @intCast(c_uint, field_ty.bitSize(target)); | 5797 | const elem_bits = @intCast(c_uint, field_ty.bitSize(mod)); |
| 6000 | const same_size_int = self.context.intType(elem_bits); | 5798 | const same_size_int = self.context.intType(elem_bits); |
| 6001 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); | 5799 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| 6002 | return self.builder.buildBitCast(truncated_int, elem_llvm_ty, ""); | 5800 | return self.builder.buildBitCast(truncated_int, elem_llvm_ty, ""); |
| 6003 | } else if (field_ty.isPtrAtRuntime()) { | 5801 | } else if (field_ty.isPtrAtRuntime(mod)) { |
| 6004 | const elem_bits = @intCast(c_uint, field_ty.bitSize(target)); | 5802 | const elem_bits = @intCast(c_uint, field_ty.bitSize(mod)); |
| 6005 | const same_size_int = self.context.intType(elem_bits); | 5803 | const same_size_int = self.context.intType(elem_bits); |
| 6006 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); | 5804 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| 6007 | return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, ""); | 5805 | return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, ""); |
| ... | @@ -6009,22 +5807,21 @@ pub const FuncGen = struct { | ... | @@ -6009,22 +5807,21 @@ pub const FuncGen = struct { |
| 6009 | return self.builder.buildTrunc(shifted_value, elem_llvm_ty, ""); | 5807 | return self.builder.buildTrunc(shifted_value, elem_llvm_ty, ""); |
| 6010 | }, | 5808 | }, |
| 6011 | else => { | 5809 | else => { |
| 6012 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | 5810 | const llvm_field_index = llvmField(struct_ty, field_index, mod).?.index; |
| 6013 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?; | ||
| 6014 | return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, ""); | 5811 | return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, ""); |
| 6015 | }, | 5812 | }, |
| 6016 | }, | 5813 | }, |
| 6017 | .Union => { | 5814 | .Union => { |
| 6018 | assert(struct_ty.containerLayout() == .Packed); | 5815 | assert(struct_ty.containerLayout(mod) == .Packed); |
| 6019 | const containing_int = struct_llvm_val; | 5816 | const containing_int = struct_llvm_val; |
| 6020 | const elem_llvm_ty = try self.dg.lowerType(field_ty); | 5817 | const elem_llvm_ty = try self.dg.lowerType(field_ty); |
| 6021 | if (field_ty.zigTypeTag() == .Float or field_ty.zigTypeTag() == .Vector) { | 5818 | if (field_ty.zigTypeTag(mod) == .Float or field_ty.zigTypeTag(mod) == .Vector) { |
| 6022 | const elem_bits = @intCast(c_uint, field_ty.bitSize(target)); | 5819 | const elem_bits = @intCast(c_uint, field_ty.bitSize(mod)); |
| 6023 | const same_size_int = self.context.intType(elem_bits); | 5820 | const same_size_int = self.context.intType(elem_bits); |
| 6024 | const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, ""); | 5821 | const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, ""); |
| 6025 | return self.builder.buildBitCast(truncated_int, elem_llvm_ty, ""); | 5822 | return self.builder.buildBitCast(truncated_int, elem_llvm_ty, ""); |
| 6026 | } else if (field_ty.isPtrAtRuntime()) { | 5823 | } else if (field_ty.isPtrAtRuntime(mod)) { |
| 6027 | const elem_bits = @intCast(c_uint, field_ty.bitSize(target)); | 5824 | const elem_bits = @intCast(c_uint, field_ty.bitSize(mod)); |
| 6028 | const same_size_int = self.context.intType(elem_bits); | 5825 | const same_size_int = self.context.intType(elem_bits); |
| 6029 | const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, ""); | 5826 | const truncated_int = self.builder.buildTrunc(containing_int, same_size_int, ""); |
| 6030 | return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, ""); | 5827 | return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, ""); |
| ... | @@ -6035,30 +5832,35 @@ pub const FuncGen = struct { | ... | @@ -6035,30 +5832,35 @@ pub const FuncGen = struct { |
| 6035 | } | 5832 | } |
| 6036 | } | 5833 | } |
| 6037 | 5834 | ||
| 6038 | switch (struct_ty.zigTypeTag()) { | 5835 | switch (struct_ty.zigTypeTag(mod)) { |
| 6039 | .Struct => { | 5836 | .Struct => { |
| 6040 | assert(struct_ty.containerLayout() != .Packed); | 5837 | assert(struct_ty.containerLayout(mod) != .Packed); |
| 6041 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | 5838 | const llvm_field = llvmField(struct_ty, field_index, mod).?; |
| 6042 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?; | ||
| 6043 | const struct_llvm_ty = try self.dg.lowerType(struct_ty); | 5839 | const struct_llvm_ty = try self.dg.lowerType(struct_ty); |
| 6044 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field_index, ""); | 5840 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field.index, ""); |
| 6045 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); | 5841 | const field_ptr_ty = try mod.ptrType(.{ |
| 6046 | if (isByRef(field_ty)) { | 5842 | .child = llvm_field.ty.toIntern(), |
| 5843 | .flags = .{ | ||
| 5844 | .alignment = InternPool.Alignment.fromNonzeroByteUnits(llvm_field.alignment), | ||
| 5845 | }, | ||
| 5846 | }); | ||
| 5847 | if (isByRef(field_ty, mod)) { | ||
| 6047 | if (canElideLoad(self, body_tail)) | 5848 | if (canElideLoad(self, body_tail)) |
| 6048 | return field_ptr; | 5849 | return field_ptr; |
| 6049 | 5850 | ||
| 6050 | return self.loadByRef(field_ptr, field_ty, ptr_ty_buf.data.alignment(target), false); | 5851 | assert(llvm_field.alignment != 0); |
| 5852 | return self.loadByRef(field_ptr, field_ty, llvm_field.alignment, false); | ||
| 6051 | } else { | 5853 | } else { |
| 6052 | return self.load(field_ptr, field_ptr_ty); | 5854 | return self.load(field_ptr, field_ptr_ty); |
| 6053 | } | 5855 | } |
| 6054 | }, | 5856 | }, |
| 6055 | .Union => { | 5857 | .Union => { |
| 6056 | const union_llvm_ty = try self.dg.lowerType(struct_ty); | 5858 | const union_llvm_ty = try self.dg.lowerType(struct_ty); |
| 6057 | const layout = struct_ty.unionGetLayout(target); | 5859 | const layout = struct_ty.unionGetLayout(mod); |
| 6058 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); | 5860 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); |
| 6059 | const field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_llvm_val, payload_index, ""); | 5861 | const field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_llvm_val, payload_index, ""); |
| 6060 | const llvm_field_ty = try self.dg.lowerType(field_ty); | 5862 | const llvm_field_ty = try self.dg.lowerType(field_ty); |
| 6061 | if (isByRef(field_ty)) { | 5863 | if (isByRef(field_ty, mod)) { |
| 6062 | if (canElideLoad(self, body_tail)) | 5864 | if (canElideLoad(self, body_tail)) |
| 6063 | return field_ptr; | 5865 | return field_ptr; |
| 6064 | 5866 | ||
| ... | @@ -6072,14 +5874,15 @@ pub const FuncGen = struct { | ... | @@ -6072,14 +5874,15 @@ pub const FuncGen = struct { |
| 6072 | } | 5874 | } |
| 6073 | 5875 | ||
| 6074 | fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5876 | fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 5877 | const mod = self.dg.module; | ||
| 6075 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5878 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 6076 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; | 5879 | const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 6077 | 5880 | ||
| 6078 | const field_ptr = try self.resolveInst(extra.field_ptr); | 5881 | const field_ptr = try self.resolveInst(extra.field_ptr); |
| 6079 | 5882 | ||
| 6080 | const target = self.dg.module.getTarget(); | 5883 | const target = self.dg.module.getTarget(); |
| 6081 | const parent_ty = self.air.getRefType(ty_pl.ty).childType(); | 5884 | const parent_ty = self.air.getRefType(ty_pl.ty).childType(mod); |
| 6082 | const field_offset = parent_ty.structFieldOffset(extra.field_index, target); | 5885 | const field_offset = parent_ty.structFieldOffset(extra.field_index, mod); |
| 6083 | 5886 | ||
| 6084 | const res_ty = try self.dg.lowerType(self.air.getRefType(ty_pl.ty)); | 5887 | const res_ty = try self.dg.lowerType(self.air.getRefType(ty_pl.ty)); |
| 6085 | if (field_offset == 0) { | 5888 | if (field_offset == 0) { |
| ... | @@ -6120,12 +5923,13 @@ pub const FuncGen = struct { | ... | @@ -6120,12 +5923,13 @@ pub const FuncGen = struct { |
| 6120 | 5923 | ||
| 6121 | fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5924 | fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6122 | const dib = self.dg.object.di_builder orelse return null; | 5925 | const dib = self.dg.object.di_builder orelse return null; |
| 6123 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5926 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; |
| 6124 | 5927 | ||
| 6125 | const func = self.air.values[ty_pl.payload].castTag(.function).?.data; | 5928 | const mod = self.dg.module; |
| 5929 | const func = mod.funcPtr(ty_fn.func); | ||
| 6126 | const decl_index = func.owner_decl; | 5930 | const decl_index = func.owner_decl; |
| 6127 | const decl = self.dg.module.declPtr(decl_index); | 5931 | const decl = mod.declPtr(decl_index); |
| 6128 | const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope); | 5932 | const di_file = try self.dg.object.getDIFile(self.gpa, mod.namespacePtr(decl.src_namespace).file_scope); |
| 6129 | self.di_file = di_file; | 5933 | self.di_file = di_file; |
| 6130 | const line_number = decl.src_line + 1; | 5934 | const line_number = decl.src_line + 1; |
| 6131 | const cur_debug_location = self.builder.getCurrentDebugLocation2(); | 5935 | const cur_debug_location = self.builder.getCurrentDebugLocation2(); |
| ... | @@ -6136,22 +5940,37 @@ pub const FuncGen = struct { | ... | @@ -6136,22 +5940,37 @@ pub const FuncGen = struct { |
| 6136 | .base_line = self.base_line, | 5940 | .base_line = self.base_line, |
| 6137 | }); | 5941 | }); |
| 6138 | 5942 | ||
| 6139 | const fqn = try decl.getFullyQualifiedName(self.dg.module); | 5943 | const fqn = try decl.getFullyQualifiedName(mod); |
| 6140 | defer self.gpa.free(fqn); | 5944 | |
| 6141 | 5945 | const is_internal_linkage = !mod.decl_exports.contains(decl_index); | |
| 6142 | const is_internal_linkage = !self.dg.module.decl_exports.contains(decl_index); | 5946 | const fn_ty = try mod.funcType(.{ |
| 5947 | .param_types = &.{}, | ||
| 5948 | .return_type = .void_type, | ||
| 5949 | .alignment = .none, | ||
| 5950 | .noalias_bits = 0, | ||
| 5951 | .comptime_bits = 0, | ||
| 5952 | .cc = .Unspecified, | ||
| 5953 | .is_var_args = false, | ||
| 5954 | .is_generic = false, | ||
| 5955 | .is_noinline = false, | ||
| 5956 | .align_is_generic = false, | ||
| 5957 | .cc_is_generic = false, | ||
| 5958 | .section_is_generic = false, | ||
| 5959 | .addrspace_is_generic = false, | ||
| 5960 | }); | ||
| 5961 | const fn_di_ty = try self.dg.object.lowerDebugType(fn_ty, .full); | ||
| 6143 | const subprogram = dib.createFunction( | 5962 | const subprogram = dib.createFunction( |
| 6144 | di_file.toScope(), | 5963 | di_file.toScope(), |
| 6145 | decl.name, | 5964 | mod.intern_pool.stringToSlice(decl.name), |
| 6146 | fqn, | 5965 | mod.intern_pool.stringToSlice(fqn), |
| 6147 | di_file, | 5966 | di_file, |
| 6148 | line_number, | 5967 | line_number, |
| 6149 | try self.dg.object.lowerDebugType(Type.initTag(.fn_void_no_args), .full), | 5968 | fn_di_ty, |
| 6150 | is_internal_linkage, | 5969 | is_internal_linkage, |
| 6151 | true, // is definition | 5970 | true, // is definition |
| 6152 | line_number + func.lbrace_line, // scope line | 5971 | line_number + func.lbrace_line, // scope line |
| 6153 | llvm.DIFlags.StaticMember, | 5972 | llvm.DIFlags.StaticMember, |
| 6154 | self.dg.module.comp.bin_file.options.optimize_mode != .Debug, | 5973 | mod.comp.bin_file.options.optimize_mode != .Debug, |
| 6155 | null, // decl_subprogram | 5974 | null, // decl_subprogram |
| 6156 | ); | 5975 | ); |
| 6157 | 5976 | ||
| ... | @@ -6163,12 +5982,12 @@ pub const FuncGen = struct { | ... | @@ -6163,12 +5982,12 @@ pub const FuncGen = struct { |
| 6163 | 5982 | ||
| 6164 | fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 5983 | fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6165 | if (self.dg.object.di_builder == null) return null; | 5984 | if (self.dg.object.di_builder == null) return null; |
| 6166 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 5985 | const ty_fn = self.air.instructions.items(.data)[inst].ty_fn; |
| 6167 | 5986 | ||
| 6168 | const func = self.air.values[ty_pl.payload].castTag(.function).?.data; | ||
| 6169 | const mod = self.dg.module; | 5987 | const mod = self.dg.module; |
| 5988 | const func = mod.funcPtr(ty_fn.func); | ||
| 6170 | const decl = mod.declPtr(func.owner_decl); | 5989 | const decl = mod.declPtr(func.owner_decl); |
| 6171 | const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope); | 5990 | const di_file = try self.dg.object.getDIFile(self.gpa, mod.namespacePtr(decl.src_namespace).file_scope); |
| 6172 | self.di_file = di_file; | 5991 | self.di_file = di_file; |
| 6173 | const old = self.dbg_inlined.pop(); | 5992 | const old = self.dbg_inlined.pop(); |
| 6174 | self.di_scope = old.scope; | 5993 | self.di_scope = old.scope; |
| ... | @@ -6192,18 +6011,19 @@ pub const FuncGen = struct { | ... | @@ -6192,18 +6011,19 @@ pub const FuncGen = struct { |
| 6192 | } | 6011 | } |
| 6193 | 6012 | ||
| 6194 | fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6013 | fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6014 | const mod = self.dg.module; | ||
| 6195 | const dib = self.dg.object.di_builder orelse return null; | 6015 | const dib = self.dg.object.di_builder orelse return null; |
| 6196 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 6016 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 6197 | const operand = try self.resolveInst(pl_op.operand); | 6017 | const operand = try self.resolveInst(pl_op.operand); |
| 6198 | const name = self.air.nullTerminatedString(pl_op.payload); | 6018 | const name = self.air.nullTerminatedString(pl_op.payload); |
| 6199 | const ptr_ty = self.air.typeOf(pl_op.operand); | 6019 | const ptr_ty = self.typeOf(pl_op.operand); |
| 6200 | 6020 | ||
| 6201 | const di_local_var = dib.createAutoVariable( | 6021 | const di_local_var = dib.createAutoVariable( |
| 6202 | self.di_scope.?, | 6022 | self.di_scope.?, |
| 6203 | name.ptr, | 6023 | name.ptr, |
| 6204 | self.di_file.?, | 6024 | self.di_file.?, |
| 6205 | self.prev_dbg_line, | 6025 | self.prev_dbg_line, |
| 6206 | try self.dg.object.lowerDebugType(ptr_ty.childType(), .full), | 6026 | try self.dg.object.lowerDebugType(ptr_ty.childType(mod), .full), |
| 6207 | true, // always preserve | 6027 | true, // always preserve |
| 6208 | 0, // flags | 6028 | 0, // flags |
| 6209 | ); | 6029 | ); |
| ... | @@ -6221,7 +6041,7 @@ pub const FuncGen = struct { | ... | @@ -6221,7 +6041,7 @@ pub const FuncGen = struct { |
| 6221 | const dib = self.dg.object.di_builder orelse return null; | 6041 | const dib = self.dg.object.di_builder orelse return null; |
| 6222 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 6042 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 6223 | const operand = try self.resolveInst(pl_op.operand); | 6043 | const operand = try self.resolveInst(pl_op.operand); |
| 6224 | const operand_ty = self.air.typeOf(pl_op.operand); | 6044 | const operand_ty = self.typeOf(pl_op.operand); |
| 6225 | const name = self.air.nullTerminatedString(pl_op.payload); | 6045 | const name = self.air.nullTerminatedString(pl_op.payload); |
| 6226 | 6046 | ||
| 6227 | if (needDbgVarWorkaround(self.dg)) { | 6047 | if (needDbgVarWorkaround(self.dg)) { |
| ... | @@ -6243,10 +6063,11 @@ pub const FuncGen = struct { | ... | @@ -6243,10 +6063,11 @@ pub const FuncGen = struct { |
| 6243 | null; | 6063 | null; |
| 6244 | const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at); | 6064 | const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at); |
| 6245 | const insert_block = self.builder.getInsertBlock(); | 6065 | const insert_block = self.builder.getInsertBlock(); |
| 6246 | if (isByRef(operand_ty)) { | 6066 | const mod = self.dg.module; |
| 6067 | if (isByRef(operand_ty, mod)) { | ||
| 6247 | _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block); | 6068 | _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block); |
| 6248 | } else if (self.dg.module.comp.bin_file.options.optimize_mode == .Debug) { | 6069 | } else if (self.dg.module.comp.bin_file.options.optimize_mode == .Debug) { |
| 6249 | const alignment = operand_ty.abiAlignment(self.dg.module.getTarget()); | 6070 | const alignment = operand_ty.abiAlignment(mod); |
| 6250 | const alloca = self.buildAlloca(operand.typeOf(), alignment); | 6071 | const alloca = self.buildAlloca(operand.typeOf(), alignment); |
| 6251 | const store_inst = self.builder.buildStore(operand, alloca); | 6072 | const store_inst = self.builder.buildStore(operand, alloca); |
| 6252 | store_inst.setAlignment(alignment); | 6073 | store_inst.setAlignment(alignment); |
| ... | @@ -6294,7 +6115,8 @@ pub const FuncGen = struct { | ... | @@ -6294,7 +6115,8 @@ pub const FuncGen = struct { |
| 6294 | // This stores whether we need to add an elementtype attribute and | 6115 | // This stores whether we need to add an elementtype attribute and |
| 6295 | // if so, the element type itself. | 6116 | // if so, the element type itself. |
| 6296 | const llvm_param_attrs = try arena.alloc(?*llvm.Type, max_param_count); | 6117 | const llvm_param_attrs = try arena.alloc(?*llvm.Type, max_param_count); |
| 6297 | const target = self.dg.module.getTarget(); | 6118 | const mod = self.dg.module; |
| 6119 | const target = mod.getTarget(); | ||
| 6298 | 6120 | ||
| 6299 | var llvm_ret_i: usize = 0; | 6121 | var llvm_ret_i: usize = 0; |
| 6300 | var llvm_param_i: usize = 0; | 6122 | var llvm_param_i: usize = 0; |
| ... | @@ -6321,9 +6143,9 @@ pub const FuncGen = struct { | ... | @@ -6321,9 +6143,9 @@ pub const FuncGen = struct { |
| 6321 | llvm_ret_indirect[i] = (output != .none) and constraintAllowsMemory(constraint); | 6143 | llvm_ret_indirect[i] = (output != .none) and constraintAllowsMemory(constraint); |
| 6322 | if (output != .none) { | 6144 | if (output != .none) { |
| 6323 | const output_inst = try self.resolveInst(output); | 6145 | const output_inst = try self.resolveInst(output); |
| 6324 | const output_ty = self.air.typeOf(output); | 6146 | const output_ty = self.typeOf(output); |
| 6325 | assert(output_ty.zigTypeTag() == .Pointer); | 6147 | assert(output_ty.zigTypeTag(mod) == .Pointer); |
| 6326 | const elem_llvm_ty = try self.dg.lowerPtrElemTy(output_ty.childType()); | 6148 | const elem_llvm_ty = try self.dg.lowerPtrElemTy(output_ty.childType(mod)); |
| 6327 | 6149 | ||
| 6328 | if (llvm_ret_indirect[i]) { | 6150 | if (llvm_ret_indirect[i]) { |
| 6329 | // Pass the result by reference as an indirect output (e.g. "=*m") | 6151 | // Pass the result by reference as an indirect output (e.g. "=*m") |
| ... | @@ -6339,7 +6161,7 @@ pub const FuncGen = struct { | ... | @@ -6339,7 +6161,7 @@ pub const FuncGen = struct { |
| 6339 | llvm_ret_i += 1; | 6161 | llvm_ret_i += 1; |
| 6340 | } | 6162 | } |
| 6341 | } else { | 6163 | } else { |
| 6342 | const ret_ty = self.air.typeOfIndex(inst); | 6164 | const ret_ty = self.typeOfIndex(inst); |
| 6343 | llvm_ret_types[llvm_ret_i] = try self.dg.lowerType(ret_ty); | 6165 | llvm_ret_types[llvm_ret_i] = try self.dg.lowerType(ret_ty); |
| 6344 | llvm_ret_i += 1; | 6166 | llvm_ret_i += 1; |
| 6345 | } | 6167 | } |
| ... | @@ -6374,15 +6196,15 @@ pub const FuncGen = struct { | ... | @@ -6374,15 +6196,15 @@ pub const FuncGen = struct { |
| 6374 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; | 6196 | extra_i += (constraint.len + name.len + (2 + 3)) / 4; |
| 6375 | 6197 | ||
| 6376 | const arg_llvm_value = try self.resolveInst(input); | 6198 | const arg_llvm_value = try self.resolveInst(input); |
| 6377 | const arg_ty = self.air.typeOf(input); | 6199 | const arg_ty = self.typeOf(input); |
| 6378 | var llvm_elem_ty: ?*llvm.Type = null; | 6200 | var llvm_elem_ty: ?*llvm.Type = null; |
| 6379 | if (isByRef(arg_ty)) { | 6201 | if (isByRef(arg_ty, mod)) { |
| 6380 | llvm_elem_ty = try self.dg.lowerPtrElemTy(arg_ty); | 6202 | llvm_elem_ty = try self.dg.lowerPtrElemTy(arg_ty); |
| 6381 | if (constraintAllowsMemory(constraint)) { | 6203 | if (constraintAllowsMemory(constraint)) { |
| 6382 | llvm_param_values[llvm_param_i] = arg_llvm_value; | 6204 | llvm_param_values[llvm_param_i] = arg_llvm_value; |
| 6383 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf(); | 6205 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf(); |
| 6384 | } else { | 6206 | } else { |
| 6385 | const alignment = arg_ty.abiAlignment(target); | 6207 | const alignment = arg_ty.abiAlignment(mod); |
| 6386 | const arg_llvm_ty = try self.dg.lowerType(arg_ty); | 6208 | const arg_llvm_ty = try self.dg.lowerType(arg_ty); |
| 6387 | const load_inst = self.builder.buildLoad(arg_llvm_ty, arg_llvm_value, ""); | 6209 | const load_inst = self.builder.buildLoad(arg_llvm_ty, arg_llvm_value, ""); |
| 6388 | load_inst.setAlignment(alignment); | 6210 | load_inst.setAlignment(alignment); |
| ... | @@ -6394,7 +6216,7 @@ pub const FuncGen = struct { | ... | @@ -6394,7 +6216,7 @@ pub const FuncGen = struct { |
| 6394 | llvm_param_values[llvm_param_i] = arg_llvm_value; | 6216 | llvm_param_values[llvm_param_i] = arg_llvm_value; |
| 6395 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf(); | 6217 | llvm_param_types[llvm_param_i] = arg_llvm_value.typeOf(); |
| 6396 | } else { | 6218 | } else { |
| 6397 | const alignment = arg_ty.abiAlignment(target); | 6219 | const alignment = arg_ty.abiAlignment(mod); |
| 6398 | const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf(), alignment); | 6220 | const arg_ptr = self.buildAlloca(arg_llvm_value.typeOf(), alignment); |
| 6399 | const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr); | 6221 | const store_inst = self.builder.buildStore(arg_llvm_value, arg_ptr); |
| 6400 | store_inst.setAlignment(alignment); | 6222 | store_inst.setAlignment(alignment); |
| ... | @@ -6424,7 +6246,7 @@ pub const FuncGen = struct { | ... | @@ -6424,7 +6246,7 @@ pub const FuncGen = struct { |
| 6424 | // an elementtype(<ty>) attribute. | 6246 | // an elementtype(<ty>) attribute. |
| 6425 | if (constraint[0] == '*') { | 6247 | if (constraint[0] == '*') { |
| 6426 | llvm_param_attrs[llvm_param_i] = llvm_elem_ty orelse | 6248 | llvm_param_attrs[llvm_param_i] = llvm_elem_ty orelse |
| 6427 | try self.dg.lowerPtrElemTy(arg_ty.childType()); | 6249 | try self.dg.lowerPtrElemTy(arg_ty.childType(mod)); |
| 6428 | } else { | 6250 | } else { |
| 6429 | llvm_param_attrs[llvm_param_i] = null; | 6251 | llvm_param_attrs[llvm_param_i] = null; |
| 6430 | } | 6252 | } |
| ... | @@ -6596,10 +6418,10 @@ pub const FuncGen = struct { | ... | @@ -6596,10 +6418,10 @@ pub const FuncGen = struct { |
| 6596 | 6418 | ||
| 6597 | if (output != .none) { | 6419 | if (output != .none) { |
| 6598 | const output_ptr = try self.resolveInst(output); | 6420 | const output_ptr = try self.resolveInst(output); |
| 6599 | const output_ptr_ty = self.air.typeOf(output); | 6421 | const output_ptr_ty = self.typeOf(output); |
| 6600 | 6422 | ||
| 6601 | const store_inst = self.builder.buildStore(output_value, output_ptr); | 6423 | const store_inst = self.builder.buildStore(output_value, output_ptr); |
| 6602 | store_inst.setAlignment(output_ptr_ty.ptrAlignment(target)); | 6424 | store_inst.setAlignment(output_ptr_ty.ptrAlignment(mod)); |
| 6603 | } else { | 6425 | } else { |
| 6604 | ret_val = output_value; | 6426 | ret_val = output_value; |
| 6605 | } | 6427 | } |
| ... | @@ -6615,22 +6437,21 @@ pub const FuncGen = struct { | ... | @@ -6615,22 +6437,21 @@ pub const FuncGen = struct { |
| 6615 | operand_is_ptr: bool, | 6437 | operand_is_ptr: bool, |
| 6616 | pred: llvm.IntPredicate, | 6438 | pred: llvm.IntPredicate, |
| 6617 | ) !?*llvm.Value { | 6439 | ) !?*llvm.Value { |
| 6440 | const mod = self.dg.module; | ||
| 6618 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6441 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6619 | const operand = try self.resolveInst(un_op); | 6442 | const operand = try self.resolveInst(un_op); |
| 6620 | const operand_ty = self.air.typeOf(un_op); | 6443 | const operand_ty = self.typeOf(un_op); |
| 6621 | const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | 6444 | const optional_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; |
| 6622 | const optional_llvm_ty = try self.dg.lowerType(optional_ty); | 6445 | const optional_llvm_ty = try self.dg.lowerType(optional_ty); |
| 6623 | var buf: Type.Payload.ElemType = undefined; | 6446 | const payload_ty = optional_ty.optionalChild(mod); |
| 6624 | const payload_ty = optional_ty.optionalChild(&buf); | 6447 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 6625 | if (optional_ty.optionalReprIsPayload()) { | ||
| 6626 | const loaded = if (operand_is_ptr) | 6448 | const loaded = if (operand_is_ptr) |
| 6627 | self.builder.buildLoad(optional_llvm_ty, operand, "") | 6449 | self.builder.buildLoad(optional_llvm_ty, operand, "") |
| 6628 | else | 6450 | else |
| 6629 | operand; | 6451 | operand; |
| 6630 | if (payload_ty.isSlice()) { | 6452 | if (payload_ty.isSlice(mod)) { |
| 6631 | const slice_ptr = self.builder.buildExtractValue(loaded, 0, ""); | 6453 | const slice_ptr = self.builder.buildExtractValue(loaded, 0, ""); |
| 6632 | var slice_buf: Type.SlicePtrFieldTypeBuffer = undefined; | 6454 | const ptr_ty = try self.dg.lowerType(payload_ty.slicePtrFieldType(mod)); |
| 6633 | const ptr_ty = try self.dg.lowerType(payload_ty.slicePtrFieldType(&slice_buf)); | ||
| 6634 | return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), ""); | 6455 | return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), ""); |
| 6635 | } | 6456 | } |
| 6636 | return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); | 6457 | return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); |
| ... | @@ -6638,7 +6459,7 @@ pub const FuncGen = struct { | ... | @@ -6638,7 +6459,7 @@ pub const FuncGen = struct { |
| 6638 | 6459 | ||
| 6639 | comptime assert(optional_layout_version == 3); | 6460 | comptime assert(optional_layout_version == 3); |
| 6640 | 6461 | ||
| 6641 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 6462 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6642 | const loaded = if (operand_is_ptr) | 6463 | const loaded = if (operand_is_ptr) |
| 6643 | self.builder.buildLoad(optional_llvm_ty, operand, "") | 6464 | self.builder.buildLoad(optional_llvm_ty, operand, "") |
| 6644 | else | 6465 | else |
| ... | @@ -6647,7 +6468,7 @@ pub const FuncGen = struct { | ... | @@ -6647,7 +6468,7 @@ pub const FuncGen = struct { |
| 6647 | return self.builder.buildICmp(pred, loaded, llvm_i8.constNull(), ""); | 6468 | return self.builder.buildICmp(pred, loaded, llvm_i8.constNull(), ""); |
| 6648 | } | 6469 | } |
| 6649 | 6470 | ||
| 6650 | const is_by_ref = operand_is_ptr or isByRef(optional_ty); | 6471 | const is_by_ref = operand_is_ptr or isByRef(optional_ty, mod); |
| 6651 | const non_null_bit = self.optIsNonNull(optional_llvm_ty, operand, is_by_ref); | 6472 | const non_null_bit = self.optIsNonNull(optional_llvm_ty, operand, is_by_ref); |
| 6652 | if (pred == .EQ) { | 6473 | if (pred == .EQ) { |
| 6653 | return self.builder.buildNot(non_null_bit, ""); | 6474 | return self.builder.buildNot(non_null_bit, ""); |
| ... | @@ -6662,15 +6483,16 @@ pub const FuncGen = struct { | ... | @@ -6662,15 +6483,16 @@ pub const FuncGen = struct { |
| 6662 | op: llvm.IntPredicate, | 6483 | op: llvm.IntPredicate, |
| 6663 | operand_is_ptr: bool, | 6484 | operand_is_ptr: bool, |
| 6664 | ) !?*llvm.Value { | 6485 | ) !?*llvm.Value { |
| 6486 | const mod = self.dg.module; | ||
| 6665 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6487 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6666 | const operand = try self.resolveInst(un_op); | 6488 | const operand = try self.resolveInst(un_op); |
| 6667 | const operand_ty = self.air.typeOf(un_op); | 6489 | const operand_ty = self.typeOf(un_op); |
| 6668 | const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | 6490 | const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; |
| 6669 | const payload_ty = err_union_ty.errorUnionPayload(); | 6491 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 6670 | const err_set_ty = try self.dg.lowerType(Type.anyerror); | 6492 | const err_set_ty = try self.dg.lowerType(Type.anyerror); |
| 6671 | const zero = err_set_ty.constNull(); | 6493 | const zero = err_set_ty.constNull(); |
| 6672 | 6494 | ||
| 6673 | if (err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 6495 | if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 6674 | const llvm_i1 = self.context.intType(1); | 6496 | const llvm_i1 = self.context.intType(1); |
| 6675 | switch (op) { | 6497 | switch (op) { |
| 6676 | .EQ => return llvm_i1.constInt(1, .False), // 0 == 0 | 6498 | .EQ => return llvm_i1.constInt(1, .False), // 0 == 0 |
| ... | @@ -6679,7 +6501,7 @@ pub const FuncGen = struct { | ... | @@ -6679,7 +6501,7 @@ pub const FuncGen = struct { |
| 6679 | } | 6501 | } |
| 6680 | } | 6502 | } |
| 6681 | 6503 | ||
| 6682 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 6504 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6683 | const loaded = if (operand_is_ptr) | 6505 | const loaded = if (operand_is_ptr) |
| 6684 | self.builder.buildLoad(try self.dg.lowerType(err_union_ty), operand, "") | 6506 | self.builder.buildLoad(try self.dg.lowerType(err_union_ty), operand, "") |
| 6685 | else | 6507 | else |
| ... | @@ -6687,10 +6509,9 @@ pub const FuncGen = struct { | ... | @@ -6687,10 +6509,9 @@ pub const FuncGen = struct { |
| 6687 | return self.builder.buildICmp(op, loaded, zero, ""); | 6509 | return self.builder.buildICmp(op, loaded, zero, ""); |
| 6688 | } | 6510 | } |
| 6689 | 6511 | ||
| 6690 | const target = self.dg.module.getTarget(); | 6512 | const err_field_index = errUnionErrorOffset(payload_ty, mod); |
| 6691 | const err_field_index = errUnionErrorOffset(payload_ty, target); | ||
| 6692 | 6513 | ||
| 6693 | if (operand_is_ptr or isByRef(err_union_ty)) { | 6514 | if (operand_is_ptr or isByRef(err_union_ty, mod)) { |
| 6694 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); | 6515 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); |
| 6695 | const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, err_field_index, ""); | 6516 | const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, err_field_index, ""); |
| 6696 | const loaded = self.builder.buildLoad(err_set_ty, err_field_ptr, ""); | 6517 | const loaded = self.builder.buildLoad(err_set_ty, err_field_ptr, ""); |
| ... | @@ -6702,17 +6523,17 @@ pub const FuncGen = struct { | ... | @@ -6702,17 +6523,17 @@ pub const FuncGen = struct { |
| 6702 | } | 6523 | } |
| 6703 | 6524 | ||
| 6704 | fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6525 | fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6526 | const mod = self.dg.module; | ||
| 6705 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 6527 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6706 | const operand = try self.resolveInst(ty_op.operand); | 6528 | const operand = try self.resolveInst(ty_op.operand); |
| 6707 | const optional_ty = self.air.typeOf(ty_op.operand).childType(); | 6529 | const optional_ty = self.typeOf(ty_op.operand).childType(mod); |
| 6708 | var buf: Type.Payload.ElemType = undefined; | 6530 | const payload_ty = optional_ty.optionalChild(mod); |
| 6709 | const payload_ty = optional_ty.optionalChild(&buf); | 6531 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6710 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 6711 | // We have a pointer to a zero-bit value and we need to return | 6532 | // We have a pointer to a zero-bit value and we need to return |
| 6712 | // a pointer to a zero-bit value. | 6533 | // a pointer to a zero-bit value. |
| 6713 | return operand; | 6534 | return operand; |
| 6714 | } | 6535 | } |
| 6715 | if (optional_ty.optionalReprIsPayload()) { | 6536 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 6716 | // The payload and the optional are the same value. | 6537 | // The payload and the optional are the same value. |
| 6717 | return operand; | 6538 | return operand; |
| 6718 | } | 6539 | } |
| ... | @@ -6723,18 +6544,18 @@ pub const FuncGen = struct { | ... | @@ -6723,18 +6544,18 @@ pub const FuncGen = struct { |
| 6723 | fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6544 | fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6724 | comptime assert(optional_layout_version == 3); | 6545 | comptime assert(optional_layout_version == 3); |
| 6725 | 6546 | ||
| 6547 | const mod = self.dg.module; | ||
| 6726 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 6548 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6727 | const operand = try self.resolveInst(ty_op.operand); | 6549 | const operand = try self.resolveInst(ty_op.operand); |
| 6728 | const optional_ty = self.air.typeOf(ty_op.operand).childType(); | 6550 | const optional_ty = self.typeOf(ty_op.operand).childType(mod); |
| 6729 | var buf: Type.Payload.ElemType = undefined; | 6551 | const payload_ty = optional_ty.optionalChild(mod); |
| 6730 | const payload_ty = optional_ty.optionalChild(&buf); | ||
| 6731 | const non_null_bit = self.context.intType(8).constInt(1, .False); | 6552 | const non_null_bit = self.context.intType(8).constInt(1, .False); |
| 6732 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 6553 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6733 | // We have a pointer to a i8. We need to set it to 1 and then return the same pointer. | 6554 | // We have a pointer to a i8. We need to set it to 1 and then return the same pointer. |
| 6734 | _ = self.builder.buildStore(non_null_bit, operand); | 6555 | _ = self.builder.buildStore(non_null_bit, operand); |
| 6735 | return operand; | 6556 | return operand; |
| 6736 | } | 6557 | } |
| 6737 | if (optional_ty.optionalReprIsPayload()) { | 6558 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 6738 | // The payload and the optional are the same value. | 6559 | // The payload and the optional are the same value. |
| 6739 | // Setting to non-null will be done when the payload is set. | 6560 | // Setting to non-null will be done when the payload is set. |
| 6740 | return operand; | 6561 | return operand; |
| ... | @@ -6754,20 +6575,21 @@ pub const FuncGen = struct { | ... | @@ -6754,20 +6575,21 @@ pub const FuncGen = struct { |
| 6754 | } | 6575 | } |
| 6755 | 6576 | ||
| 6756 | fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { | 6577 | fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 6578 | const mod = self.dg.module; | ||
| 6757 | const inst = body_tail[0]; | 6579 | const inst = body_tail[0]; |
| 6758 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 6580 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6759 | const operand = try self.resolveInst(ty_op.operand); | 6581 | const operand = try self.resolveInst(ty_op.operand); |
| 6760 | const optional_ty = self.air.typeOf(ty_op.operand); | 6582 | const optional_ty = self.typeOf(ty_op.operand); |
| 6761 | const payload_ty = self.air.typeOfIndex(inst); | 6583 | const payload_ty = self.typeOfIndex(inst); |
| 6762 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null; | 6584 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; |
| 6763 | 6585 | ||
| 6764 | if (optional_ty.optionalReprIsPayload()) { | 6586 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 6765 | // Payload value is the same as the optional value. | 6587 | // Payload value is the same as the optional value. |
| 6766 | return operand; | 6588 | return operand; |
| 6767 | } | 6589 | } |
| 6768 | 6590 | ||
| 6769 | const opt_llvm_ty = try self.dg.lowerType(optional_ty); | 6591 | const opt_llvm_ty = try self.dg.lowerType(optional_ty); |
| 6770 | const can_elide_load = if (isByRef(payload_ty)) self.canElideLoad(body_tail) else false; | 6592 | const can_elide_load = if (isByRef(payload_ty, mod)) self.canElideLoad(body_tail) else false; |
| 6771 | return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, can_elide_load); | 6593 | return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, can_elide_load); |
| 6772 | } | 6594 | } |
| 6773 | 6595 | ||
| ... | @@ -6776,32 +6598,32 @@ pub const FuncGen = struct { | ... | @@ -6776,32 +6598,32 @@ pub const FuncGen = struct { |
| 6776 | body_tail: []const Air.Inst.Index, | 6598 | body_tail: []const Air.Inst.Index, |
| 6777 | operand_is_ptr: bool, | 6599 | operand_is_ptr: bool, |
| 6778 | ) !?*llvm.Value { | 6600 | ) !?*llvm.Value { |
| 6601 | const mod = self.dg.module; | ||
| 6779 | const inst = body_tail[0]; | 6602 | const inst = body_tail[0]; |
| 6780 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 6603 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6781 | const operand = try self.resolveInst(ty_op.operand); | 6604 | const operand = try self.resolveInst(ty_op.operand); |
| 6782 | const operand_ty = self.air.typeOf(ty_op.operand); | 6605 | const operand_ty = self.typeOf(ty_op.operand); |
| 6783 | const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | 6606 | const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; |
| 6784 | const result_ty = self.air.typeOfIndex(inst); | 6607 | const result_ty = self.typeOfIndex(inst); |
| 6785 | const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty; | 6608 | const payload_ty = if (operand_is_ptr) result_ty.childType(mod) else result_ty; |
| 6786 | const target = self.dg.module.getTarget(); | ||
| 6787 | 6609 | ||
| 6788 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 6610 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6789 | return if (operand_is_ptr) operand else null; | 6611 | return if (operand_is_ptr) operand else null; |
| 6790 | } | 6612 | } |
| 6791 | const offset = errUnionPayloadOffset(payload_ty, target); | 6613 | const offset = errUnionPayloadOffset(payload_ty, mod); |
| 6792 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); | 6614 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); |
| 6793 | if (operand_is_ptr) { | 6615 | if (operand_is_ptr) { |
| 6794 | return self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, ""); | 6616 | return self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, ""); |
| 6795 | } else if (isByRef(err_union_ty)) { | 6617 | } else if (isByRef(err_union_ty, mod)) { |
| 6796 | const payload_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, ""); | 6618 | const payload_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, ""); |
| 6797 | if (isByRef(payload_ty)) { | 6619 | if (isByRef(payload_ty, mod)) { |
| 6798 | if (self.canElideLoad(body_tail)) | 6620 | if (self.canElideLoad(body_tail)) |
| 6799 | return payload_ptr; | 6621 | return payload_ptr; |
| 6800 | 6622 | ||
| 6801 | return self.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(target), false); | 6623 | return self.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(mod), false); |
| 6802 | } | 6624 | } |
| 6803 | const load_inst = self.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, ""); | 6625 | const load_inst = self.builder.buildLoad(err_union_llvm_ty.structGetTypeAtIndex(offset), payload_ptr, ""); |
| 6804 | load_inst.setAlignment(payload_ty.abiAlignment(target)); | 6626 | load_inst.setAlignment(payload_ty.abiAlignment(mod)); |
| 6805 | return load_inst; | 6627 | return load_inst; |
| 6806 | } | 6628 | } |
| 6807 | return self.builder.buildExtractValue(operand, offset, ""); | 6629 | return self.builder.buildExtractValue(operand, offset, ""); |
| ... | @@ -6812,11 +6634,12 @@ pub const FuncGen = struct { | ... | @@ -6812,11 +6634,12 @@ pub const FuncGen = struct { |
| 6812 | inst: Air.Inst.Index, | 6634 | inst: Air.Inst.Index, |
| 6813 | operand_is_ptr: bool, | 6635 | operand_is_ptr: bool, |
| 6814 | ) !?*llvm.Value { | 6636 | ) !?*llvm.Value { |
| 6637 | const mod = self.dg.module; | ||
| 6815 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 6638 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6816 | const operand = try self.resolveInst(ty_op.operand); | 6639 | const operand = try self.resolveInst(ty_op.operand); |
| 6817 | const operand_ty = self.air.typeOf(ty_op.operand); | 6640 | const operand_ty = self.typeOf(ty_op.operand); |
| 6818 | const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | 6641 | const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty; |
| 6819 | if (err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 6642 | if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 6820 | const err_llvm_ty = try self.dg.lowerType(Type.anyerror); | 6643 | const err_llvm_ty = try self.dg.lowerType(Type.anyerror); |
| 6821 | if (operand_is_ptr) { | 6644 | if (operand_is_ptr) { |
| 6822 | return operand; | 6645 | return operand; |
| ... | @@ -6827,16 +6650,15 @@ pub const FuncGen = struct { | ... | @@ -6827,16 +6650,15 @@ pub const FuncGen = struct { |
| 6827 | 6650 | ||
| 6828 | const err_set_llvm_ty = try self.dg.lowerType(Type.anyerror); | 6651 | const err_set_llvm_ty = try self.dg.lowerType(Type.anyerror); |
| 6829 | 6652 | ||
| 6830 | const payload_ty = err_union_ty.errorUnionPayload(); | 6653 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 6831 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 6654 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6832 | if (!operand_is_ptr) return operand; | 6655 | if (!operand_is_ptr) return operand; |
| 6833 | return self.builder.buildLoad(err_set_llvm_ty, operand, ""); | 6656 | return self.builder.buildLoad(err_set_llvm_ty, operand, ""); |
| 6834 | } | 6657 | } |
| 6835 | 6658 | ||
| 6836 | const target = self.dg.module.getTarget(); | 6659 | const offset = errUnionErrorOffset(payload_ty, mod); |
| 6837 | const offset = errUnionErrorOffset(payload_ty, target); | ||
| 6838 | 6660 | ||
| 6839 | if (operand_is_ptr or isByRef(err_union_ty)) { | 6661 | if (operand_is_ptr or isByRef(err_union_ty, mod)) { |
| 6840 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); | 6662 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); |
| 6841 | const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, ""); | 6663 | const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, ""); |
| 6842 | return self.builder.buildLoad(err_set_llvm_ty, err_field_ptr, ""); | 6664 | return self.builder.buildLoad(err_set_llvm_ty, err_field_ptr, ""); |
| ... | @@ -6846,30 +6668,30 @@ pub const FuncGen = struct { | ... | @@ -6846,30 +6668,30 @@ pub const FuncGen = struct { |
| 6846 | } | 6668 | } |
| 6847 | 6669 | ||
| 6848 | fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6670 | fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6671 | const mod = self.dg.module; | ||
| 6849 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 6672 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6850 | const operand = try self.resolveInst(ty_op.operand); | 6673 | const operand = try self.resolveInst(ty_op.operand); |
| 6851 | const err_union_ty = self.air.typeOf(ty_op.operand).childType(); | 6674 | const err_union_ty = self.typeOf(ty_op.operand).childType(mod); |
| 6852 | 6675 | ||
| 6853 | const payload_ty = err_union_ty.errorUnionPayload(); | 6676 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 6854 | const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = Value.zero }); | 6677 | const non_error_val = try self.dg.lowerValue(.{ .ty = Type.anyerror, .val = try mod.intValue(Type.err_int, 0) }); |
| 6855 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 6678 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6856 | _ = self.builder.buildStore(non_error_val, operand); | 6679 | _ = self.builder.buildStore(non_error_val, operand); |
| 6857 | return operand; | 6680 | return operand; |
| 6858 | } | 6681 | } |
| 6859 | const target = self.dg.module.getTarget(); | ||
| 6860 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); | 6682 | const err_union_llvm_ty = try self.dg.lowerType(err_union_ty); |
| 6861 | { | 6683 | { |
| 6862 | const error_offset = errUnionErrorOffset(payload_ty, target); | 6684 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 6863 | // First set the non-error value. | 6685 | // First set the non-error value. |
| 6864 | const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, ""); | 6686 | const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, ""); |
| 6865 | const store_inst = self.builder.buildStore(non_error_val, non_null_ptr); | 6687 | const store_inst = self.builder.buildStore(non_error_val, non_null_ptr); |
| 6866 | store_inst.setAlignment(Type.anyerror.abiAlignment(target)); | 6688 | store_inst.setAlignment(Type.anyerror.abiAlignment(mod)); |
| 6867 | } | 6689 | } |
| 6868 | // Then return the payload pointer (only if it is used). | 6690 | // Then return the payload pointer (only if it is used). |
| 6869 | if (self.liveness.isUnused(inst)) | 6691 | if (self.liveness.isUnused(inst)) |
| 6870 | return null; | 6692 | return null; |
| 6871 | 6693 | ||
| 6872 | const payload_offset = errUnionPayloadOffset(payload_ty, target); | 6694 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| 6873 | return self.builder.buildStructGEP(err_union_llvm_ty, operand, payload_offset, ""); | 6695 | return self.builder.buildStructGEP(err_union_llvm_ty, operand, payload_offset, ""); |
| 6874 | } | 6696 | } |
| 6875 | 6697 | ||
| ... | @@ -6885,42 +6707,41 @@ pub const FuncGen = struct { | ... | @@ -6885,42 +6707,41 @@ pub const FuncGen = struct { |
| 6885 | } | 6707 | } |
| 6886 | 6708 | ||
| 6887 | fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6709 | fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6888 | const target = self.dg.module.getTarget(); | ||
| 6889 | |||
| 6890 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 6710 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 6891 | //const struct_ty = try self.resolveInst(ty_pl.ty); | 6711 | //const struct_ty = try self.resolveInst(ty_pl.ty); |
| 6892 | const struct_ty = self.air.getRefType(ty_pl.ty); | 6712 | const struct_ty = self.air.getRefType(ty_pl.ty); |
| 6893 | const field_index = ty_pl.payload; | 6713 | const field_index = ty_pl.payload; |
| 6894 | 6714 | ||
| 6895 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | 6715 | const mod = self.dg.module; |
| 6896 | const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?; | 6716 | const llvm_field = llvmField(struct_ty, field_index, mod).?; |
| 6897 | const struct_llvm_ty = try self.dg.lowerType(struct_ty); | 6717 | const struct_llvm_ty = try self.dg.lowerType(struct_ty); |
| 6898 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field_index, ""); | 6718 | const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, self.err_ret_trace.?, llvm_field.index, ""); |
| 6899 | const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base); | 6719 | const field_ptr_ty = try mod.ptrType(.{ |
| 6720 | .child = llvm_field.ty.toIntern(), | ||
| 6721 | .flags = .{ | ||
| 6722 | .alignment = InternPool.Alignment.fromNonzeroByteUnits(llvm_field.alignment), | ||
| 6723 | }, | ||
| 6724 | }); | ||
| 6900 | return self.load(field_ptr, field_ptr_ty); | 6725 | return self.load(field_ptr, field_ptr_ty); |
| 6901 | } | 6726 | } |
| 6902 | 6727 | ||
| 6903 | fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6728 | fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6729 | const mod = self.dg.module; | ||
| 6904 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 6730 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6905 | const payload_ty = self.air.typeOf(ty_op.operand); | 6731 | const payload_ty = self.typeOf(ty_op.operand); |
| 6906 | const non_null_bit = self.context.intType(8).constInt(1, .False); | 6732 | const non_null_bit = self.context.intType(8).constInt(1, .False); |
| 6907 | comptime assert(optional_layout_version == 3); | 6733 | comptime assert(optional_layout_version == 3); |
| 6908 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit; | 6734 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return non_null_bit; |
| 6909 | const operand = try self.resolveInst(ty_op.operand); | 6735 | const operand = try self.resolveInst(ty_op.operand); |
| 6910 | const optional_ty = self.air.typeOfIndex(inst); | 6736 | const optional_ty = self.typeOfIndex(inst); |
| 6911 | if (optional_ty.optionalReprIsPayload()) { | 6737 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 6912 | return operand; | 6738 | return operand; |
| 6913 | } | 6739 | } |
| 6914 | const llvm_optional_ty = try self.dg.lowerType(optional_ty); | 6740 | const llvm_optional_ty = try self.dg.lowerType(optional_ty); |
| 6915 | if (isByRef(optional_ty)) { | 6741 | if (isByRef(optional_ty, mod)) { |
| 6916 | const target = self.dg.module.getTarget(); | 6742 | const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(mod)); |
| 6917 | const optional_ptr = self.buildAlloca(llvm_optional_ty, optional_ty.abiAlignment(target)); | ||
| 6918 | const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, ""); | 6743 | const payload_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 0, ""); |
| 6919 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 6744 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); |
| 6920 | .base = .{ .tag = .single_mut_pointer }, | ||
| 6921 | .data = payload_ty, | ||
| 6922 | }; | ||
| 6923 | const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 6924 | try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); | 6745 | try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); |
| 6925 | const non_null_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 1, ""); | 6746 | const non_null_ptr = self.builder.buildStructGEP(llvm_optional_ty, optional_ptr, 1, ""); |
| 6926 | _ = self.builder.buildStore(non_null_bit, non_null_ptr); | 6747 | _ = self.builder.buildStore(non_null_bit, non_null_ptr); |
| ... | @@ -6931,30 +6752,26 @@ pub const FuncGen = struct { | ... | @@ -6931,30 +6752,26 @@ pub const FuncGen = struct { |
| 6931 | } | 6752 | } |
| 6932 | 6753 | ||
| 6933 | fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6754 | fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6755 | const mod = self.dg.module; | ||
| 6934 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 6756 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6935 | const err_un_ty = self.air.typeOfIndex(inst); | 6757 | const err_un_ty = self.typeOfIndex(inst); |
| 6936 | const operand = try self.resolveInst(ty_op.operand); | 6758 | const operand = try self.resolveInst(ty_op.operand); |
| 6937 | const payload_ty = self.air.typeOf(ty_op.operand); | 6759 | const payload_ty = self.typeOf(ty_op.operand); |
| 6938 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 6760 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6939 | return operand; | 6761 | return operand; |
| 6940 | } | 6762 | } |
| 6941 | const ok_err_code = (try self.dg.lowerType(Type.anyerror)).constNull(); | 6763 | const ok_err_code = (try self.dg.lowerType(Type.anyerror)).constNull(); |
| 6942 | const err_un_llvm_ty = try self.dg.lowerType(err_un_ty); | 6764 | const err_un_llvm_ty = try self.dg.lowerType(err_un_ty); |
| 6943 | 6765 | ||
| 6944 | const target = self.dg.module.getTarget(); | 6766 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| 6945 | const payload_offset = errUnionPayloadOffset(payload_ty, target); | 6767 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 6946 | const error_offset = errUnionErrorOffset(payload_ty, target); | 6768 | if (isByRef(err_un_ty, mod)) { |
| 6947 | if (isByRef(err_un_ty)) { | 6769 | const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod)); |
| 6948 | const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target)); | ||
| 6949 | const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, ""); | 6770 | const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 6950 | const store_inst = self.builder.buildStore(ok_err_code, err_ptr); | 6771 | const store_inst = self.builder.buildStore(ok_err_code, err_ptr); |
| 6951 | store_inst.setAlignment(Type.anyerror.abiAlignment(target)); | 6772 | store_inst.setAlignment(Type.anyerror.abiAlignment(mod)); |
| 6952 | const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, ""); | 6773 | const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, ""); |
| 6953 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 6774 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); |
| 6954 | .base = .{ .tag = .single_mut_pointer }, | ||
| 6955 | .data = payload_ty, | ||
| 6956 | }; | ||
| 6957 | const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 6958 | try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); | 6775 | try self.store(payload_ptr, payload_ptr_ty, operand, .NotAtomic); |
| 6959 | return result_ptr; | 6776 | return result_ptr; |
| 6960 | } | 6777 | } |
| ... | @@ -6964,29 +6781,25 @@ pub const FuncGen = struct { | ... | @@ -6964,29 +6781,25 @@ pub const FuncGen = struct { |
| 6964 | } | 6781 | } |
| 6965 | 6782 | ||
| 6966 | fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6783 | fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6784 | const mod = self.dg.module; | ||
| 6967 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 6785 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 6968 | const err_un_ty = self.air.typeOfIndex(inst); | 6786 | const err_un_ty = self.typeOfIndex(inst); |
| 6969 | const payload_ty = err_un_ty.errorUnionPayload(); | 6787 | const payload_ty = err_un_ty.errorUnionPayload(mod); |
| 6970 | const operand = try self.resolveInst(ty_op.operand); | 6788 | const operand = try self.resolveInst(ty_op.operand); |
| 6971 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 6789 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 6972 | return operand; | 6790 | return operand; |
| 6973 | } | 6791 | } |
| 6974 | const err_un_llvm_ty = try self.dg.lowerType(err_un_ty); | 6792 | const err_un_llvm_ty = try self.dg.lowerType(err_un_ty); |
| 6975 | 6793 | ||
| 6976 | const target = self.dg.module.getTarget(); | 6794 | const payload_offset = errUnionPayloadOffset(payload_ty, mod); |
| 6977 | const payload_offset = errUnionPayloadOffset(payload_ty, target); | 6795 | const error_offset = errUnionErrorOffset(payload_ty, mod); |
| 6978 | const error_offset = errUnionErrorOffset(payload_ty, target); | 6796 | if (isByRef(err_un_ty, mod)) { |
| 6979 | if (isByRef(err_un_ty)) { | 6797 | const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(mod)); |
| 6980 | const result_ptr = self.buildAlloca(err_un_llvm_ty, err_un_ty.abiAlignment(target)); | ||
| 6981 | const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, ""); | 6798 | const err_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, error_offset, ""); |
| 6982 | const store_inst = self.builder.buildStore(operand, err_ptr); | 6799 | const store_inst = self.builder.buildStore(operand, err_ptr); |
| 6983 | store_inst.setAlignment(Type.anyerror.abiAlignment(target)); | 6800 | store_inst.setAlignment(Type.anyerror.abiAlignment(mod)); |
| 6984 | const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, ""); | 6801 | const payload_ptr = self.builder.buildStructGEP(err_un_llvm_ty, result_ptr, payload_offset, ""); |
| 6985 | var ptr_ty_payload: Type.Payload.ElemType = .{ | 6802 | const payload_ptr_ty = try mod.singleMutPtrType(payload_ty); |
| 6986 | .base = .{ .tag = .single_mut_pointer }, | ||
| 6987 | .data = payload_ty, | ||
| 6988 | }; | ||
| 6989 | const payload_ptr_ty = Type.initPayload(&ptr_ty_payload.base); | ||
| 6990 | // TODO store undef to payload_ptr | 6803 | // TODO store undef to payload_ptr |
| 6991 | _ = payload_ptr; | 6804 | _ = payload_ptr; |
| 6992 | _ = payload_ptr_ty; | 6805 | _ = payload_ptr_ty; |
| ... | @@ -7021,20 +6834,20 @@ pub const FuncGen = struct { | ... | @@ -7021,20 +6834,20 @@ pub const FuncGen = struct { |
| 7021 | } | 6834 | } |
| 7022 | 6835 | ||
| 7023 | fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6836 | fn airVectorStoreElem(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6837 | const mod = self.dg.module; | ||
| 7024 | const data = self.air.instructions.items(.data)[inst].vector_store_elem; | 6838 | const data = self.air.instructions.items(.data)[inst].vector_store_elem; |
| 7025 | const extra = self.air.extraData(Air.Bin, data.payload).data; | 6839 | const extra = self.air.extraData(Air.Bin, data.payload).data; |
| 7026 | 6840 | ||
| 7027 | const vector_ptr = try self.resolveInst(data.vector_ptr); | 6841 | const vector_ptr = try self.resolveInst(data.vector_ptr); |
| 7028 | const vector_ptr_ty = self.air.typeOf(data.vector_ptr); | 6842 | const vector_ptr_ty = self.typeOf(data.vector_ptr); |
| 7029 | const index = try self.resolveInst(extra.lhs); | 6843 | const index = try self.resolveInst(extra.lhs); |
| 7030 | const operand = try self.resolveInst(extra.rhs); | 6844 | const operand = try self.resolveInst(extra.rhs); |
| 7031 | 6845 | ||
| 7032 | const loaded_vector = blk: { | 6846 | const loaded_vector = blk: { |
| 7033 | const elem_llvm_ty = try self.dg.lowerType(vector_ptr_ty.childType()); | 6847 | const elem_llvm_ty = try self.dg.lowerType(vector_ptr_ty.childType(mod)); |
| 7034 | const load_inst = self.builder.buildLoad(elem_llvm_ty, vector_ptr, ""); | 6848 | const load_inst = self.builder.buildLoad(elem_llvm_ty, vector_ptr, ""); |
| 7035 | const target = self.dg.module.getTarget(); | 6849 | load_inst.setAlignment(vector_ptr_ty.ptrAlignment(mod)); |
| 7036 | load_inst.setAlignment(vector_ptr_ty.ptrAlignment(target)); | 6850 | load_inst.setVolatile(llvm.Bool.fromBool(vector_ptr_ty.isVolatilePtr(mod))); |
| 7037 | load_inst.setVolatile(llvm.Bool.fromBool(vector_ptr_ty.isVolatilePtr())); | ||
| 7038 | break :blk load_inst; | 6851 | break :blk load_inst; |
| 7039 | }; | 6852 | }; |
| 7040 | const modified_vector = self.builder.buildInsertElement(loaded_vector, operand, index, ""); | 6853 | const modified_vector = self.builder.buildInsertElement(loaded_vector, operand, index, ""); |
| ... | @@ -7043,24 +6856,26 @@ pub const FuncGen = struct { | ... | @@ -7043,24 +6856,26 @@ pub const FuncGen = struct { |
| 7043 | } | 6856 | } |
| 7044 | 6857 | ||
| 7045 | fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6858 | fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6859 | const mod = self.dg.module; | ||
| 7046 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 6860 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7047 | const lhs = try self.resolveInst(bin_op.lhs); | 6861 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7048 | const rhs = try self.resolveInst(bin_op.rhs); | 6862 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7049 | const scalar_ty = self.air.typeOfIndex(inst).scalarType(); | 6863 | const scalar_ty = self.typeOfIndex(inst).scalarType(mod); |
| 7050 | 6864 | ||
| 7051 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmin, scalar_ty, 2, .{ lhs, rhs }); | 6865 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmin, scalar_ty, 2, .{ lhs, rhs }); |
| 7052 | if (scalar_ty.isSignedInt()) return self.builder.buildSMin(lhs, rhs, ""); | 6866 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMin(lhs, rhs, ""); |
| 7053 | return self.builder.buildUMin(lhs, rhs, ""); | 6867 | return self.builder.buildUMin(lhs, rhs, ""); |
| 7054 | } | 6868 | } |
| 7055 | 6869 | ||
| 7056 | fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6870 | fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6871 | const mod = self.dg.module; | ||
| 7057 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 6872 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7058 | const lhs = try self.resolveInst(bin_op.lhs); | 6873 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7059 | const rhs = try self.resolveInst(bin_op.rhs); | 6874 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7060 | const scalar_ty = self.air.typeOfIndex(inst).scalarType(); | 6875 | const scalar_ty = self.typeOfIndex(inst).scalarType(mod); |
| 7061 | 6876 | ||
| 7062 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmax, scalar_ty, 2, .{ lhs, rhs }); | 6877 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmax, scalar_ty, 2, .{ lhs, rhs }); |
| 7063 | if (scalar_ty.isSignedInt()) return self.builder.buildSMax(lhs, rhs, ""); | 6878 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMax(lhs, rhs, ""); |
| 7064 | return self.builder.buildUMax(lhs, rhs, ""); | 6879 | return self.builder.buildUMax(lhs, rhs, ""); |
| 7065 | } | 6880 | } |
| 7066 | 6881 | ||
| ... | @@ -7069,7 +6884,7 @@ pub const FuncGen = struct { | ... | @@ -7069,7 +6884,7 @@ pub const FuncGen = struct { |
| 7069 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 6884 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7070 | const ptr = try self.resolveInst(bin_op.lhs); | 6885 | const ptr = try self.resolveInst(bin_op.lhs); |
| 7071 | const len = try self.resolveInst(bin_op.rhs); | 6886 | const len = try self.resolveInst(bin_op.rhs); |
| 7072 | const inst_ty = self.air.typeOfIndex(inst); | 6887 | const inst_ty = self.typeOfIndex(inst); |
| 7073 | const llvm_slice_ty = try self.dg.lowerType(inst_ty); | 6888 | const llvm_slice_ty = try self.dg.lowerType(inst_ty); |
| 7074 | 6889 | ||
| 7075 | // In case of slicing a global, the result type looks something like `{ i8*, i64 }` | 6890 | // In case of slicing a global, the result type looks something like `{ i8*, i64 }` |
| ... | @@ -7081,14 +6896,15 @@ pub const FuncGen = struct { | ... | @@ -7081,14 +6896,15 @@ pub const FuncGen = struct { |
| 7081 | fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { | 6896 | fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7082 | self.builder.setFastMath(want_fast_math); | 6897 | self.builder.setFastMath(want_fast_math); |
| 7083 | 6898 | ||
| 6899 | const mod = self.dg.module; | ||
| 7084 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 6900 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7085 | const lhs = try self.resolveInst(bin_op.lhs); | 6901 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7086 | const rhs = try self.resolveInst(bin_op.rhs); | 6902 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7087 | const inst_ty = self.air.typeOfIndex(inst); | 6903 | const inst_ty = self.typeOfIndex(inst); |
| 7088 | const scalar_ty = inst_ty.scalarType(); | 6904 | const scalar_ty = inst_ty.scalarType(mod); |
| 7089 | 6905 | ||
| 7090 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.add, inst_ty, 2, .{ lhs, rhs }); | 6906 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.add, inst_ty, 2, .{ lhs, rhs }); |
| 7091 | if (scalar_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, ""); | 6907 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildNSWAdd(lhs, rhs, ""); |
| 7092 | return self.builder.buildNUWAdd(lhs, rhs, ""); | 6908 | return self.builder.buildNUWAdd(lhs, rhs, ""); |
| 7093 | } | 6909 | } |
| 7094 | 6910 | ||
| ... | @@ -7103,14 +6919,15 @@ pub const FuncGen = struct { | ... | @@ -7103,14 +6919,15 @@ pub const FuncGen = struct { |
| 7103 | } | 6919 | } |
| 7104 | 6920 | ||
| 7105 | fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6921 | fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6922 | const mod = self.dg.module; | ||
| 7106 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 6923 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7107 | const lhs = try self.resolveInst(bin_op.lhs); | 6924 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7108 | const rhs = try self.resolveInst(bin_op.rhs); | 6925 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7109 | const inst_ty = self.air.typeOfIndex(inst); | 6926 | const inst_ty = self.typeOfIndex(inst); |
| 7110 | const scalar_ty = inst_ty.scalarType(); | 6927 | const scalar_ty = inst_ty.scalarType(mod); |
| 7111 | 6928 | ||
| 7112 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{}); | 6929 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{}); |
| 7113 | if (scalar_ty.isSignedInt()) return self.builder.buildSAddSat(lhs, rhs, ""); | 6930 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildSAddSat(lhs, rhs, ""); |
| 7114 | 6931 | ||
| 7115 | return self.builder.buildUAddSat(lhs, rhs, ""); | 6932 | return self.builder.buildUAddSat(lhs, rhs, ""); |
| 7116 | } | 6933 | } |
| ... | @@ -7118,14 +6935,15 @@ pub const FuncGen = struct { | ... | @@ -7118,14 +6935,15 @@ pub const FuncGen = struct { |
| 7118 | fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { | 6935 | fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7119 | self.builder.setFastMath(want_fast_math); | 6936 | self.builder.setFastMath(want_fast_math); |
| 7120 | 6937 | ||
| 6938 | const mod = self.dg.module; | ||
| 7121 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 6939 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7122 | const lhs = try self.resolveInst(bin_op.lhs); | 6940 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7123 | const rhs = try self.resolveInst(bin_op.rhs); | 6941 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7124 | const inst_ty = self.air.typeOfIndex(inst); | 6942 | const inst_ty = self.typeOfIndex(inst); |
| 7125 | const scalar_ty = inst_ty.scalarType(); | 6943 | const scalar_ty = inst_ty.scalarType(mod); |
| 7126 | 6944 | ||
| 7127 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.sub, inst_ty, 2, .{ lhs, rhs }); | 6945 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.sub, inst_ty, 2, .{ lhs, rhs }); |
| 7128 | if (scalar_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, ""); | 6946 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildNSWSub(lhs, rhs, ""); |
| 7129 | return self.builder.buildNUWSub(lhs, rhs, ""); | 6947 | return self.builder.buildNUWSub(lhs, rhs, ""); |
| 7130 | } | 6948 | } |
| 7131 | 6949 | ||
| ... | @@ -7140,28 +6958,30 @@ pub const FuncGen = struct { | ... | @@ -7140,28 +6958,30 @@ pub const FuncGen = struct { |
| 7140 | } | 6958 | } |
| 7141 | 6959 | ||
| 7142 | fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6960 | fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6961 | const mod = self.dg.module; | ||
| 7143 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 6962 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7144 | const lhs = try self.resolveInst(bin_op.lhs); | 6963 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7145 | const rhs = try self.resolveInst(bin_op.rhs); | 6964 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7146 | const inst_ty = self.air.typeOfIndex(inst); | 6965 | const inst_ty = self.typeOfIndex(inst); |
| 7147 | const scalar_ty = inst_ty.scalarType(); | 6966 | const scalar_ty = inst_ty.scalarType(mod); |
| 7148 | 6967 | ||
| 7149 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{}); | 6968 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{}); |
| 7150 | if (scalar_ty.isSignedInt()) return self.builder.buildSSubSat(lhs, rhs, ""); | 6969 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildSSubSat(lhs, rhs, ""); |
| 7151 | return self.builder.buildUSubSat(lhs, rhs, ""); | 6970 | return self.builder.buildUSubSat(lhs, rhs, ""); |
| 7152 | } | 6971 | } |
| 7153 | 6972 | ||
| 7154 | fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { | 6973 | fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7155 | self.builder.setFastMath(want_fast_math); | 6974 | self.builder.setFastMath(want_fast_math); |
| 7156 | 6975 | ||
| 6976 | const mod = self.dg.module; | ||
| 7157 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 6977 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7158 | const lhs = try self.resolveInst(bin_op.lhs); | 6978 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7159 | const rhs = try self.resolveInst(bin_op.rhs); | 6979 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7160 | const inst_ty = self.air.typeOfIndex(inst); | 6980 | const inst_ty = self.typeOfIndex(inst); |
| 7161 | const scalar_ty = inst_ty.scalarType(); | 6981 | const scalar_ty = inst_ty.scalarType(mod); |
| 7162 | 6982 | ||
| 7163 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.mul, inst_ty, 2, .{ lhs, rhs }); | 6983 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.mul, inst_ty, 2, .{ lhs, rhs }); |
| 7164 | if (scalar_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, ""); | 6984 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildNSWMul(lhs, rhs, ""); |
| 7165 | return self.builder.buildNUWMul(lhs, rhs, ""); | 6985 | return self.builder.buildNUWMul(lhs, rhs, ""); |
| 7166 | } | 6986 | } |
| 7167 | 6987 | ||
| ... | @@ -7176,14 +6996,15 @@ pub const FuncGen = struct { | ... | @@ -7176,14 +6996,15 @@ pub const FuncGen = struct { |
| 7176 | } | 6996 | } |
| 7177 | 6997 | ||
| 7178 | fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 6998 | fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6999 | const mod = self.dg.module; | ||
| 7179 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7000 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7180 | const lhs = try self.resolveInst(bin_op.lhs); | 7001 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7181 | const rhs = try self.resolveInst(bin_op.rhs); | 7002 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7182 | const inst_ty = self.air.typeOfIndex(inst); | 7003 | const inst_ty = self.typeOfIndex(inst); |
| 7183 | const scalar_ty = inst_ty.scalarType(); | 7004 | const scalar_ty = inst_ty.scalarType(mod); |
| 7184 | 7005 | ||
| 7185 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{}); | 7006 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{}); |
| 7186 | if (scalar_ty.isSignedInt()) return self.builder.buildSMulFixSat(lhs, rhs, ""); | 7007 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildSMulFixSat(lhs, rhs, ""); |
| 7187 | return self.builder.buildUMulFixSat(lhs, rhs, ""); | 7008 | return self.builder.buildUMulFixSat(lhs, rhs, ""); |
| 7188 | } | 7009 | } |
| 7189 | 7010 | ||
| ... | @@ -7193,7 +7014,7 @@ pub const FuncGen = struct { | ... | @@ -7193,7 +7014,7 @@ pub const FuncGen = struct { |
| 7193 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7014 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7194 | const lhs = try self.resolveInst(bin_op.lhs); | 7015 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7195 | const rhs = try self.resolveInst(bin_op.rhs); | 7016 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7196 | const inst_ty = self.air.typeOfIndex(inst); | 7017 | const inst_ty = self.typeOfIndex(inst); |
| 7197 | 7018 | ||
| 7198 | return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); | 7019 | return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); |
| 7199 | } | 7020 | } |
| ... | @@ -7201,39 +7022,40 @@ pub const FuncGen = struct { | ... | @@ -7201,39 +7022,40 @@ pub const FuncGen = struct { |
| 7201 | fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { | 7022 | fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7202 | self.builder.setFastMath(want_fast_math); | 7023 | self.builder.setFastMath(want_fast_math); |
| 7203 | 7024 | ||
| 7025 | const mod = self.dg.module; | ||
| 7204 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7026 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7205 | const lhs = try self.resolveInst(bin_op.lhs); | 7027 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7206 | const rhs = try self.resolveInst(bin_op.rhs); | 7028 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7207 | const inst_ty = self.air.typeOfIndex(inst); | 7029 | const inst_ty = self.typeOfIndex(inst); |
| 7208 | const scalar_ty = inst_ty.scalarType(); | 7030 | const scalar_ty = inst_ty.scalarType(mod); |
| 7209 | 7031 | ||
| 7210 | if (scalar_ty.isRuntimeFloat()) { | 7032 | if (scalar_ty.isRuntimeFloat()) { |
| 7211 | const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); | 7033 | const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); |
| 7212 | return self.buildFloatOp(.trunc, inst_ty, 1, .{result}); | 7034 | return self.buildFloatOp(.trunc, inst_ty, 1, .{result}); |
| 7213 | } | 7035 | } |
| 7214 | if (scalar_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, ""); | 7036 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildSDiv(lhs, rhs, ""); |
| 7215 | return self.builder.buildUDiv(lhs, rhs, ""); | 7037 | return self.builder.buildUDiv(lhs, rhs, ""); |
| 7216 | } | 7038 | } |
| 7217 | 7039 | ||
| 7218 | fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { | 7040 | fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7219 | self.builder.setFastMath(want_fast_math); | 7041 | self.builder.setFastMath(want_fast_math); |
| 7220 | 7042 | ||
| 7043 | const mod = self.dg.module; | ||
| 7221 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7044 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7222 | const lhs = try self.resolveInst(bin_op.lhs); | 7045 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7223 | const rhs = try self.resolveInst(bin_op.rhs); | 7046 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7224 | const inst_ty = self.air.typeOfIndex(inst); | 7047 | const inst_ty = self.typeOfIndex(inst); |
| 7225 | const scalar_ty = inst_ty.scalarType(); | 7048 | const scalar_ty = inst_ty.scalarType(mod); |
| 7226 | 7049 | ||
| 7227 | if (scalar_ty.isRuntimeFloat()) { | 7050 | if (scalar_ty.isRuntimeFloat()) { |
| 7228 | const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); | 7051 | const result = try self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); |
| 7229 | return self.buildFloatOp(.floor, inst_ty, 1, .{result}); | 7052 | return self.buildFloatOp(.floor, inst_ty, 1, .{result}); |
| 7230 | } | 7053 | } |
| 7231 | if (scalar_ty.isSignedInt()) { | 7054 | if (scalar_ty.isSignedInt(mod)) { |
| 7232 | const target = self.dg.module.getTarget(); | ||
| 7233 | const inst_llvm_ty = try self.dg.lowerType(inst_ty); | 7055 | const inst_llvm_ty = try self.dg.lowerType(inst_ty); |
| 7234 | const scalar_bit_size_minus_one = scalar_ty.bitSize(target) - 1; | 7056 | const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1; |
| 7235 | const bit_size_minus_one = if (inst_ty.zigTypeTag() == .Vector) const_vector: { | 7057 | const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: { |
| 7236 | const vec_len = inst_ty.vectorLen(); | 7058 | const vec_len = inst_ty.vectorLen(mod); |
| 7237 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); | 7059 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 7238 | 7060 | ||
| 7239 | const shifts = try self.gpa.alloc(*llvm.Value, vec_len); | 7061 | const shifts = try self.gpa.alloc(*llvm.Value, vec_len); |
| ... | @@ -7258,40 +7080,43 @@ pub const FuncGen = struct { | ... | @@ -7258,40 +7080,43 @@ pub const FuncGen = struct { |
| 7258 | fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { | 7080 | fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7259 | self.builder.setFastMath(want_fast_math); | 7081 | self.builder.setFastMath(want_fast_math); |
| 7260 | 7082 | ||
| 7083 | const mod = self.dg.module; | ||
| 7261 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7084 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7262 | const lhs = try self.resolveInst(bin_op.lhs); | 7085 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7263 | const rhs = try self.resolveInst(bin_op.rhs); | 7086 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7264 | const inst_ty = self.air.typeOfIndex(inst); | 7087 | const inst_ty = self.typeOfIndex(inst); |
| 7265 | const scalar_ty = inst_ty.scalarType(); | 7088 | const scalar_ty = inst_ty.scalarType(mod); |
| 7266 | 7089 | ||
| 7267 | if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); | 7090 | if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); |
| 7268 | if (scalar_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, ""); | 7091 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildExactSDiv(lhs, rhs, ""); |
| 7269 | return self.builder.buildExactUDiv(lhs, rhs, ""); | 7092 | return self.builder.buildExactUDiv(lhs, rhs, ""); |
| 7270 | } | 7093 | } |
| 7271 | 7094 | ||
| 7272 | fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { | 7095 | fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7273 | self.builder.setFastMath(want_fast_math); | 7096 | self.builder.setFastMath(want_fast_math); |
| 7274 | 7097 | ||
| 7098 | const mod = self.dg.module; | ||
| 7275 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7099 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7276 | const lhs = try self.resolveInst(bin_op.lhs); | 7100 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7277 | const rhs = try self.resolveInst(bin_op.rhs); | 7101 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7278 | const inst_ty = self.air.typeOfIndex(inst); | 7102 | const inst_ty = self.typeOfIndex(inst); |
| 7279 | const scalar_ty = inst_ty.scalarType(); | 7103 | const scalar_ty = inst_ty.scalarType(mod); |
| 7280 | 7104 | ||
| 7281 | if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs }); | 7105 | if (scalar_ty.isRuntimeFloat()) return self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs }); |
| 7282 | if (scalar_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, ""); | 7106 | if (scalar_ty.isSignedInt(mod)) return self.builder.buildSRem(lhs, rhs, ""); |
| 7283 | return self.builder.buildURem(lhs, rhs, ""); | 7107 | return self.builder.buildURem(lhs, rhs, ""); |
| 7284 | } | 7108 | } |
| 7285 | 7109 | ||
| 7286 | fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { | 7110 | fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 7287 | self.builder.setFastMath(want_fast_math); | 7111 | self.builder.setFastMath(want_fast_math); |
| 7288 | 7112 | ||
| 7113 | const mod = self.dg.module; | ||
| 7289 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7114 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7290 | const lhs = try self.resolveInst(bin_op.lhs); | 7115 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7291 | const rhs = try self.resolveInst(bin_op.rhs); | 7116 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7292 | const inst_ty = self.air.typeOfIndex(inst); | 7117 | const inst_ty = self.typeOfIndex(inst); |
| 7293 | const inst_llvm_ty = try self.dg.lowerType(inst_ty); | 7118 | const inst_llvm_ty = try self.dg.lowerType(inst_ty); |
| 7294 | const scalar_ty = inst_ty.scalarType(); | 7119 | const scalar_ty = inst_ty.scalarType(mod); |
| 7295 | 7120 | ||
| 7296 | if (scalar_ty.isRuntimeFloat()) { | 7121 | if (scalar_ty.isRuntimeFloat()) { |
| 7297 | const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs }); | 7122 | const a = try self.buildFloatOp(.fmod, inst_ty, 2, .{ lhs, rhs }); |
| ... | @@ -7301,11 +7126,10 @@ pub const FuncGen = struct { | ... | @@ -7301,11 +7126,10 @@ pub const FuncGen = struct { |
| 7301 | const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero }); | 7126 | const ltz = try self.buildFloatCmp(.lt, inst_ty, .{ lhs, zero }); |
| 7302 | return self.builder.buildSelect(ltz, c, a, ""); | 7127 | return self.builder.buildSelect(ltz, c, a, ""); |
| 7303 | } | 7128 | } |
| 7304 | if (scalar_ty.isSignedInt()) { | 7129 | if (scalar_ty.isSignedInt(mod)) { |
| 7305 | const target = self.dg.module.getTarget(); | 7130 | const scalar_bit_size_minus_one = scalar_ty.bitSize(mod) - 1; |
| 7306 | const scalar_bit_size_minus_one = scalar_ty.bitSize(target) - 1; | 7131 | const bit_size_minus_one = if (inst_ty.zigTypeTag(mod) == .Vector) const_vector: { |
| 7307 | const bit_size_minus_one = if (inst_ty.zigTypeTag() == .Vector) const_vector: { | 7132 | const vec_len = inst_ty.vectorLen(mod); |
| 7308 | const vec_len = inst_ty.vectorLen(); | ||
| 7309 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); | 7133 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 7310 | 7134 | ||
| 7311 | const shifts = try self.gpa.alloc(*llvm.Value, vec_len); | 7135 | const shifts = try self.gpa.alloc(*llvm.Value, vec_len); |
| ... | @@ -7328,13 +7152,14 @@ pub const FuncGen = struct { | ... | @@ -7328,13 +7152,14 @@ pub const FuncGen = struct { |
| 7328 | } | 7152 | } |
| 7329 | 7153 | ||
| 7330 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7154 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7155 | const mod = self.dg.module; | ||
| 7331 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 7156 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 7332 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 7157 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7333 | const ptr = try self.resolveInst(bin_op.lhs); | 7158 | const ptr = try self.resolveInst(bin_op.lhs); |
| 7334 | const offset = try self.resolveInst(bin_op.rhs); | 7159 | const offset = try self.resolveInst(bin_op.rhs); |
| 7335 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 7160 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 7336 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); | 7161 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType(mod)); |
| 7337 | switch (ptr_ty.ptrSize()) { | 7162 | switch (ptr_ty.ptrSize(mod)) { |
| 7338 | .One => { | 7163 | .One => { |
| 7339 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. | 7164 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 7340 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), offset }; | 7165 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), offset }; |
| ... | @@ -7353,14 +7178,15 @@ pub const FuncGen = struct { | ... | @@ -7353,14 +7178,15 @@ pub const FuncGen = struct { |
| 7353 | } | 7178 | } |
| 7354 | 7179 | ||
| 7355 | fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7180 | fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7181 | const mod = self.dg.module; | ||
| 7356 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 7182 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 7357 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 7183 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7358 | const ptr = try self.resolveInst(bin_op.lhs); | 7184 | const ptr = try self.resolveInst(bin_op.lhs); |
| 7359 | const offset = try self.resolveInst(bin_op.rhs); | 7185 | const offset = try self.resolveInst(bin_op.rhs); |
| 7360 | const negative_offset = self.builder.buildNeg(offset, ""); | 7186 | const negative_offset = self.builder.buildNeg(offset, ""); |
| 7361 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 7187 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 7362 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); | 7188 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType(mod)); |
| 7363 | switch (ptr_ty.ptrSize()) { | 7189 | switch (ptr_ty.ptrSize(mod)) { |
| 7364 | .One => { | 7190 | .One => { |
| 7365 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. | 7191 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 7366 | const indices: [2]*llvm.Value = .{ | 7192 | const indices: [2]*llvm.Value = .{ |
| ... | @@ -7386,36 +7212,33 @@ pub const FuncGen = struct { | ... | @@ -7386,36 +7212,33 @@ pub const FuncGen = struct { |
| 7386 | signed_intrinsic: []const u8, | 7212 | signed_intrinsic: []const u8, |
| 7387 | unsigned_intrinsic: []const u8, | 7213 | unsigned_intrinsic: []const u8, |
| 7388 | ) !?*llvm.Value { | 7214 | ) !?*llvm.Value { |
| 7215 | const mod = self.dg.module; | ||
| 7389 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 7216 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 7390 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 7217 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7391 | 7218 | ||
| 7392 | const lhs = try self.resolveInst(extra.lhs); | 7219 | const lhs = try self.resolveInst(extra.lhs); |
| 7393 | const rhs = try self.resolveInst(extra.rhs); | 7220 | const rhs = try self.resolveInst(extra.rhs); |
| 7394 | 7221 | ||
| 7395 | const lhs_ty = self.air.typeOf(extra.lhs); | 7222 | const lhs_ty = self.typeOf(extra.lhs); |
| 7396 | const scalar_ty = lhs_ty.scalarType(); | 7223 | const scalar_ty = lhs_ty.scalarType(mod); |
| 7397 | const dest_ty = self.air.typeOfIndex(inst); | 7224 | const dest_ty = self.typeOfIndex(inst); |
| 7398 | 7225 | ||
| 7399 | const intrinsic_name = if (scalar_ty.isSignedInt()) signed_intrinsic else unsigned_intrinsic; | 7226 | const intrinsic_name = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic; |
| 7400 | 7227 | ||
| 7401 | const llvm_lhs_ty = try self.dg.lowerType(lhs_ty); | 7228 | const llvm_lhs_ty = try self.dg.lowerType(lhs_ty); |
| 7402 | const llvm_dest_ty = try self.dg.lowerType(dest_ty); | 7229 | const llvm_dest_ty = try self.dg.lowerType(dest_ty); |
| 7403 | 7230 | ||
| 7404 | const tg = self.dg.module.getTarget(); | ||
| 7405 | |||
| 7406 | const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty}); | 7231 | const llvm_fn = self.getIntrinsic(intrinsic_name, &.{llvm_lhs_ty}); |
| 7407 | const result_struct = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &[_]*llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, ""); | 7232 | const result_struct = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &[_]*llvm.Value{ lhs, rhs }, 2, .Fast, .Auto, ""); |
| 7408 | 7233 | ||
| 7409 | const result = self.builder.buildExtractValue(result_struct, 0, ""); | 7234 | const result = self.builder.buildExtractValue(result_struct, 0, ""); |
| 7410 | const overflow_bit = self.builder.buildExtractValue(result_struct, 1, ""); | 7235 | const overflow_bit = self.builder.buildExtractValue(result_struct, 1, ""); |
| 7411 | 7236 | ||
| 7412 | var ty_buf: Type.Payload.Pointer = undefined; | 7237 | const result_index = llvmField(dest_ty, 0, mod).?.index; |
| 7413 | const result_index = llvmFieldIndex(dest_ty, 0, tg, &ty_buf).?; | 7238 | const overflow_index = llvmField(dest_ty, 1, mod).?.index; |
| 7414 | const overflow_index = llvmFieldIndex(dest_ty, 1, tg, &ty_buf).?; | ||
| 7415 | 7239 | ||
| 7416 | if (isByRef(dest_ty)) { | 7240 | if (isByRef(dest_ty, mod)) { |
| 7417 | const target = self.dg.module.getTarget(); | 7241 | const result_alignment = dest_ty.abiAlignment(mod); |
| 7418 | const result_alignment = dest_ty.abiAlignment(target); | ||
| 7419 | const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment); | 7242 | const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment); |
| 7420 | { | 7243 | { |
| 7421 | const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, ""); | 7244 | const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, ""); |
| ... | @@ -7486,8 +7309,9 @@ pub const FuncGen = struct { | ... | @@ -7486,8 +7309,9 @@ pub const FuncGen = struct { |
| 7486 | ty: Type, | 7309 | ty: Type, |
| 7487 | params: [2]*llvm.Value, | 7310 | params: [2]*llvm.Value, |
| 7488 | ) !*llvm.Value { | 7311 | ) !*llvm.Value { |
| 7312 | const mod = self.dg.module; | ||
| 7489 | const target = self.dg.module.getTarget(); | 7313 | const target = self.dg.module.getTarget(); |
| 7490 | const scalar_ty = ty.scalarType(); | 7314 | const scalar_ty = ty.scalarType(mod); |
| 7491 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); | 7315 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 7492 | 7316 | ||
| 7493 | if (intrinsicsAllowed(scalar_ty, target)) { | 7317 | if (intrinsicsAllowed(scalar_ty, target)) { |
| ... | @@ -7531,8 +7355,8 @@ pub const FuncGen = struct { | ... | @@ -7531,8 +7355,8 @@ pub const FuncGen = struct { |
| 7531 | .gte => .SGE, | 7355 | .gte => .SGE, |
| 7532 | }; | 7356 | }; |
| 7533 | 7357 | ||
| 7534 | if (ty.zigTypeTag() == .Vector) { | 7358 | if (ty.zigTypeTag(mod) == .Vector) { |
| 7535 | const vec_len = ty.vectorLen(); | 7359 | const vec_len = ty.vectorLen(mod); |
| 7536 | const vector_result_ty = llvm_i32.vectorType(vec_len); | 7360 | const vector_result_ty = llvm_i32.vectorType(vec_len); |
| 7537 | 7361 | ||
| 7538 | var result = vector_result_ty.getUndef(); | 7362 | var result = vector_result_ty.getUndef(); |
| ... | @@ -7587,8 +7411,9 @@ pub const FuncGen = struct { | ... | @@ -7587,8 +7411,9 @@ pub const FuncGen = struct { |
| 7587 | comptime params_len: usize, | 7411 | comptime params_len: usize, |
| 7588 | params: [params_len]*llvm.Value, | 7412 | params: [params_len]*llvm.Value, |
| 7589 | ) !*llvm.Value { | 7413 | ) !*llvm.Value { |
| 7590 | const target = self.dg.module.getTarget(); | 7414 | const mod = self.dg.module; |
| 7591 | const scalar_ty = ty.scalarType(); | 7415 | const target = mod.getTarget(); |
| 7416 | const scalar_ty = ty.scalarType(mod); | ||
| 7592 | const llvm_ty = try self.dg.lowerType(ty); | 7417 | const llvm_ty = try self.dg.lowerType(ty); |
| 7593 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); | 7418 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 7594 | 7419 | ||
| ... | @@ -7615,9 +7440,9 @@ pub const FuncGen = struct { | ... | @@ -7615,9 +7440,9 @@ pub const FuncGen = struct { |
| 7615 | const one = int_llvm_ty.constInt(1, .False); | 7440 | const one = int_llvm_ty.constInt(1, .False); |
| 7616 | const shift_amt = int_llvm_ty.constInt(float_bits - 1, .False); | 7441 | const shift_amt = int_llvm_ty.constInt(float_bits - 1, .False); |
| 7617 | const sign_mask = one.constShl(shift_amt); | 7442 | const sign_mask = one.constShl(shift_amt); |
| 7618 | const result = if (ty.zigTypeTag() == .Vector) blk: { | 7443 | const result = if (ty.zigTypeTag(mod) == .Vector) blk: { |
| 7619 | const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(), sign_mask, ""); | 7444 | const splat_sign_mask = self.builder.buildVectorSplat(ty.vectorLen(mod), sign_mask, ""); |
| 7620 | const cast_ty = int_llvm_ty.vectorType(ty.vectorLen()); | 7445 | const cast_ty = int_llvm_ty.vectorType(ty.vectorLen(mod)); |
| 7621 | const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty, ""); | 7446 | const bitcasted_operand = self.builder.buildBitCast(params[0], cast_ty, ""); |
| 7622 | break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, ""); | 7447 | break :blk self.builder.buildXor(bitcasted_operand, splat_sign_mask, ""); |
| 7623 | } else blk: { | 7448 | } else blk: { |
| ... | @@ -7662,9 +7487,9 @@ pub const FuncGen = struct { | ... | @@ -7662,9 +7487,9 @@ pub const FuncGen = struct { |
| 7662 | .libc => |fn_name| b: { | 7487 | .libc => |fn_name| b: { |
| 7663 | const param_types = [3]*llvm.Type{ scalar_llvm_ty, scalar_llvm_ty, scalar_llvm_ty }; | 7488 | const param_types = [3]*llvm.Type{ scalar_llvm_ty, scalar_llvm_ty, scalar_llvm_ty }; |
| 7664 | const libc_fn = self.getLibcFunction(fn_name, param_types[0..params.len], scalar_llvm_ty); | 7489 | const libc_fn = self.getLibcFunction(fn_name, param_types[0..params.len], scalar_llvm_ty); |
| 7665 | if (ty.zigTypeTag() == .Vector) { | 7490 | if (ty.zigTypeTag(mod) == .Vector) { |
| 7666 | const result = llvm_ty.getUndef(); | 7491 | const result = llvm_ty.getUndef(); |
| 7667 | return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen()); | 7492 | return self.buildElementwiseCall(libc_fn, &params, result, ty.vectorLen(mod)); |
| 7668 | } | 7493 | } |
| 7669 | 7494 | ||
| 7670 | break :b libc_fn; | 7495 | break :b libc_fn; |
| ... | @@ -7681,47 +7506,44 @@ pub const FuncGen = struct { | ... | @@ -7681,47 +7506,44 @@ pub const FuncGen = struct { |
| 7681 | const mulend2 = try self.resolveInst(extra.rhs); | 7506 | const mulend2 = try self.resolveInst(extra.rhs); |
| 7682 | const addend = try self.resolveInst(pl_op.operand); | 7507 | const addend = try self.resolveInst(pl_op.operand); |
| 7683 | 7508 | ||
| 7684 | const ty = self.air.typeOfIndex(inst); | 7509 | const ty = self.typeOfIndex(inst); |
| 7685 | return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend }); | 7510 | return self.buildFloatOp(.fma, ty, 3, .{ mulend1, mulend2, addend }); |
| 7686 | } | 7511 | } |
| 7687 | 7512 | ||
| 7688 | fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7513 | fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7514 | const mod = self.dg.module; | ||
| 7689 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 7515 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 7690 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 7516 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7691 | 7517 | ||
| 7692 | const lhs = try self.resolveInst(extra.lhs); | 7518 | const lhs = try self.resolveInst(extra.lhs); |
| 7693 | const rhs = try self.resolveInst(extra.rhs); | 7519 | const rhs = try self.resolveInst(extra.rhs); |
| 7694 | 7520 | ||
| 7695 | const lhs_ty = self.air.typeOf(extra.lhs); | 7521 | const lhs_ty = self.typeOf(extra.lhs); |
| 7696 | const rhs_ty = self.air.typeOf(extra.rhs); | 7522 | const rhs_ty = self.typeOf(extra.rhs); |
| 7697 | const lhs_scalar_ty = lhs_ty.scalarType(); | 7523 | const lhs_scalar_ty = lhs_ty.scalarType(mod); |
| 7698 | const rhs_scalar_ty = rhs_ty.scalarType(); | 7524 | const rhs_scalar_ty = rhs_ty.scalarType(mod); |
| 7699 | 7525 | ||
| 7700 | const dest_ty = self.air.typeOfIndex(inst); | 7526 | const dest_ty = self.typeOfIndex(inst); |
| 7701 | const llvm_dest_ty = try self.dg.lowerType(dest_ty); | 7527 | const llvm_dest_ty = try self.dg.lowerType(dest_ty); |
| 7702 | 7528 | ||
| 7703 | const tg = self.dg.module.getTarget(); | 7529 | const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod)) |
| 7704 | |||
| 7705 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg)) | ||
| 7706 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "") | 7530 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "") |
| 7707 | else | 7531 | else |
| 7708 | rhs; | 7532 | rhs; |
| 7709 | 7533 | ||
| 7710 | const result = self.builder.buildShl(lhs, casted_rhs, ""); | 7534 | const result = self.builder.buildShl(lhs, casted_rhs, ""); |
| 7711 | const reconstructed = if (lhs_scalar_ty.isSignedInt()) | 7535 | const reconstructed = if (lhs_scalar_ty.isSignedInt(mod)) |
| 7712 | self.builder.buildAShr(result, casted_rhs, "") | 7536 | self.builder.buildAShr(result, casted_rhs, "") |
| 7713 | else | 7537 | else |
| 7714 | self.builder.buildLShr(result, casted_rhs, ""); | 7538 | self.builder.buildLShr(result, casted_rhs, ""); |
| 7715 | 7539 | ||
| 7716 | const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); | 7540 | const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); |
| 7717 | 7541 | ||
| 7718 | var ty_buf: Type.Payload.Pointer = undefined; | 7542 | const result_index = llvmField(dest_ty, 0, mod).?.index; |
| 7719 | const result_index = llvmFieldIndex(dest_ty, 0, tg, &ty_buf).?; | 7543 | const overflow_index = llvmField(dest_ty, 1, mod).?.index; |
| 7720 | const overflow_index = llvmFieldIndex(dest_ty, 1, tg, &ty_buf).?; | ||
| 7721 | 7544 | ||
| 7722 | if (isByRef(dest_ty)) { | 7545 | if (isByRef(dest_ty, mod)) { |
| 7723 | const target = self.dg.module.getTarget(); | 7546 | const result_alignment = dest_ty.abiAlignment(mod); |
| 7724 | const result_alignment = dest_ty.abiAlignment(target); | ||
| 7725 | const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment); | 7547 | const alloca_inst = self.buildAlloca(llvm_dest_ty, result_alignment); |
| 7726 | { | 7548 | { |
| 7727 | const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, ""); | 7549 | const field_ptr = self.builder.buildStructGEP(llvm_dest_ty, alloca_inst, result_index, ""); |
| ... | @@ -7763,40 +7585,38 @@ pub const FuncGen = struct { | ... | @@ -7763,40 +7585,38 @@ pub const FuncGen = struct { |
| 7763 | } | 7585 | } |
| 7764 | 7586 | ||
| 7765 | fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7587 | fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7588 | const mod = self.dg.module; | ||
| 7766 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7589 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7767 | 7590 | ||
| 7768 | const lhs = try self.resolveInst(bin_op.lhs); | 7591 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7769 | const rhs = try self.resolveInst(bin_op.rhs); | 7592 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7770 | 7593 | ||
| 7771 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 7594 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 7772 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 7595 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 7773 | const lhs_scalar_ty = lhs_ty.scalarType(); | 7596 | const lhs_scalar_ty = lhs_ty.scalarType(mod); |
| 7774 | const rhs_scalar_ty = rhs_ty.scalarType(); | 7597 | const rhs_scalar_ty = rhs_ty.scalarType(mod); |
| 7775 | |||
| 7776 | const tg = self.dg.module.getTarget(); | ||
| 7777 | 7598 | ||
| 7778 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg)) | 7599 | const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod)) |
| 7779 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "") | 7600 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "") |
| 7780 | else | 7601 | else |
| 7781 | rhs; | 7602 | rhs; |
| 7782 | if (lhs_scalar_ty.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, ""); | 7603 | if (lhs_scalar_ty.isSignedInt(mod)) return self.builder.buildNSWShl(lhs, casted_rhs, ""); |
| 7783 | return self.builder.buildNUWShl(lhs, casted_rhs, ""); | 7604 | return self.builder.buildNUWShl(lhs, casted_rhs, ""); |
| 7784 | } | 7605 | } |
| 7785 | 7606 | ||
| 7786 | fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7607 | fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7608 | const mod = self.dg.module; | ||
| 7787 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7609 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7788 | 7610 | ||
| 7789 | const lhs = try self.resolveInst(bin_op.lhs); | 7611 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7790 | const rhs = try self.resolveInst(bin_op.rhs); | 7612 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7791 | 7613 | ||
| 7792 | const lhs_type = self.air.typeOf(bin_op.lhs); | 7614 | const lhs_type = self.typeOf(bin_op.lhs); |
| 7793 | const rhs_type = self.air.typeOf(bin_op.rhs); | 7615 | const rhs_type = self.typeOf(bin_op.rhs); |
| 7794 | const lhs_scalar_ty = lhs_type.scalarType(); | 7616 | const lhs_scalar_ty = lhs_type.scalarType(mod); |
| 7795 | const rhs_scalar_ty = rhs_type.scalarType(); | 7617 | const rhs_scalar_ty = rhs_type.scalarType(mod); |
| 7796 | |||
| 7797 | const tg = self.dg.module.getTarget(); | ||
| 7798 | 7618 | ||
| 7799 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg)) | 7619 | const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod)) |
| 7800 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_type), "") | 7620 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_type), "") |
| 7801 | else | 7621 | else |
| 7802 | rhs; | 7622 | rhs; |
| ... | @@ -7804,24 +7624,24 @@ pub const FuncGen = struct { | ... | @@ -7804,24 +7624,24 @@ pub const FuncGen = struct { |
| 7804 | } | 7624 | } |
| 7805 | 7625 | ||
| 7806 | fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7626 | fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7627 | const mod = self.dg.module; | ||
| 7807 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7628 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7808 | 7629 | ||
| 7809 | const lhs = try self.resolveInst(bin_op.lhs); | 7630 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7810 | const rhs = try self.resolveInst(bin_op.rhs); | 7631 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7811 | 7632 | ||
| 7812 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 7633 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 7813 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 7634 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 7814 | const lhs_scalar_ty = lhs_ty.scalarType(); | 7635 | const lhs_scalar_ty = lhs_ty.scalarType(mod); |
| 7815 | const rhs_scalar_ty = rhs_ty.scalarType(); | 7636 | const rhs_scalar_ty = rhs_ty.scalarType(mod); |
| 7816 | const tg = self.dg.module.getTarget(); | 7637 | const lhs_bits = lhs_scalar_ty.bitSize(mod); |
| 7817 | const lhs_bits = lhs_scalar_ty.bitSize(tg); | ||
| 7818 | 7638 | ||
| 7819 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_bits) | 7639 | const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_bits) |
| 7820 | self.builder.buildZExt(rhs, lhs.typeOf(), "") | 7640 | self.builder.buildZExt(rhs, lhs.typeOf(), "") |
| 7821 | else | 7641 | else |
| 7822 | rhs; | 7642 | rhs; |
| 7823 | 7643 | ||
| 7824 | const result = if (lhs_scalar_ty.isSignedInt()) | 7644 | const result = if (lhs_scalar_ty.isSignedInt(mod)) |
| 7825 | self.builder.buildSShlSat(lhs, casted_rhs, "") | 7645 | self.builder.buildSShlSat(lhs, casted_rhs, "") |
| 7826 | else | 7646 | else |
| 7827 | self.builder.buildUShlSat(lhs, casted_rhs, ""); | 7647 | self.builder.buildUShlSat(lhs, casted_rhs, ""); |
| ... | @@ -7834,8 +7654,8 @@ pub const FuncGen = struct { | ... | @@ -7834,8 +7654,8 @@ pub const FuncGen = struct { |
| 7834 | const lhs_scalar_llvm_ty = try self.dg.lowerType(lhs_scalar_ty); | 7654 | const lhs_scalar_llvm_ty = try self.dg.lowerType(lhs_scalar_ty); |
| 7835 | const bits = lhs_scalar_llvm_ty.constInt(lhs_bits, .False); | 7655 | const bits = lhs_scalar_llvm_ty.constInt(lhs_bits, .False); |
| 7836 | const lhs_max = lhs_scalar_llvm_ty.constAllOnes(); | 7656 | const lhs_max = lhs_scalar_llvm_ty.constAllOnes(); |
| 7837 | if (rhs_ty.zigTypeTag() == .Vector) { | 7657 | if (rhs_ty.zigTypeTag(mod) == .Vector) { |
| 7838 | const vec_len = rhs_ty.vectorLen(); | 7658 | const vec_len = rhs_ty.vectorLen(mod); |
| 7839 | const bits_vec = self.builder.buildVectorSplat(vec_len, bits, ""); | 7659 | const bits_vec = self.builder.buildVectorSplat(vec_len, bits, ""); |
| 7840 | const lhs_max_vec = self.builder.buildVectorSplat(vec_len, lhs_max, ""); | 7660 | const lhs_max_vec = self.builder.buildVectorSplat(vec_len, lhs_max, ""); |
| 7841 | const in_range = self.builder.buildICmp(.ULT, rhs, bits_vec, ""); | 7661 | const in_range = self.builder.buildICmp(.ULT, rhs, bits_vec, ""); |
| ... | @@ -7847,23 +7667,22 @@ pub const FuncGen = struct { | ... | @@ -7847,23 +7667,22 @@ pub const FuncGen = struct { |
| 7847 | } | 7667 | } |
| 7848 | 7668 | ||
| 7849 | fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*llvm.Value { | 7669 | fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*llvm.Value { |
| 7670 | const mod = self.dg.module; | ||
| 7850 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 7671 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 7851 | 7672 | ||
| 7852 | const lhs = try self.resolveInst(bin_op.lhs); | 7673 | const lhs = try self.resolveInst(bin_op.lhs); |
| 7853 | const rhs = try self.resolveInst(bin_op.rhs); | 7674 | const rhs = try self.resolveInst(bin_op.rhs); |
| 7854 | 7675 | ||
| 7855 | const lhs_ty = self.air.typeOf(bin_op.lhs); | 7676 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 7856 | const rhs_ty = self.air.typeOf(bin_op.rhs); | 7677 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 7857 | const lhs_scalar_ty = lhs_ty.scalarType(); | 7678 | const lhs_scalar_ty = lhs_ty.scalarType(mod); |
| 7858 | const rhs_scalar_ty = rhs_ty.scalarType(); | 7679 | const rhs_scalar_ty = rhs_ty.scalarType(mod); |
| 7859 | 7680 | ||
| 7860 | const tg = self.dg.module.getTarget(); | 7681 | const casted_rhs = if (rhs_scalar_ty.bitSize(mod) < lhs_scalar_ty.bitSize(mod)) |
| 7861 | |||
| 7862 | const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg)) | ||
| 7863 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "") | 7682 | self.builder.buildZExt(rhs, try self.dg.lowerType(lhs_ty), "") |
| 7864 | else | 7683 | else |
| 7865 | rhs; | 7684 | rhs; |
| 7866 | const is_signed_int = lhs_scalar_ty.isSignedInt(); | 7685 | const is_signed_int = lhs_scalar_ty.isSignedInt(mod); |
| 7867 | 7686 | ||
| 7868 | if (is_exact) { | 7687 | if (is_exact) { |
| 7869 | if (is_signed_int) { | 7688 | if (is_signed_int) { |
| ... | @@ -7881,14 +7700,14 @@ pub const FuncGen = struct { | ... | @@ -7881,14 +7700,14 @@ pub const FuncGen = struct { |
| 7881 | } | 7700 | } |
| 7882 | 7701 | ||
| 7883 | fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7702 | fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7884 | const target = self.dg.module.getTarget(); | 7703 | const mod = self.dg.module; |
| 7885 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 7704 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7886 | const dest_ty = self.air.typeOfIndex(inst); | 7705 | const dest_ty = self.typeOfIndex(inst); |
| 7887 | const dest_info = dest_ty.intInfo(target); | 7706 | const dest_info = dest_ty.intInfo(mod); |
| 7888 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); | 7707 | const dest_llvm_ty = try self.dg.lowerType(dest_ty); |
| 7889 | const operand = try self.resolveInst(ty_op.operand); | 7708 | const operand = try self.resolveInst(ty_op.operand); |
| 7890 | const operand_ty = self.air.typeOf(ty_op.operand); | 7709 | const operand_ty = self.typeOf(ty_op.operand); |
| 7891 | const operand_info = operand_ty.intInfo(target); | 7710 | const operand_info = operand_ty.intInfo(mod); |
| 7892 | 7711 | ||
| 7893 | if (operand_info.bits < dest_info.bits) { | 7712 | if (operand_info.bits < dest_info.bits) { |
| 7894 | switch (operand_info.signedness) { | 7713 | switch (operand_info.signedness) { |
| ... | @@ -7905,16 +7724,17 @@ pub const FuncGen = struct { | ... | @@ -7905,16 +7724,17 @@ pub const FuncGen = struct { |
| 7905 | fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7724 | fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7906 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 7725 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7907 | const operand = try self.resolveInst(ty_op.operand); | 7726 | const operand = try self.resolveInst(ty_op.operand); |
| 7908 | const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); | 7727 | const dest_llvm_ty = try self.dg.lowerType(self.typeOfIndex(inst)); |
| 7909 | return self.builder.buildTrunc(operand, dest_llvm_ty, ""); | 7728 | return self.builder.buildTrunc(operand, dest_llvm_ty, ""); |
| 7910 | } | 7729 | } |
| 7911 | 7730 | ||
| 7912 | fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7731 | fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7732 | const mod = self.dg.module; | ||
| 7913 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 7733 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7914 | const operand = try self.resolveInst(ty_op.operand); | 7734 | const operand = try self.resolveInst(ty_op.operand); |
| 7915 | const operand_ty = self.air.typeOf(ty_op.operand); | 7735 | const operand_ty = self.typeOf(ty_op.operand); |
| 7916 | const dest_ty = self.air.typeOfIndex(inst); | 7736 | const dest_ty = self.typeOfIndex(inst); |
| 7917 | const target = self.dg.module.getTarget(); | 7737 | const target = mod.getTarget(); |
| 7918 | const dest_bits = dest_ty.floatBits(target); | 7738 | const dest_bits = dest_ty.floatBits(target); |
| 7919 | const src_bits = operand_ty.floatBits(target); | 7739 | const src_bits = operand_ty.floatBits(target); |
| 7920 | 7740 | ||
| ... | @@ -7939,11 +7759,12 @@ pub const FuncGen = struct { | ... | @@ -7939,11 +7759,12 @@ pub const FuncGen = struct { |
| 7939 | } | 7759 | } |
| 7940 | 7760 | ||
| 7941 | fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7761 | fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7762 | const mod = self.dg.module; | ||
| 7942 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 7763 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7943 | const operand = try self.resolveInst(ty_op.operand); | 7764 | const operand = try self.resolveInst(ty_op.operand); |
| 7944 | const operand_ty = self.air.typeOf(ty_op.operand); | 7765 | const operand_ty = self.typeOf(ty_op.operand); |
| 7945 | const dest_ty = self.air.typeOfIndex(inst); | 7766 | const dest_ty = self.typeOfIndex(inst); |
| 7946 | const target = self.dg.module.getTarget(); | 7767 | const target = mod.getTarget(); |
| 7947 | const dest_bits = dest_ty.floatBits(target); | 7768 | const dest_bits = dest_ty.floatBits(target); |
| 7948 | const src_bits = operand_ty.floatBits(target); | 7769 | const src_bits = operand_ty.floatBits(target); |
| 7949 | 7770 | ||
| ... | @@ -7970,25 +7791,25 @@ pub const FuncGen = struct { | ... | @@ -7970,25 +7791,25 @@ pub const FuncGen = struct { |
| 7970 | fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7791 | fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7971 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 7792 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 7972 | const operand = try self.resolveInst(un_op); | 7793 | const operand = try self.resolveInst(un_op); |
| 7973 | const ptr_ty = self.air.typeOf(un_op); | 7794 | const ptr_ty = self.typeOf(un_op); |
| 7974 | const operand_ptr = self.sliceOrArrayPtr(operand, ptr_ty); | 7795 | const operand_ptr = self.sliceOrArrayPtr(operand, ptr_ty); |
| 7975 | const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); | 7796 | const dest_llvm_ty = try self.dg.lowerType(self.typeOfIndex(inst)); |
| 7976 | return self.builder.buildPtrToInt(operand_ptr, dest_llvm_ty, ""); | 7797 | return self.builder.buildPtrToInt(operand_ptr, dest_llvm_ty, ""); |
| 7977 | } | 7798 | } |
| 7978 | 7799 | ||
| 7979 | fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !*llvm.Value { | 7800 | fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !*llvm.Value { |
| 7980 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 7801 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7981 | const operand_ty = self.air.typeOf(ty_op.operand); | 7802 | const operand_ty = self.typeOf(ty_op.operand); |
| 7982 | const inst_ty = self.air.typeOfIndex(inst); | 7803 | const inst_ty = self.typeOfIndex(inst); |
| 7983 | const operand = try self.resolveInst(ty_op.operand); | 7804 | const operand = try self.resolveInst(ty_op.operand); |
| 7984 | return self.bitCast(operand, operand_ty, inst_ty); | 7805 | return self.bitCast(operand, operand_ty, inst_ty); |
| 7985 | } | 7806 | } |
| 7986 | 7807 | ||
| 7987 | fn bitCast(self: *FuncGen, operand: *llvm.Value, operand_ty: Type, inst_ty: Type) !*llvm.Value { | 7808 | fn bitCast(self: *FuncGen, operand: *llvm.Value, operand_ty: Type, inst_ty: Type) !*llvm.Value { |
| 7988 | const operand_is_ref = isByRef(operand_ty); | 7809 | const mod = self.dg.module; |
| 7989 | const result_is_ref = isByRef(inst_ty); | 7810 | const operand_is_ref = isByRef(operand_ty, mod); |
| 7811 | const result_is_ref = isByRef(inst_ty, mod); | ||
| 7990 | const llvm_dest_ty = try self.dg.lowerType(inst_ty); | 7812 | const llvm_dest_ty = try self.dg.lowerType(inst_ty); |
| 7991 | const target = self.dg.module.getTarget(); | ||
| 7992 | 7813 | ||
| 7993 | if (operand_is_ref and result_is_ref) { | 7814 | if (operand_is_ref and result_is_ref) { |
| 7994 | // They are both pointers, so just return the same opaque pointer :) | 7815 | // They are both pointers, so just return the same opaque pointer :) |
| ... | @@ -8001,27 +7822,27 @@ pub const FuncGen = struct { | ... | @@ -8001,27 +7822,27 @@ pub const FuncGen = struct { |
| 8001 | return self.builder.buildZExtOrBitCast(operand, llvm_dest_ty, ""); | 7822 | return self.builder.buildZExtOrBitCast(operand, llvm_dest_ty, ""); |
| 8002 | } | 7823 | } |
| 8003 | 7824 | ||
| 8004 | if (operand_ty.zigTypeTag() == .Int and inst_ty.isPtrAtRuntime()) { | 7825 | if (operand_ty.zigTypeTag(mod) == .Int and inst_ty.isPtrAtRuntime(mod)) { |
| 8005 | return self.builder.buildIntToPtr(operand, llvm_dest_ty, ""); | 7826 | return self.builder.buildIntToPtr(operand, llvm_dest_ty, ""); |
| 8006 | } | 7827 | } |
| 8007 | 7828 | ||
| 8008 | if (operand_ty.zigTypeTag() == .Vector and inst_ty.zigTypeTag() == .Array) { | 7829 | if (operand_ty.zigTypeTag(mod) == .Vector and inst_ty.zigTypeTag(mod) == .Array) { |
| 8009 | const elem_ty = operand_ty.childType(); | 7830 | const elem_ty = operand_ty.childType(mod); |
| 8010 | if (!result_is_ref) { | 7831 | if (!result_is_ref) { |
| 8011 | return self.dg.todo("implement bitcast vector to non-ref array", .{}); | 7832 | return self.dg.todo("implement bitcast vector to non-ref array", .{}); |
| 8012 | } | 7833 | } |
| 8013 | const array_ptr = self.buildAlloca(llvm_dest_ty, null); | 7834 | const array_ptr = self.buildAlloca(llvm_dest_ty, null); |
| 8014 | const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8; | 7835 | const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8; |
| 8015 | if (bitcast_ok) { | 7836 | if (bitcast_ok) { |
| 8016 | const llvm_store = self.builder.buildStore(operand, array_ptr); | 7837 | const llvm_store = self.builder.buildStore(operand, array_ptr); |
| 8017 | llvm_store.setAlignment(inst_ty.abiAlignment(target)); | 7838 | llvm_store.setAlignment(inst_ty.abiAlignment(mod)); |
| 8018 | } else { | 7839 | } else { |
| 8019 | // If the ABI size of the element type is not evenly divisible by size in bits; | 7840 | // If the ABI size of the element type is not evenly divisible by size in bits; |
| 8020 | // a simple bitcast will not work, and we fall back to extractelement. | 7841 | // a simple bitcast will not work, and we fall back to extractelement. |
| 8021 | const llvm_usize = try self.dg.lowerType(Type.usize); | 7842 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| 8022 | const llvm_u32 = self.context.intType(32); | 7843 | const llvm_u32 = self.context.intType(32); |
| 8023 | const zero = llvm_usize.constNull(); | 7844 | const zero = llvm_usize.constNull(); |
| 8024 | const vector_len = operand_ty.arrayLen(); | 7845 | const vector_len = operand_ty.arrayLen(mod); |
| 8025 | var i: u64 = 0; | 7846 | var i: u64 = 0; |
| 8026 | while (i < vector_len) : (i += 1) { | 7847 | while (i < vector_len) : (i += 1) { |
| 8027 | const index_usize = llvm_usize.constInt(i, .False); | 7848 | const index_usize = llvm_usize.constInt(i, .False); |
| ... | @@ -8033,19 +7854,19 @@ pub const FuncGen = struct { | ... | @@ -8033,19 +7854,19 @@ pub const FuncGen = struct { |
| 8033 | } | 7854 | } |
| 8034 | } | 7855 | } |
| 8035 | return array_ptr; | 7856 | return array_ptr; |
| 8036 | } else if (operand_ty.zigTypeTag() == .Array and inst_ty.zigTypeTag() == .Vector) { | 7857 | } else if (operand_ty.zigTypeTag(mod) == .Array and inst_ty.zigTypeTag(mod) == .Vector) { |
| 8037 | const elem_ty = operand_ty.childType(); | 7858 | const elem_ty = operand_ty.childType(mod); |
| 8038 | const llvm_vector_ty = try self.dg.lowerType(inst_ty); | 7859 | const llvm_vector_ty = try self.dg.lowerType(inst_ty); |
| 8039 | if (!operand_is_ref) { | 7860 | if (!operand_is_ref) { |
| 8040 | return self.dg.todo("implement bitcast non-ref array to vector", .{}); | 7861 | return self.dg.todo("implement bitcast non-ref array to vector", .{}); |
| 8041 | } | 7862 | } |
| 8042 | 7863 | ||
| 8043 | const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8; | 7864 | const bitcast_ok = elem_ty.bitSize(mod) == elem_ty.abiSize(mod) * 8; |
| 8044 | if (bitcast_ok) { | 7865 | if (bitcast_ok) { |
| 8045 | const vector = self.builder.buildLoad(llvm_vector_ty, operand, ""); | 7866 | const vector = self.builder.buildLoad(llvm_vector_ty, operand, ""); |
| 8046 | // The array is aligned to the element's alignment, while the vector might have a completely | 7867 | // The array is aligned to the element's alignment, while the vector might have a completely |
| 8047 | // different alignment. This means we need to enforce the alignment of this load. | 7868 | // different alignment. This means we need to enforce the alignment of this load. |
| 8048 | vector.setAlignment(elem_ty.abiAlignment(target)); | 7869 | vector.setAlignment(elem_ty.abiAlignment(mod)); |
| 8049 | return vector; | 7870 | return vector; |
| 8050 | } else { | 7871 | } else { |
| 8051 | // If the ABI size of the element type is not evenly divisible by size in bits; | 7872 | // If the ABI size of the element type is not evenly divisible by size in bits; |
| ... | @@ -8055,7 +7876,7 @@ pub const FuncGen = struct { | ... | @@ -8055,7 +7876,7 @@ pub const FuncGen = struct { |
| 8055 | const llvm_usize = try self.dg.lowerType(Type.usize); | 7876 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| 8056 | const llvm_u32 = self.context.intType(32); | 7877 | const llvm_u32 = self.context.intType(32); |
| 8057 | const zero = llvm_usize.constNull(); | 7878 | const zero = llvm_usize.constNull(); |
| 8058 | const vector_len = operand_ty.arrayLen(); | 7879 | const vector_len = operand_ty.arrayLen(mod); |
| 8059 | var vector = llvm_vector_ty.getUndef(); | 7880 | var vector = llvm_vector_ty.getUndef(); |
| 8060 | var i: u64 = 0; | 7881 | var i: u64 = 0; |
| 8061 | while (i < vector_len) : (i += 1) { | 7882 | while (i < vector_len) : (i += 1) { |
| ... | @@ -8073,12 +7894,12 @@ pub const FuncGen = struct { | ... | @@ -8073,12 +7894,12 @@ pub const FuncGen = struct { |
| 8073 | 7894 | ||
| 8074 | if (operand_is_ref) { | 7895 | if (operand_is_ref) { |
| 8075 | const load_inst = self.builder.buildLoad(llvm_dest_ty, operand, ""); | 7896 | const load_inst = self.builder.buildLoad(llvm_dest_ty, operand, ""); |
| 8076 | load_inst.setAlignment(operand_ty.abiAlignment(target)); | 7897 | load_inst.setAlignment(operand_ty.abiAlignment(mod)); |
| 8077 | return load_inst; | 7898 | return load_inst; |
| 8078 | } | 7899 | } |
| 8079 | 7900 | ||
| 8080 | if (result_is_ref) { | 7901 | if (result_is_ref) { |
| 8081 | const alignment = @max(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target)); | 7902 | const alignment = @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)); |
| 8082 | const result_ptr = self.buildAlloca(llvm_dest_ty, alignment); | 7903 | const result_ptr = self.buildAlloca(llvm_dest_ty, alignment); |
| 8083 | const store_inst = self.builder.buildStore(operand, result_ptr); | 7904 | const store_inst = self.builder.buildStore(operand, result_ptr); |
| 8084 | store_inst.setAlignment(alignment); | 7905 | store_inst.setAlignment(alignment); |
| ... | @@ -8089,7 +7910,7 @@ pub const FuncGen = struct { | ... | @@ -8089,7 +7910,7 @@ pub const FuncGen = struct { |
| 8089 | // Both our operand and our result are values, not pointers, | 7910 | // Both our operand and our result are values, not pointers, |
| 8090 | // but LLVM won't let us bitcast struct values. | 7911 | // but LLVM won't let us bitcast struct values. |
| 8091 | // Therefore, we store operand to alloca, then load for result. | 7912 | // Therefore, we store operand to alloca, then load for result. |
| 8092 | const alignment = @max(operand_ty.abiAlignment(target), inst_ty.abiAlignment(target)); | 7913 | const alignment = @max(operand_ty.abiAlignment(mod), inst_ty.abiAlignment(mod)); |
| 8093 | const result_ptr = self.buildAlloca(llvm_dest_ty, alignment); | 7914 | const result_ptr = self.buildAlloca(llvm_dest_ty, alignment); |
| 8094 | const store_inst = self.builder.buildStore(operand, result_ptr); | 7915 | const store_inst = self.builder.buildStore(operand, result_ptr); |
| 8095 | store_inst.setAlignment(alignment); | 7916 | store_inst.setAlignment(alignment); |
| ... | @@ -8108,22 +7929,23 @@ pub const FuncGen = struct { | ... | @@ -8108,22 +7929,23 @@ pub const FuncGen = struct { |
| 8108 | } | 7929 | } |
| 8109 | 7930 | ||
| 8110 | fn airArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7931 | fn airArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7932 | const mod = self.dg.module; | ||
| 8111 | const arg_val = self.args[self.arg_index]; | 7933 | const arg_val = self.args[self.arg_index]; |
| 8112 | self.arg_index += 1; | 7934 | self.arg_index += 1; |
| 8113 | 7935 | ||
| 8114 | const inst_ty = self.air.typeOfIndex(inst); | 7936 | const inst_ty = self.typeOfIndex(inst); |
| 8115 | if (self.dg.object.di_builder) |dib| { | 7937 | if (self.dg.object.di_builder) |dib| { |
| 8116 | if (needDbgVarWorkaround(self.dg)) { | 7938 | if (needDbgVarWorkaround(self.dg)) { |
| 8117 | return arg_val; | 7939 | return arg_val; |
| 8118 | } | 7940 | } |
| 8119 | 7941 | ||
| 8120 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; | 7942 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 8121 | const func = self.dg.decl.getFunction().?; | 7943 | const func = self.dg.decl.getOwnedFunction(mod).?; |
| 8122 | const lbrace_line = self.dg.module.declPtr(func.owner_decl).src_line + func.lbrace_line + 1; | 7944 | const lbrace_line = mod.declPtr(func.owner_decl).src_line + func.lbrace_line + 1; |
| 8123 | const lbrace_col = func.lbrace_column + 1; | 7945 | const lbrace_col = func.lbrace_column + 1; |
| 8124 | const di_local_var = dib.createParameterVariable( | 7946 | const di_local_var = dib.createParameterVariable( |
| 8125 | self.di_scope.?, | 7947 | self.di_scope.?, |
| 8126 | func.getParamName(self.dg.module, src_index).ptr, // TODO test 0 bit args | 7948 | func.getParamName(mod, src_index).ptr, // TODO test 0 bit args |
| 8127 | self.di_file.?, | 7949 | self.di_file.?, |
| 8128 | lbrace_line, | 7950 | lbrace_line, |
| 8129 | try self.dg.object.lowerDebugType(inst_ty, .full), | 7951 | try self.dg.object.lowerDebugType(inst_ty, .full), |
| ... | @@ -8134,10 +7956,10 @@ pub const FuncGen = struct { | ... | @@ -8134,10 +7956,10 @@ pub const FuncGen = struct { |
| 8134 | 7956 | ||
| 8135 | const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null); | 7957 | const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null); |
| 8136 | const insert_block = self.builder.getInsertBlock(); | 7958 | const insert_block = self.builder.getInsertBlock(); |
| 8137 | if (isByRef(inst_ty)) { | 7959 | if (isByRef(inst_ty, mod)) { |
| 8138 | _ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block); | 7960 | _ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block); |
| 8139 | } else if (self.dg.module.comp.bin_file.options.optimize_mode == .Debug) { | 7961 | } else if (self.dg.module.comp.bin_file.options.optimize_mode == .Debug) { |
| 8140 | const alignment = inst_ty.abiAlignment(self.dg.module.getTarget()); | 7962 | const alignment = inst_ty.abiAlignment(mod); |
| 8141 | const alloca = self.buildAlloca(arg_val.typeOf(), alignment); | 7963 | const alloca = self.buildAlloca(arg_val.typeOf(), alignment); |
| 8142 | const store_inst = self.builder.buildStore(arg_val, alloca); | 7964 | const store_inst = self.builder.buildStore(arg_val, alloca); |
| 8143 | store_inst.setAlignment(alignment); | 7965 | store_inst.setAlignment(alignment); |
| ... | @@ -8151,24 +7973,24 @@ pub const FuncGen = struct { | ... | @@ -8151,24 +7973,24 @@ pub const FuncGen = struct { |
| 8151 | } | 7973 | } |
| 8152 | 7974 | ||
| 8153 | fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7975 | fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8154 | const ptr_ty = self.air.typeOfIndex(inst); | 7976 | const mod = self.dg.module; |
| 8155 | const pointee_type = ptr_ty.childType(); | 7977 | const ptr_ty = self.typeOfIndex(inst); |
| 8156 | if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty); | 7978 | const pointee_type = ptr_ty.childType(mod); |
| 7979 | if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return self.dg.lowerPtrToVoid(ptr_ty); | ||
| 8157 | 7980 | ||
| 8158 | const pointee_llvm_ty = try self.dg.lowerType(pointee_type); | 7981 | const pointee_llvm_ty = try self.dg.lowerType(pointee_type); |
| 8159 | const target = self.dg.module.getTarget(); | 7982 | const alignment = ptr_ty.ptrAlignment(mod); |
| 8160 | const alignment = ptr_ty.ptrAlignment(target); | ||
| 8161 | return self.buildAlloca(pointee_llvm_ty, alignment); | 7983 | return self.buildAlloca(pointee_llvm_ty, alignment); |
| 8162 | } | 7984 | } |
| 8163 | 7985 | ||
| 8164 | fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7986 | fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8165 | const ptr_ty = self.air.typeOfIndex(inst); | 7987 | const mod = self.dg.module; |
| 8166 | const ret_ty = ptr_ty.childType(); | 7988 | const ptr_ty = self.typeOfIndex(inst); |
| 8167 | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty); | 7989 | const ret_ty = ptr_ty.childType(mod); |
| 7990 | if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return self.dg.lowerPtrToVoid(ptr_ty); | ||
| 8168 | if (self.ret_ptr) |ret_ptr| return ret_ptr; | 7991 | if (self.ret_ptr) |ret_ptr| return ret_ptr; |
| 8169 | const ret_llvm_ty = try self.dg.lowerType(ret_ty); | 7992 | const ret_llvm_ty = try self.dg.lowerType(ret_ty); |
| 8170 | const target = self.dg.module.getTarget(); | 7993 | return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(mod)); |
| 8171 | return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(target)); | ||
| 8172 | } | 7994 | } |
| 8173 | 7995 | ||
| 8174 | /// Use this instead of builder.buildAlloca, because this function makes sure to | 7996 | /// Use this instead of builder.buildAlloca, because this function makes sure to |
| ... | @@ -8178,12 +8000,13 @@ pub const FuncGen = struct { | ... | @@ -8178,12 +8000,13 @@ pub const FuncGen = struct { |
| 8178 | } | 8000 | } |
| 8179 | 8001 | ||
| 8180 | fn airStore(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !?*llvm.Value { | 8002 | fn airStore(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !?*llvm.Value { |
| 8003 | const mod = self.dg.module; | ||
| 8181 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 8004 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8182 | const dest_ptr = try self.resolveInst(bin_op.lhs); | 8005 | const dest_ptr = try self.resolveInst(bin_op.lhs); |
| 8183 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 8006 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 8184 | const operand_ty = ptr_ty.childType(); | 8007 | const operand_ty = ptr_ty.childType(mod); |
| 8185 | 8008 | ||
| 8186 | const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false; | 8009 | const val_is_undef = if (try self.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep(mod) else false; |
| 8187 | if (val_is_undef) { | 8010 | if (val_is_undef) { |
| 8188 | // Even if safety is disabled, we still emit a memset to undefined since it conveys | 8011 | // Even if safety is disabled, we still emit a memset to undefined since it conveys |
| 8189 | // extra information to LLVM. However, safety makes the difference between using | 8012 | // extra information to LLVM. However, safety makes the difference between using |
| ... | @@ -8193,13 +8016,12 @@ pub const FuncGen = struct { | ... | @@ -8193,13 +8016,12 @@ pub const FuncGen = struct { |
| 8193 | u8_llvm_ty.constInt(0xaa, .False) | 8016 | u8_llvm_ty.constInt(0xaa, .False) |
| 8194 | else | 8017 | else |
| 8195 | u8_llvm_ty.getUndef(); | 8018 | u8_llvm_ty.getUndef(); |
| 8196 | const target = self.dg.module.getTarget(); | 8019 | const operand_size = operand_ty.abiSize(mod); |
| 8197 | const operand_size = operand_ty.abiSize(target); | ||
| 8198 | const usize_llvm_ty = try self.dg.lowerType(Type.usize); | 8020 | const usize_llvm_ty = try self.dg.lowerType(Type.usize); |
| 8199 | const len = usize_llvm_ty.constInt(operand_size, .False); | 8021 | const len = usize_llvm_ty.constInt(operand_size, .False); |
| 8200 | const dest_ptr_align = ptr_ty.ptrAlignment(target); | 8022 | const dest_ptr_align = ptr_ty.ptrAlignment(mod); |
| 8201 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr()); | 8023 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr(mod)); |
| 8202 | if (safety and self.dg.module.comp.bin_file.options.valgrind) { | 8024 | if (safety and mod.comp.bin_file.options.valgrind) { |
| 8203 | self.valgrindMarkUndef(dest_ptr, len); | 8025 | self.valgrindMarkUndef(dest_ptr, len); |
| 8204 | } | 8026 | } |
| 8205 | return null; | 8027 | return null; |
| ... | @@ -8217,8 +8039,10 @@ pub const FuncGen = struct { | ... | @@ -8217,8 +8039,10 @@ pub const FuncGen = struct { |
| 8217 | /// | 8039 | /// |
| 8218 | /// The first instruction of `body_tail` is the one whose copy we want to elide. | 8040 | /// The first instruction of `body_tail` is the one whose copy we want to elide. |
| 8219 | fn canElideLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) bool { | 8041 | fn canElideLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) bool { |
| 8042 | const mod = fg.dg.module; | ||
| 8043 | const ip = &mod.intern_pool; | ||
| 8220 | for (body_tail[1..]) |body_inst| { | 8044 | for (body_tail[1..]) |body_inst| { |
| 8221 | switch (fg.liveness.categorizeOperand(fg.air, body_inst, body_tail[0])) { | 8045 | switch (fg.liveness.categorizeOperand(fg.air, body_inst, body_tail[0], ip)) { |
| 8222 | .none => continue, | 8046 | .none => continue, |
| 8223 | .write, .noret, .complex => return false, | 8047 | .write, .noret, .complex => return false, |
| 8224 | .tomb => return true, | 8048 | .tomb => return true, |
| ... | @@ -8230,14 +8054,15 @@ pub const FuncGen = struct { | ... | @@ -8230,14 +8054,15 @@ pub const FuncGen = struct { |
| 8230 | } | 8054 | } |
| 8231 | 8055 | ||
| 8232 | fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { | 8056 | fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value { |
| 8057 | const mod = fg.dg.module; | ||
| 8233 | const inst = body_tail[0]; | 8058 | const inst = body_tail[0]; |
| 8234 | const ty_op = fg.air.instructions.items(.data)[inst].ty_op; | 8059 | const ty_op = fg.air.instructions.items(.data)[inst].ty_op; |
| 8235 | const ptr_ty = fg.air.typeOf(ty_op.operand); | 8060 | const ptr_ty = fg.typeOf(ty_op.operand); |
| 8236 | const ptr_info = ptr_ty.ptrInfo().data; | 8061 | const ptr_info = ptr_ty.ptrInfo(mod); |
| 8237 | const ptr = try fg.resolveInst(ty_op.operand); | 8062 | const ptr = try fg.resolveInst(ty_op.operand); |
| 8238 | 8063 | ||
| 8239 | elide: { | 8064 | elide: { |
| 8240 | if (!isByRef(ptr_info.pointee_type)) break :elide; | 8065 | if (!isByRef(ptr_info.pointee_type, mod)) break :elide; |
| 8241 | if (!canElideLoad(fg, body_tail)) break :elide; | 8066 | if (!canElideLoad(fg, body_tail)) break :elide; |
| 8242 | return ptr; | 8067 | return ptr; |
| 8243 | } | 8068 | } |
| ... | @@ -8261,8 +8086,9 @@ pub const FuncGen = struct { | ... | @@ -8261,8 +8086,9 @@ pub const FuncGen = struct { |
| 8261 | 8086 | ||
| 8262 | fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8087 | fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8263 | _ = inst; | 8088 | _ = inst; |
| 8089 | const mod = self.dg.module; | ||
| 8264 | const llvm_usize = try self.dg.lowerType(Type.usize); | 8090 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| 8265 | const target = self.dg.module.getTarget(); | 8091 | const target = mod.getTarget(); |
| 8266 | if (!target_util.supportsReturnAddress(target)) { | 8092 | if (!target_util.supportsReturnAddress(target)) { |
| 8267 | // https://github.com/ziglang/zig/issues/11946 | 8093 | // https://github.com/ziglang/zig/issues/11946 |
| 8268 | return llvm_usize.constNull(); | 8094 | return llvm_usize.constNull(); |
| ... | @@ -8301,16 +8127,17 @@ pub const FuncGen = struct { | ... | @@ -8301,16 +8127,17 @@ pub const FuncGen = struct { |
| 8301 | } | 8127 | } |
| 8302 | 8128 | ||
| 8303 | fn airCmpxchg(self: *FuncGen, inst: Air.Inst.Index, is_weak: bool) !?*llvm.Value { | 8129 | fn airCmpxchg(self: *FuncGen, inst: Air.Inst.Index, is_weak: bool) !?*llvm.Value { |
| 8130 | const mod = self.dg.module; | ||
| 8304 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 8131 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 8305 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; | 8132 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 8306 | const ptr = try self.resolveInst(extra.ptr); | 8133 | const ptr = try self.resolveInst(extra.ptr); |
| 8307 | var expected_value = try self.resolveInst(extra.expected_value); | 8134 | var expected_value = try self.resolveInst(extra.expected_value); |
| 8308 | var new_value = try self.resolveInst(extra.new_value); | 8135 | var new_value = try self.resolveInst(extra.new_value); |
| 8309 | const operand_ty = self.air.typeOf(extra.ptr).elemType(); | 8136 | const operand_ty = self.typeOf(extra.ptr).childType(mod); |
| 8310 | const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false); | 8137 | const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false); |
| 8311 | if (opt_abi_ty) |abi_ty| { | 8138 | if (opt_abi_ty) |abi_ty| { |
| 8312 | // operand needs widening and truncating | 8139 | // operand needs widening and truncating |
| 8313 | if (operand_ty.isSignedInt()) { | 8140 | if (operand_ty.isSignedInt(mod)) { |
| 8314 | expected_value = self.builder.buildSExt(expected_value, abi_ty, ""); | 8141 | expected_value = self.builder.buildSExt(expected_value, abi_ty, ""); |
| 8315 | new_value = self.builder.buildSExt(new_value, abi_ty, ""); | 8142 | new_value = self.builder.buildSExt(new_value, abi_ty, ""); |
| 8316 | } else { | 8143 | } else { |
| ... | @@ -8328,7 +8155,7 @@ pub const FuncGen = struct { | ... | @@ -8328,7 +8155,7 @@ pub const FuncGen = struct { |
| 8328 | ); | 8155 | ); |
| 8329 | result.setWeak(llvm.Bool.fromBool(is_weak)); | 8156 | result.setWeak(llvm.Bool.fromBool(is_weak)); |
| 8330 | 8157 | ||
| 8331 | const optional_ty = self.air.typeOfIndex(inst); | 8158 | const optional_ty = self.typeOfIndex(inst); |
| 8332 | 8159 | ||
| 8333 | var payload = self.builder.buildExtractValue(result, 0, ""); | 8160 | var payload = self.builder.buildExtractValue(result, 0, ""); |
| 8334 | if (opt_abi_ty != null) { | 8161 | if (opt_abi_ty != null) { |
| ... | @@ -8336,7 +8163,7 @@ pub const FuncGen = struct { | ... | @@ -8336,7 +8163,7 @@ pub const FuncGen = struct { |
| 8336 | } | 8163 | } |
| 8337 | const success_bit = self.builder.buildExtractValue(result, 1, ""); | 8164 | const success_bit = self.builder.buildExtractValue(result, 1, ""); |
| 8338 | 8165 | ||
| 8339 | if (optional_ty.optionalReprIsPayload()) { | 8166 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 8340 | return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, ""); | 8167 | return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, ""); |
| 8341 | } | 8168 | } |
| 8342 | 8169 | ||
| ... | @@ -8347,13 +8174,14 @@ pub const FuncGen = struct { | ... | @@ -8347,13 +8174,14 @@ pub const FuncGen = struct { |
| 8347 | } | 8174 | } |
| 8348 | 8175 | ||
| 8349 | fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8176 | fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8177 | const mod = self.dg.module; | ||
| 8350 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 8178 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 8351 | const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data; | 8179 | const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 8352 | const ptr = try self.resolveInst(pl_op.operand); | 8180 | const ptr = try self.resolveInst(pl_op.operand); |
| 8353 | const ptr_ty = self.air.typeOf(pl_op.operand); | 8181 | const ptr_ty = self.typeOf(pl_op.operand); |
| 8354 | const operand_ty = ptr_ty.elemType(); | 8182 | const operand_ty = ptr_ty.childType(mod); |
| 8355 | const operand = try self.resolveInst(extra.operand); | 8183 | const operand = try self.resolveInst(extra.operand); |
| 8356 | const is_signed_int = operand_ty.isSignedInt(); | 8184 | const is_signed_int = operand_ty.isSignedInt(mod); |
| 8357 | const is_float = operand_ty.isRuntimeFloat(); | 8185 | const is_float = operand_ty.isRuntimeFloat(); |
| 8358 | const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float); | 8186 | const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float); |
| 8359 | const ordering = toLlvmAtomicOrdering(extra.ordering()); | 8187 | const ordering = toLlvmAtomicOrdering(extra.ordering()); |
| ... | @@ -8402,17 +8230,17 @@ pub const FuncGen = struct { | ... | @@ -8402,17 +8230,17 @@ pub const FuncGen = struct { |
| 8402 | } | 8230 | } |
| 8403 | 8231 | ||
| 8404 | fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8232 | fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8233 | const mod = self.dg.module; | ||
| 8405 | const atomic_load = self.air.instructions.items(.data)[inst].atomic_load; | 8234 | const atomic_load = self.air.instructions.items(.data)[inst].atomic_load; |
| 8406 | const ptr = try self.resolveInst(atomic_load.ptr); | 8235 | const ptr = try self.resolveInst(atomic_load.ptr); |
| 8407 | const ptr_ty = self.air.typeOf(atomic_load.ptr); | 8236 | const ptr_ty = self.typeOf(atomic_load.ptr); |
| 8408 | const ptr_info = ptr_ty.ptrInfo().data; | 8237 | const ptr_info = ptr_ty.ptrInfo(mod); |
| 8409 | const elem_ty = ptr_info.pointee_type; | 8238 | const elem_ty = ptr_info.pointee_type; |
| 8410 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) | 8239 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 8411 | return null; | 8240 | return null; |
| 8412 | const ordering = toLlvmAtomicOrdering(atomic_load.order); | 8241 | const ordering = toLlvmAtomicOrdering(atomic_load.order); |
| 8413 | const opt_abi_llvm_ty = self.dg.getAtomicAbiType(elem_ty, false); | 8242 | const opt_abi_llvm_ty = self.dg.getAtomicAbiType(elem_ty, false); |
| 8414 | const target = self.dg.module.getTarget(); | 8243 | const ptr_alignment = ptr_info.alignment(mod); |
| 8415 | const ptr_alignment = ptr_info.alignment(target); | ||
| 8416 | const ptr_volatile = llvm.Bool.fromBool(ptr_info.@"volatile"); | 8244 | const ptr_volatile = llvm.Bool.fromBool(ptr_info.@"volatile"); |
| 8417 | const elem_llvm_ty = try self.dg.lowerType(elem_ty); | 8245 | const elem_llvm_ty = try self.dg.lowerType(elem_ty); |
| 8418 | 8246 | ||
| ... | @@ -8436,17 +8264,18 @@ pub const FuncGen = struct { | ... | @@ -8436,17 +8264,18 @@ pub const FuncGen = struct { |
| 8436 | inst: Air.Inst.Index, | 8264 | inst: Air.Inst.Index, |
| 8437 | ordering: llvm.AtomicOrdering, | 8265 | ordering: llvm.AtomicOrdering, |
| 8438 | ) !?*llvm.Value { | 8266 | ) !?*llvm.Value { |
| 8267 | const mod = self.dg.module; | ||
| 8439 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 8268 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8440 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 8269 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 8441 | const operand_ty = ptr_ty.childType(); | 8270 | const operand_ty = ptr_ty.childType(mod); |
| 8442 | if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return null; | 8271 | if (!operand_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return null; |
| 8443 | const ptr = try self.resolveInst(bin_op.lhs); | 8272 | const ptr = try self.resolveInst(bin_op.lhs); |
| 8444 | var element = try self.resolveInst(bin_op.rhs); | 8273 | var element = try self.resolveInst(bin_op.rhs); |
| 8445 | const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false); | 8274 | const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false); |
| 8446 | 8275 | ||
| 8447 | if (opt_abi_ty) |abi_ty| { | 8276 | if (opt_abi_ty) |abi_ty| { |
| 8448 | // operand needs widening | 8277 | // operand needs widening |
| 8449 | if (operand_ty.isSignedInt()) { | 8278 | if (operand_ty.isSignedInt(mod)) { |
| 8450 | element = self.builder.buildSExt(element, abi_ty, ""); | 8279 | element = self.builder.buildSExt(element, abi_ty, ""); |
| 8451 | } else { | 8280 | } else { |
| 8452 | element = self.builder.buildZExt(element, abi_ty, ""); | 8281 | element = self.builder.buildZExt(element, abi_ty, ""); |
| ... | @@ -8457,19 +8286,19 @@ pub const FuncGen = struct { | ... | @@ -8457,19 +8286,19 @@ pub const FuncGen = struct { |
| 8457 | } | 8286 | } |
| 8458 | 8287 | ||
| 8459 | fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !?*llvm.Value { | 8288 | fn airMemset(self: *FuncGen, inst: Air.Inst.Index, safety: bool) !?*llvm.Value { |
| 8289 | const mod = self.dg.module; | ||
| 8460 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 8290 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8461 | const dest_slice = try self.resolveInst(bin_op.lhs); | 8291 | const dest_slice = try self.resolveInst(bin_op.lhs); |
| 8462 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 8292 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 8463 | const elem_ty = self.air.typeOf(bin_op.rhs); | 8293 | const elem_ty = self.typeOf(bin_op.rhs); |
| 8464 | const module = self.dg.module; | 8294 | const target = mod.getTarget(); |
| 8465 | const target = module.getTarget(); | 8295 | const dest_ptr_align = ptr_ty.ptrAlignment(mod); |
| 8466 | const dest_ptr_align = ptr_ty.ptrAlignment(target); | ||
| 8467 | const u8_llvm_ty = self.context.intType(8); | 8296 | const u8_llvm_ty = self.context.intType(8); |
| 8468 | const dest_ptr = self.sliceOrArrayPtr(dest_slice, ptr_ty); | 8297 | const dest_ptr = self.sliceOrArrayPtr(dest_slice, ptr_ty); |
| 8469 | const is_volatile = ptr_ty.isVolatilePtr(); | 8298 | const is_volatile = ptr_ty.isVolatilePtr(mod); |
| 8470 | 8299 | ||
| 8471 | if (self.air.value(bin_op.rhs)) |elem_val| { | 8300 | if (try self.air.value(bin_op.rhs, mod)) |elem_val| { |
| 8472 | if (elem_val.isUndefDeep()) { | 8301 | if (elem_val.isUndefDeep(mod)) { |
| 8473 | // Even if safety is disabled, we still emit a memset to undefined since it conveys | 8302 | // Even if safety is disabled, we still emit a memset to undefined since it conveys |
| 8474 | // extra information to LLVM. However, safety makes the difference between using | 8303 | // extra information to LLVM. However, safety makes the difference between using |
| 8475 | // 0xaa or actual undefined for the fill byte. | 8304 | // 0xaa or actual undefined for the fill byte. |
| ... | @@ -8480,7 +8309,7 @@ pub const FuncGen = struct { | ... | @@ -8480,7 +8309,7 @@ pub const FuncGen = struct { |
| 8480 | const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); | 8309 | const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 8481 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); | 8310 | _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); |
| 8482 | 8311 | ||
| 8483 | if (safety and module.comp.bin_file.options.valgrind) { | 8312 | if (safety and mod.comp.bin_file.options.valgrind) { |
| 8484 | self.valgrindMarkUndef(dest_ptr, len); | 8313 | self.valgrindMarkUndef(dest_ptr, len); |
| 8485 | } | 8314 | } |
| 8486 | return null; | 8315 | return null; |
| ... | @@ -8490,8 +8319,7 @@ pub const FuncGen = struct { | ... | @@ -8490,8 +8319,7 @@ pub const FuncGen = struct { |
| 8490 | // repeating byte pattern, for example, `@as(u64, 0)` has a | 8319 | // repeating byte pattern, for example, `@as(u64, 0)` has a |
| 8491 | // repeating byte pattern of 0 bytes. In such case, the memset | 8320 | // repeating byte pattern of 0 bytes. In such case, the memset |
| 8492 | // intrinsic can be used. | 8321 | // intrinsic can be used. |
| 8493 | var value_buffer: Value.Payload.U64 = undefined; | 8322 | if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| { |
| 8494 | if (try elem_val.hasRepeatedByteRepr(elem_ty, module, &value_buffer)) |byte_val| { | ||
| 8495 | const fill_byte = try self.resolveValue(.{ | 8323 | const fill_byte = try self.resolveValue(.{ |
| 8496 | .ty = Type.u8, | 8324 | .ty = Type.u8, |
| 8497 | .val = byte_val, | 8325 | .val = byte_val, |
| ... | @@ -8503,7 +8331,7 @@ pub const FuncGen = struct { | ... | @@ -8503,7 +8331,7 @@ pub const FuncGen = struct { |
| 8503 | } | 8331 | } |
| 8504 | 8332 | ||
| 8505 | const value = try self.resolveInst(bin_op.rhs); | 8333 | const value = try self.resolveInst(bin_op.rhs); |
| 8506 | const elem_abi_size = elem_ty.abiSize(target); | 8334 | const elem_abi_size = elem_ty.abiSize(mod); |
| 8507 | 8335 | ||
| 8508 | if (elem_abi_size == 1) { | 8336 | if (elem_abi_size == 1) { |
| 8509 | // In this case we can take advantage of LLVM's intrinsic. | 8337 | // In this case we can take advantage of LLVM's intrinsic. |
| ... | @@ -8535,9 +8363,9 @@ pub const FuncGen = struct { | ... | @@ -8535,9 +8363,9 @@ pub const FuncGen = struct { |
| 8535 | const end_block = self.context.appendBasicBlock(self.llvm_func, "InlineMemsetEnd"); | 8363 | const end_block = self.context.appendBasicBlock(self.llvm_func, "InlineMemsetEnd"); |
| 8536 | 8364 | ||
| 8537 | const llvm_usize_ty = self.context.intType(target.ptrBitWidth()); | 8365 | const llvm_usize_ty = self.context.intType(target.ptrBitWidth()); |
| 8538 | const len = switch (ptr_ty.ptrSize()) { | 8366 | const len = switch (ptr_ty.ptrSize(mod)) { |
| 8539 | .Slice => self.builder.buildExtractValue(dest_slice, 1, ""), | 8367 | .Slice => self.builder.buildExtractValue(dest_slice, 1, ""), |
| 8540 | .One => llvm_usize_ty.constInt(ptr_ty.childType().arrayLen(), .False), | 8368 | .One => llvm_usize_ty.constInt(ptr_ty.childType(mod).arrayLen(mod), .False), |
| 8541 | .Many, .C => unreachable, | 8369 | .Many, .C => unreachable, |
| 8542 | }; | 8370 | }; |
| 8543 | const elem_llvm_ty = try self.dg.lowerType(elem_ty); | 8371 | const elem_llvm_ty = try self.dg.lowerType(elem_ty); |
| ... | @@ -8551,9 +8379,9 @@ pub const FuncGen = struct { | ... | @@ -8551,9 +8379,9 @@ pub const FuncGen = struct { |
| 8551 | _ = self.builder.buildCondBr(end, body_block, end_block); | 8379 | _ = self.builder.buildCondBr(end, body_block, end_block); |
| 8552 | 8380 | ||
| 8553 | self.builder.positionBuilderAtEnd(body_block); | 8381 | self.builder.positionBuilderAtEnd(body_block); |
| 8554 | const elem_abi_alignment = elem_ty.abiAlignment(target); | 8382 | const elem_abi_alignment = elem_ty.abiAlignment(mod); |
| 8555 | const it_ptr_alignment = @min(elem_abi_alignment, dest_ptr_align); | 8383 | const it_ptr_alignment = @min(elem_abi_alignment, dest_ptr_align); |
| 8556 | if (isByRef(elem_ty)) { | 8384 | if (isByRef(elem_ty, mod)) { |
| 8557 | _ = self.builder.buildMemCpy( | 8385 | _ = self.builder.buildMemCpy( |
| 8558 | it_ptr, | 8386 | it_ptr, |
| 8559 | it_ptr_alignment, | 8387 | it_ptr_alignment, |
| ... | @@ -8583,19 +8411,19 @@ pub const FuncGen = struct { | ... | @@ -8583,19 +8411,19 @@ pub const FuncGen = struct { |
| 8583 | fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8411 | fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8584 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 8412 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8585 | const dest_slice = try self.resolveInst(bin_op.lhs); | 8413 | const dest_slice = try self.resolveInst(bin_op.lhs); |
| 8586 | const dest_ptr_ty = self.air.typeOf(bin_op.lhs); | 8414 | const dest_ptr_ty = self.typeOf(bin_op.lhs); |
| 8587 | const src_slice = try self.resolveInst(bin_op.rhs); | 8415 | const src_slice = try self.resolveInst(bin_op.rhs); |
| 8588 | const src_ptr_ty = self.air.typeOf(bin_op.rhs); | 8416 | const src_ptr_ty = self.typeOf(bin_op.rhs); |
| 8589 | const src_ptr = self.sliceOrArrayPtr(src_slice, src_ptr_ty); | 8417 | const src_ptr = self.sliceOrArrayPtr(src_slice, src_ptr_ty); |
| 8590 | const len = self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty); | 8418 | const len = self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty); |
| 8591 | const dest_ptr = self.sliceOrArrayPtr(dest_slice, dest_ptr_ty); | 8419 | const dest_ptr = self.sliceOrArrayPtr(dest_slice, dest_ptr_ty); |
| 8592 | const is_volatile = src_ptr_ty.isVolatilePtr() or dest_ptr_ty.isVolatilePtr(); | 8420 | const mod = self.dg.module; |
| 8593 | const target = self.dg.module.getTarget(); | 8421 | const is_volatile = src_ptr_ty.isVolatilePtr(mod) or dest_ptr_ty.isVolatilePtr(mod); |
| 8594 | _ = self.builder.buildMemCpy( | 8422 | _ = self.builder.buildMemCpy( |
| 8595 | dest_ptr, | 8423 | dest_ptr, |
| 8596 | dest_ptr_ty.ptrAlignment(target), | 8424 | dest_ptr_ty.ptrAlignment(mod), |
| 8597 | src_ptr, | 8425 | src_ptr, |
| 8598 | src_ptr_ty.ptrAlignment(target), | 8426 | src_ptr_ty.ptrAlignment(mod), |
| 8599 | len, | 8427 | len, |
| 8600 | is_volatile, | 8428 | is_volatile, |
| 8601 | ); | 8429 | ); |
| ... | @@ -8603,10 +8431,10 @@ pub const FuncGen = struct { | ... | @@ -8603,10 +8431,10 @@ pub const FuncGen = struct { |
| 8603 | } | 8431 | } |
| 8604 | 8432 | ||
| 8605 | fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8433 | fn airSetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8434 | const mod = self.dg.module; | ||
| 8606 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 8435 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 8607 | const un_ty = self.air.typeOf(bin_op.lhs).childType(); | 8436 | const un_ty = self.typeOf(bin_op.lhs).childType(mod); |
| 8608 | const target = self.dg.module.getTarget(); | 8437 | const layout = un_ty.unionGetLayout(mod); |
| 8609 | const layout = un_ty.unionGetLayout(target); | ||
| 8610 | if (layout.tag_size == 0) return null; | 8438 | if (layout.tag_size == 0) return null; |
| 8611 | const union_ptr = try self.resolveInst(bin_op.lhs); | 8439 | const union_ptr = try self.resolveInst(bin_op.lhs); |
| 8612 | const new_tag = try self.resolveInst(bin_op.rhs); | 8440 | const new_tag = try self.resolveInst(bin_op.rhs); |
| ... | @@ -8624,13 +8452,13 @@ pub const FuncGen = struct { | ... | @@ -8624,13 +8452,13 @@ pub const FuncGen = struct { |
| 8624 | } | 8452 | } |
| 8625 | 8453 | ||
| 8626 | fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8454 | fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8455 | const mod = self.dg.module; | ||
| 8627 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 8456 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8628 | const un_ty = self.air.typeOf(ty_op.operand); | 8457 | const un_ty = self.typeOf(ty_op.operand); |
| 8629 | const target = self.dg.module.getTarget(); | 8458 | const layout = un_ty.unionGetLayout(mod); |
| 8630 | const layout = un_ty.unionGetLayout(target); | ||
| 8631 | if (layout.tag_size == 0) return null; | 8459 | if (layout.tag_size == 0) return null; |
| 8632 | const union_handle = try self.resolveInst(ty_op.operand); | 8460 | const union_handle = try self.resolveInst(ty_op.operand); |
| 8633 | if (isByRef(un_ty)) { | 8461 | if (isByRef(un_ty, mod)) { |
| 8634 | const llvm_un_ty = try self.dg.lowerType(un_ty); | 8462 | const llvm_un_ty = try self.dg.lowerType(un_ty); |
| 8635 | if (layout.payload_size == 0) { | 8463 | if (layout.payload_size == 0) { |
| 8636 | return self.builder.buildLoad(llvm_un_ty, union_handle, ""); | 8464 | return self.builder.buildLoad(llvm_un_ty, union_handle, ""); |
| ... | @@ -8650,7 +8478,7 @@ pub const FuncGen = struct { | ... | @@ -8650,7 +8478,7 @@ pub const FuncGen = struct { |
| 8650 | fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !?*llvm.Value { | 8478 | fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !?*llvm.Value { |
| 8651 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8479 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8652 | const operand = try self.resolveInst(un_op); | 8480 | const operand = try self.resolveInst(un_op); |
| 8653 | const operand_ty = self.air.typeOf(un_op); | 8481 | const operand_ty = self.typeOf(un_op); |
| 8654 | 8482 | ||
| 8655 | return self.buildFloatOp(op, operand_ty, 1, .{operand}); | 8483 | return self.buildFloatOp(op, operand_ty, 1, .{operand}); |
| 8656 | } | 8484 | } |
| ... | @@ -8660,14 +8488,15 @@ pub const FuncGen = struct { | ... | @@ -8660,14 +8488,15 @@ pub const FuncGen = struct { |
| 8660 | 8488 | ||
| 8661 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8489 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8662 | const operand = try self.resolveInst(un_op); | 8490 | const operand = try self.resolveInst(un_op); |
| 8663 | const operand_ty = self.air.typeOf(un_op); | 8491 | const operand_ty = self.typeOf(un_op); |
| 8664 | 8492 | ||
| 8665 | return self.buildFloatOp(.neg, operand_ty, 1, .{operand}); | 8493 | return self.buildFloatOp(.neg, operand_ty, 1, .{operand}); |
| 8666 | } | 8494 | } |
| 8667 | 8495 | ||
| 8668 | fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value { | 8496 | fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value { |
| 8497 | const mod = self.dg.module; | ||
| 8669 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 8498 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8670 | const operand_ty = self.air.typeOf(ty_op.operand); | 8499 | const operand_ty = self.typeOf(ty_op.operand); |
| 8671 | const operand = try self.resolveInst(ty_op.operand); | 8500 | const operand = try self.resolveInst(ty_op.operand); |
| 8672 | 8501 | ||
| 8673 | const llvm_i1 = self.context.intType(1); | 8502 | const llvm_i1 = self.context.intType(1); |
| ... | @@ -8676,12 +8505,11 @@ pub const FuncGen = struct { | ... | @@ -8676,12 +8505,11 @@ pub const FuncGen = struct { |
| 8676 | 8505 | ||
| 8677 | const params = [_]*llvm.Value{ operand, llvm_i1.constNull() }; | 8506 | const params = [_]*llvm.Value{ operand, llvm_i1.constNull() }; |
| 8678 | const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, ""); | 8507 | const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, ""); |
| 8679 | const result_ty = self.air.typeOfIndex(inst); | 8508 | const result_ty = self.typeOfIndex(inst); |
| 8680 | const result_llvm_ty = try self.dg.lowerType(result_ty); | 8509 | const result_llvm_ty = try self.dg.lowerType(result_ty); |
| 8681 | 8510 | ||
| 8682 | const target = self.dg.module.getTarget(); | 8511 | const bits = operand_ty.intInfo(mod).bits; |
| 8683 | const bits = operand_ty.intInfo(target).bits; | 8512 | const result_bits = result_ty.intInfo(mod).bits; |
| 8684 | const result_bits = result_ty.intInfo(target).bits; | ||
| 8685 | if (bits > result_bits) { | 8513 | if (bits > result_bits) { |
| 8686 | return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, ""); | 8514 | return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, ""); |
| 8687 | } else if (bits < result_bits) { | 8515 | } else if (bits < result_bits) { |
| ... | @@ -8692,8 +8520,9 @@ pub const FuncGen = struct { | ... | @@ -8692,8 +8520,9 @@ pub const FuncGen = struct { |
| 8692 | } | 8520 | } |
| 8693 | 8521 | ||
| 8694 | fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value { | 8522 | fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value { |
| 8523 | const mod = self.dg.module; | ||
| 8695 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 8524 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8696 | const operand_ty = self.air.typeOf(ty_op.operand); | 8525 | const operand_ty = self.typeOf(ty_op.operand); |
| 8697 | const operand = try self.resolveInst(ty_op.operand); | 8526 | const operand = try self.resolveInst(ty_op.operand); |
| 8698 | 8527 | ||
| 8699 | const params = [_]*llvm.Value{operand}; | 8528 | const params = [_]*llvm.Value{operand}; |
| ... | @@ -8701,12 +8530,11 @@ pub const FuncGen = struct { | ... | @@ -8701,12 +8530,11 @@ pub const FuncGen = struct { |
| 8701 | const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty}); | 8530 | const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty}); |
| 8702 | 8531 | ||
| 8703 | const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, ""); | 8532 | const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, ""); |
| 8704 | const result_ty = self.air.typeOfIndex(inst); | 8533 | const result_ty = self.typeOfIndex(inst); |
| 8705 | const result_llvm_ty = try self.dg.lowerType(result_ty); | 8534 | const result_llvm_ty = try self.dg.lowerType(result_ty); |
| 8706 | 8535 | ||
| 8707 | const target = self.dg.module.getTarget(); | 8536 | const bits = operand_ty.intInfo(mod).bits; |
| 8708 | const bits = operand_ty.intInfo(target).bits; | 8537 | const result_bits = result_ty.intInfo(mod).bits; |
| 8709 | const result_bits = result_ty.intInfo(target).bits; | ||
| 8710 | if (bits > result_bits) { | 8538 | if (bits > result_bits) { |
| 8711 | return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, ""); | 8539 | return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, ""); |
| 8712 | } else if (bits < result_bits) { | 8540 | } else if (bits < result_bits) { |
| ... | @@ -8717,10 +8545,10 @@ pub const FuncGen = struct { | ... | @@ -8717,10 +8545,10 @@ pub const FuncGen = struct { |
| 8717 | } | 8545 | } |
| 8718 | 8546 | ||
| 8719 | fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value { | 8547 | fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value { |
| 8720 | const target = self.dg.module.getTarget(); | 8548 | const mod = self.dg.module; |
| 8721 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 8549 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8722 | const operand_ty = self.air.typeOf(ty_op.operand); | 8550 | const operand_ty = self.typeOf(ty_op.operand); |
| 8723 | var bits = operand_ty.intInfo(target).bits; | 8551 | var bits = operand_ty.intInfo(mod).bits; |
| 8724 | assert(bits % 8 == 0); | 8552 | assert(bits % 8 == 0); |
| 8725 | 8553 | ||
| 8726 | var operand = try self.resolveInst(ty_op.operand); | 8554 | var operand = try self.resolveInst(ty_op.operand); |
| ... | @@ -8730,8 +8558,8 @@ pub const FuncGen = struct { | ... | @@ -8730,8 +8558,8 @@ pub const FuncGen = struct { |
| 8730 | // If not an even byte-multiple, we need zero-extend + shift-left 1 byte | 8558 | // If not an even byte-multiple, we need zero-extend + shift-left 1 byte |
| 8731 | // The truncated result at the end will be the correct bswap | 8559 | // The truncated result at the end will be the correct bswap |
| 8732 | const scalar_llvm_ty = self.context.intType(bits + 8); | 8560 | const scalar_llvm_ty = self.context.intType(bits + 8); |
| 8733 | if (operand_ty.zigTypeTag() == .Vector) { | 8561 | if (operand_ty.zigTypeTag(mod) == .Vector) { |
| 8734 | const vec_len = operand_ty.vectorLen(); | 8562 | const vec_len = operand_ty.vectorLen(mod); |
| 8735 | operand_llvm_ty = scalar_llvm_ty.vectorType(vec_len); | 8563 | operand_llvm_ty = scalar_llvm_ty.vectorType(vec_len); |
| 8736 | 8564 | ||
| 8737 | const shifts = try self.gpa.alloc(*llvm.Value, vec_len); | 8565 | const shifts = try self.gpa.alloc(*llvm.Value, vec_len); |
| ... | @@ -8757,9 +8585,9 @@ pub const FuncGen = struct { | ... | @@ -8757,9 +8585,9 @@ pub const FuncGen = struct { |
| 8757 | 8585 | ||
| 8758 | const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, ""); | 8586 | const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, ""); |
| 8759 | 8587 | ||
| 8760 | const result_ty = self.air.typeOfIndex(inst); | 8588 | const result_ty = self.typeOfIndex(inst); |
| 8761 | const result_llvm_ty = try self.dg.lowerType(result_ty); | 8589 | const result_llvm_ty = try self.dg.lowerType(result_ty); |
| 8762 | const result_bits = result_ty.intInfo(target).bits; | 8590 | const result_bits = result_ty.intInfo(mod).bits; |
| 8763 | if (bits > result_bits) { | 8591 | if (bits > result_bits) { |
| 8764 | return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, ""); | 8592 | return self.builder.buildTrunc(wrong_size_result, result_llvm_ty, ""); |
| 8765 | } else if (bits < result_bits) { | 8593 | } else if (bits < result_bits) { |
| ... | @@ -8770,28 +8598,23 @@ pub const FuncGen = struct { | ... | @@ -8770,28 +8598,23 @@ pub const FuncGen = struct { |
| 8770 | } | 8598 | } |
| 8771 | 8599 | ||
| 8772 | fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8600 | fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8601 | const mod = self.dg.module; | ||
| 8773 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 8602 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 8774 | const operand = try self.resolveInst(ty_op.operand); | 8603 | const operand = try self.resolveInst(ty_op.operand); |
| 8775 | const error_set_ty = self.air.getRefType(ty_op.ty); | 8604 | const error_set_ty = self.air.getRefType(ty_op.ty); |
| 8776 | 8605 | ||
| 8777 | const names = error_set_ty.errorSetNames(); | 8606 | const names = error_set_ty.errorSetNames(mod); |
| 8778 | const valid_block = self.context.appendBasicBlock(self.llvm_func, "Valid"); | 8607 | const valid_block = self.context.appendBasicBlock(self.llvm_func, "Valid"); |
| 8779 | const invalid_block = self.context.appendBasicBlock(self.llvm_func, "Invalid"); | 8608 | const invalid_block = self.context.appendBasicBlock(self.llvm_func, "Invalid"); |
| 8780 | const end_block = self.context.appendBasicBlock(self.llvm_func, "End"); | 8609 | const end_block = self.context.appendBasicBlock(self.llvm_func, "End"); |
| 8781 | const switch_instr = self.builder.buildSwitch(operand, invalid_block, @intCast(c_uint, names.len)); | 8610 | const switch_instr = self.builder.buildSwitch(operand, invalid_block, @intCast(c_uint, names.len)); |
| 8782 | 8611 | ||
| 8783 | for (names) |name| { | 8612 | for (names) |name| { |
| 8784 | const err_int = self.dg.module.global_error_set.get(name).?; | 8613 | const err_int = @intCast(Module.ErrorInt, mod.global_error_set.getIndex(name).?); |
| 8785 | const this_tag_int_value = int: { | 8614 | const this_tag_int_value = try self.dg.lowerValue(.{ |
| 8786 | var tag_val_payload: Value.Payload.U64 = .{ | 8615 | .ty = Type.err_int, |
| 8787 | .base = .{ .tag = .int_u64 }, | 8616 | .val = try mod.intValue(Type.err_int, err_int), |
| 8788 | .data = err_int, | 8617 | }); |
| 8789 | }; | ||
| 8790 | break :int try self.dg.lowerValue(.{ | ||
| 8791 | .ty = Type.err_int, | ||
| 8792 | .val = Value.initPayload(&tag_val_payload.base), | ||
| 8793 | }); | ||
| 8794 | }; | ||
| 8795 | switch_instr.addCase(this_tag_int_value, valid_block); | 8618 | switch_instr.addCase(this_tag_int_value, valid_block); |
| 8796 | } | 8619 | } |
| 8797 | self.builder.positionBuilderAtEnd(valid_block); | 8620 | self.builder.positionBuilderAtEnd(valid_block); |
| ... | @@ -8817,7 +8640,7 @@ pub const FuncGen = struct { | ... | @@ -8817,7 +8640,7 @@ pub const FuncGen = struct { |
| 8817 | fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8640 | fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8818 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8641 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8819 | const operand = try self.resolveInst(un_op); | 8642 | const operand = try self.resolveInst(un_op); |
| 8820 | const enum_ty = self.air.typeOf(un_op); | 8643 | const enum_ty = self.typeOf(un_op); |
| 8821 | 8644 | ||
| 8822 | const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty); | 8645 | const llvm_fn = try self.getIsNamedEnumValueFunction(enum_ty); |
| 8823 | const params = [_]*llvm.Value{operand}; | 8646 | const params = [_]*llvm.Value{operand}; |
| ... | @@ -8825,25 +8648,22 @@ pub const FuncGen = struct { | ... | @@ -8825,25 +8648,22 @@ pub const FuncGen = struct { |
| 8825 | } | 8648 | } |
| 8826 | 8649 | ||
| 8827 | fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value { | 8650 | fn getIsNamedEnumValueFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value { |
| 8828 | const enum_decl = enum_ty.getOwnerDecl(); | 8651 | const mod = self.dg.module; |
| 8652 | const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type; | ||
| 8829 | 8653 | ||
| 8830 | // TODO: detect when the type changes and re-emit this function. | 8654 | // TODO: detect when the type changes and re-emit this function. |
| 8831 | const gop = try self.dg.object.named_enum_map.getOrPut(self.dg.gpa, enum_decl); | 8655 | const gop = try self.dg.object.named_enum_map.getOrPut(self.dg.gpa, enum_type.decl); |
| 8832 | if (gop.found_existing) return gop.value_ptr.*; | 8656 | if (gop.found_existing) return gop.value_ptr.*; |
| 8833 | errdefer assert(self.dg.object.named_enum_map.remove(enum_decl)); | 8657 | errdefer assert(self.dg.object.named_enum_map.remove(enum_type.decl)); |
| 8834 | 8658 | ||
| 8835 | var arena_allocator = std.heap.ArenaAllocator.init(self.gpa); | 8659 | var arena_allocator = std.heap.ArenaAllocator.init(self.gpa); |
| 8836 | defer arena_allocator.deinit(); | 8660 | defer arena_allocator.deinit(); |
| 8837 | const arena = arena_allocator.allocator(); | 8661 | const arena = arena_allocator.allocator(); |
| 8838 | 8662 | ||
| 8839 | const mod = self.dg.module; | 8663 | const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod); |
| 8840 | const fqn = try mod.declPtr(enum_decl).getFullyQualifiedName(mod); | 8664 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{}", .{fqn.fmt(&mod.intern_pool)}); |
| 8841 | defer self.gpa.free(fqn); | ||
| 8842 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{s}", .{fqn}); | ||
| 8843 | 8665 | ||
| 8844 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | 8666 | const param_types = [_]*llvm.Type{try self.dg.lowerType(enum_type.tag_ty.toType())}; |
| 8845 | const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer); | ||
| 8846 | const param_types = [_]*llvm.Type{try self.dg.lowerType(int_tag_ty)}; | ||
| 8847 | 8667 | ||
| 8848 | const llvm_ret_ty = try self.dg.lowerType(Type.bool); | 8668 | const llvm_ret_ty = try self.dg.lowerType(Type.bool); |
| 8849 | const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False); | 8669 | const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False); |
| ... | @@ -8866,21 +8686,17 @@ pub const FuncGen = struct { | ... | @@ -8866,21 +8686,17 @@ pub const FuncGen = struct { |
| 8866 | self.builder.positionBuilderAtEnd(entry_block); | 8686 | self.builder.positionBuilderAtEnd(entry_block); |
| 8867 | self.builder.clearCurrentDebugLocation(); | 8687 | self.builder.clearCurrentDebugLocation(); |
| 8868 | 8688 | ||
| 8869 | const fields = enum_ty.enumFields(); | ||
| 8870 | const named_block = self.context.appendBasicBlock(fn_val, "Named"); | 8689 | const named_block = self.context.appendBasicBlock(fn_val, "Named"); |
| 8871 | const unnamed_block = self.context.appendBasicBlock(fn_val, "Unnamed"); | 8690 | const unnamed_block = self.context.appendBasicBlock(fn_val, "Unnamed"); |
| 8872 | const tag_int_value = fn_val.getParam(0); | 8691 | const tag_int_value = fn_val.getParam(0); |
| 8873 | const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block, @intCast(c_uint, fields.count())); | 8692 | const switch_instr = self.builder.buildSwitch(tag_int_value, unnamed_block, @intCast(c_uint, enum_type.names.len)); |
| 8874 | 8693 | ||
| 8875 | for (fields.keys(), 0..) |_, field_index| { | 8694 | for (enum_type.names, 0..) |_, field_index_usize| { |
| 8695 | const field_index = @intCast(u32, field_index_usize); | ||
| 8876 | const this_tag_int_value = int: { | 8696 | const this_tag_int_value = int: { |
| 8877 | var tag_val_payload: Value.Payload.U32 = .{ | ||
| 8878 | .base = .{ .tag = .enum_field_index }, | ||
| 8879 | .data = @intCast(u32, field_index), | ||
| 8880 | }; | ||
| 8881 | break :int try self.dg.lowerValue(.{ | 8697 | break :int try self.dg.lowerValue(.{ |
| 8882 | .ty = enum_ty, | 8698 | .ty = enum_ty, |
| 8883 | .val = Value.initPayload(&tag_val_payload.base), | 8699 | .val = try mod.enumValueFieldIndex(enum_ty, field_index), |
| 8884 | }); | 8700 | }); |
| 8885 | }; | 8701 | }; |
| 8886 | switch_instr.addCase(this_tag_int_value, named_block); | 8702 | switch_instr.addCase(this_tag_int_value, named_block); |
| ... | @@ -8896,7 +8712,7 @@ pub const FuncGen = struct { | ... | @@ -8896,7 +8712,7 @@ pub const FuncGen = struct { |
| 8896 | fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8712 | fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8897 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8713 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8898 | const operand = try self.resolveInst(un_op); | 8714 | const operand = try self.resolveInst(un_op); |
| 8899 | const enum_ty = self.air.typeOf(un_op); | 8715 | const enum_ty = self.typeOf(un_op); |
| 8900 | 8716 | ||
| 8901 | const llvm_fn = try self.getEnumTagNameFunction(enum_ty); | 8717 | const llvm_fn = try self.getEnumTagNameFunction(enum_ty); |
| 8902 | const params = [_]*llvm.Value{operand}; | 8718 | const params = [_]*llvm.Value{operand}; |
| ... | @@ -8904,31 +8720,27 @@ pub const FuncGen = struct { | ... | @@ -8904,31 +8720,27 @@ pub const FuncGen = struct { |
| 8904 | } | 8720 | } |
| 8905 | 8721 | ||
| 8906 | fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value { | 8722 | fn getEnumTagNameFunction(self: *FuncGen, enum_ty: Type) !*llvm.Value { |
| 8907 | const enum_decl = enum_ty.getOwnerDecl(); | 8723 | const mod = self.dg.module; |
| 8724 | const enum_type = mod.intern_pool.indexToKey(enum_ty.toIntern()).enum_type; | ||
| 8908 | 8725 | ||
| 8909 | // TODO: detect when the type changes and re-emit this function. | 8726 | // TODO: detect when the type changes and re-emit this function. |
| 8910 | const gop = try self.dg.object.decl_map.getOrPut(self.dg.gpa, enum_decl); | 8727 | const gop = try self.dg.object.decl_map.getOrPut(self.dg.gpa, enum_type.decl); |
| 8911 | if (gop.found_existing) return gop.value_ptr.*; | 8728 | if (gop.found_existing) return gop.value_ptr.*; |
| 8912 | errdefer assert(self.dg.object.decl_map.remove(enum_decl)); | 8729 | errdefer assert(self.dg.object.decl_map.remove(enum_type.decl)); |
| 8913 | 8730 | ||
| 8914 | var arena_allocator = std.heap.ArenaAllocator.init(self.gpa); | 8731 | var arena_allocator = std.heap.ArenaAllocator.init(self.gpa); |
| 8915 | defer arena_allocator.deinit(); | 8732 | defer arena_allocator.deinit(); |
| 8916 | const arena = arena_allocator.allocator(); | 8733 | const arena = arena_allocator.allocator(); |
| 8917 | 8734 | ||
| 8918 | const mod = self.dg.module; | 8735 | const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod); |
| 8919 | const fqn = try mod.declPtr(enum_decl).getFullyQualifiedName(mod); | 8736 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{}", .{fqn.fmt(&mod.intern_pool)}); |
| 8920 | defer self.gpa.free(fqn); | ||
| 8921 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); | ||
| 8922 | 8737 | ||
| 8923 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | 8738 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 8924 | const llvm_ret_ty = try self.dg.lowerType(slice_ty); | 8739 | const llvm_ret_ty = try self.dg.lowerType(slice_ty); |
| 8925 | const usize_llvm_ty = try self.dg.lowerType(Type.usize); | 8740 | const usize_llvm_ty = try self.dg.lowerType(Type.usize); |
| 8926 | const target = self.dg.module.getTarget(); | 8741 | const slice_alignment = slice_ty.abiAlignment(mod); |
| 8927 | const slice_alignment = slice_ty.abiAlignment(target); | ||
| 8928 | 8742 | ||
| 8929 | var int_tag_type_buffer: Type.Payload.Bits = undefined; | 8743 | const param_types = [_]*llvm.Type{try self.dg.lowerType(enum_type.tag_ty.toType())}; |
| 8930 | const int_tag_ty = enum_ty.intTagType(&int_tag_type_buffer); | ||
| 8931 | const param_types = [_]*llvm.Type{try self.dg.lowerType(int_tag_ty)}; | ||
| 8932 | 8744 | ||
| 8933 | const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False); | 8745 | const fn_type = llvm.functionType(llvm_ret_ty, &param_types, param_types.len, .False); |
| 8934 | const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); | 8746 | const fn_val = self.dg.object.llvm_module.addFunction(llvm_fn_name, fn_type); |
| ... | @@ -8950,16 +8762,17 @@ pub const FuncGen = struct { | ... | @@ -8950,16 +8762,17 @@ pub const FuncGen = struct { |
| 8950 | self.builder.positionBuilderAtEnd(entry_block); | 8762 | self.builder.positionBuilderAtEnd(entry_block); |
| 8951 | self.builder.clearCurrentDebugLocation(); | 8763 | self.builder.clearCurrentDebugLocation(); |
| 8952 | 8764 | ||
| 8953 | const fields = enum_ty.enumFields(); | ||
| 8954 | const bad_value_block = self.context.appendBasicBlock(fn_val, "BadValue"); | 8765 | const bad_value_block = self.context.appendBasicBlock(fn_val, "BadValue"); |
| 8955 | const tag_int_value = fn_val.getParam(0); | 8766 | const tag_int_value = fn_val.getParam(0); |
| 8956 | const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @intCast(c_uint, fields.count())); | 8767 | const switch_instr = self.builder.buildSwitch(tag_int_value, bad_value_block, @intCast(c_uint, enum_type.names.len)); |
| 8957 | 8768 | ||
| 8958 | const array_ptr_indices = [_]*llvm.Value{ | 8769 | const array_ptr_indices = [_]*llvm.Value{ |
| 8959 | usize_llvm_ty.constNull(), usize_llvm_ty.constNull(), | 8770 | usize_llvm_ty.constNull(), usize_llvm_ty.constNull(), |
| 8960 | }; | 8771 | }; |
| 8961 | 8772 | ||
| 8962 | for (fields.keys(), 0..) |name, field_index| { | 8773 | for (enum_type.names, 0..) |name_ip, field_index_usize| { |
| 8774 | const field_index = @intCast(u32, field_index_usize); | ||
| 8775 | const name = mod.intern_pool.stringToSlice(name_ip); | ||
| 8963 | const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False); | 8776 | const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False); |
| 8964 | const str_init_llvm_ty = str_init.typeOf(); | 8777 | const str_init_llvm_ty = str_init.typeOf(); |
| 8965 | const str_global = self.dg.object.llvm_module.addGlobal(str_init_llvm_ty, ""); | 8778 | const str_global = self.dg.object.llvm_module.addGlobal(str_init_llvm_ty, ""); |
| ... | @@ -8982,16 +8795,10 @@ pub const FuncGen = struct { | ... | @@ -8982,16 +8795,10 @@ pub const FuncGen = struct { |
| 8982 | slice_global.setAlignment(slice_alignment); | 8795 | slice_global.setAlignment(slice_alignment); |
| 8983 | 8796 | ||
| 8984 | const return_block = self.context.appendBasicBlock(fn_val, "Name"); | 8797 | const return_block = self.context.appendBasicBlock(fn_val, "Name"); |
| 8985 | const this_tag_int_value = int: { | 8798 | const this_tag_int_value = try self.dg.lowerValue(.{ |
| 8986 | var tag_val_payload: Value.Payload.U32 = .{ | 8799 | .ty = enum_ty, |
| 8987 | .base = .{ .tag = .enum_field_index }, | 8800 | .val = try mod.enumValueFieldIndex(enum_ty, field_index), |
| 8988 | .data = @intCast(u32, field_index), | 8801 | }); |
| 8989 | }; | ||
| 8990 | break :int try self.dg.lowerValue(.{ | ||
| 8991 | .ty = enum_ty, | ||
| 8992 | .val = Value.initPayload(&tag_val_payload.base), | ||
| 8993 | }); | ||
| 8994 | }; | ||
| 8995 | switch_instr.addCase(this_tag_int_value, return_block); | 8802 | switch_instr.addCase(this_tag_int_value, return_block); |
| 8996 | 8803 | ||
| 8997 | self.builder.positionBuilderAtEnd(return_block); | 8804 | self.builder.positionBuilderAtEnd(return_block); |
| ... | @@ -9027,7 +8834,7 @@ pub const FuncGen = struct { | ... | @@ -9027,7 +8834,7 @@ pub const FuncGen = struct { |
| 9027 | fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8834 | fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 9028 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8835 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 9029 | const operand = try self.resolveInst(un_op); | 8836 | const operand = try self.resolveInst(un_op); |
| 9030 | const slice_ty = self.air.typeOfIndex(inst); | 8837 | const slice_ty = self.typeOfIndex(inst); |
| 9031 | const slice_llvm_ty = try self.dg.lowerType(slice_ty); | 8838 | const slice_llvm_ty = try self.dg.lowerType(slice_ty); |
| 9032 | 8839 | ||
| 9033 | const error_name_table_ptr = try self.getErrorNameTable(); | 8840 | const error_name_table_ptr = try self.getErrorNameTable(); |
| ... | @@ -9039,10 +8846,11 @@ pub const FuncGen = struct { | ... | @@ -9039,10 +8846,11 @@ pub const FuncGen = struct { |
| 9039 | } | 8846 | } |
| 9040 | 8847 | ||
| 9041 | fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8848 | fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8849 | const mod = self.dg.module; | ||
| 9042 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 8850 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 9043 | const scalar = try self.resolveInst(ty_op.operand); | 8851 | const scalar = try self.resolveInst(ty_op.operand); |
| 9044 | const vector_ty = self.air.typeOfIndex(inst); | 8852 | const vector_ty = self.typeOfIndex(inst); |
| 9045 | const len = vector_ty.vectorLen(); | 8853 | const len = vector_ty.vectorLen(mod); |
| 9046 | return self.builder.buildVectorSplat(len, scalar, ""); | 8854 | return self.builder.buildVectorSplat(len, scalar, ""); |
| 9047 | } | 8855 | } |
| 9048 | 8856 | ||
| ... | @@ -9057,13 +8865,14 @@ pub const FuncGen = struct { | ... | @@ -9057,13 +8865,14 @@ pub const FuncGen = struct { |
| 9057 | } | 8865 | } |
| 9058 | 8866 | ||
| 9059 | fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 8867 | fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 8868 | const mod = self.dg.module; | ||
| 9060 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 8869 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 9061 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; | 8870 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 9062 | const a = try self.resolveInst(extra.a); | 8871 | const a = try self.resolveInst(extra.a); |
| 9063 | const b = try self.resolveInst(extra.b); | 8872 | const b = try self.resolveInst(extra.b); |
| 9064 | const mask = self.air.values[extra.mask]; | 8873 | const mask = extra.mask.toValue(); |
| 9065 | const mask_len = extra.mask_len; | 8874 | const mask_len = extra.mask_len; |
| 9066 | const a_len = self.air.typeOf(extra.a).vectorLen(); | 8875 | const a_len = self.typeOf(extra.a).vectorLen(mod); |
| 9067 | 8876 | ||
| 9068 | // LLVM uses integers larger than the length of the first array to | 8877 | // LLVM uses integers larger than the length of the first array to |
| 9069 | // index into the second array. This was deemed unnecessarily fragile | 8878 | // index into the second array. This was deemed unnecessarily fragile |
| ... | @@ -9076,12 +8885,11 @@ pub const FuncGen = struct { | ... | @@ -9076,12 +8885,11 @@ pub const FuncGen = struct { |
| 9076 | const llvm_i32 = self.context.intType(32); | 8885 | const llvm_i32 = self.context.intType(32); |
| 9077 | 8886 | ||
| 9078 | for (values, 0..) |*val, i| { | 8887 | for (values, 0..) |*val, i| { |
| 9079 | var buf: Value.ElemValueBuffer = undefined; | 8888 | const elem = try mask.elemValue(mod, i); |
| 9080 | const elem = mask.elemValueBuffer(self.dg.module, i, &buf); | 8889 | if (elem.isUndef(mod)) { |
| 9081 | if (elem.isUndef()) { | ||
| 9082 | val.* = llvm_i32.getUndef(); | 8890 | val.* = llvm_i32.getUndef(); |
| 9083 | } else { | 8891 | } else { |
| 9084 | const int = elem.toSignedInt(self.dg.module.getTarget()); | 8892 | const int = elem.toSignedInt(mod); |
| 9085 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); | 8893 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); |
| 9086 | val.* = llvm_i32.constInt(unsigned, .False); | 8894 | val.* = llvm_i32.constInt(unsigned, .False); |
| 9087 | } | 8895 | } |
| ... | @@ -9157,32 +8965,33 @@ pub const FuncGen = struct { | ... | @@ -9157,32 +8965,33 @@ pub const FuncGen = struct { |
| 9157 | 8965 | ||
| 9158 | fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { | 8966 | fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value { |
| 9159 | self.builder.setFastMath(want_fast_math); | 8967 | self.builder.setFastMath(want_fast_math); |
| 9160 | const target = self.dg.module.getTarget(); | 8968 | const mod = self.dg.module; |
| 8969 | const target = mod.getTarget(); | ||
| 9161 | 8970 | ||
| 9162 | const reduce = self.air.instructions.items(.data)[inst].reduce; | 8971 | const reduce = self.air.instructions.items(.data)[inst].reduce; |
| 9163 | const operand = try self.resolveInst(reduce.operand); | 8972 | const operand = try self.resolveInst(reduce.operand); |
| 9164 | const operand_ty = self.air.typeOf(reduce.operand); | 8973 | const operand_ty = self.typeOf(reduce.operand); |
| 9165 | const scalar_ty = self.air.typeOfIndex(inst); | 8974 | const scalar_ty = self.typeOfIndex(inst); |
| 9166 | 8975 | ||
| 9167 | switch (reduce.operation) { | 8976 | switch (reduce.operation) { |
| 9168 | .And => return self.builder.buildAndReduce(operand), | 8977 | .And => return self.builder.buildAndReduce(operand), |
| 9169 | .Or => return self.builder.buildOrReduce(operand), | 8978 | .Or => return self.builder.buildOrReduce(operand), |
| 9170 | .Xor => return self.builder.buildXorReduce(operand), | 8979 | .Xor => return self.builder.buildXorReduce(operand), |
| 9171 | .Min => switch (scalar_ty.zigTypeTag()) { | 8980 | .Min => switch (scalar_ty.zigTypeTag(mod)) { |
| 9172 | .Int => return self.builder.buildIntMinReduce(operand, scalar_ty.isSignedInt()), | 8981 | .Int => return self.builder.buildIntMinReduce(operand, scalar_ty.isSignedInt(mod)), |
| 9173 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { | 8982 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9174 | return self.builder.buildFPMinReduce(operand); | 8983 | return self.builder.buildFPMinReduce(operand); |
| 9175 | }, | 8984 | }, |
| 9176 | else => unreachable, | 8985 | else => unreachable, |
| 9177 | }, | 8986 | }, |
| 9178 | .Max => switch (scalar_ty.zigTypeTag()) { | 8987 | .Max => switch (scalar_ty.zigTypeTag(mod)) { |
| 9179 | .Int => return self.builder.buildIntMaxReduce(operand, scalar_ty.isSignedInt()), | 8988 | .Int => return self.builder.buildIntMaxReduce(operand, scalar_ty.isSignedInt(mod)), |
| 9180 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { | 8989 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9181 | return self.builder.buildFPMaxReduce(operand); | 8990 | return self.builder.buildFPMaxReduce(operand); |
| 9182 | }, | 8991 | }, |
| 9183 | else => unreachable, | 8992 | else => unreachable, |
| 9184 | }, | 8993 | }, |
| 9185 | .Add => switch (scalar_ty.zigTypeTag()) { | 8994 | .Add => switch (scalar_ty.zigTypeTag(mod)) { |
| 9186 | .Int => return self.builder.buildAddReduce(operand), | 8995 | .Int => return self.builder.buildAddReduce(operand), |
| 9187 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { | 8996 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9188 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); | 8997 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| ... | @@ -9191,7 +9000,7 @@ pub const FuncGen = struct { | ... | @@ -9191,7 +9000,7 @@ pub const FuncGen = struct { |
| 9191 | }, | 9000 | }, |
| 9192 | else => unreachable, | 9001 | else => unreachable, |
| 9193 | }, | 9002 | }, |
| 9194 | .Mul => switch (scalar_ty.zigTypeTag()) { | 9003 | .Mul => switch (scalar_ty.zigTypeTag(mod)) { |
| 9195 | .Int => return self.builder.buildMulReduce(operand), | 9004 | .Int => return self.builder.buildMulReduce(operand), |
| 9196 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { | 9005 | .Float => if (intrinsicsAllowed(scalar_ty, target)) { |
| 9197 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); | 9006 | const scalar_llvm_ty = try self.dg.lowerType(scalar_ty); |
| ... | @@ -9221,35 +9030,32 @@ pub const FuncGen = struct { | ... | @@ -9221,35 +9030,32 @@ pub const FuncGen = struct { |
| 9221 | }) catch unreachable, | 9030 | }) catch unreachable, |
| 9222 | else => unreachable, | 9031 | else => unreachable, |
| 9223 | }; | 9032 | }; |
| 9224 | var init_value_payload = Value.Payload.Float_32{ | ||
| 9225 | .data = switch (reduce.operation) { | ||
| 9226 | .Min => std.math.nan(f32), | ||
| 9227 | .Max => std.math.nan(f32), | ||
| 9228 | .Add => -0.0, | ||
| 9229 | .Mul => 1.0, | ||
| 9230 | else => unreachable, | ||
| 9231 | }, | ||
| 9232 | }; | ||
| 9233 | 9033 | ||
| 9234 | const param_llvm_ty = try self.dg.lowerType(scalar_ty); | 9034 | const param_llvm_ty = try self.dg.lowerType(scalar_ty); |
| 9235 | const param_types = [2]*llvm.Type{ param_llvm_ty, param_llvm_ty }; | 9035 | const param_types = [2]*llvm.Type{ param_llvm_ty, param_llvm_ty }; |
| 9236 | const libc_fn = self.getLibcFunction(fn_name, &param_types, param_llvm_ty); | 9036 | const libc_fn = self.getLibcFunction(fn_name, &param_types, param_llvm_ty); |
| 9237 | const init_value = try self.dg.lowerValue(.{ | 9037 | const init_value = try self.dg.lowerValue(.{ |
| 9238 | .ty = scalar_ty, | 9038 | .ty = scalar_ty, |
| 9239 | .val = Value.initPayload(&init_value_payload.base), | 9039 | .val = try mod.floatValue(scalar_ty, switch (reduce.operation) { |
| 9040 | .Min => std.math.nan(f32), | ||
| 9041 | .Max => std.math.nan(f32), | ||
| 9042 | .Add => -0.0, | ||
| 9043 | .Mul => 1.0, | ||
| 9044 | else => unreachable, | ||
| 9045 | }), | ||
| 9240 | }); | 9046 | }); |
| 9241 | return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(), init_value); | 9047 | return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value); |
| 9242 | } | 9048 | } |
| 9243 | 9049 | ||
| 9244 | fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 9050 | fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 9051 | const mod = self.dg.module; | ||
| 9245 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 9052 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 9246 | const result_ty = self.air.typeOfIndex(inst); | 9053 | const result_ty = self.typeOfIndex(inst); |
| 9247 | const len = @intCast(usize, result_ty.arrayLen()); | 9054 | const len = @intCast(usize, result_ty.arrayLen(mod)); |
| 9248 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); | 9055 | const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]); |
| 9249 | const llvm_result_ty = try self.dg.lowerType(result_ty); | 9056 | const llvm_result_ty = try self.dg.lowerType(result_ty); |
| 9250 | const target = self.dg.module.getTarget(); | ||
| 9251 | 9057 | ||
| 9252 | switch (result_ty.zigTypeTag()) { | 9058 | switch (result_ty.zigTypeTag(mod)) { |
| 9253 | .Vector => { | 9059 | .Vector => { |
| 9254 | const llvm_u32 = self.context.intType(32); | 9060 | const llvm_u32 = self.context.intType(32); |
| 9255 | 9061 | ||
| ... | @@ -9262,10 +9068,10 @@ pub const FuncGen = struct { | ... | @@ -9262,10 +9068,10 @@ pub const FuncGen = struct { |
| 9262 | return vector; | 9068 | return vector; |
| 9263 | }, | 9069 | }, |
| 9264 | .Struct => { | 9070 | .Struct => { |
| 9265 | if (result_ty.containerLayout() == .Packed) { | 9071 | if (result_ty.containerLayout(mod) == .Packed) { |
| 9266 | const struct_obj = result_ty.castTag(.@"struct").?.data; | 9072 | const struct_obj = mod.typeToStruct(result_ty).?; |
| 9267 | assert(struct_obj.haveLayout()); | 9073 | assert(struct_obj.haveLayout()); |
| 9268 | const big_bits = struct_obj.backing_int_ty.bitSize(target); | 9074 | const big_bits = struct_obj.backing_int_ty.bitSize(mod); |
| 9269 | const int_llvm_ty = self.context.intType(@intCast(c_uint, big_bits)); | 9075 | const int_llvm_ty = self.context.intType(@intCast(c_uint, big_bits)); |
| 9270 | const fields = struct_obj.fields.values(); | 9076 | const fields = struct_obj.fields.values(); |
| 9271 | comptime assert(Type.packed_struct_layout_version == 2); | 9077 | comptime assert(Type.packed_struct_layout_version == 2); |
| ... | @@ -9273,12 +9079,12 @@ pub const FuncGen = struct { | ... | @@ -9273,12 +9079,12 @@ pub const FuncGen = struct { |
| 9273 | var running_bits: u16 = 0; | 9079 | var running_bits: u16 = 0; |
| 9274 | for (elements, 0..) |elem, i| { | 9080 | for (elements, 0..) |elem, i| { |
| 9275 | const field = fields[i]; | 9081 | const field = fields[i]; |
| 9276 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 9082 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 9277 | 9083 | ||
| 9278 | const non_int_val = try self.resolveInst(elem); | 9084 | const non_int_val = try self.resolveInst(elem); |
| 9279 | const ty_bit_size = @intCast(u16, field.ty.bitSize(target)); | 9085 | const ty_bit_size = @intCast(u16, field.ty.bitSize(mod)); |
| 9280 | const small_int_ty = self.context.intType(ty_bit_size); | 9086 | const small_int_ty = self.context.intType(ty_bit_size); |
| 9281 | const small_int_val = if (field.ty.isPtrAtRuntime()) | 9087 | const small_int_val = if (field.ty.isPtrAtRuntime(mod)) |
| 9282 | self.builder.buildPtrToInt(non_int_val, small_int_ty, "") | 9088 | self.builder.buildPtrToInt(non_int_val, small_int_ty, "") |
| 9283 | else | 9089 | else |
| 9284 | self.builder.buildBitCast(non_int_val, small_int_ty, ""); | 9090 | self.builder.buildBitCast(non_int_val, small_int_ty, ""); |
| ... | @@ -9294,30 +9100,28 @@ pub const FuncGen = struct { | ... | @@ -9294,30 +9100,28 @@ pub const FuncGen = struct { |
| 9294 | return running_int; | 9100 | return running_int; |
| 9295 | } | 9101 | } |
| 9296 | 9102 | ||
| 9297 | var ptr_ty_buf: Type.Payload.Pointer = undefined; | 9103 | if (isByRef(result_ty, mod)) { |
| 9298 | |||
| 9299 | if (isByRef(result_ty)) { | ||
| 9300 | const llvm_u32 = self.context.intType(32); | 9104 | const llvm_u32 = self.context.intType(32); |
| 9301 | // TODO in debug builds init to undef so that the padding will be 0xaa | 9105 | // TODO in debug builds init to undef so that the padding will be 0xaa |
| 9302 | // even if we fully populate the fields. | 9106 | // even if we fully populate the fields. |
| 9303 | const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(target)); | 9107 | const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(mod)); |
| 9304 | 9108 | ||
| 9305 | var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined }; | 9109 | var indices: [2]*llvm.Value = .{ llvm_u32.constNull(), undefined }; |
| 9306 | for (elements, 0..) |elem, i| { | 9110 | for (elements, 0..) |elem, i| { |
| 9307 | if (result_ty.structFieldValueComptime(i) != null) continue; | 9111 | if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue; |
| 9308 | 9112 | ||
| 9309 | const llvm_elem = try self.resolveInst(elem); | 9113 | const llvm_elem = try self.resolveInst(elem); |
| 9310 | const llvm_i = llvmFieldIndex(result_ty, i, target, &ptr_ty_buf).?; | 9114 | const llvm_i = llvmField(result_ty, i, mod).?.index; |
| 9311 | indices[1] = llvm_u32.constInt(llvm_i, .False); | 9115 | indices[1] = llvm_u32.constInt(llvm_i, .False); |
| 9312 | const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, ""); | 9116 | const field_ptr = self.builder.buildInBoundsGEP(llvm_result_ty, alloca_inst, &indices, indices.len, ""); |
| 9313 | var field_ptr_payload: Type.Payload.Pointer = .{ | 9117 | const field_ptr_ty = try mod.ptrType(.{ |
| 9314 | .data = .{ | 9118 | .child = self.typeOf(elem).toIntern(), |
| 9315 | .pointee_type = self.air.typeOf(elem), | 9119 | .flags = .{ |
| 9316 | .@"align" = result_ty.structFieldAlign(i, target), | 9120 | .alignment = InternPool.Alignment.fromNonzeroByteUnits( |
| 9317 | .@"addrspace" = .generic, | 9121 | result_ty.structFieldAlign(i, mod), |
| 9122 | ), | ||
| 9318 | }, | 9123 | }, |
| 9319 | }; | 9124 | }); |
| 9320 | const field_ptr_ty = Type.initPayload(&field_ptr_payload.base); | ||
| 9321 | try self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic); | 9125 | try self.store(field_ptr, field_ptr_ty, llvm_elem, .NotAtomic); |
| 9322 | } | 9126 | } |
| 9323 | 9127 | ||
| ... | @@ -9325,29 +9129,25 @@ pub const FuncGen = struct { | ... | @@ -9325,29 +9129,25 @@ pub const FuncGen = struct { |
| 9325 | } else { | 9129 | } else { |
| 9326 | var result = llvm_result_ty.getUndef(); | 9130 | var result = llvm_result_ty.getUndef(); |
| 9327 | for (elements, 0..) |elem, i| { | 9131 | for (elements, 0..) |elem, i| { |
| 9328 | if (result_ty.structFieldValueComptime(i) != null) continue; | 9132 | if ((try result_ty.structFieldValueComptime(mod, i)) != null) continue; |
| 9329 | 9133 | ||
| 9330 | const llvm_elem = try self.resolveInst(elem); | 9134 | const llvm_elem = try self.resolveInst(elem); |
| 9331 | const llvm_i = llvmFieldIndex(result_ty, i, target, &ptr_ty_buf).?; | 9135 | const llvm_i = llvmField(result_ty, i, mod).?.index; |
| 9332 | result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, ""); | 9136 | result = self.builder.buildInsertValue(result, llvm_elem, llvm_i, ""); |
| 9333 | } | 9137 | } |
| 9334 | return result; | 9138 | return result; |
| 9335 | } | 9139 | } |
| 9336 | }, | 9140 | }, |
| 9337 | .Array => { | 9141 | .Array => { |
| 9338 | assert(isByRef(result_ty)); | 9142 | assert(isByRef(result_ty, mod)); |
| 9339 | 9143 | ||
| 9340 | const llvm_usize = try self.dg.lowerType(Type.usize); | 9144 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| 9341 | const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(target)); | 9145 | const alloca_inst = self.buildAlloca(llvm_result_ty, result_ty.abiAlignment(mod)); |
| 9342 | 9146 | ||
| 9343 | const array_info = result_ty.arrayInfo(); | 9147 | const array_info = result_ty.arrayInfo(mod); |
| 9344 | var elem_ptr_payload: Type.Payload.Pointer = .{ | 9148 | const elem_ptr_ty = try mod.ptrType(.{ |
| 9345 | .data = .{ | 9149 | .child = array_info.elem_type.toIntern(), |
| 9346 | .pointee_type = array_info.elem_type, | 9150 | }); |
| 9347 | .@"addrspace" = .generic, | ||
| 9348 | }, | ||
| 9349 | }; | ||
| 9350 | const elem_ptr_ty = Type.initPayload(&elem_ptr_payload.base); | ||
| 9351 | 9151 | ||
| 9352 | for (elements, 0..) |elem, i| { | 9152 | for (elements, 0..) |elem, i| { |
| 9353 | const indices: [2]*llvm.Value = .{ | 9153 | const indices: [2]*llvm.Value = .{ |
| ... | @@ -9379,22 +9179,22 @@ pub const FuncGen = struct { | ... | @@ -9379,22 +9179,22 @@ pub const FuncGen = struct { |
| 9379 | } | 9179 | } |
| 9380 | 9180 | ||
| 9381 | fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 9181 | fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 9182 | const mod = self.dg.module; | ||
| 9382 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 9183 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 9383 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; | 9184 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 9384 | const union_ty = self.air.typeOfIndex(inst); | 9185 | const union_ty = self.typeOfIndex(inst); |
| 9385 | const union_llvm_ty = try self.dg.lowerType(union_ty); | 9186 | const union_llvm_ty = try self.dg.lowerType(union_ty); |
| 9386 | const target = self.dg.module.getTarget(); | 9187 | const layout = union_ty.unionGetLayout(mod); |
| 9387 | const layout = union_ty.unionGetLayout(target); | 9188 | const union_obj = mod.typeToUnion(union_ty).?; |
| 9388 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | ||
| 9389 | 9189 | ||
| 9390 | if (union_obj.layout == .Packed) { | 9190 | if (union_obj.layout == .Packed) { |
| 9391 | const big_bits = union_ty.bitSize(target); | 9191 | const big_bits = union_ty.bitSize(mod); |
| 9392 | const int_llvm_ty = self.context.intType(@intCast(c_uint, big_bits)); | 9192 | const int_llvm_ty = self.context.intType(@intCast(c_uint, big_bits)); |
| 9393 | const field = union_obj.fields.values()[extra.field_index]; | 9193 | const field = union_obj.fields.values()[extra.field_index]; |
| 9394 | const non_int_val = try self.resolveInst(extra.init); | 9194 | const non_int_val = try self.resolveInst(extra.init); |
| 9395 | const ty_bit_size = @intCast(u16, field.ty.bitSize(target)); | 9195 | const ty_bit_size = @intCast(u16, field.ty.bitSize(mod)); |
| 9396 | const small_int_ty = self.context.intType(ty_bit_size); | 9196 | const small_int_ty = self.context.intType(ty_bit_size); |
| 9397 | const small_int_val = if (field.ty.isPtrAtRuntime()) | 9197 | const small_int_val = if (field.ty.isPtrAtRuntime(mod)) |
| 9398 | self.builder.buildPtrToInt(non_int_val, small_int_ty, "") | 9198 | self.builder.buildPtrToInt(non_int_val, small_int_ty, "") |
| 9399 | else | 9199 | else |
| 9400 | self.builder.buildBitCast(non_int_val, small_int_ty, ""); | 9200 | self.builder.buildBitCast(non_int_val, small_int_ty, ""); |
| ... | @@ -9402,26 +9202,21 @@ pub const FuncGen = struct { | ... | @@ -9402,26 +9202,21 @@ pub const FuncGen = struct { |
| 9402 | } | 9202 | } |
| 9403 | 9203 | ||
| 9404 | const tag_int = blk: { | 9204 | const tag_int = blk: { |
| 9405 | const tag_ty = union_ty.unionTagTypeHypothetical(); | 9205 | const tag_ty = union_ty.unionTagTypeHypothetical(mod); |
| 9406 | const union_field_name = union_obj.fields.keys()[extra.field_index]; | 9206 | const union_field_name = union_obj.fields.keys()[extra.field_index]; |
| 9407 | const enum_field_index = tag_ty.enumFieldIndex(union_field_name).?; | 9207 | const enum_field_index = tag_ty.enumFieldIndex(union_field_name, mod).?; |
| 9408 | var tag_val_payload: Value.Payload.U32 = .{ | 9208 | const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index); |
| 9409 | .base = .{ .tag = .enum_field_index }, | 9209 | const tag_int_val = try tag_val.enumToInt(tag_ty, mod); |
| 9410 | .data = @intCast(u32, enum_field_index), | 9210 | break :blk tag_int_val.toUnsignedInt(mod); |
| 9411 | }; | ||
| 9412 | const tag_val = Value.initPayload(&tag_val_payload.base); | ||
| 9413 | var int_payload: Value.Payload.U64 = undefined; | ||
| 9414 | const tag_int_val = tag_val.enumToInt(tag_ty, &int_payload); | ||
| 9415 | break :blk tag_int_val.toUnsignedInt(target); | ||
| 9416 | }; | 9211 | }; |
| 9417 | if (layout.payload_size == 0) { | 9212 | if (layout.payload_size == 0) { |
| 9418 | if (layout.tag_size == 0) { | 9213 | if (layout.tag_size == 0) { |
| 9419 | return null; | 9214 | return null; |
| 9420 | } | 9215 | } |
| 9421 | assert(!isByRef(union_ty)); | 9216 | assert(!isByRef(union_ty, mod)); |
| 9422 | return union_llvm_ty.constInt(tag_int, .False); | 9217 | return union_llvm_ty.constInt(tag_int, .False); |
| 9423 | } | 9218 | } |
| 9424 | assert(isByRef(union_ty)); | 9219 | assert(isByRef(union_ty, mod)); |
| 9425 | // The llvm type of the alloca will be the named LLVM union type, and will not | 9220 | // The llvm type of the alloca will be the named LLVM union type, and will not |
| 9426 | // necessarily match the format that we need, depending on which tag is active. | 9221 | // necessarily match the format that we need, depending on which tag is active. |
| 9427 | // We must construct the correct unnamed struct type here, in order to then set | 9222 | // We must construct the correct unnamed struct type here, in order to then set |
| ... | @@ -9431,12 +9226,12 @@ pub const FuncGen = struct { | ... | @@ -9431,12 +9226,12 @@ pub const FuncGen = struct { |
| 9431 | assert(union_obj.haveFieldTypes()); | 9226 | assert(union_obj.haveFieldTypes()); |
| 9432 | const field = union_obj.fields.values()[extra.field_index]; | 9227 | const field = union_obj.fields.values()[extra.field_index]; |
| 9433 | const field_llvm_ty = try self.dg.lowerType(field.ty); | 9228 | const field_llvm_ty = try self.dg.lowerType(field.ty); |
| 9434 | const field_size = field.ty.abiSize(target); | 9229 | const field_size = field.ty.abiSize(mod); |
| 9435 | const field_align = field.normalAlignment(target); | 9230 | const field_align = field.normalAlignment(mod); |
| 9436 | 9231 | ||
| 9437 | const llvm_union_ty = t: { | 9232 | const llvm_union_ty = t: { |
| 9438 | const payload = p: { | 9233 | const payload = p: { |
| 9439 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) { | 9234 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 9440 | const padding_len = @intCast(c_uint, layout.payload_size); | 9235 | const padding_len = @intCast(c_uint, layout.payload_size); |
| 9441 | break :p self.context.intType(8).arrayType(padding_len); | 9236 | break :p self.context.intType(8).arrayType(padding_len); |
| 9442 | } | 9237 | } |
| ... | @@ -9472,14 +9267,12 @@ pub const FuncGen = struct { | ... | @@ -9472,14 +9267,12 @@ pub const FuncGen = struct { |
| 9472 | // tag and the payload. | 9267 | // tag and the payload. |
| 9473 | const index_type = self.context.intType(32); | 9268 | const index_type = self.context.intType(32); |
| 9474 | 9269 | ||
| 9475 | var field_ptr_payload: Type.Payload.Pointer = .{ | 9270 | const field_ptr_ty = try mod.ptrType(.{ |
| 9476 | .data = .{ | 9271 | .child = field.ty.toIntern(), |
| 9477 | .pointee_type = field.ty, | 9272 | .flags = .{ |
| 9478 | .@"align" = field_align, | 9273 | .alignment = InternPool.Alignment.fromNonzeroByteUnits(field_align), |
| 9479 | .@"addrspace" = .generic, | ||
| 9480 | }, | 9274 | }, |
| 9481 | }; | 9275 | }); |
| 9482 | const field_ptr_ty = Type.initPayload(&field_ptr_payload.base); | ||
| 9483 | if (layout.tag_size == 0) { | 9276 | if (layout.tag_size == 0) { |
| 9484 | const indices: [3]*llvm.Value = .{ | 9277 | const indices: [3]*llvm.Value = .{ |
| 9485 | index_type.constNull(), | 9278 | index_type.constNull(), |
| ... | @@ -9511,7 +9304,7 @@ pub const FuncGen = struct { | ... | @@ -9511,7 +9304,7 @@ pub const FuncGen = struct { |
| 9511 | const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty); | 9304 | const tag_llvm_ty = try self.dg.lowerType(union_obj.tag_ty); |
| 9512 | const llvm_tag = tag_llvm_ty.constInt(tag_int, .False); | 9305 | const llvm_tag = tag_llvm_ty.constInt(tag_int, .False); |
| 9513 | const store_inst = self.builder.buildStore(llvm_tag, field_ptr); | 9306 | const store_inst = self.builder.buildStore(llvm_tag, field_ptr); |
| 9514 | store_inst.setAlignment(union_obj.tag_ty.abiAlignment(target)); | 9307 | store_inst.setAlignment(union_obj.tag_ty.abiAlignment(mod)); |
| 9515 | } | 9308 | } |
| 9516 | 9309 | ||
| 9517 | return result_ptr; | 9310 | return result_ptr; |
| ... | @@ -9535,7 +9328,8 @@ pub const FuncGen = struct { | ... | @@ -9535,7 +9328,8 @@ pub const FuncGen = struct { |
| 9535 | // by the target. | 9328 | // by the target. |
| 9536 | // To work around this, don't emit llvm.prefetch in this case. | 9329 | // To work around this, don't emit llvm.prefetch in this case. |
| 9537 | // See https://bugs.llvm.org/show_bug.cgi?id=21037 | 9330 | // See https://bugs.llvm.org/show_bug.cgi?id=21037 |
| 9538 | const target = self.dg.module.getTarget(); | 9331 | const mod = self.dg.module; |
| 9332 | const target = mod.getTarget(); | ||
| 9539 | switch (prefetch.cache) { | 9333 | switch (prefetch.cache) { |
| 9540 | .instruction => switch (target.cpu.arch) { | 9334 | .instruction => switch (target.cpu.arch) { |
| 9541 | .x86_64, | 9335 | .x86_64, |
| ... | @@ -9584,7 +9378,7 @@ pub const FuncGen = struct { | ... | @@ -9584,7 +9378,7 @@ pub const FuncGen = struct { |
| 9584 | 9378 | ||
| 9585 | fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 9379 | fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 9586 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 9380 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 9587 | const inst_ty = self.air.typeOfIndex(inst); | 9381 | const inst_ty = self.typeOfIndex(inst); |
| 9588 | const operand = try self.resolveInst(ty_op.operand); | 9382 | const operand = try self.resolveInst(ty_op.operand); |
| 9589 | 9383 | ||
| 9590 | const llvm_dest_ty = try self.dg.lowerType(inst_ty); | 9384 | const llvm_dest_ty = try self.dg.lowerType(inst_ty); |
| ... | @@ -9658,8 +9452,9 @@ pub const FuncGen = struct { | ... | @@ -9658,8 +9452,9 @@ pub const FuncGen = struct { |
| 9658 | return table; | 9452 | return table; |
| 9659 | } | 9453 | } |
| 9660 | 9454 | ||
| 9661 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | 9455 | const mod = self.dg.module; |
| 9662 | const slice_alignment = slice_ty.abiAlignment(self.dg.module.getTarget()); | 9456 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 9457 | const slice_alignment = slice_ty.abiAlignment(mod); | ||
| 9663 | const llvm_slice_ptr_ty = self.context.pointerType(0); // TODO: Address space | 9458 | const llvm_slice_ptr_ty = self.context.pointerType(0); // TODO: Address space |
| 9664 | 9459 | ||
| 9665 | const error_name_table_global = self.dg.object.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table"); | 9460 | const error_name_table_global = self.dg.object.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table"); |
| ... | @@ -9701,16 +9496,15 @@ pub const FuncGen = struct { | ... | @@ -9701,16 +9496,15 @@ pub const FuncGen = struct { |
| 9701 | opt_ty: Type, | 9496 | opt_ty: Type, |
| 9702 | can_elide_load: bool, | 9497 | can_elide_load: bool, |
| 9703 | ) !*llvm.Value { | 9498 | ) !*llvm.Value { |
| 9704 | var buf: Type.Payload.ElemType = undefined; | 9499 | const mod = fg.dg.module; |
| 9705 | const payload_ty = opt_ty.optionalChild(&buf); | 9500 | const payload_ty = opt_ty.optionalChild(mod); |
| 9706 | 9501 | ||
| 9707 | if (isByRef(opt_ty)) { | 9502 | if (isByRef(opt_ty, mod)) { |
| 9708 | // We have a pointer and we need to return a pointer to the first field. | 9503 | // We have a pointer and we need to return a pointer to the first field. |
| 9709 | const payload_ptr = fg.builder.buildStructGEP(opt_llvm_ty, opt_handle, 0, ""); | 9504 | const payload_ptr = fg.builder.buildStructGEP(opt_llvm_ty, opt_handle, 0, ""); |
| 9710 | 9505 | ||
| 9711 | const target = fg.dg.module.getTarget(); | 9506 | const payload_alignment = payload_ty.abiAlignment(mod); |
| 9712 | const payload_alignment = payload_ty.abiAlignment(target); | 9507 | if (isByRef(payload_ty, mod)) { |
| 9713 | if (isByRef(payload_ty)) { | ||
| 9714 | if (can_elide_load) | 9508 | if (can_elide_load) |
| 9715 | return payload_ptr; | 9509 | return payload_ptr; |
| 9716 | 9510 | ||
| ... | @@ -9722,7 +9516,7 @@ pub const FuncGen = struct { | ... | @@ -9722,7 +9516,7 @@ pub const FuncGen = struct { |
| 9722 | return load_inst; | 9516 | return load_inst; |
| 9723 | } | 9517 | } |
| 9724 | 9518 | ||
| 9725 | assert(!isByRef(payload_ty)); | 9519 | assert(!isByRef(payload_ty, mod)); |
| 9726 | return fg.builder.buildExtractValue(opt_handle, 0, ""); | 9520 | return fg.builder.buildExtractValue(opt_handle, 0, ""); |
| 9727 | } | 9521 | } |
| 9728 | 9522 | ||
| ... | @@ -9734,10 +9528,10 @@ pub const FuncGen = struct { | ... | @@ -9734,10 +9528,10 @@ pub const FuncGen = struct { |
| 9734 | ) !?*llvm.Value { | 9528 | ) !?*llvm.Value { |
| 9735 | const optional_llvm_ty = try self.dg.lowerType(optional_ty); | 9529 | const optional_llvm_ty = try self.dg.lowerType(optional_ty); |
| 9736 | const non_null_field = self.builder.buildZExt(non_null_bit, self.context.intType(8), ""); | 9530 | const non_null_field = self.builder.buildZExt(non_null_bit, self.context.intType(8), ""); |
| 9531 | const mod = self.dg.module; | ||
| 9737 | 9532 | ||
| 9738 | if (isByRef(optional_ty)) { | 9533 | if (isByRef(optional_ty, mod)) { |
| 9739 | const target = self.dg.module.getTarget(); | 9534 | const payload_alignment = optional_ty.abiAlignment(mod); |
| 9740 | const payload_alignment = optional_ty.abiAlignment(target); | ||
| 9741 | const alloca_inst = self.buildAlloca(optional_llvm_ty, payload_alignment); | 9535 | const alloca_inst = self.buildAlloca(optional_llvm_ty, payload_alignment); |
| 9742 | 9536 | ||
| 9743 | { | 9537 | { |
| ... | @@ -9765,13 +9559,13 @@ pub const FuncGen = struct { | ... | @@ -9765,13 +9559,13 @@ pub const FuncGen = struct { |
| 9765 | struct_ptr_ty: Type, | 9559 | struct_ptr_ty: Type, |
| 9766 | field_index: u32, | 9560 | field_index: u32, |
| 9767 | ) !?*llvm.Value { | 9561 | ) !?*llvm.Value { |
| 9768 | const target = self.dg.object.target; | 9562 | const mod = self.dg.module; |
| 9769 | const struct_ty = struct_ptr_ty.childType(); | 9563 | const struct_ty = struct_ptr_ty.childType(mod); |
| 9770 | switch (struct_ty.zigTypeTag()) { | 9564 | switch (struct_ty.zigTypeTag(mod)) { |
| 9771 | .Struct => switch (struct_ty.containerLayout()) { | 9565 | .Struct => switch (struct_ty.containerLayout(mod)) { |
| 9772 | .Packed => { | 9566 | .Packed => { |
| 9773 | const result_ty = self.air.typeOfIndex(inst); | 9567 | const result_ty = self.typeOfIndex(inst); |
| 9774 | const result_ty_info = result_ty.ptrInfo().data; | 9568 | const result_ty_info = result_ty.ptrInfo(mod); |
| 9775 | 9569 | ||
| 9776 | if (result_ty_info.host_size != 0) { | 9570 | if (result_ty_info.host_size != 0) { |
| 9777 | // From LLVM's perspective, a pointer to a packed struct and a pointer | 9571 | // From LLVM's perspective, a pointer to a packed struct and a pointer |
| ... | @@ -9783,7 +9577,7 @@ pub const FuncGen = struct { | ... | @@ -9783,7 +9577,7 @@ pub const FuncGen = struct { |
| 9783 | 9577 | ||
| 9784 | // We have a pointer to a packed struct field that happens to be byte-aligned. | 9578 | // We have a pointer to a packed struct field that happens to be byte-aligned. |
| 9785 | // Offset our operand pointer by the correct number of bytes. | 9579 | // Offset our operand pointer by the correct number of bytes. |
| 9786 | const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, target); | 9580 | const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, mod); |
| 9787 | if (byte_offset == 0) return struct_ptr; | 9581 | if (byte_offset == 0) return struct_ptr; |
| 9788 | const byte_llvm_ty = self.context.intType(8); | 9582 | const byte_llvm_ty = self.context.intType(8); |
| 9789 | const llvm_usize = try self.dg.lowerType(Type.usize); | 9583 | const llvm_usize = try self.dg.lowerType(Type.usize); |
| ... | @@ -9794,24 +9588,23 @@ pub const FuncGen = struct { | ... | @@ -9794,24 +9588,23 @@ pub const FuncGen = struct { |
| 9794 | else => { | 9588 | else => { |
| 9795 | const struct_llvm_ty = try self.dg.lowerPtrElemTy(struct_ty); | 9589 | const struct_llvm_ty = try self.dg.lowerPtrElemTy(struct_ty); |
| 9796 | 9590 | ||
| 9797 | var ty_buf: Type.Payload.Pointer = undefined; | 9591 | if (llvmField(struct_ty, field_index, mod)) |llvm_field| { |
| 9798 | if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| { | 9592 | return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field.index, ""); |
| 9799 | return self.builder.buildStructGEP(struct_llvm_ty, struct_ptr, llvm_field_index, ""); | ||
| 9800 | } else { | 9593 | } else { |
| 9801 | // If we found no index then this means this is a zero sized field at the | 9594 | // If we found no index then this means this is a zero sized field at the |
| 9802 | // end of the struct. Treat our struct pointer as an array of two and get | 9595 | // end of the struct. Treat our struct pointer as an array of two and get |
| 9803 | // the index to the element at index `1` to get a pointer to the end of | 9596 | // the index to the element at index `1` to get a pointer to the end of |
| 9804 | // the struct. | 9597 | // the struct. |
| 9805 | const llvm_u32 = self.context.intType(32); | 9598 | const llvm_u32 = self.context.intType(32); |
| 9806 | const llvm_index = llvm_u32.constInt(@boolToInt(struct_ty.hasRuntimeBitsIgnoreComptime()), .False); | 9599 | const llvm_index = llvm_u32.constInt(@boolToInt(struct_ty.hasRuntimeBitsIgnoreComptime(mod)), .False); |
| 9807 | const indices: [1]*llvm.Value = .{llvm_index}; | 9600 | const indices: [1]*llvm.Value = .{llvm_index}; |
| 9808 | return self.builder.buildInBoundsGEP(struct_llvm_ty, struct_ptr, &indices, indices.len, ""); | 9601 | return self.builder.buildInBoundsGEP(struct_llvm_ty, struct_ptr, &indices, indices.len, ""); |
| 9809 | } | 9602 | } |
| 9810 | }, | 9603 | }, |
| 9811 | }, | 9604 | }, |
| 9812 | .Union => { | 9605 | .Union => { |
| 9813 | const layout = struct_ty.unionGetLayout(target); | 9606 | const layout = struct_ty.unionGetLayout(mod); |
| 9814 | if (layout.payload_size == 0 or struct_ty.containerLayout() == .Packed) return struct_ptr; | 9607 | if (layout.payload_size == 0 or struct_ty.containerLayout(mod) == .Packed) return struct_ptr; |
| 9815 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); | 9608 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); |
| 9816 | const union_llvm_ty = try self.dg.lowerType(struct_ty); | 9609 | const union_llvm_ty = try self.dg.lowerType(struct_ty); |
| 9817 | const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_ptr, payload_index, ""); | 9610 | const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, struct_ptr, payload_index, ""); |
| ... | @@ -9835,12 +9628,12 @@ pub const FuncGen = struct { | ... | @@ -9835,12 +9628,12 @@ pub const FuncGen = struct { |
| 9835 | ptr_alignment: u32, | 9628 | ptr_alignment: u32, |
| 9836 | is_volatile: bool, | 9629 | is_volatile: bool, |
| 9837 | ) !*llvm.Value { | 9630 | ) !*llvm.Value { |
| 9631 | const mod = fg.dg.module; | ||
| 9838 | const pointee_llvm_ty = try fg.dg.lowerType(pointee_type); | 9632 | const pointee_llvm_ty = try fg.dg.lowerType(pointee_type); |
| 9839 | const target = fg.dg.module.getTarget(); | 9633 | const result_align = @max(ptr_alignment, pointee_type.abiAlignment(mod)); |
| 9840 | const result_align = @max(ptr_alignment, pointee_type.abiAlignment(target)); | ||
| 9841 | const result_ptr = fg.buildAlloca(pointee_llvm_ty, result_align); | 9634 | const result_ptr = fg.buildAlloca(pointee_llvm_ty, result_align); |
| 9842 | const llvm_usize = fg.context.intType(Type.usize.intInfo(target).bits); | 9635 | const llvm_usize = fg.context.intType(Type.usize.intInfo(mod).bits); |
| 9843 | const size_bytes = pointee_type.abiSize(target); | 9636 | const size_bytes = pointee_type.abiSize(mod); |
| 9844 | _ = fg.builder.buildMemCpy( | 9637 | _ = fg.builder.buildMemCpy( |
| 9845 | result_ptr, | 9638 | result_ptr, |
| 9846 | result_align, | 9639 | result_align, |
| ... | @@ -9856,12 +9649,12 @@ pub const FuncGen = struct { | ... | @@ -9856,12 +9649,12 @@ pub const FuncGen = struct { |
| 9856 | /// alloca and copies the value into it, then returns the alloca instruction. | 9649 | /// alloca and copies the value into it, then returns the alloca instruction. |
| 9857 | /// For isByRef=false types, it creates a load instruction and returns it. | 9650 | /// For isByRef=false types, it creates a load instruction and returns it. |
| 9858 | fn load(self: *FuncGen, ptr: *llvm.Value, ptr_ty: Type) !?*llvm.Value { | 9651 | fn load(self: *FuncGen, ptr: *llvm.Value, ptr_ty: Type) !?*llvm.Value { |
| 9859 | const info = ptr_ty.ptrInfo().data; | 9652 | const mod = self.dg.module; |
| 9860 | if (!info.pointee_type.hasRuntimeBitsIgnoreComptime()) return null; | 9653 | const info = ptr_ty.ptrInfo(mod); |
| 9654 | if (!info.pointee_type.hasRuntimeBitsIgnoreComptime(mod)) return null; | ||
| 9861 | 9655 | ||
| 9862 | const target = self.dg.module.getTarget(); | 9656 | const ptr_alignment = info.alignment(mod); |
| 9863 | const ptr_alignment = info.alignment(target); | 9657 | const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr(mod)); |
| 9864 | const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr()); | ||
| 9865 | 9658 | ||
| 9866 | assert(info.vector_index != .runtime); | 9659 | assert(info.vector_index != .runtime); |
| 9867 | if (info.vector_index != .none) { | 9660 | if (info.vector_index != .none) { |
| ... | @@ -9877,7 +9670,7 @@ pub const FuncGen = struct { | ... | @@ -9877,7 +9670,7 @@ pub const FuncGen = struct { |
| 9877 | } | 9670 | } |
| 9878 | 9671 | ||
| 9879 | if (info.host_size == 0) { | 9672 | if (info.host_size == 0) { |
| 9880 | if (isByRef(info.pointee_type)) { | 9673 | if (isByRef(info.pointee_type, mod)) { |
| 9881 | return self.loadByRef(ptr, info.pointee_type, ptr_alignment, info.@"volatile"); | 9674 | return self.loadByRef(ptr, info.pointee_type, ptr_alignment, info.@"volatile"); |
| 9882 | } | 9675 | } |
| 9883 | const elem_llvm_ty = try self.dg.lowerType(info.pointee_type); | 9676 | const elem_llvm_ty = try self.dg.lowerType(info.pointee_type); |
| ... | @@ -9892,13 +9685,13 @@ pub const FuncGen = struct { | ... | @@ -9892,13 +9685,13 @@ pub const FuncGen = struct { |
| 9892 | containing_int.setAlignment(ptr_alignment); | 9685 | containing_int.setAlignment(ptr_alignment); |
| 9893 | containing_int.setVolatile(ptr_volatile); | 9686 | containing_int.setVolatile(ptr_volatile); |
| 9894 | 9687 | ||
| 9895 | const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target)); | 9688 | const elem_bits = @intCast(c_uint, ptr_ty.childType(mod).bitSize(mod)); |
| 9896 | const shift_amt = containing_int.typeOf().constInt(info.bit_offset, .False); | 9689 | const shift_amt = containing_int.typeOf().constInt(info.bit_offset, .False); |
| 9897 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt, ""); | 9690 | const shifted_value = self.builder.buildLShr(containing_int, shift_amt, ""); |
| 9898 | const elem_llvm_ty = try self.dg.lowerType(info.pointee_type); | 9691 | const elem_llvm_ty = try self.dg.lowerType(info.pointee_type); |
| 9899 | 9692 | ||
| 9900 | if (isByRef(info.pointee_type)) { | 9693 | if (isByRef(info.pointee_type, mod)) { |
| 9901 | const result_align = info.pointee_type.abiAlignment(target); | 9694 | const result_align = info.pointee_type.abiAlignment(mod); |
| 9902 | const result_ptr = self.buildAlloca(elem_llvm_ty, result_align); | 9695 | const result_ptr = self.buildAlloca(elem_llvm_ty, result_align); |
| 9903 | 9696 | ||
| 9904 | const same_size_int = self.context.intType(elem_bits); | 9697 | const same_size_int = self.context.intType(elem_bits); |
| ... | @@ -9908,13 +9701,13 @@ pub const FuncGen = struct { | ... | @@ -9908,13 +9701,13 @@ pub const FuncGen = struct { |
| 9908 | return result_ptr; | 9701 | return result_ptr; |
| 9909 | } | 9702 | } |
| 9910 | 9703 | ||
| 9911 | if (info.pointee_type.zigTypeTag() == .Float or info.pointee_type.zigTypeTag() == .Vector) { | 9704 | if (info.pointee_type.zigTypeTag(mod) == .Float or info.pointee_type.zigTypeTag(mod) == .Vector) { |
| 9912 | const same_size_int = self.context.intType(elem_bits); | 9705 | const same_size_int = self.context.intType(elem_bits); |
| 9913 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); | 9706 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| 9914 | return self.builder.buildBitCast(truncated_int, elem_llvm_ty, ""); | 9707 | return self.builder.buildBitCast(truncated_int, elem_llvm_ty, ""); |
| 9915 | } | 9708 | } |
| 9916 | 9709 | ||
| 9917 | if (info.pointee_type.isPtrAtRuntime()) { | 9710 | if (info.pointee_type.isPtrAtRuntime(mod)) { |
| 9918 | const same_size_int = self.context.intType(elem_bits); | 9711 | const same_size_int = self.context.intType(elem_bits); |
| 9919 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); | 9712 | const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, ""); |
| 9920 | return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, ""); | 9713 | return self.builder.buildIntToPtr(truncated_int, elem_llvm_ty, ""); |
| ... | @@ -9930,13 +9723,13 @@ pub const FuncGen = struct { | ... | @@ -9930,13 +9723,13 @@ pub const FuncGen = struct { |
| 9930 | elem: *llvm.Value, | 9723 | elem: *llvm.Value, |
| 9931 | ordering: llvm.AtomicOrdering, | 9724 | ordering: llvm.AtomicOrdering, |
| 9932 | ) !void { | 9725 | ) !void { |
| 9933 | const info = ptr_ty.ptrInfo().data; | 9726 | const mod = self.dg.module; |
| 9727 | const info = ptr_ty.ptrInfo(mod); | ||
| 9934 | const elem_ty = info.pointee_type; | 9728 | const elem_ty = info.pointee_type; |
| 9935 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { | 9729 | if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) { |
| 9936 | return; | 9730 | return; |
| 9937 | } | 9731 | } |
| 9938 | const target = self.dg.module.getTarget(); | 9732 | const ptr_alignment = ptr_ty.ptrAlignment(mod); |
| 9939 | const ptr_alignment = ptr_ty.ptrAlignment(target); | ||
| 9940 | const ptr_volatile = llvm.Bool.fromBool(info.@"volatile"); | 9733 | const ptr_volatile = llvm.Bool.fromBool(info.@"volatile"); |
| 9941 | 9734 | ||
| 9942 | assert(info.vector_index != .runtime); | 9735 | assert(info.vector_index != .runtime); |
| ... | @@ -9964,13 +9757,13 @@ pub const FuncGen = struct { | ... | @@ -9964,13 +9757,13 @@ pub const FuncGen = struct { |
| 9964 | assert(ordering == .NotAtomic); | 9757 | assert(ordering == .NotAtomic); |
| 9965 | containing_int.setAlignment(ptr_alignment); | 9758 | containing_int.setAlignment(ptr_alignment); |
| 9966 | containing_int.setVolatile(ptr_volatile); | 9759 | containing_int.setVolatile(ptr_volatile); |
| 9967 | const elem_bits = @intCast(c_uint, ptr_ty.elemType().bitSize(target)); | 9760 | const elem_bits = @intCast(c_uint, ptr_ty.childType(mod).bitSize(mod)); |
| 9968 | const containing_int_ty = containing_int.typeOf(); | 9761 | const containing_int_ty = containing_int.typeOf(); |
| 9969 | const shift_amt = containing_int_ty.constInt(info.bit_offset, .False); | 9762 | const shift_amt = containing_int_ty.constInt(info.bit_offset, .False); |
| 9970 | // Convert to equally-sized integer type in order to perform the bit | 9763 | // Convert to equally-sized integer type in order to perform the bit |
| 9971 | // operations on the value to store | 9764 | // operations on the value to store |
| 9972 | const value_bits_type = self.context.intType(elem_bits); | 9765 | const value_bits_type = self.context.intType(elem_bits); |
| 9973 | const value_bits = if (elem_ty.isPtrAtRuntime()) | 9766 | const value_bits = if (elem_ty.isPtrAtRuntime(mod)) |
| 9974 | self.builder.buildPtrToInt(elem, value_bits_type, "") | 9767 | self.builder.buildPtrToInt(elem, value_bits_type, "") |
| 9975 | else | 9768 | else |
| 9976 | self.builder.buildBitCast(elem, value_bits_type, ""); | 9769 | self.builder.buildBitCast(elem, value_bits_type, ""); |
| ... | @@ -9991,7 +9784,7 @@ pub const FuncGen = struct { | ... | @@ -9991,7 +9784,7 @@ pub const FuncGen = struct { |
| 9991 | store_inst.setVolatile(ptr_volatile); | 9784 | store_inst.setVolatile(ptr_volatile); |
| 9992 | return; | 9785 | return; |
| 9993 | } | 9786 | } |
| 9994 | if (!isByRef(elem_ty)) { | 9787 | if (!isByRef(elem_ty, mod)) { |
| 9995 | const store_inst = self.builder.buildStore(elem, ptr); | 9788 | const store_inst = self.builder.buildStore(elem, ptr); |
| 9996 | store_inst.setOrdering(ordering); | 9789 | store_inst.setOrdering(ordering); |
| 9997 | store_inst.setAlignment(ptr_alignment); | 9790 | store_inst.setAlignment(ptr_alignment); |
| ... | @@ -9999,13 +9792,13 @@ pub const FuncGen = struct { | ... | @@ -9999,13 +9792,13 @@ pub const FuncGen = struct { |
| 9999 | return; | 9792 | return; |
| 10000 | } | 9793 | } |
| 10001 | assert(ordering == .NotAtomic); | 9794 | assert(ordering == .NotAtomic); |
| 10002 | const size_bytes = elem_ty.abiSize(target); | 9795 | const size_bytes = elem_ty.abiSize(mod); |
| 10003 | _ = self.builder.buildMemCpy( | 9796 | _ = self.builder.buildMemCpy( |
| 10004 | ptr, | 9797 | ptr, |
| 10005 | ptr_alignment, | 9798 | ptr_alignment, |
| 10006 | elem, | 9799 | elem, |
| 10007 | elem_ty.abiAlignment(target), | 9800 | elem_ty.abiAlignment(mod), |
| 10008 | self.context.intType(Type.usize.intInfo(target).bits).constInt(size_bytes, .False), | 9801 | self.context.intType(Type.usize.intInfo(mod).bits).constInt(size_bytes, .False), |
| 10009 | info.@"volatile", | 9802 | info.@"volatile", |
| 10010 | ); | 9803 | ); |
| 10011 | } | 9804 | } |
| ... | @@ -10030,11 +9823,12 @@ pub const FuncGen = struct { | ... | @@ -10030,11 +9823,12 @@ pub const FuncGen = struct { |
| 10030 | a4: *llvm.Value, | 9823 | a4: *llvm.Value, |
| 10031 | a5: *llvm.Value, | 9824 | a5: *llvm.Value, |
| 10032 | ) *llvm.Value { | 9825 | ) *llvm.Value { |
| 10033 | const target = fg.dg.module.getTarget(); | 9826 | const mod = fg.dg.module; |
| 9827 | const target = mod.getTarget(); | ||
| 10034 | if (!target_util.hasValgrindSupport(target)) return default_value; | 9828 | if (!target_util.hasValgrindSupport(target)) return default_value; |
| 10035 | 9829 | ||
| 10036 | const usize_llvm_ty = fg.context.intType(target.ptrBitWidth()); | 9830 | const usize_llvm_ty = fg.context.intType(target.ptrBitWidth()); |
| 10037 | const usize_alignment = @intCast(c_uint, Type.usize.abiSize(target)); | 9831 | const usize_alignment = @intCast(c_uint, Type.usize.abiSize(mod)); |
| 10038 | 9832 | ||
| 10039 | const array_llvm_ty = usize_llvm_ty.arrayType(6); | 9833 | const array_llvm_ty = usize_llvm_ty.arrayType(6); |
| 10040 | const array_ptr = fg.valgrind_client_request_array orelse a: { | 9834 | const array_ptr = fg.valgrind_client_request_array orelse a: { |
| ... | @@ -10111,6 +9905,16 @@ pub const FuncGen = struct { | ... | @@ -10111,6 +9905,16 @@ pub const FuncGen = struct { |
| 10111 | ); | 9905 | ); |
| 10112 | return call; | 9906 | return call; |
| 10113 | } | 9907 | } |
| 9908 | |||
| 9909 | fn typeOf(fg: *FuncGen, inst: Air.Inst.Ref) Type { | ||
| 9910 | const mod = fg.dg.module; | ||
| 9911 | return fg.air.typeOf(inst, &mod.intern_pool); | ||
| 9912 | } | ||
| 9913 | |||
| 9914 | fn typeOfIndex(fg: *FuncGen, inst: Air.Inst.Index) Type { | ||
| 9915 | const mod = fg.dg.module; | ||
| 9916 | return fg.air.typeOfIndex(inst, &mod.intern_pool); | ||
| 9917 | } | ||
| 10114 | }; | 9918 | }; |
| 10115 | 9919 | ||
| 10116 | fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void { | 9920 | fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void { |
| ... | @@ -10444,62 +10248,64 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, targ | ... | @@ -10444,62 +10248,64 @@ fn toLlvmGlobalAddressSpace(wanted_address_space: std.builtin.AddressSpace, targ |
| 10444 | }; | 10248 | }; |
| 10445 | } | 10249 | } |
| 10446 | 10250 | ||
| 10251 | const LlvmField = struct { | ||
| 10252 | index: c_uint, | ||
| 10253 | ty: Type, | ||
| 10254 | alignment: u32, | ||
| 10255 | }; | ||
| 10256 | |||
| 10447 | /// Take into account 0 bit fields and padding. Returns null if an llvm | 10257 | /// Take into account 0 bit fields and padding. Returns null if an llvm |
| 10448 | /// field could not be found. | 10258 | /// field could not be found. |
| 10449 | /// This only happens if you want the field index of a zero sized field at | 10259 | /// This only happens if you want the field index of a zero sized field at |
| 10450 | /// the end of the struct. | 10260 | /// the end of the struct. |
| 10451 | fn llvmFieldIndex( | 10261 | fn llvmField(ty: Type, field_index: usize, mod: *Module) ?LlvmField { |
| 10452 | ty: Type, | ||
| 10453 | field_index: usize, | ||
| 10454 | target: std.Target, | ||
| 10455 | ptr_pl_buf: *Type.Payload.Pointer, | ||
| 10456 | ) ?c_uint { | ||
| 10457 | // Detects where we inserted extra padding fields so that we can skip | 10262 | // Detects where we inserted extra padding fields so that we can skip |
| 10458 | // over them in this function. | 10263 | // over them in this function. |
| 10459 | comptime assert(struct_layout_version == 2); | 10264 | comptime assert(struct_layout_version == 2); |
| 10460 | var offset: u64 = 0; | 10265 | var offset: u64 = 0; |
| 10461 | var big_align: u32 = 0; | 10266 | var big_align: u32 = 0; |
| 10462 | 10267 | ||
| 10463 | if (ty.isSimpleTupleOrAnonStruct()) { | 10268 | const struct_type = switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 10464 | const tuple = ty.tupleFields(); | 10269 | .anon_struct_type => |tuple| { |
| 10465 | var llvm_field_index: c_uint = 0; | 10270 | var llvm_field_index: c_uint = 0; |
| 10466 | for (tuple.types, 0..) |field_ty, i| { | 10271 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { |
| 10467 | if (tuple.values[i].tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; | 10272 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; |
| 10468 | 10273 | ||
| 10469 | const field_align = field_ty.abiAlignment(target); | 10274 | const field_align = field_ty.toType().abiAlignment(mod); |
| 10470 | big_align = @max(big_align, field_align); | 10275 | big_align = @max(big_align, field_align); |
| 10471 | const prev_offset = offset; | 10276 | const prev_offset = offset; |
| 10472 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 10277 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 10473 | 10278 | ||
| 10474 | const padding_len = offset - prev_offset; | 10279 | const padding_len = offset - prev_offset; |
| 10475 | if (padding_len > 0) { | 10280 | if (padding_len > 0) { |
| 10476 | llvm_field_index += 1; | 10281 | llvm_field_index += 1; |
| 10477 | } | 10282 | } |
| 10478 | 10283 | ||
| 10479 | if (field_index <= i) { | 10284 | if (field_index <= i) { |
| 10480 | ptr_pl_buf.* = .{ | 10285 | return .{ |
| 10481 | .data = .{ | 10286 | .index = llvm_field_index, |
| 10482 | .pointee_type = field_ty, | 10287 | .ty = field_ty.toType(), |
| 10483 | .@"align" = field_align, | 10288 | .alignment = field_align, |
| 10484 | .@"addrspace" = .generic, | 10289 | }; |
| 10485 | }, | 10290 | } |
| 10486 | }; | ||
| 10487 | return llvm_field_index; | ||
| 10488 | } | ||
| 10489 | 10291 | ||
| 10490 | llvm_field_index += 1; | 10292 | llvm_field_index += 1; |
| 10491 | offset += field_ty.abiSize(target); | 10293 | offset += field_ty.toType().abiSize(mod); |
| 10492 | } | 10294 | } |
| 10493 | return null; | 10295 | return null; |
| 10494 | } | 10296 | }, |
| 10495 | const layout = ty.containerLayout(); | 10297 | .struct_type => |s| s, |
| 10298 | else => unreachable, | ||
| 10299 | }; | ||
| 10300 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 10301 | const layout = struct_obj.layout; | ||
| 10496 | assert(layout != .Packed); | 10302 | assert(layout != .Packed); |
| 10497 | 10303 | ||
| 10498 | var llvm_field_index: c_uint = 0; | 10304 | var llvm_field_index: c_uint = 0; |
| 10499 | var it = ty.castTag(.@"struct").?.data.runtimeFieldIterator(); | 10305 | var it = struct_obj.runtimeFieldIterator(mod); |
| 10500 | while (it.next()) |field_and_index| { | 10306 | while (it.next()) |field_and_index| { |
| 10501 | const field = field_and_index.field; | 10307 | const field = field_and_index.field; |
| 10502 | const field_align = field.alignment(target, layout); | 10308 | const field_align = field.alignment(mod, layout); |
| 10503 | big_align = @max(big_align, field_align); | 10309 | big_align = @max(big_align, field_align); |
| 10504 | const prev_offset = offset; | 10310 | const prev_offset = offset; |
| 10505 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 10311 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| ... | @@ -10510,54 +10316,52 @@ fn llvmFieldIndex( | ... | @@ -10510,54 +10316,52 @@ fn llvmFieldIndex( |
| 10510 | } | 10316 | } |
| 10511 | 10317 | ||
| 10512 | if (field_index == field_and_index.index) { | 10318 | if (field_index == field_and_index.index) { |
| 10513 | ptr_pl_buf.* = .{ | 10319 | return .{ |
| 10514 | .data = .{ | 10320 | .index = llvm_field_index, |
| 10515 | .pointee_type = field.ty, | 10321 | .ty = field.ty, |
| 10516 | .@"align" = field_align, | 10322 | .alignment = field_align, |
| 10517 | .@"addrspace" = .generic, | ||
| 10518 | }, | ||
| 10519 | }; | 10323 | }; |
| 10520 | return llvm_field_index; | ||
| 10521 | } | 10324 | } |
| 10522 | 10325 | ||
| 10523 | llvm_field_index += 1; | 10326 | llvm_field_index += 1; |
| 10524 | offset += field.ty.abiSize(target); | 10327 | offset += field.ty.abiSize(mod); |
| 10525 | } else { | 10328 | } else { |
| 10526 | // We did not find an llvm field that corresponds to this zig field. | 10329 | // We did not find an llvm field that corresponds to this zig field. |
| 10527 | return null; | 10330 | return null; |
| 10528 | } | 10331 | } |
| 10529 | } | 10332 | } |
| 10530 | 10333 | ||
| 10531 | fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool { | 10334 | fn firstParamSRet(fn_info: InternPool.Key.FuncType, mod: *Module) bool { |
| 10532 | if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) return false; | 10335 | if (!fn_info.return_type.toType().hasRuntimeBitsIgnoreComptime(mod)) return false; |
| 10533 | 10336 | ||
| 10337 | const target = mod.getTarget(); | ||
| 10534 | switch (fn_info.cc) { | 10338 | switch (fn_info.cc) { |
| 10535 | .Unspecified, .Inline => return isByRef(fn_info.return_type), | 10339 | .Unspecified, .Inline => return isByRef(fn_info.return_type.toType(), mod), |
| 10536 | .C => switch (target.cpu.arch) { | 10340 | .C => switch (target.cpu.arch) { |
| 10537 | .mips, .mipsel => return false, | 10341 | .mips, .mipsel => return false, |
| 10538 | .x86_64 => switch (target.os.tag) { | 10342 | .x86_64 => switch (target.os.tag) { |
| 10539 | .windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory, | 10343 | .windows => return x86_64_abi.classifyWindows(fn_info.return_type.toType(), mod) == .memory, |
| 10540 | else => return firstParamSRetSystemV(fn_info.return_type, target), | 10344 | else => return firstParamSRetSystemV(fn_info.return_type.toType(), mod), |
| 10541 | }, | 10345 | }, |
| 10542 | .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect, | 10346 | .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type.toType(), mod)[0] == .indirect, |
| 10543 | .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target) == .memory, | 10347 | .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type.toType(), mod) == .memory, |
| 10544 | .arm, .armeb => switch (arm_c_abi.classifyType(fn_info.return_type, target, .ret)) { | 10348 | .arm, .armeb => switch (arm_c_abi.classifyType(fn_info.return_type.toType(), mod, .ret)) { |
| 10545 | .memory, .i64_array => return true, | 10349 | .memory, .i64_array => return true, |
| 10546 | .i32_array => |size| return size != 1, | 10350 | .i32_array => |size| return size != 1, |
| 10547 | .byval => return false, | 10351 | .byval => return false, |
| 10548 | }, | 10352 | }, |
| 10549 | .riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type, target) == .memory, | 10353 | .riscv32, .riscv64 => return riscv_c_abi.classifyType(fn_info.return_type.toType(), mod) == .memory, |
| 10550 | else => return false, // TODO investigate C ABI for other architectures | 10354 | else => return false, // TODO investigate C ABI for other architectures |
| 10551 | }, | 10355 | }, |
| 10552 | .SysV => return firstParamSRetSystemV(fn_info.return_type, target), | 10356 | .SysV => return firstParamSRetSystemV(fn_info.return_type.toType(), mod), |
| 10553 | .Win64 => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory, | 10357 | .Win64 => return x86_64_abi.classifyWindows(fn_info.return_type.toType(), mod) == .memory, |
| 10554 | .Stdcall => return !isScalar(fn_info.return_type), | 10358 | .Stdcall => return !isScalar(mod, fn_info.return_type.toType()), |
| 10555 | else => return false, | 10359 | else => return false, |
| 10556 | } | 10360 | } |
| 10557 | } | 10361 | } |
| 10558 | 10362 | ||
| 10559 | fn firstParamSRetSystemV(ty: Type, target: std.Target) bool { | 10363 | fn firstParamSRetSystemV(ty: Type, mod: *Module) bool { |
| 10560 | const class = x86_64_abi.classifySystemV(ty, target, .ret); | 10364 | const class = x86_64_abi.classifySystemV(ty, mod, .ret); |
| 10561 | if (class[0] == .memory) return true; | 10365 | if (class[0] == .memory) return true; |
| 10562 | if (class[0] == .x87 and class[2] != .none) return true; | 10366 | if (class[0] == .x87 and class[2] != .none) return true; |
| 10563 | return false; | 10367 | return false; |
| ... | @@ -10566,75 +10370,77 @@ fn firstParamSRetSystemV(ty: Type, target: std.Target) bool { | ... | @@ -10566,75 +10370,77 @@ fn firstParamSRetSystemV(ty: Type, target: std.Target) bool { |
| 10566 | /// In order to support the C calling convention, some return types need to be lowered | 10370 | /// In order to support the C calling convention, some return types need to be lowered |
| 10567 | /// completely differently in the function prototype to honor the C ABI, and then | 10371 | /// completely differently in the function prototype to honor the C ABI, and then |
| 10568 | /// be effectively bitcasted to the actual return type. | 10372 | /// be effectively bitcasted to the actual return type. |
| 10569 | fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { | 10373 | fn lowerFnRetTy(dg: *DeclGen, fn_info: InternPool.Key.FuncType) !*llvm.Type { |
| 10570 | if (!fn_info.return_type.hasRuntimeBitsIgnoreComptime()) { | 10374 | const mod = dg.module; |
| 10375 | const return_type = fn_info.return_type.toType(); | ||
| 10376 | if (!return_type.hasRuntimeBitsIgnoreComptime(mod)) { | ||
| 10571 | // If the return type is an error set or an error union, then we make this | 10377 | // If the return type is an error set or an error union, then we make this |
| 10572 | // anyerror return type instead, so that it can be coerced into a function | 10378 | // anyerror return type instead, so that it can be coerced into a function |
| 10573 | // pointer type which has anyerror as the return type. | 10379 | // pointer type which has anyerror as the return type. |
| 10574 | if (fn_info.return_type.isError()) { | 10380 | if (return_type.isError(mod)) { |
| 10575 | return dg.lowerType(Type.anyerror); | 10381 | return dg.lowerType(Type.anyerror); |
| 10576 | } else { | 10382 | } else { |
| 10577 | return dg.context.voidType(); | 10383 | return dg.context.voidType(); |
| 10578 | } | 10384 | } |
| 10579 | } | 10385 | } |
| 10580 | const target = dg.module.getTarget(); | 10386 | const target = mod.getTarget(); |
| 10581 | switch (fn_info.cc) { | 10387 | switch (fn_info.cc) { |
| 10582 | .Unspecified, .Inline => { | 10388 | .Unspecified, .Inline => { |
| 10583 | if (isByRef(fn_info.return_type)) { | 10389 | if (isByRef(return_type, mod)) { |
| 10584 | return dg.context.voidType(); | 10390 | return dg.context.voidType(); |
| 10585 | } else { | 10391 | } else { |
| 10586 | return dg.lowerType(fn_info.return_type); | 10392 | return dg.lowerType(return_type); |
| 10587 | } | 10393 | } |
| 10588 | }, | 10394 | }, |
| 10589 | .C => { | 10395 | .C => { |
| 10590 | switch (target.cpu.arch) { | 10396 | switch (target.cpu.arch) { |
| 10591 | .mips, .mipsel => return dg.lowerType(fn_info.return_type), | 10397 | .mips, .mipsel => return dg.lowerType(return_type), |
| 10592 | .x86_64 => switch (target.os.tag) { | 10398 | .x86_64 => switch (target.os.tag) { |
| 10593 | .windows => return lowerWin64FnRetTy(dg, fn_info), | 10399 | .windows => return lowerWin64FnRetTy(dg, fn_info), |
| 10594 | else => return lowerSystemVFnRetTy(dg, fn_info), | 10400 | else => return lowerSystemVFnRetTy(dg, fn_info), |
| 10595 | }, | 10401 | }, |
| 10596 | .wasm32 => { | 10402 | .wasm32 => { |
| 10597 | if (isScalar(fn_info.return_type)) { | 10403 | if (isScalar(mod, return_type)) { |
| 10598 | return dg.lowerType(fn_info.return_type); | 10404 | return dg.lowerType(return_type); |
| 10599 | } | 10405 | } |
| 10600 | const classes = wasm_c_abi.classifyType(fn_info.return_type, target); | 10406 | const classes = wasm_c_abi.classifyType(return_type, mod); |
| 10601 | if (classes[0] == .indirect or classes[0] == .none) { | 10407 | if (classes[0] == .indirect or classes[0] == .none) { |
| 10602 | return dg.context.voidType(); | 10408 | return dg.context.voidType(); |
| 10603 | } | 10409 | } |
| 10604 | 10410 | ||
| 10605 | assert(classes[0] == .direct and classes[1] == .none); | 10411 | assert(classes[0] == .direct and classes[1] == .none); |
| 10606 | const scalar_type = wasm_c_abi.scalarType(fn_info.return_type, target); | 10412 | const scalar_type = wasm_c_abi.scalarType(return_type, mod); |
| 10607 | const abi_size = scalar_type.abiSize(target); | 10413 | const abi_size = scalar_type.abiSize(mod); |
| 10608 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); | 10414 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10609 | }, | 10415 | }, |
| 10610 | .aarch64, .aarch64_be => { | 10416 | .aarch64, .aarch64_be => { |
| 10611 | switch (aarch64_c_abi.classifyType(fn_info.return_type, target)) { | 10417 | switch (aarch64_c_abi.classifyType(return_type, mod)) { |
| 10612 | .memory => return dg.context.voidType(), | 10418 | .memory => return dg.context.voidType(), |
| 10613 | .float_array => return dg.lowerType(fn_info.return_type), | 10419 | .float_array => return dg.lowerType(return_type), |
| 10614 | .byval => return dg.lowerType(fn_info.return_type), | 10420 | .byval => return dg.lowerType(return_type), |
| 10615 | .integer => { | 10421 | .integer => { |
| 10616 | const bit_size = fn_info.return_type.bitSize(target); | 10422 | const bit_size = return_type.bitSize(mod); |
| 10617 | return dg.context.intType(@intCast(c_uint, bit_size)); | 10423 | return dg.context.intType(@intCast(c_uint, bit_size)); |
| 10618 | }, | 10424 | }, |
| 10619 | .double_integer => return dg.context.intType(64).arrayType(2), | 10425 | .double_integer => return dg.context.intType(64).arrayType(2), |
| 10620 | } | 10426 | } |
| 10621 | }, | 10427 | }, |
| 10622 | .arm, .armeb => { | 10428 | .arm, .armeb => { |
| 10623 | switch (arm_c_abi.classifyType(fn_info.return_type, target, .ret)) { | 10429 | switch (arm_c_abi.classifyType(return_type, mod, .ret)) { |
| 10624 | .memory, .i64_array => return dg.context.voidType(), | 10430 | .memory, .i64_array => return dg.context.voidType(), |
| 10625 | .i32_array => |len| if (len == 1) { | 10431 | .i32_array => |len| if (len == 1) { |
| 10626 | return dg.context.intType(32); | 10432 | return dg.context.intType(32); |
| 10627 | } else { | 10433 | } else { |
| 10628 | return dg.context.voidType(); | 10434 | return dg.context.voidType(); |
| 10629 | }, | 10435 | }, |
| 10630 | .byval => return dg.lowerType(fn_info.return_type), | 10436 | .byval => return dg.lowerType(return_type), |
| 10631 | } | 10437 | } |
| 10632 | }, | 10438 | }, |
| 10633 | .riscv32, .riscv64 => { | 10439 | .riscv32, .riscv64 => { |
| 10634 | switch (riscv_c_abi.classifyType(fn_info.return_type, target)) { | 10440 | switch (riscv_c_abi.classifyType(return_type, mod)) { |
| 10635 | .memory => return dg.context.voidType(), | 10441 | .memory => return dg.context.voidType(), |
| 10636 | .integer => { | 10442 | .integer => { |
| 10637 | const bit_size = fn_info.return_type.bitSize(target); | 10443 | const bit_size = return_type.bitSize(mod); |
| 10638 | return dg.context.intType(@intCast(c_uint, bit_size)); | 10444 | return dg.context.intType(@intCast(c_uint, bit_size)); |
| 10639 | }, | 10445 | }, |
| 10640 | .double_integer => { | 10446 | .double_integer => { |
| ... | @@ -10644,50 +10450,52 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { | ... | @@ -10644,50 +10450,52 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10644 | }; | 10450 | }; |
| 10645 | return dg.context.structType(&llvm_types_buffer, 2, .False); | 10451 | return dg.context.structType(&llvm_types_buffer, 2, .False); |
| 10646 | }, | 10452 | }, |
| 10647 | .byval => return dg.lowerType(fn_info.return_type), | 10453 | .byval => return dg.lowerType(return_type), |
| 10648 | } | 10454 | } |
| 10649 | }, | 10455 | }, |
| 10650 | // TODO investigate C ABI for other architectures | 10456 | // TODO investigate C ABI for other architectures |
| 10651 | else => return dg.lowerType(fn_info.return_type), | 10457 | else => return dg.lowerType(return_type), |
| 10652 | } | 10458 | } |
| 10653 | }, | 10459 | }, |
| 10654 | .Win64 => return lowerWin64FnRetTy(dg, fn_info), | 10460 | .Win64 => return lowerWin64FnRetTy(dg, fn_info), |
| 10655 | .SysV => return lowerSystemVFnRetTy(dg, fn_info), | 10461 | .SysV => return lowerSystemVFnRetTy(dg, fn_info), |
| 10656 | .Stdcall => { | 10462 | .Stdcall => { |
| 10657 | if (isScalar(fn_info.return_type)) { | 10463 | if (isScalar(mod, return_type)) { |
| 10658 | return dg.lowerType(fn_info.return_type); | 10464 | return dg.lowerType(return_type); |
| 10659 | } else { | 10465 | } else { |
| 10660 | return dg.context.voidType(); | 10466 | return dg.context.voidType(); |
| 10661 | } | 10467 | } |
| 10662 | }, | 10468 | }, |
| 10663 | else => return dg.lowerType(fn_info.return_type), | 10469 | else => return dg.lowerType(return_type), |
| 10664 | } | 10470 | } |
| 10665 | } | 10471 | } |
| 10666 | 10472 | ||
| 10667 | fn lowerWin64FnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { | 10473 | fn lowerWin64FnRetTy(dg: *DeclGen, fn_info: InternPool.Key.FuncType) !*llvm.Type { |
| 10668 | const target = dg.module.getTarget(); | 10474 | const mod = dg.module; |
| 10669 | switch (x86_64_abi.classifyWindows(fn_info.return_type, target)) { | 10475 | const return_type = fn_info.return_type.toType(); |
| 10476 | switch (x86_64_abi.classifyWindows(return_type, mod)) { | ||
| 10670 | .integer => { | 10477 | .integer => { |
| 10671 | if (isScalar(fn_info.return_type)) { | 10478 | if (isScalar(mod, return_type)) { |
| 10672 | return dg.lowerType(fn_info.return_type); | 10479 | return dg.lowerType(return_type); |
| 10673 | } else { | 10480 | } else { |
| 10674 | const abi_size = fn_info.return_type.abiSize(target); | 10481 | const abi_size = return_type.abiSize(mod); |
| 10675 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); | 10482 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10676 | } | 10483 | } |
| 10677 | }, | 10484 | }, |
| 10678 | .win_i128 => return dg.context.intType(64).vectorType(2), | 10485 | .win_i128 => return dg.context.intType(64).vectorType(2), |
| 10679 | .memory => return dg.context.voidType(), | 10486 | .memory => return dg.context.voidType(), |
| 10680 | .sse => return dg.lowerType(fn_info.return_type), | 10487 | .sse => return dg.lowerType(return_type), |
| 10681 | else => unreachable, | 10488 | else => unreachable, |
| 10682 | } | 10489 | } |
| 10683 | } | 10490 | } |
| 10684 | 10491 | ||
| 10685 | fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { | 10492 | fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: InternPool.Key.FuncType) !*llvm.Type { |
| 10686 | if (isScalar(fn_info.return_type)) { | 10493 | const mod = dg.module; |
| 10687 | return dg.lowerType(fn_info.return_type); | 10494 | const return_type = fn_info.return_type.toType(); |
| 10495 | if (isScalar(mod, return_type)) { | ||
| 10496 | return dg.lowerType(return_type); | ||
| 10688 | } | 10497 | } |
| 10689 | const target = dg.module.getTarget(); | 10498 | const classes = x86_64_abi.classifySystemV(return_type, mod, .ret); |
| 10690 | const classes = x86_64_abi.classifySystemV(fn_info.return_type, target, .ret); | ||
| 10691 | if (classes[0] == .memory) { | 10499 | if (classes[0] == .memory) { |
| 10692 | return dg.context.voidType(); | 10500 | return dg.context.voidType(); |
| 10693 | } | 10501 | } |
| ... | @@ -10728,7 +10536,7 @@ fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm | ... | @@ -10728,7 +10536,7 @@ fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm |
| 10728 | } | 10536 | } |
| 10729 | } | 10537 | } |
| 10730 | if (classes[0] == .integer and classes[1] == .none) { | 10538 | if (classes[0] == .integer and classes[1] == .none) { |
| 10731 | const abi_size = fn_info.return_type.abiSize(target); | 10539 | const abi_size = return_type.abiSize(mod); |
| 10732 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); | 10540 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 10733 | } | 10541 | } |
| 10734 | return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False); | 10542 | return dg.context.structType(&llvm_types_buffer, llvm_types_index, .False); |
| ... | @@ -10736,10 +10544,9 @@ fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm | ... | @@ -10736,10 +10544,9 @@ fn lowerSystemVFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm |
| 10736 | 10544 | ||
| 10737 | const ParamTypeIterator = struct { | 10545 | const ParamTypeIterator = struct { |
| 10738 | dg: *DeclGen, | 10546 | dg: *DeclGen, |
| 10739 | fn_info: Type.Payload.Function.Data, | 10547 | fn_info: InternPool.Key.FuncType, |
| 10740 | zig_index: u32, | 10548 | zig_index: u32, |
| 10741 | llvm_index: u32, | 10549 | llvm_index: u32, |
| 10742 | target: std.Target, | ||
| 10743 | llvm_types_len: u32, | 10550 | llvm_types_len: u32, |
| 10744 | llvm_types_buffer: [8]*llvm.Type, | 10551 | llvm_types_buffer: [8]*llvm.Type, |
| 10745 | byval_attr: bool, | 10552 | byval_attr: bool, |
| ... | @@ -10762,7 +10569,7 @@ const ParamTypeIterator = struct { | ... | @@ -10762,7 +10569,7 @@ const ParamTypeIterator = struct { |
| 10762 | if (it.zig_index >= it.fn_info.param_types.len) return null; | 10569 | if (it.zig_index >= it.fn_info.param_types.len) return null; |
| 10763 | const ty = it.fn_info.param_types[it.zig_index]; | 10570 | const ty = it.fn_info.param_types[it.zig_index]; |
| 10764 | it.byval_attr = false; | 10571 | it.byval_attr = false; |
| 10765 | return nextInner(it, ty); | 10572 | return nextInner(it, ty.toType()); |
| 10766 | } | 10573 | } |
| 10767 | 10574 | ||
| 10768 | /// `airCall` uses this instead of `next` so that it can take into account variadic functions. | 10575 | /// `airCall` uses this instead of `next` so that it can take into account variadic functions. |
| ... | @@ -10771,15 +10578,18 @@ const ParamTypeIterator = struct { | ... | @@ -10771,15 +10578,18 @@ const ParamTypeIterator = struct { |
| 10771 | if (it.zig_index >= args.len) { | 10578 | if (it.zig_index >= args.len) { |
| 10772 | return null; | 10579 | return null; |
| 10773 | } else { | 10580 | } else { |
| 10774 | return nextInner(it, fg.air.typeOf(args[it.zig_index])); | 10581 | return nextInner(it, fg.typeOf(args[it.zig_index])); |
| 10775 | } | 10582 | } |
| 10776 | } else { | 10583 | } else { |
| 10777 | return nextInner(it, it.fn_info.param_types[it.zig_index]); | 10584 | return nextInner(it, it.fn_info.param_types[it.zig_index].toType()); |
| 10778 | } | 10585 | } |
| 10779 | } | 10586 | } |
| 10780 | 10587 | ||
| 10781 | fn nextInner(it: *ParamTypeIterator, ty: Type) ?Lowering { | 10588 | fn nextInner(it: *ParamTypeIterator, ty: Type) ?Lowering { |
| 10782 | if (!ty.hasRuntimeBitsIgnoreComptime()) { | 10589 | const mod = it.dg.module; |
| 10590 | const target = mod.getTarget(); | ||
| 10591 | |||
| 10592 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) { | ||
| 10783 | it.zig_index += 1; | 10593 | it.zig_index += 1; |
| 10784 | return .no_bits; | 10594 | return .no_bits; |
| 10785 | } | 10595 | } |
| ... | @@ -10787,11 +10597,10 @@ const ParamTypeIterator = struct { | ... | @@ -10787,11 +10597,10 @@ const ParamTypeIterator = struct { |
| 10787 | .Unspecified, .Inline => { | 10597 | .Unspecified, .Inline => { |
| 10788 | it.zig_index += 1; | 10598 | it.zig_index += 1; |
| 10789 | it.llvm_index += 1; | 10599 | it.llvm_index += 1; |
| 10790 | var buf: Type.Payload.ElemType = undefined; | 10600 | if (ty.isSlice(mod) or (ty.zigTypeTag(mod) == .Optional and ty.optionalChild(mod).isSlice(mod))) { |
| 10791 | if (ty.isSlice() or (ty.zigTypeTag() == .Optional and ty.optionalChild(&buf).isSlice())) { | ||
| 10792 | it.llvm_index += 1; | 10601 | it.llvm_index += 1; |
| 10793 | return .slice; | 10602 | return .slice; |
| 10794 | } else if (isByRef(ty)) { | 10603 | } else if (isByRef(ty, mod)) { |
| 10795 | return .byref; | 10604 | return .byref; |
| 10796 | } else { | 10605 | } else { |
| 10797 | return .byval; | 10606 | return .byval; |
| ... | @@ -10801,23 +10610,23 @@ const ParamTypeIterator = struct { | ... | @@ -10801,23 +10610,23 @@ const ParamTypeIterator = struct { |
| 10801 | @panic("TODO implement async function lowering in the LLVM backend"); | 10610 | @panic("TODO implement async function lowering in the LLVM backend"); |
| 10802 | }, | 10611 | }, |
| 10803 | .C => { | 10612 | .C => { |
| 10804 | switch (it.target.cpu.arch) { | 10613 | switch (target.cpu.arch) { |
| 10805 | .mips, .mipsel => { | 10614 | .mips, .mipsel => { |
| 10806 | it.zig_index += 1; | 10615 | it.zig_index += 1; |
| 10807 | it.llvm_index += 1; | 10616 | it.llvm_index += 1; |
| 10808 | return .byval; | 10617 | return .byval; |
| 10809 | }, | 10618 | }, |
| 10810 | .x86_64 => switch (it.target.os.tag) { | 10619 | .x86_64 => switch (target.os.tag) { |
| 10811 | .windows => return it.nextWin64(ty), | 10620 | .windows => return it.nextWin64(ty), |
| 10812 | else => return it.nextSystemV(ty), | 10621 | else => return it.nextSystemV(ty), |
| 10813 | }, | 10622 | }, |
| 10814 | .wasm32 => { | 10623 | .wasm32 => { |
| 10815 | it.zig_index += 1; | 10624 | it.zig_index += 1; |
| 10816 | it.llvm_index += 1; | 10625 | it.llvm_index += 1; |
| 10817 | if (isScalar(ty)) { | 10626 | if (isScalar(mod, ty)) { |
| 10818 | return .byval; | 10627 | return .byval; |
| 10819 | } | 10628 | } |
| 10820 | const classes = wasm_c_abi.classifyType(ty, it.target); | 10629 | const classes = wasm_c_abi.classifyType(ty, mod); |
| 10821 | if (classes[0] == .indirect) { | 10630 | if (classes[0] == .indirect) { |
| 10822 | return .byref; | 10631 | return .byref; |
| 10823 | } | 10632 | } |
| ... | @@ -10826,7 +10635,7 @@ const ParamTypeIterator = struct { | ... | @@ -10826,7 +10635,7 @@ const ParamTypeIterator = struct { |
| 10826 | .aarch64, .aarch64_be => { | 10635 | .aarch64, .aarch64_be => { |
| 10827 | it.zig_index += 1; | 10636 | it.zig_index += 1; |
| 10828 | it.llvm_index += 1; | 10637 | it.llvm_index += 1; |
| 10829 | switch (aarch64_c_abi.classifyType(ty, it.target)) { | 10638 | switch (aarch64_c_abi.classifyType(ty, mod)) { |
| 10830 | .memory => return .byref_mut, | 10639 | .memory => return .byref_mut, |
| 10831 | .float_array => |len| return Lowering{ .float_array = len }, | 10640 | .float_array => |len| return Lowering{ .float_array = len }, |
| 10832 | .byval => return .byval, | 10641 | .byval => return .byval, |
| ... | @@ -10841,7 +10650,7 @@ const ParamTypeIterator = struct { | ... | @@ -10841,7 +10650,7 @@ const ParamTypeIterator = struct { |
| 10841 | .arm, .armeb => { | 10650 | .arm, .armeb => { |
| 10842 | it.zig_index += 1; | 10651 | it.zig_index += 1; |
| 10843 | it.llvm_index += 1; | 10652 | it.llvm_index += 1; |
| 10844 | switch (arm_c_abi.classifyType(ty, it.target, .arg)) { | 10653 | switch (arm_c_abi.classifyType(ty, mod, .arg)) { |
| 10845 | .memory => { | 10654 | .memory => { |
| 10846 | it.byval_attr = true; | 10655 | it.byval_attr = true; |
| 10847 | return .byref; | 10656 | return .byref; |
| ... | @@ -10854,10 +10663,10 @@ const ParamTypeIterator = struct { | ... | @@ -10854,10 +10663,10 @@ const ParamTypeIterator = struct { |
| 10854 | .riscv32, .riscv64 => { | 10663 | .riscv32, .riscv64 => { |
| 10855 | it.zig_index += 1; | 10664 | it.zig_index += 1; |
| 10856 | it.llvm_index += 1; | 10665 | it.llvm_index += 1; |
| 10857 | if (ty.tag() == .f16) { | 10666 | if (ty.toIntern() == .f16_type) { |
| 10858 | return .as_u16; | 10667 | return .as_u16; |
| 10859 | } | 10668 | } |
| 10860 | switch (riscv_c_abi.classifyType(ty, it.target)) { | 10669 | switch (riscv_c_abi.classifyType(ty, mod)) { |
| 10861 | .memory => return .byref_mut, | 10670 | .memory => return .byref_mut, |
| 10862 | .byval => return .byval, | 10671 | .byval => return .byval, |
| 10863 | .integer => return .abi_sized_int, | 10672 | .integer => return .abi_sized_int, |
| ... | @@ -10878,7 +10687,7 @@ const ParamTypeIterator = struct { | ... | @@ -10878,7 +10687,7 @@ const ParamTypeIterator = struct { |
| 10878 | it.zig_index += 1; | 10687 | it.zig_index += 1; |
| 10879 | it.llvm_index += 1; | 10688 | it.llvm_index += 1; |
| 10880 | 10689 | ||
| 10881 | if (isScalar(ty)) { | 10690 | if (isScalar(mod, ty)) { |
| 10882 | return .byval; | 10691 | return .byval; |
| 10883 | } else { | 10692 | } else { |
| 10884 | it.byval_attr = true; | 10693 | it.byval_attr = true; |
| ... | @@ -10894,9 +10703,10 @@ const ParamTypeIterator = struct { | ... | @@ -10894,9 +10703,10 @@ const ParamTypeIterator = struct { |
| 10894 | } | 10703 | } |
| 10895 | 10704 | ||
| 10896 | fn nextWin64(it: *ParamTypeIterator, ty: Type) ?Lowering { | 10705 | fn nextWin64(it: *ParamTypeIterator, ty: Type) ?Lowering { |
| 10897 | switch (x86_64_abi.classifyWindows(ty, it.target)) { | 10706 | const mod = it.dg.module; |
| 10707 | switch (x86_64_abi.classifyWindows(ty, mod)) { | ||
| 10898 | .integer => { | 10708 | .integer => { |
| 10899 | if (isScalar(ty)) { | 10709 | if (isScalar(mod, ty)) { |
| 10900 | it.zig_index += 1; | 10710 | it.zig_index += 1; |
| 10901 | it.llvm_index += 1; | 10711 | it.llvm_index += 1; |
| 10902 | return .byval; | 10712 | return .byval; |
| ... | @@ -10926,14 +10736,15 @@ const ParamTypeIterator = struct { | ... | @@ -10926,14 +10736,15 @@ const ParamTypeIterator = struct { |
| 10926 | } | 10736 | } |
| 10927 | 10737 | ||
| 10928 | fn nextSystemV(it: *ParamTypeIterator, ty: Type) ?Lowering { | 10738 | fn nextSystemV(it: *ParamTypeIterator, ty: Type) ?Lowering { |
| 10929 | const classes = x86_64_abi.classifySystemV(ty, it.target, .arg); | 10739 | const mod = it.dg.module; |
| 10740 | const classes = x86_64_abi.classifySystemV(ty, mod, .arg); | ||
| 10930 | if (classes[0] == .memory) { | 10741 | if (classes[0] == .memory) { |
| 10931 | it.zig_index += 1; | 10742 | it.zig_index += 1; |
| 10932 | it.llvm_index += 1; | 10743 | it.llvm_index += 1; |
| 10933 | it.byval_attr = true; | 10744 | it.byval_attr = true; |
| 10934 | return .byref; | 10745 | return .byref; |
| 10935 | } | 10746 | } |
| 10936 | if (isScalar(ty)) { | 10747 | if (isScalar(mod, ty)) { |
| 10937 | it.zig_index += 1; | 10748 | it.zig_index += 1; |
| 10938 | it.llvm_index += 1; | 10749 | it.llvm_index += 1; |
| 10939 | return .byval; | 10750 | return .byval; |
| ... | @@ -10986,13 +10797,12 @@ const ParamTypeIterator = struct { | ... | @@ -10986,13 +10797,12 @@ const ParamTypeIterator = struct { |
| 10986 | } | 10797 | } |
| 10987 | }; | 10798 | }; |
| 10988 | 10799 | ||
| 10989 | fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTypeIterator { | 10800 | fn iterateParamTypes(dg: *DeclGen, fn_info: InternPool.Key.FuncType) ParamTypeIterator { |
| 10990 | return .{ | 10801 | return .{ |
| 10991 | .dg = dg, | 10802 | .dg = dg, |
| 10992 | .fn_info = fn_info, | 10803 | .fn_info = fn_info, |
| 10993 | .zig_index = 0, | 10804 | .zig_index = 0, |
| 10994 | .llvm_index = 0, | 10805 | .llvm_index = 0, |
| 10995 | .target = dg.module.getTarget(), | ||
| 10996 | .llvm_types_buffer = undefined, | 10806 | .llvm_types_buffer = undefined, |
| 10997 | .llvm_types_len = 0, | 10807 | .llvm_types_len = 0, |
| 10998 | .byval_attr = false, | 10808 | .byval_attr = false, |
| ... | @@ -11001,16 +10811,17 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp | ... | @@ -11001,16 +10811,17 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp |
| 11001 | 10811 | ||
| 11002 | fn ccAbiPromoteInt( | 10812 | fn ccAbiPromoteInt( |
| 11003 | cc: std.builtin.CallingConvention, | 10813 | cc: std.builtin.CallingConvention, |
| 11004 | target: std.Target, | 10814 | mod: *Module, |
| 11005 | ty: Type, | 10815 | ty: Type, |
| 11006 | ) ?std.builtin.Signedness { | 10816 | ) ?std.builtin.Signedness { |
| 10817 | const target = mod.getTarget(); | ||
| 11007 | switch (cc) { | 10818 | switch (cc) { |
| 11008 | .Unspecified, .Inline, .Async => return null, | 10819 | .Unspecified, .Inline, .Async => return null, |
| 11009 | else => {}, | 10820 | else => {}, |
| 11010 | } | 10821 | } |
| 11011 | const int_info = switch (ty.zigTypeTag()) { | 10822 | const int_info = switch (ty.zigTypeTag(mod)) { |
| 11012 | .Bool => Type.u1.intInfo(target), | 10823 | .Bool => Type.u1.intInfo(mod), |
| 11013 | .Int, .Enum, .ErrorSet => ty.intInfo(target), | 10824 | .Int, .Enum, .ErrorSet => ty.intInfo(mod), |
| 11014 | else => return null, | 10825 | else => return null, |
| 11015 | }; | 10826 | }; |
| 11016 | if (int_info.bits <= 16) return int_info.signedness; | 10827 | if (int_info.bits <= 16) return int_info.signedness; |
| ... | @@ -11039,12 +10850,12 @@ fn ccAbiPromoteInt( | ... | @@ -11039,12 +10850,12 @@ fn ccAbiPromoteInt( |
| 11039 | 10850 | ||
| 11040 | /// This is the one source of truth for whether a type is passed around as an LLVM pointer, | 10851 | /// This is the one source of truth for whether a type is passed around as an LLVM pointer, |
| 11041 | /// or as an LLVM value. | 10852 | /// or as an LLVM value. |
| 11042 | fn isByRef(ty: Type) bool { | 10853 | fn isByRef(ty: Type, mod: *Module) bool { |
| 11043 | // For tuples and structs, if there are more than this many non-void | 10854 | // For tuples and structs, if there are more than this many non-void |
| 11044 | // fields, then we make it byref, otherwise byval. | 10855 | // fields, then we make it byref, otherwise byval. |
| 11045 | const max_fields_byval = 0; | 10856 | const max_fields_byval = 0; |
| 11046 | 10857 | ||
| 11047 | switch (ty.zigTypeTag()) { | 10858 | switch (ty.zigTypeTag(mod)) { |
| 11048 | .Type, | 10859 | .Type, |
| 11049 | .ComptimeInt, | 10860 | .ComptimeInt, |
| 11050 | .ComptimeFloat, | 10861 | .ComptimeFloat, |
| ... | @@ -11067,51 +10878,53 @@ fn isByRef(ty: Type) bool { | ... | @@ -11067,51 +10878,53 @@ fn isByRef(ty: Type) bool { |
| 11067 | .AnyFrame, | 10878 | .AnyFrame, |
| 11068 | => return false, | 10879 | => return false, |
| 11069 | 10880 | ||
| 11070 | .Array, .Frame => return ty.hasRuntimeBits(), | 10881 | .Array, .Frame => return ty.hasRuntimeBits(mod), |
| 11071 | .Struct => { | 10882 | .Struct => { |
| 11072 | // Packed structs are represented to LLVM as integers. | 10883 | // Packed structs are represented to LLVM as integers. |
| 11073 | if (ty.containerLayout() == .Packed) return false; | 10884 | if (ty.containerLayout(mod) == .Packed) return false; |
| 11074 | if (ty.isSimpleTupleOrAnonStruct()) { | 10885 | const struct_type = switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 11075 | const tuple = ty.tupleFields(); | 10886 | .anon_struct_type => |tuple| { |
| 11076 | var count: usize = 0; | 10887 | var count: usize = 0; |
| 11077 | for (tuple.values, 0..) |field_val, i| { | 10888 | for (tuple.types, tuple.values) |field_ty, field_val| { |
| 11078 | if (field_val.tag() != .unreachable_value or !tuple.types[i].hasRuntimeBits()) continue; | 10889 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; |
| 11079 | 10890 | ||
| 11080 | count += 1; | 10891 | count += 1; |
| 11081 | if (count > max_fields_byval) return true; | 10892 | if (count > max_fields_byval) return true; |
| 11082 | if (isByRef(tuple.types[i])) return true; | 10893 | if (isByRef(field_ty.toType(), mod)) return true; |
| 11083 | } | 10894 | } |
| 11084 | return false; | 10895 | return false; |
| 11085 | } | 10896 | }, |
| 10897 | .struct_type => |s| s, | ||
| 10898 | else => unreachable, | ||
| 10899 | }; | ||
| 10900 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 11086 | var count: usize = 0; | 10901 | var count: usize = 0; |
| 11087 | const fields = ty.structFields(); | 10902 | for (struct_obj.fields.values()) |field| { |
| 11088 | for (fields.values()) |field| { | 10903 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; |
| 11089 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; | ||
| 11090 | 10904 | ||
| 11091 | count += 1; | 10905 | count += 1; |
| 11092 | if (count > max_fields_byval) return true; | 10906 | if (count > max_fields_byval) return true; |
| 11093 | if (isByRef(field.ty)) return true; | 10907 | if (isByRef(field.ty, mod)) return true; |
| 11094 | } | 10908 | } |
| 11095 | return false; | 10909 | return false; |
| 11096 | }, | 10910 | }, |
| 11097 | .Union => switch (ty.containerLayout()) { | 10911 | .Union => switch (ty.containerLayout(mod)) { |
| 11098 | .Packed => return false, | 10912 | .Packed => return false, |
| 11099 | else => return ty.hasRuntimeBits(), | 10913 | else => return ty.hasRuntimeBits(mod), |
| 11100 | }, | 10914 | }, |
| 11101 | .ErrorUnion => { | 10915 | .ErrorUnion => { |
| 11102 | const payload_ty = ty.errorUnionPayload(); | 10916 | const payload_ty = ty.errorUnionPayload(mod); |
| 11103 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 10917 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 11104 | return false; | 10918 | return false; |
| 11105 | } | 10919 | } |
| 11106 | return true; | 10920 | return true; |
| 11107 | }, | 10921 | }, |
| 11108 | .Optional => { | 10922 | .Optional => { |
| 11109 | var buf: Type.Payload.ElemType = undefined; | 10923 | const payload_ty = ty.optionalChild(mod); |
| 11110 | const payload_ty = ty.optionalChild(&buf); | 10924 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 11111 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 11112 | return false; | 10925 | return false; |
| 11113 | } | 10926 | } |
| 11114 | if (ty.optionalReprIsPayload()) { | 10927 | if (ty.optionalReprIsPayload(mod)) { |
| 11115 | return false; | 10928 | return false; |
| 11116 | } | 10929 | } |
| 11117 | return true; | 10930 | return true; |
| ... | @@ -11119,8 +10932,8 @@ fn isByRef(ty: Type) bool { | ... | @@ -11119,8 +10932,8 @@ fn isByRef(ty: Type) bool { |
| 11119 | } | 10932 | } |
| 11120 | } | 10933 | } |
| 11121 | 10934 | ||
| 11122 | fn isScalar(ty: Type) bool { | 10935 | fn isScalar(mod: *Module, ty: Type) bool { |
| 11123 | return switch (ty.zigTypeTag()) { | 10936 | return switch (ty.zigTypeTag(mod)) { |
| 11124 | .Void, | 10937 | .Void, |
| 11125 | .Bool, | 10938 | .Bool, |
| 11126 | .NoReturn, | 10939 | .NoReturn, |
| ... | @@ -11134,8 +10947,8 @@ fn isScalar(ty: Type) bool { | ... | @@ -11134,8 +10947,8 @@ fn isScalar(ty: Type) bool { |
| 11134 | .Vector, | 10947 | .Vector, |
| 11135 | => true, | 10948 | => true, |
| 11136 | 10949 | ||
| 11137 | .Struct => ty.containerLayout() == .Packed, | 10950 | .Struct => ty.containerLayout(mod) == .Packed, |
| 11138 | .Union => ty.containerLayout() == .Packed, | 10951 | .Union => ty.containerLayout(mod) == .Packed, |
| 11139 | else => false, | 10952 | else => false, |
| 11140 | }; | 10953 | }; |
| 11141 | } | 10954 | } |
| ... | @@ -11184,10 +10997,10 @@ fn backendSupportsF128(target: std.Target) bool { | ... | @@ -11184,10 +10997,10 @@ fn backendSupportsF128(target: std.Target) bool { |
| 11184 | /// LLVM does not support all relevant intrinsics for all targets, so we | 10997 | /// LLVM does not support all relevant intrinsics for all targets, so we |
| 11185 | /// may need to manually generate a libc call | 10998 | /// may need to manually generate a libc call |
| 11186 | fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { | 10999 | fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { |
| 11187 | return switch (scalar_ty.tag()) { | 11000 | return switch (scalar_ty.toIntern()) { |
| 11188 | .f16 => backendSupportsF16(target), | 11001 | .f16_type => backendSupportsF16(target), |
| 11189 | .f80 => (target.c_type_bit_size(.longdouble) == 80) and backendSupportsF80(target), | 11002 | .f80_type => (target.c_type_bit_size(.longdouble) == 80) and backendSupportsF80(target), |
| 11190 | .f128 => (target.c_type_bit_size(.longdouble) == 128) and backendSupportsF128(target), | 11003 | .f128_type => (target.c_type_bit_size(.longdouble) == 128) and backendSupportsF128(target), |
| 11191 | else => true, | 11004 | else => true, |
| 11192 | }; | 11005 | }; |
| 11193 | } | 11006 | } |
| ... | @@ -11304,12 +11117,12 @@ fn buildAllocaInner( | ... | @@ -11304,12 +11117,12 @@ fn buildAllocaInner( |
| 11304 | return alloca; | 11117 | return alloca; |
| 11305 | } | 11118 | } |
| 11306 | 11119 | ||
| 11307 | fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u1 { | 11120 | fn errUnionPayloadOffset(payload_ty: Type, mod: *Module) u1 { |
| 11308 | return @boolToInt(Type.anyerror.abiAlignment(target) > payload_ty.abiAlignment(target)); | 11121 | return @boolToInt(Type.anyerror.abiAlignment(mod) > payload_ty.abiAlignment(mod)); |
| 11309 | } | 11122 | } |
| 11310 | 11123 | ||
| 11311 | fn errUnionErrorOffset(payload_ty: Type, target: std.Target) u1 { | 11124 | fn errUnionErrorOffset(payload_ty: Type, mod: *Module) u1 { |
| 11312 | return @boolToInt(Type.anyerror.abiAlignment(target) <= payload_ty.abiAlignment(target)); | 11125 | return @boolToInt(Type.anyerror.abiAlignment(mod) <= payload_ty.abiAlignment(mod)); |
| 11313 | } | 11126 | } |
| 11314 | 11127 | ||
| 11315 | /// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location | 11128 | /// Returns true for asm constraint (e.g. "=*m", "=r") if it accepts a memory location |
src/codegen/spirv.zig+414-417| ... | @@ -218,8 +218,9 @@ pub const DeclGen = struct { | ... | @@ -218,8 +218,9 @@ pub const DeclGen = struct { |
| 218 | 218 | ||
| 219 | pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error { | 219 | pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error { |
| 220 | @setCold(true); | 220 | @setCold(true); |
| 221 | const mod = self.module; | ||
| 221 | const src = LazySrcLoc.nodeOffset(0); | 222 | const src = LazySrcLoc.nodeOffset(0); |
| 222 | const src_loc = src.toSrcLoc(self.module.declPtr(self.decl_index)); | 223 | const src_loc = src.toSrcLoc(self.module.declPtr(self.decl_index), mod); |
| 223 | assert(self.error_msg == null); | 224 | assert(self.error_msg == null); |
| 224 | self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args); | 225 | self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args); |
| 225 | return error.CodegenFail; | 226 | return error.CodegenFail; |
| ... | @@ -231,12 +232,13 @@ pub const DeclGen = struct { | ... | @@ -231,12 +232,13 @@ pub const DeclGen = struct { |
| 231 | 232 | ||
| 232 | /// Fetch the result-id for a previously generated instruction or constant. | 233 | /// Fetch the result-id for a previously generated instruction or constant. |
| 233 | fn resolve(self: *DeclGen, inst: Air.Inst.Ref) !IdRef { | 234 | fn resolve(self: *DeclGen, inst: Air.Inst.Ref) !IdRef { |
| 234 | if (self.air.value(inst)) |val| { | 235 | const mod = self.module; |
| 235 | const ty = self.air.typeOf(inst); | 236 | if (try self.air.value(inst, mod)) |val| { |
| 236 | if (ty.zigTypeTag() == .Fn) { | 237 | const ty = self.typeOf(inst); |
| 237 | const fn_decl_index = switch (val.tag()) { | 238 | if (ty.zigTypeTag(mod) == .Fn) { |
| 238 | .extern_fn => val.castTag(.extern_fn).?.data.owner_decl, | 239 | const fn_decl_index = switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 239 | .function => val.castTag(.function).?.data.owner_decl, | 240 | .extern_func => |extern_func| extern_func.decl, |
| 241 | .func => |func| mod.funcPtr(func.index).owner_decl, | ||
| 240 | else => unreachable, | 242 | else => unreachable, |
| 241 | }; | 243 | }; |
| 242 | const spv_decl_index = try self.resolveDecl(fn_decl_index); | 244 | const spv_decl_index = try self.resolveDecl(fn_decl_index); |
| ... | @@ -254,12 +256,12 @@ pub const DeclGen = struct { | ... | @@ -254,12 +256,12 @@ pub const DeclGen = struct { |
| 254 | /// Note: Function does not actually generate the decl. | 256 | /// Note: Function does not actually generate the decl. |
| 255 | fn resolveDecl(self: *DeclGen, decl_index: Module.Decl.Index) !SpvModule.Decl.Index { | 257 | fn resolveDecl(self: *DeclGen, decl_index: Module.Decl.Index) !SpvModule.Decl.Index { |
| 256 | const decl = self.module.declPtr(decl_index); | 258 | const decl = self.module.declPtr(decl_index); |
| 257 | self.module.markDeclAlive(decl); | 259 | try self.module.markDeclAlive(decl); |
| 258 | 260 | ||
| 259 | const entry = try self.decl_link.getOrPut(decl_index); | 261 | const entry = try self.decl_link.getOrPut(decl_index); |
| 260 | if (!entry.found_existing) { | 262 | if (!entry.found_existing) { |
| 261 | // TODO: Extern fn? | 263 | // TODO: Extern fn? |
| 262 | const kind: SpvModule.DeclKind = if (decl.val.tag() == .function) | 264 | const kind: SpvModule.DeclKind = if (decl.val.getFunctionIndex(self.module) != .none) |
| 263 | .func | 265 | .func |
| 264 | else | 266 | else |
| 265 | .global; | 267 | .global; |
| ... | @@ -340,8 +342,9 @@ pub const DeclGen = struct { | ... | @@ -340,8 +342,9 @@ pub const DeclGen = struct { |
| 340 | } | 342 | } |
| 341 | 343 | ||
| 342 | fn arithmeticTypeInfo(self: *DeclGen, ty: Type) !ArithmeticTypeInfo { | 344 | fn arithmeticTypeInfo(self: *DeclGen, ty: Type) !ArithmeticTypeInfo { |
| 345 | const mod = self.module; | ||
| 343 | const target = self.getTarget(); | 346 | const target = self.getTarget(); |
| 344 | return switch (ty.zigTypeTag()) { | 347 | return switch (ty.zigTypeTag(mod)) { |
| 345 | .Bool => ArithmeticTypeInfo{ | 348 | .Bool => ArithmeticTypeInfo{ |
| 346 | .bits = 1, // Doesn't matter for this class. | 349 | .bits = 1, // Doesn't matter for this class. |
| 347 | .is_vector = false, | 350 | .is_vector = false, |
| ... | @@ -355,7 +358,7 @@ pub const DeclGen = struct { | ... | @@ -355,7 +358,7 @@ pub const DeclGen = struct { |
| 355 | .class = .float, | 358 | .class = .float, |
| 356 | }, | 359 | }, |
| 357 | .Int => blk: { | 360 | .Int => blk: { |
| 358 | const int_info = ty.intInfo(target); | 361 | const int_info = ty.intInfo(mod); |
| 359 | // TODO: Maybe it's useful to also return this value. | 362 | // TODO: Maybe it's useful to also return this value. |
| 360 | const maybe_backing_bits = self.backingIntBits(int_info.bits); | 363 | const maybe_backing_bits = self.backingIntBits(int_info.bits); |
| 361 | break :blk ArithmeticTypeInfo{ | 364 | break :blk ArithmeticTypeInfo{ |
| ... | @@ -533,34 +536,35 @@ pub const DeclGen = struct { | ... | @@ -533,34 +536,35 @@ pub const DeclGen = struct { |
| 533 | } | 536 | } |
| 534 | 537 | ||
| 535 | fn addInt(self: *@This(), ty: Type, val: Value) !void { | 538 | fn addInt(self: *@This(), ty: Type, val: Value) !void { |
| 536 | const target = self.dg.getTarget(); | 539 | const mod = self.dg.module; |
| 537 | const int_info = ty.intInfo(target); | 540 | const int_info = ty.intInfo(mod); |
| 538 | const int_bits = switch (int_info.signedness) { | 541 | const int_bits = switch (int_info.signedness) { |
| 539 | .signed => @bitCast(u64, val.toSignedInt(target)), | 542 | .signed => @bitCast(u64, val.toSignedInt(mod)), |
| 540 | .unsigned => val.toUnsignedInt(target), | 543 | .unsigned => val.toUnsignedInt(mod), |
| 541 | }; | 544 | }; |
| 542 | 545 | ||
| 543 | // TODO: Swap endianess if the compiler is big endian. | 546 | // TODO: Swap endianess if the compiler is big endian. |
| 544 | const len = ty.abiSize(target); | 547 | const len = ty.abiSize(mod); |
| 545 | try self.addBytes(std.mem.asBytes(&int_bits)[0..@intCast(usize, len)]); | 548 | try self.addBytes(std.mem.asBytes(&int_bits)[0..@intCast(usize, len)]); |
| 546 | } | 549 | } |
| 547 | 550 | ||
| 548 | fn addFloat(self: *@This(), ty: Type, val: Value) !void { | 551 | fn addFloat(self: *@This(), ty: Type, val: Value) !void { |
| 552 | const mod = self.dg.module; | ||
| 549 | const target = self.dg.getTarget(); | 553 | const target = self.dg.getTarget(); |
| 550 | const len = ty.abiSize(target); | 554 | const len = ty.abiSize(mod); |
| 551 | 555 | ||
| 552 | // TODO: Swap endianess if the compiler is big endian. | 556 | // TODO: Swap endianess if the compiler is big endian. |
| 553 | switch (ty.floatBits(target)) { | 557 | switch (ty.floatBits(target)) { |
| 554 | 16 => { | 558 | 16 => { |
| 555 | const float_bits = val.toFloat(f16); | 559 | const float_bits = val.toFloat(f16, mod); |
| 556 | try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]); | 560 | try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]); |
| 557 | }, | 561 | }, |
| 558 | 32 => { | 562 | 32 => { |
| 559 | const float_bits = val.toFloat(f32); | 563 | const float_bits = val.toFloat(f32, mod); |
| 560 | try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]); | 564 | try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]); |
| 561 | }, | 565 | }, |
| 562 | 64 => { | 566 | 64 => { |
| 563 | const float_bits = val.toFloat(f64); | 567 | const float_bits = val.toFloat(f64, mod); |
| 564 | try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]); | 568 | try self.addBytes(std.mem.asBytes(&float_bits)[0..@intCast(usize, len)]); |
| 565 | }, | 569 | }, |
| 566 | else => unreachable, | 570 | else => unreachable, |
| ... | @@ -569,6 +573,7 @@ pub const DeclGen = struct { | ... | @@ -569,6 +573,7 @@ pub const DeclGen = struct { |
| 569 | 573 | ||
| 570 | fn addDeclRef(self: *@This(), ty: Type, decl_index: Decl.Index) !void { | 574 | fn addDeclRef(self: *@This(), ty: Type, decl_index: Decl.Index) !void { |
| 571 | const dg = self.dg; | 575 | const dg = self.dg; |
| 576 | const mod = dg.module; | ||
| 572 | 577 | ||
| 573 | const ty_ref = try self.dg.resolveType(ty, .indirect); | 578 | const ty_ref = try self.dg.resolveType(ty, .indirect); |
| 574 | const ty_id = dg.typeId(ty_ref); | 579 | const ty_id = dg.typeId(ty_ref); |
| ... | @@ -576,19 +581,18 @@ pub const DeclGen = struct { | ... | @@ -576,19 +581,18 @@ pub const DeclGen = struct { |
| 576 | const decl = dg.module.declPtr(decl_index); | 581 | const decl = dg.module.declPtr(decl_index); |
| 577 | const spv_decl_index = try dg.resolveDecl(decl_index); | 582 | const spv_decl_index = try dg.resolveDecl(decl_index); |
| 578 | 583 | ||
| 579 | switch (decl.val.tag()) { | 584 | switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { |
| 580 | .function => { | 585 | .func => { |
| 581 | // TODO: Properly lower function pointers. For now we are going to hack around it and | 586 | // TODO: Properly lower function pointers. For now we are going to hack around it and |
| 582 | // just generate an empty pointer. Function pointers are represented by usize for now, | 587 | // just generate an empty pointer. Function pointers are represented by usize for now, |
| 583 | // though. | 588 | // though. |
| 584 | try self.addInt(Type.usize, Value.initTag(.zero)); | 589 | try self.addInt(Type.usize, Value.zero_usize); |
| 585 | // TODO: Add dependency | 590 | // TODO: Add dependency |
| 586 | return; | 591 | return; |
| 587 | }, | 592 | }, |
| 588 | .extern_fn => unreachable, // TODO | 593 | .extern_func => unreachable, // TODO |
| 589 | else => { | 594 | else => { |
| 590 | const result_id = dg.spv.allocId(); | 595 | const result_id = dg.spv.allocId(); |
| 591 | log.debug("addDeclRef: id = {}, index = {}, name = {s}", .{ result_id.id, @enumToInt(spv_decl_index), decl.name }); | ||
| 592 | 596 | ||
| 593 | try self.decl_deps.put(spv_decl_index, {}); | 597 | try self.decl_deps.put(spv_decl_index, {}); |
| 594 | 598 | ||
| ... | @@ -606,117 +610,122 @@ pub const DeclGen = struct { | ... | @@ -606,117 +610,122 @@ pub const DeclGen = struct { |
| 606 | } | 610 | } |
| 607 | } | 611 | } |
| 608 | 612 | ||
| 609 | fn lower(self: *@This(), ty: Type, val: Value) !void { | 613 | fn lower(self: *@This(), ty: Type, arg_val: Value) !void { |
| 610 | const target = self.dg.getTarget(); | ||
| 611 | const dg = self.dg; | 614 | const dg = self.dg; |
| 615 | const mod = dg.module; | ||
| 616 | |||
| 617 | var val = arg_val; | ||
| 618 | switch (mod.intern_pool.indexToKey(val.toIntern())) { | ||
| 619 | .runtime_value => |rt| val = rt.val.toValue(), | ||
| 620 | else => {}, | ||
| 621 | } | ||
| 612 | 622 | ||
| 613 | if (val.isUndef()) { | 623 | if (val.isUndefDeep(mod)) { |
| 614 | const size = ty.abiSize(target); | 624 | const size = ty.abiSize(mod); |
| 615 | return try self.addUndef(size); | 625 | return try self.addUndef(size); |
| 616 | } | 626 | } |
| 617 | 627 | ||
| 618 | switch (ty.zigTypeTag()) { | 628 | switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 619 | .Int => try self.addInt(ty, val), | 629 | .int_type, |
| 620 | .Float => try self.addFloat(ty, val), | 630 | .ptr_type, |
| 621 | .Bool => try self.addConstBool(val.toBool()), | 631 | .array_type, |
| 622 | .Array => switch (val.tag()) { | 632 | .vector_type, |
| 623 | .aggregate => { | 633 | .opt_type, |
| 624 | const elem_vals = val.castTag(.aggregate).?.data; | 634 | .anyframe_type, |
| 625 | const elem_ty = ty.elemType(); | 635 | .error_union_type, |
| 626 | const len = @intCast(u32, ty.arrayLenIncludingSentinel()); // TODO: limit spir-v to 32 bit arrays in a more elegant way. | 636 | .simple_type, |
| 627 | for (elem_vals[0..len]) |elem_val| { | 637 | .struct_type, |
| 628 | try self.lower(elem_ty, elem_val); | 638 | .anon_struct_type, |
| 629 | } | 639 | .union_type, |
| 630 | }, | 640 | .opaque_type, |
| 631 | .repeated => { | 641 | .enum_type, |
| 632 | const elem_val = val.castTag(.repeated).?.data; | 642 | .func_type, |
| 633 | const elem_ty = ty.elemType(); | 643 | .error_set_type, |
| 634 | const len = @intCast(u32, ty.arrayLen()); | 644 | .inferred_error_set_type, |
| 635 | for (0..len) |_| { | 645 | => unreachable, // types, not values |
| 636 | try self.lower(elem_ty, elem_val); | 646 | |
| 637 | } | 647 | .undef, .runtime_value => unreachable, // handled above |
| 638 | if (ty.sentinel()) |sentinel| { | 648 | .simple_value => |simple_value| switch (simple_value) { |
| 639 | try self.lower(elem_ty, sentinel); | 649 | .undefined, |
| 640 | } | 650 | .void, |
| 641 | }, | 651 | .null, |
| 642 | .str_lit => { | 652 | .empty_struct, |
| 643 | const str_lit = val.castTag(.str_lit).?.data; | 653 | .@"unreachable", |
| 644 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | 654 | .generic_poison, |
| 645 | try self.addBytes(bytes); | 655 | => unreachable, // non-runtime values |
| 646 | if (ty.sentinel()) |sentinel| { | 656 | .false, .true => try self.addConstBool(val.toBool()), |
| 647 | try self.addByte(@intCast(u8, sentinel.toUnsignedInt(target))); | ||
| 648 | } | ||
| 649 | }, | ||
| 650 | .bytes => { | ||
| 651 | const bytes = val.castTag(.bytes).?.data; | ||
| 652 | try self.addBytes(bytes); | ||
| 653 | }, | ||
| 654 | else => |tag| return dg.todo("indirect array constant with tag {s}", .{@tagName(tag)}), | ||
| 655 | }, | 657 | }, |
| 656 | .Pointer => switch (val.tag()) { | 658 | .variable, |
| 657 | .decl_ref_mut => { | 659 | .extern_func, |
| 658 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | 660 | .func, |
| 659 | try self.addDeclRef(ty, decl_index); | 661 | .enum_literal, |
| 660 | }, | 662 | .empty_enum_value, |
| 661 | .decl_ref => { | 663 | => unreachable, // non-runtime values |
| 662 | const decl_index = val.castTag(.decl_ref).?.data; | 664 | .int => try self.addInt(ty, val), |
| 663 | try self.addDeclRef(ty, decl_index); | 665 | .err => |err| { |
| 664 | }, | 666 | const int = try mod.getErrorValue(err.name); |
| 665 | .slice => { | 667 | try self.addConstInt(u16, @intCast(u16, int)); |
| 666 | const slice = val.castTag(.slice).?.data; | 668 | }, |
| 669 | .error_union => |error_union| { | ||
| 670 | 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); | ||
| 667 | 673 | ||
| 668 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 674 | const eu_layout = dg.errorUnionLayout(payload_ty); |
| 669 | const ptr_ty = ty.slicePtrFieldType(&buf); | 675 | if (!eu_layout.payload_has_bits) { |
| 676 | return try self.lower(Type.anyerror, error_val); | ||
| 677 | } | ||
| 670 | 678 | ||
| 671 | try self.lower(ptr_ty, slice.ptr); | 679 | const payload_size = payload_ty.abiSize(mod); |
| 672 | try self.addInt(Type.usize, slice.len); | 680 | const error_size = Type.anyerror.abiAlignment(mod); |
| 673 | }, | 681 | const ty_size = ty.abiSize(mod); |
| 674 | .null_value, .zero => try self.addNullPtr(try dg.resolveType(ty, .indirect)), | 682 | const padding = ty_size - payload_size - error_size; |
| 675 | .int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => { | 683 | |
| 676 | try self.addInt(Type.usize, val); | 684 | const payload_val = switch (error_union.val) { |
| 677 | }, | 685 | .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }), |
| 678 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), | 686 | .payload => |payload| payload, |
| 679 | }, | 687 | }.toValue(); |
| 680 | .Struct => { | 688 | |
| 681 | if (ty.isSimpleTupleOrAnonStruct()) { | 689 | if (eu_layout.error_first) { |
| 682 | unreachable; // TODO | 690 | try self.lower(Type.anyerror, error_val); |
| 691 | try self.lower(payload_ty, payload_val); | ||
| 683 | } else { | 692 | } else { |
| 684 | const struct_ty = ty.castTag(.@"struct").?.data; | 693 | try self.lower(payload_ty, payload_val); |
| 694 | try self.lower(Type.anyerror, error_val); | ||
| 695 | } | ||
| 685 | 696 | ||
| 686 | if (struct_ty.layout == .Packed) { | 697 | try self.addUndef(padding); |
| 687 | return dg.todo("packed struct constants", .{}); | 698 | }, |
| 688 | } | 699 | .enum_tag => { |
| 700 | const int_val = try val.enumToInt(ty, mod); | ||
| 689 | 701 | ||
| 690 | const struct_begin = self.size; | 702 | const int_ty = ty.intTagType(mod); |
| 691 | const field_vals = val.castTag(.aggregate).?.data; | ||
| 692 | for (struct_ty.fields.values(), 0..) |field, i| { | ||
| 693 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; | ||
| 694 | try self.lower(field.ty, field_vals[i]); | ||
| 695 | 703 | ||
| 696 | // Add padding if required. | 704 | try self.lower(int_ty, int_val); |
| 697 | // TODO: Add to type generation as well? | 705 | }, |
| 698 | const unpadded_field_end = self.size - struct_begin; | 706 | .float => try self.addFloat(ty, val), |
| 699 | const padded_field_end = ty.structFieldOffset(i + 1, target); | 707 | .ptr => |ptr| { |
| 700 | const padding = padded_field_end - unpadded_field_end; | 708 | switch (ptr.addr) { |
| 701 | try self.addUndef(padding); | 709 | .decl => |decl| try self.addDeclRef(ty, decl), |
| 702 | } | 710 | .mut_decl => |mut_decl| try self.addDeclRef(ty, mut_decl.decl), |
| 711 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), | ||
| 712 | } | ||
| 713 | if (ptr.len != .none) { | ||
| 714 | try self.addInt(Type.usize, ptr.len.toValue()); | ||
| 703 | } | 715 | } |
| 704 | }, | 716 | }, |
| 705 | .Optional => { | 717 | .opt => { |
| 706 | var opt_buf: Type.Payload.ElemType = undefined; | 718 | const payload_ty = ty.optionalChild(mod); |
| 707 | const payload_ty = ty.optionalChild(&opt_buf); | 719 | const payload_val = val.optionalValue(mod); |
| 708 | const has_payload = !val.isNull(); | 720 | const abi_size = ty.abiSize(mod); |
| 709 | const abi_size = ty.abiSize(target); | 721 | |
| 710 | 722 | if (!payload_ty.hasRuntimeBits(mod)) { | |
| 711 | if (!payload_ty.hasRuntimeBits()) { | 723 | try self.addConstBool(payload_val != null); |
| 712 | try self.addConstBool(has_payload); | ||
| 713 | return; | 724 | return; |
| 714 | } else if (ty.optionalReprIsPayload()) { | 725 | } else if (ty.optionalReprIsPayload(mod)) { |
| 715 | // Optional representation is a nullable pointer or slice. | 726 | // Optional representation is a nullable pointer or slice. |
| 716 | if (val.castTag(.opt_payload)) |payload| { | 727 | if (payload_val) |pl_val| { |
| 717 | try self.lower(payload_ty, payload.data); | 728 | try self.lower(payload_ty, pl_val); |
| 718 | } else if (has_payload) { | ||
| 719 | try self.lower(payload_ty, val); | ||
| 720 | } else { | 729 | } else { |
| 721 | const ptr_ty_ref = try dg.resolveType(ty, .indirect); | 730 | const ptr_ty_ref = try dg.resolveType(ty, .indirect); |
| 722 | try self.addNullPtr(ptr_ty_ref); | 731 | try self.addNullPtr(ptr_ty_ref); |
| ... | @@ -729,102 +738,98 @@ pub const DeclGen = struct { | ... | @@ -729,102 +738,98 @@ pub const DeclGen = struct { |
| 729 | 738 | ||
| 730 | // Subtract 1 for @sizeOf(bool). | 739 | // Subtract 1 for @sizeOf(bool). |
| 731 | // TODO: Make this not hardcoded. | 740 | // TODO: Make this not hardcoded. |
| 732 | const payload_size = payload_ty.abiSize(target); | 741 | const payload_size = payload_ty.abiSize(mod); |
| 733 | const padding = abi_size - payload_size - 1; | 742 | const padding = abi_size - payload_size - 1; |
| 734 | 743 | ||
| 735 | if (val.castTag(.opt_payload)) |payload| { | 744 | if (payload_val) |pl_val| { |
| 736 | try self.lower(payload_ty, payload.data); | 745 | try self.lower(payload_ty, pl_val); |
| 737 | } else { | 746 | } else { |
| 738 | try self.addUndef(payload_size); | 747 | try self.addUndef(payload_size); |
| 739 | } | 748 | } |
| 740 | try self.addConstBool(has_payload); | 749 | try self.addConstBool(payload_val != null); |
| 741 | try self.addUndef(padding); | 750 | try self.addUndef(padding); |
| 742 | }, | 751 | }, |
| 743 | .Enum => { | 752 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 744 | var int_val_buffer: Value.Payload.U64 = undefined; | 753 | .array_type => |array_type| { |
| 745 | const int_val = val.enumToInt(ty, &int_val_buffer); | 754 | const elem_ty = array_type.child.toType(); |
| 755 | switch (aggregate.storage) { | ||
| 756 | .bytes => |bytes| try self.addBytes(bytes), | ||
| 757 | .elems, .repeated_elem => { | ||
| 758 | for (0..array_type.len) |i| { | ||
| 759 | try self.lower(elem_ty, switch (aggregate.storage) { | ||
| 760 | .bytes => unreachable, | ||
| 761 | .elems => |elem_vals| elem_vals[@intCast(usize, i)].toValue(), | ||
| 762 | .repeated_elem => |elem_val| elem_val.toValue(), | ||
| 763 | }); | ||
| 764 | } | ||
| 765 | }, | ||
| 766 | } | ||
| 767 | if (array_type.sentinel != .none) { | ||
| 768 | try self.lower(elem_ty, array_type.sentinel.toValue()); | ||
| 769 | } | ||
| 770 | }, | ||
| 771 | .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}), | ||
| 772 | .struct_type => { | ||
| 773 | const struct_ty = mod.typeToStruct(ty).?; | ||
| 746 | 774 | ||
| 747 | var int_ty_buffer: Type.Payload.Bits = undefined; | 775 | if (struct_ty.layout == .Packed) { |
| 748 | const int_ty = ty.intTagType(&int_ty_buffer); | 776 | return dg.todo("packed struct constants", .{}); |
| 777 | } | ||
| 749 | 778 | ||
| 750 | try self.lower(int_ty, int_val); | 779 | const struct_begin = self.size; |
| 780 | const field_vals = val.castTag(.aggregate).?.data; | ||
| 781 | for (struct_ty.fields.values(), 0..) |field, i| { | ||
| 782 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | ||
| 783 | try self.lower(field.ty, field_vals[i]); | ||
| 784 | |||
| 785 | // Add padding if required. | ||
| 786 | // TODO: Add to type generation as well? | ||
| 787 | const unpadded_field_end = self.size - struct_begin; | ||
| 788 | const padded_field_end = ty.structFieldOffset(i + 1, mod); | ||
| 789 | const padding = padded_field_end - unpadded_field_end; | ||
| 790 | try self.addUndef(padding); | ||
| 791 | } | ||
| 792 | }, | ||
| 793 | .anon_struct_type => unreachable, // TODO | ||
| 794 | else => unreachable, | ||
| 751 | }, | 795 | }, |
| 752 | .Union => { | 796 | .un => |un| { |
| 753 | const tag_and_val = val.castTag(.@"union").?.data; | 797 | const layout = ty.unionGetLayout(mod); |
| 754 | const layout = ty.unionGetLayout(target); | ||
| 755 | 798 | ||
| 756 | if (layout.payload_size == 0) { | 799 | if (layout.payload_size == 0) { |
| 757 | return try self.lower(ty.unionTagTypeSafety().?, tag_and_val.tag); | 800 | return try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); |
| 758 | } | 801 | } |
| 759 | 802 | ||
| 760 | const union_ty = ty.cast(Type.Payload.Union).?.data; | 803 | const union_ty = mod.typeToUnion(ty).?; |
| 761 | if (union_ty.layout == .Packed) { | 804 | if (union_ty.layout == .Packed) { |
| 762 | return dg.todo("packed union constants", .{}); | 805 | return dg.todo("packed union constants", .{}); |
| 763 | } | 806 | } |
| 764 | 807 | ||
| 765 | const active_field = ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?; | 808 | const active_field = ty.unionTagFieldIndex(un.tag.toValue(), dg.module).?; |
| 766 | const active_field_ty = union_ty.fields.values()[active_field].ty; | 809 | const active_field_ty = union_ty.fields.values()[active_field].ty; |
| 767 | 810 | ||
| 768 | const has_tag = layout.tag_size != 0; | 811 | const has_tag = layout.tag_size != 0; |
| 769 | const tag_first = layout.tag_align >= layout.payload_align; | 812 | const tag_first = layout.tag_align >= layout.payload_align; |
| 770 | 813 | ||
| 771 | if (has_tag and tag_first) { | 814 | if (has_tag and tag_first) { |
| 772 | try self.lower(ty.unionTagTypeSafety().?, tag_and_val.tag); | 815 | try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); |
| 773 | } | 816 | } |
| 774 | 817 | ||
| 775 | const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime()) blk: { | 818 | const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: { |
| 776 | try self.lower(active_field_ty, tag_and_val.val); | 819 | try self.lower(active_field_ty, un.val.toValue()); |
| 777 | break :blk active_field_ty.abiSize(target); | 820 | break :blk active_field_ty.abiSize(mod); |
| 778 | } else 0; | 821 | } else 0; |
| 779 | 822 | ||
| 780 | const payload_padding_len = layout.payload_size - active_field_size; | 823 | const payload_padding_len = layout.payload_size - active_field_size; |
| 781 | try self.addUndef(payload_padding_len); | 824 | try self.addUndef(payload_padding_len); |
| 782 | 825 | ||
| 783 | if (has_tag and !tag_first) { | 826 | if (has_tag and !tag_first) { |
| 784 | try self.lower(ty.unionTagTypeSafety().?, tag_and_val.tag); | 827 | try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); |
| 785 | } | 828 | } |
| 786 | 829 | ||
| 787 | try self.addUndef(layout.padding); | 830 | try self.addUndef(layout.padding); |
| 788 | }, | 831 | }, |
| 789 | .ErrorSet => switch (val.tag()) { | 832 | .memoized_call => unreachable, |
| 790 | .@"error" => { | ||
| 791 | const err_name = val.castTag(.@"error").?.data.name; | ||
| 792 | const kv = try dg.module.getErrorValue(err_name); | ||
| 793 | try self.addConstInt(u16, @intCast(u16, kv.value)); | ||
| 794 | }, | ||
| 795 | .zero => { | ||
| 796 | // Unactivated error set. | ||
| 797 | try self.addConstInt(u16, 0); | ||
| 798 | }, | ||
| 799 | else => unreachable, | ||
| 800 | }, | ||
| 801 | .ErrorUnion => { | ||
| 802 | const payload_ty = ty.errorUnionPayload(); | ||
| 803 | const is_pl = val.errorUnionIsPayload(); | ||
| 804 | const error_val = if (!is_pl) val else Value.initTag(.zero); | ||
| 805 | |||
| 806 | const eu_layout = dg.errorUnionLayout(payload_ty); | ||
| 807 | if (!eu_layout.payload_has_bits) { | ||
| 808 | return try self.lower(Type.anyerror, error_val); | ||
| 809 | } | ||
| 810 | |||
| 811 | const payload_size = payload_ty.abiSize(target); | ||
| 812 | const error_size = Type.anyerror.abiAlignment(target); | ||
| 813 | const ty_size = ty.abiSize(target); | ||
| 814 | const padding = ty_size - payload_size - error_size; | ||
| 815 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef); | ||
| 816 | |||
| 817 | if (eu_layout.error_first) { | ||
| 818 | try self.lower(Type.anyerror, error_val); | ||
| 819 | try self.lower(payload_ty, payload_val); | ||
| 820 | } else { | ||
| 821 | try self.lower(payload_ty, payload_val); | ||
| 822 | try self.lower(Type.anyerror, error_val); | ||
| 823 | } | ||
| 824 | |||
| 825 | try self.addUndef(padding); | ||
| 826 | }, | ||
| 827 | else => |tag| return dg.todo("indirect constant of type {s}", .{@tagName(tag)}), | ||
| 828 | } | 833 | } |
| 829 | } | 834 | } |
| 830 | }; | 835 | }; |
| ... | @@ -878,7 +883,7 @@ pub const DeclGen = struct { | ... | @@ -878,7 +883,7 @@ pub const DeclGen = struct { |
| 878 | // const target = self.getTarget(); | 883 | // const target = self.getTarget(); |
| 879 | 884 | ||
| 880 | // TODO: Fix the resulting global linking for these paths. | 885 | // TODO: Fix the resulting global linking for these paths. |
| 881 | // if (val.isUndef()) { | 886 | // if (val.isUndef(mod)) { |
| 882 | // // Special case: the entire value is undefined. In this case, we can just | 887 | // // Special case: the entire value is undefined. In this case, we can just |
| 883 | // // generate an OpVariable with no initializer. | 888 | // // generate an OpVariable with no initializer. |
| 884 | // return try section.emit(self.spv.gpa, .OpVariable, .{ | 889 | // return try section.emit(self.spv.gpa, .OpVariable, .{ |
| ... | @@ -886,7 +891,7 @@ pub const DeclGen = struct { | ... | @@ -886,7 +891,7 @@ pub const DeclGen = struct { |
| 886 | // .id_result = result_id, | 891 | // .id_result = result_id, |
| 887 | // .storage_class = storage_class, | 892 | // .storage_class = storage_class, |
| 888 | // }); | 893 | // }); |
| 889 | // } else if (ty.abiSize(target) == 0) { | 894 | // } else if (ty.abiSize(mod) == 0) { |
| 890 | // // Special case: if the type has no size, then return an undefined pointer. | 895 | // // Special case: if the type has no size, then return an undefined pointer. |
| 891 | // return try section.emit(self.spv.gpa, .OpUndef, .{ | 896 | // return try section.emit(self.spv.gpa, .OpUndef, .{ |
| 892 | // .id_result_type = self.typeId(ptr_ty_ref), | 897 | // .id_result_type = self.typeId(ptr_ty_ref), |
| ... | @@ -968,68 +973,25 @@ pub const DeclGen = struct { | ... | @@ -968,68 +973,25 @@ pub const DeclGen = struct { |
| 968 | /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. | 973 | /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. |
| 969 | /// This function should only be called during function code generation. | 974 | /// This function should only be called during function code generation. |
| 970 | fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef { | 975 | fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef { |
| 971 | const target = self.getTarget(); | 976 | const mod = self.module; |
| 972 | const result_ty_ref = try self.resolveType(ty, repr); | 977 | const result_ty_ref = try self.resolveType(ty, repr); |
| 973 | 978 | ||
| 974 | log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); | 979 | log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); |
| 975 | 980 | ||
| 976 | if (val.isUndef()) { | 981 | if (val.isUndef(mod)) { |
| 977 | return self.spv.constUndef(result_ty_ref); | 982 | return self.spv.constUndef(result_ty_ref); |
| 978 | } | 983 | } |
| 979 | 984 | ||
| 980 | switch (ty.zigTypeTag()) { | 985 | switch (ty.zigTypeTag(mod)) { |
| 981 | .Int => { | 986 | .Int => { |
| 982 | if (ty.isSignedInt()) { | 987 | if (ty.isSignedInt(mod)) { |
| 983 | return try self.spv.constInt(result_ty_ref, val.toSignedInt(target)); | 988 | return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod)); |
| 984 | } else { | 989 | } else { |
| 985 | return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(target)); | 990 | return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod)); |
| 986 | } | 991 | } |
| 987 | }, | 992 | }, |
| 988 | .Bool => switch (repr) { | 993 | .Bool => { |
| 989 | .direct => return try self.spv.constBool(result_ty_ref, val.toBool()), | 994 | @compileError("TODO merge conflict failure"); |
| 990 | .indirect => return try self.spv.constInt(result_ty_ref, @boolToInt(val.toBool())), | ||
| 991 | }, | ||
| 992 | .Float => return switch (ty.floatBits(target)) { | ||
| 993 | 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16) } } }), | ||
| 994 | 32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32) } } }), | ||
| 995 | 64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64) } } }), | ||
| 996 | 80, 128 => unreachable, // TODO | ||
| 997 | else => unreachable, | ||
| 998 | }, | ||
| 999 | .ErrorSet => { | ||
| 1000 | const value = switch (val.tag()) { | ||
| 1001 | .@"error" => blk: { | ||
| 1002 | const err_name = val.castTag(.@"error").?.data.name; | ||
| 1003 | const kv = try self.module.getErrorValue(err_name); | ||
| 1004 | break :blk @intCast(u16, kv.value); | ||
| 1005 | }, | ||
| 1006 | .zero => 0, | ||
| 1007 | else => unreachable, | ||
| 1008 | }; | ||
| 1009 | |||
| 1010 | return try self.spv.constInt(result_ty_ref, value); | ||
| 1011 | }, | ||
| 1012 | .ErrorUnion => { | ||
| 1013 | const payload_ty = ty.errorUnionPayload(); | ||
| 1014 | const is_pl = val.errorUnionIsPayload(); | ||
| 1015 | const error_val = if (!is_pl) val else Value.initTag(.zero); | ||
| 1016 | |||
| 1017 | const eu_layout = self.errorUnionLayout(payload_ty); | ||
| 1018 | if (!eu_layout.payload_has_bits) { | ||
| 1019 | return try self.constant(Type.anyerror, error_val, repr); | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef); | ||
| 1023 | |||
| 1024 | var members: [2]IdRef = undefined; | ||
| 1025 | if (eu_layout.error_first) { | ||
| 1026 | members[0] = try self.constant(Type.anyerror, error_val, .indirect); | ||
| 1027 | members[1] = try self.constant(payload_ty, payload_val, .indirect); | ||
| 1028 | } else { | ||
| 1029 | members[0] = try self.constant(payload_ty, payload_val, .indirect); | ||
| 1030 | members[1] = try self.constant(Type.anyerror, error_val, .indirect); | ||
| 1031 | } | ||
| 1032 | return try self.spv.constComposite(result_ty_ref, &members); | ||
| 1033 | }, | 995 | }, |
| 1034 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra | 996 | // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra |
| 1035 | // OpVariable that is not really required. | 997 | // OpVariable that is not really required. |
| ... | @@ -1037,7 +999,7 @@ pub const DeclGen = struct { | ... | @@ -1037,7 +999,7 @@ pub const DeclGen = struct { |
| 1037 | // The value cannot be generated directly, so generate it as an indirect constant, | 999 | // The value cannot be generated directly, so generate it as an indirect constant, |
| 1038 | // and then perform an OpLoad. | 1000 | // and then perform an OpLoad. |
| 1039 | const result_id = self.spv.allocId(); | 1001 | const result_id = self.spv.allocId(); |
| 1040 | const alignment = ty.abiAlignment(target); | 1002 | const alignment = ty.abiAlignment(mod); |
| 1041 | const spv_decl_index = try self.spv.allocDecl(.global); | 1003 | const spv_decl_index = try self.spv.allocDecl(.global); |
| 1042 | 1004 | ||
| 1043 | try self.lowerIndirectConstant( | 1005 | try self.lowerIndirectConstant( |
| ... | @@ -1114,9 +1076,9 @@ pub const DeclGen = struct { | ... | @@ -1114,9 +1076,9 @@ pub const DeclGen = struct { |
| 1114 | /// NOTE: When the active field is set to something other than the most aligned field, the | 1076 | /// NOTE: When the active field is set to something other than the most aligned field, the |
| 1115 | /// resulting struct will be *underaligned*. | 1077 | /// resulting struct will be *underaligned*. |
| 1116 | fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef { | 1078 | fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef { |
| 1117 | const target = self.getTarget(); | 1079 | const mod = self.module; |
| 1118 | const layout = ty.unionGetLayout(target); | 1080 | const layout = ty.unionGetLayout(mod); |
| 1119 | const union_ty = ty.cast(Type.Payload.Union).?.data; | 1081 | const union_ty = mod.typeToUnion(ty).?; |
| 1120 | 1082 | ||
| 1121 | if (union_ty.layout == .Packed) { | 1083 | if (union_ty.layout == .Packed) { |
| 1122 | return self.todo("packed union types", .{}); | 1084 | return self.todo("packed union types", .{}); |
| ... | @@ -1143,11 +1105,11 @@ pub const DeclGen = struct { | ... | @@ -1143,11 +1105,11 @@ pub const DeclGen = struct { |
| 1143 | const active_field = maybe_active_field orelse layout.most_aligned_field; | 1105 | const active_field = maybe_active_field orelse layout.most_aligned_field; |
| 1144 | const active_field_ty = union_ty.fields.values()[active_field].ty; | 1106 | const active_field_ty = union_ty.fields.values()[active_field].ty; |
| 1145 | 1107 | ||
| 1146 | const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime()) blk: { | 1108 | const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: { |
| 1147 | const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect); | 1109 | const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect); |
| 1148 | member_types.appendAssumeCapacity(active_payload_ty_ref); | 1110 | member_types.appendAssumeCapacity(active_payload_ty_ref); |
| 1149 | member_names.appendAssumeCapacity(try self.spv.resolveString("payload")); | 1111 | member_names.appendAssumeCapacity(try self.spv.resolveString("payload")); |
| 1150 | break :blk active_field_ty.abiSize(target); | 1112 | break :blk active_field_ty.abiSize(mod); |
| 1151 | } else 0; | 1113 | } else 0; |
| 1152 | 1114 | ||
| 1153 | const payload_padding_len = layout.payload_size - active_field_size; | 1115 | const payload_padding_len = layout.payload_size - active_field_size; |
| ... | @@ -1177,21 +1139,21 @@ pub const DeclGen = struct { | ... | @@ -1177,21 +1139,21 @@ pub const DeclGen = struct { |
| 1177 | 1139 | ||
| 1178 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. | 1140 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. |
| 1179 | fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!CacheRef { | 1141 | fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!CacheRef { |
| 1142 | const mod = self.module; | ||
| 1180 | log.debug("resolveType: ty = {}", .{ty.fmt(self.module)}); | 1143 | log.debug("resolveType: ty = {}", .{ty.fmt(self.module)}); |
| 1181 | const target = self.getTarget(); | 1144 | const target = self.getTarget(); |
| 1182 | switch (ty.zigTypeTag()) { | 1145 | switch (ty.zigTypeTag(mod)) { |
| 1183 | .Void, .NoReturn => return try self.spv.resolve(.void_type), | 1146 | .Void, .NoReturn => return try self.spv.resolve(.void_type), |
| 1184 | .Bool => switch (repr) { | 1147 | .Bool => switch (repr) { |
| 1185 | .direct => return try self.spv.resolve(.bool_type), | 1148 | .direct => return try self.spv.resolve(.bool_type), |
| 1186 | .indirect => return try self.intType(.unsigned, 1), | 1149 | .indirect => return try self.intType(.unsigned, 1), |
| 1187 | }, | 1150 | }, |
| 1188 | .Int => { | 1151 | .Int => { |
| 1189 | const int_info = ty.intInfo(target); | 1152 | const int_info = ty.intInfo(mod); |
| 1190 | return try self.intType(int_info.signedness, int_info.bits); | 1153 | return try self.intType(int_info.signedness, int_info.bits); |
| 1191 | }, | 1154 | }, |
| 1192 | .Enum => { | 1155 | .Enum => { |
| 1193 | var buffer: Type.Payload.Bits = undefined; | 1156 | const tag_ty = ty.intTagType(mod); |
| 1194 | const tag_ty = ty.intTagType(&buffer); | ||
| 1195 | return self.resolveType(tag_ty, repr); | 1157 | return self.resolveType(tag_ty, repr); |
| 1196 | }, | 1158 | }, |
| 1197 | .Float => { | 1159 | .Float => { |
| ... | @@ -1213,17 +1175,18 @@ pub const DeclGen = struct { | ... | @@ -1213,17 +1175,18 @@ pub const DeclGen = struct { |
| 1213 | return try self.spv.resolve(.{ .float_type = .{ .bits = bits } }); | 1175 | return try self.spv.resolve(.{ .float_type = .{ .bits = bits } }); |
| 1214 | }, | 1176 | }, |
| 1215 | .Array => { | 1177 | .Array => { |
| 1216 | const elem_ty = ty.childType(); | 1178 | const elem_ty = ty.childType(mod); |
| 1217 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); | 1179 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); |
| 1218 | const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel()) orelse { | 1180 | const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse { |
| 1219 | return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel()}); | 1181 | return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)}); |
| 1220 | }; | 1182 | }; |
| 1221 | return self.spv.arrayType(total_len, elem_ty_ref); | 1183 | return self.spv.arrayType(total_len, elem_ty_ref); |
| 1222 | }, | 1184 | }, |
| 1223 | .Fn => switch (repr) { | 1185 | .Fn => switch (repr) { |
| 1224 | .direct => { | 1186 | .direct => { |
| 1187 | const fn_info = mod.typeToFunc(ty).?; | ||
| 1225 | // TODO: Put this somewhere in Sema.zig | 1188 | // TODO: Put this somewhere in Sema.zig |
| 1226 | if (ty.fnIsVarArgs()) | 1189 | if (fn_info.is_var_args) |
| 1227 | return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); | 1190 | return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); |
| 1228 | 1191 | ||
| 1229 | const param_ty_refs = try self.gpa.alloc(CacheRef, ty.fnParamLen()); | 1192 | const param_ty_refs = try self.gpa.alloc(CacheRef, ty.fnParamLen()); |
| ... | @@ -1245,7 +1208,7 @@ pub const DeclGen = struct { | ... | @@ -1245,7 +1208,7 @@ pub const DeclGen = struct { |
| 1245 | }, | 1208 | }, |
| 1246 | }, | 1209 | }, |
| 1247 | .Pointer => { | 1210 | .Pointer => { |
| 1248 | const ptr_info = ty.ptrInfo().data; | 1211 | const ptr_info = ty.ptrInfo(mod); |
| 1249 | 1212 | ||
| 1250 | const storage_class = spvStorageClass(ptr_info.@"addrspace"); | 1213 | const storage_class = spvStorageClass(ptr_info.@"addrspace"); |
| 1251 | const child_ty_ref = try self.resolveType(ptr_info.pointee_type, .indirect); | 1214 | const child_ty_ref = try self.resolveType(ptr_info.pointee_type, .indirect); |
| ... | @@ -1277,8 +1240,8 @@ pub const DeclGen = struct { | ... | @@ -1277,8 +1240,8 @@ pub const DeclGen = struct { |
| 1277 | // TODO: Properly verify sizes and child type. | 1240 | // TODO: Properly verify sizes and child type. |
| 1278 | 1241 | ||
| 1279 | return try self.spv.resolve(.{ .vector_type = .{ | 1242 | return try self.spv.resolve(.{ .vector_type = .{ |
| 1280 | .component_type = try self.resolveType(ty.elemType(), repr), | 1243 | .component_type = try self.resolveType(ty.childType(mod), repr), |
| 1281 | .component_count = @intCast(u32, ty.vectorLen()), | 1244 | .component_count = @intCast(u32, ty.vectorLen(mod)), |
| 1282 | } }); | 1245 | } }); |
| 1283 | }, | 1246 | }, |
| 1284 | .Struct => { | 1247 | .Struct => { |
| ... | @@ -1290,7 +1253,7 @@ pub const DeclGen = struct { | ... | @@ -1290,7 +1253,7 @@ pub const DeclGen = struct { |
| 1290 | var member_index: usize = 0; | 1253 | var member_index: usize = 0; |
| 1291 | for (tuple.types, 0..) |field_ty, i| { | 1254 | for (tuple.types, 0..) |field_ty, i| { |
| 1292 | const field_val = tuple.values[i]; | 1255 | const field_val = tuple.values[i]; |
| 1293 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; | 1256 | if (field_val.ip_index != .unreachable_value or !field_ty.hasRuntimeBits(mod)) continue; |
| 1294 | 1257 | ||
| 1295 | member_types[member_index] = try self.resolveType(field_ty, .indirect); | 1258 | member_types[member_index] = try self.resolveType(field_ty, .indirect); |
| 1296 | member_index += 1; | 1259 | member_index += 1; |
| ... | @@ -1301,7 +1264,7 @@ pub const DeclGen = struct { | ... | @@ -1301,7 +1264,7 @@ pub const DeclGen = struct { |
| 1301 | } }); | 1264 | } }); |
| 1302 | } | 1265 | } |
| 1303 | 1266 | ||
| 1304 | const struct_ty = ty.castTag(.@"struct").?.data; | 1267 | const struct_ty = mod.typeToStruct(ty).?; |
| 1305 | 1268 | ||
| 1306 | if (struct_ty.layout == .Packed) { | 1269 | if (struct_ty.layout == .Packed) { |
| 1307 | return try self.resolveType(struct_ty.backing_int_ty, .direct); | 1270 | return try self.resolveType(struct_ty.backing_int_ty, .direct); |
| ... | @@ -1314,16 +1277,16 @@ pub const DeclGen = struct { | ... | @@ -1314,16 +1277,16 @@ pub const DeclGen = struct { |
| 1314 | defer self.gpa.free(member_names); | 1277 | defer self.gpa.free(member_names); |
| 1315 | 1278 | ||
| 1316 | var member_index: usize = 0; | 1279 | var member_index: usize = 0; |
| 1317 | for (struct_ty.fields.values(), 0..) |field, i| { | 1280 | const struct_obj = void; // TODO |
| 1318 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; | 1281 | for (struct_obj.fields.values(), 0..) |field, i| { |
| 1282 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | ||
| 1319 | 1283 | ||
| 1320 | member_types[member_index] = try self.resolveType(field.ty, .indirect); | 1284 | member_types[member_index] = try self.resolveType(field.ty, .indirect); |
| 1321 | member_names[member_index] = try self.spv.resolveString(struct_ty.fields.keys()[i]); | 1285 | member_names[member_index] = try self.spv.resolveString(struct_ty.fields.keys()[i]); |
| 1322 | member_index += 1; | 1286 | member_index += 1; |
| 1323 | } | 1287 | } |
| 1324 | 1288 | ||
| 1325 | const name = try struct_ty.getFullyQualifiedName(self.module); | 1289 | const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(self.module)); |
| 1326 | defer self.module.gpa.free(name); | ||
| 1327 | 1290 | ||
| 1328 | return try self.spv.resolve(.{ .struct_type = .{ | 1291 | return try self.spv.resolve(.{ .struct_type = .{ |
| 1329 | .name = try self.spv.resolveString(name), | 1292 | .name = try self.spv.resolveString(name), |
| ... | @@ -1332,9 +1295,8 @@ pub const DeclGen = struct { | ... | @@ -1332,9 +1295,8 @@ pub const DeclGen = struct { |
| 1332 | } }); | 1295 | } }); |
| 1333 | }, | 1296 | }, |
| 1334 | .Optional => { | 1297 | .Optional => { |
| 1335 | var buf: Type.Payload.ElemType = undefined; | 1298 | const payload_ty = ty.optionalChild(mod); |
| 1336 | const payload_ty = ty.optionalChild(&buf); | 1299 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1337 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | ||
| 1338 | // Just use a bool. | 1300 | // Just use a bool. |
| 1339 | // Note: Always generate the bool with indirect format, to save on some sanity | 1301 | // Note: Always generate the bool with indirect format, to save on some sanity |
| 1340 | // Perform the conversion to a direct bool when the field is extracted. | 1302 | // Perform the conversion to a direct bool when the field is extracted. |
| ... | @@ -1342,7 +1304,7 @@ pub const DeclGen = struct { | ... | @@ -1342,7 +1304,7 @@ pub const DeclGen = struct { |
| 1342 | } | 1304 | } |
| 1343 | 1305 | ||
| 1344 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); | 1306 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); |
| 1345 | if (ty.optionalReprIsPayload()) { | 1307 | if (ty.optionalReprIsPayload(mod)) { |
| 1346 | // Optional is actually a pointer or a slice. | 1308 | // Optional is actually a pointer or a slice. |
| 1347 | return payload_ty_ref; | 1309 | return payload_ty_ref; |
| 1348 | } | 1310 | } |
| ... | @@ -1360,7 +1322,7 @@ pub const DeclGen = struct { | ... | @@ -1360,7 +1322,7 @@ pub const DeclGen = struct { |
| 1360 | .Union => return try self.resolveUnionType(ty, null), | 1322 | .Union => return try self.resolveUnionType(ty, null), |
| 1361 | .ErrorSet => return try self.intType(.unsigned, 16), | 1323 | .ErrorSet => return try self.intType(.unsigned, 16), |
| 1362 | .ErrorUnion => { | 1324 | .ErrorUnion => { |
| 1363 | const payload_ty = ty.errorUnionPayload(); | 1325 | const payload_ty = ty.errorUnionPayload(mod); |
| 1364 | const error_ty_ref = try self.resolveType(Type.anyerror, .indirect); | 1326 | const error_ty_ref = try self.resolveType(Type.anyerror, .indirect); |
| 1365 | 1327 | ||
| 1366 | const eu_layout = self.errorUnionLayout(payload_ty); | 1328 | const eu_layout = self.errorUnionLayout(payload_ty); |
| ... | @@ -1445,14 +1407,14 @@ pub const DeclGen = struct { | ... | @@ -1445,14 +1407,14 @@ pub const DeclGen = struct { |
| 1445 | }; | 1407 | }; |
| 1446 | 1408 | ||
| 1447 | fn errorUnionLayout(self: *DeclGen, payload_ty: Type) ErrorUnionLayout { | 1409 | fn errorUnionLayout(self: *DeclGen, payload_ty: Type) ErrorUnionLayout { |
| 1448 | const target = self.getTarget(); | 1410 | const mod = self.module; |
| 1449 | 1411 | ||
| 1450 | const error_align = Type.anyerror.abiAlignment(target); | 1412 | const error_align = Type.anyerror.abiAlignment(mod); |
| 1451 | const payload_align = payload_ty.abiAlignment(target); | 1413 | const payload_align = payload_ty.abiAlignment(mod); |
| 1452 | 1414 | ||
| 1453 | const error_first = error_align > payload_align; | 1415 | const error_first = error_align > payload_align; |
| 1454 | return .{ | 1416 | return .{ |
| 1455 | .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(), | 1417 | .payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(mod), |
| 1456 | .error_first = error_first, | 1418 | .error_first = error_first, |
| 1457 | }; | 1419 | }; |
| 1458 | } | 1420 | } |
| ... | @@ -1529,28 +1491,28 @@ pub const DeclGen = struct { | ... | @@ -1529,28 +1491,28 @@ pub const DeclGen = struct { |
| 1529 | } | 1491 | } |
| 1530 | 1492 | ||
| 1531 | fn genDecl(self: *DeclGen) !void { | 1493 | fn genDecl(self: *DeclGen) !void { |
| 1532 | const decl = self.module.declPtr(self.decl_index); | 1494 | if (true) @panic("TODO: update SPIR-V backend for InternPool changes"); |
| 1495 | const mod = self.module; | ||
| 1496 | const decl = mod.declPtr(self.decl_index); | ||
| 1533 | const spv_decl_index = try self.resolveDecl(self.decl_index); | 1497 | const spv_decl_index = try self.resolveDecl(self.decl_index); |
| 1534 | 1498 | ||
| 1535 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; | 1499 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| 1536 | log.debug("genDecl: id = {}, index = {}, name = {s}", .{ decl_id.id, @enumToInt(spv_decl_index), decl.name }); | ||
| 1537 | 1500 | ||
| 1538 | if (decl.val.castTag(.function)) |_| { | 1501 | if (decl.val.getFunction(mod)) |_| { |
| 1539 | assert(decl.ty.zigTypeTag() == .Fn); | 1502 | assert(decl.ty.zigTypeTag(mod) == .Fn); |
| 1540 | const prototype_id = try self.resolveTypeId(decl.ty); | 1503 | const prototype_id = try self.resolveTypeId(decl.ty); |
| 1541 | try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ | 1504 | try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ |
| 1542 | .id_result_type = try self.resolveTypeId(decl.ty.fnReturnType()), | 1505 | .id_result_type = try self.resolveTypeId(decl.ty.fnReturnType(mod)), |
| 1543 | .id_result = decl_id, | 1506 | .id_result = decl_id, |
| 1544 | .function_control = .{}, // TODO: We can set inline here if the type requires it. | 1507 | .function_control = .{}, // TODO: We can set inline here if the type requires it. |
| 1545 | .function_type = prototype_id, | 1508 | .function_type = prototype_id, |
| 1546 | }); | 1509 | }); |
| 1547 | 1510 | ||
| 1548 | const params = decl.ty.fnParamLen(); | 1511 | const fn_info = mod.typeToFunc(decl.ty).?; |
| 1549 | var i: usize = 0; | ||
| 1550 | 1512 | ||
| 1551 | try self.args.ensureUnusedCapacity(self.gpa, params); | 1513 | try self.args.ensureUnusedCapacity(self.gpa, fn_info.param_types.len); |
| 1552 | while (i < params) : (i += 1) { | 1514 | for (fn_info.param_types) |param_type| { |
| 1553 | const param_type_id = try self.resolveTypeId(decl.ty.fnParamType(i)); | 1515 | const param_type_id = try self.resolveTypeId(param_type.toType()); |
| 1554 | const arg_result_id = self.spv.allocId(); | 1516 | const arg_result_id = self.spv.allocId(); |
| 1555 | try self.func.prologue.emit(self.spv.gpa, .OpFunctionParameter, .{ | 1517 | try self.func.prologue.emit(self.spv.gpa, .OpFunctionParameter, .{ |
| 1556 | .id_result_type = param_type_id, | 1518 | .id_result_type = param_type_id, |
| ... | @@ -1576,8 +1538,7 @@ pub const DeclGen = struct { | ... | @@ -1576,8 +1538,7 @@ pub const DeclGen = struct { |
| 1576 | try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); | 1538 | try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); |
| 1577 | try self.spv.addFunction(spv_decl_index, self.func); | 1539 | try self.spv.addFunction(spv_decl_index, self.func); |
| 1578 | 1540 | ||
| 1579 | const fqn = try decl.getFullyQualifiedName(self.module); | 1541 | const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(self.module)); |
| 1580 | defer self.module.gpa.free(fqn); | ||
| 1581 | 1542 | ||
| 1582 | try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ | 1543 | try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ |
| 1583 | .target = decl_id, | 1544 | .target = decl_id, |
| ... | @@ -1589,12 +1550,12 @@ pub const DeclGen = struct { | ... | @@ -1589,12 +1550,12 @@ pub const DeclGen = struct { |
| 1589 | try self.generateTestEntryPoint(fqn, spv_decl_index); | 1550 | try self.generateTestEntryPoint(fqn, spv_decl_index); |
| 1590 | } | 1551 | } |
| 1591 | } else { | 1552 | } else { |
| 1592 | const init_val = if (decl.val.castTag(.variable)) |payload| | 1553 | const init_val = if (decl.val.getVariable(mod)) |payload| |
| 1593 | payload.data.init | 1554 | payload.init.toValue() |
| 1594 | else | 1555 | else |
| 1595 | decl.val; | 1556 | decl.val; |
| 1596 | 1557 | ||
| 1597 | if (init_val.tag() == .unreachable_value) { | 1558 | if (init_val.ip_index == .unreachable_value) { |
| 1598 | return self.todo("importing extern variables", .{}); | 1559 | return self.todo("importing extern variables", .{}); |
| 1599 | } | 1560 | } |
| 1600 | 1561 | ||
| ... | @@ -1634,7 +1595,8 @@ pub const DeclGen = struct { | ... | @@ -1634,7 +1595,8 @@ pub const DeclGen = struct { |
| 1634 | /// Convert representation from indirect (in memory) to direct (in 'register') | 1595 | /// Convert representation from indirect (in memory) to direct (in 'register') |
| 1635 | /// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct). | 1596 | /// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct). |
| 1636 | fn convertToDirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef { | 1597 | fn convertToDirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef { |
| 1637 | return switch (ty.zigTypeTag()) { | 1598 | const mod = self.module; |
| 1599 | return switch (ty.zigTypeTag(mod)) { | ||
| 1638 | .Bool => blk: { | 1600 | .Bool => blk: { |
| 1639 | const direct_bool_ty_ref = try self.resolveType(ty, .direct); | 1601 | const direct_bool_ty_ref = try self.resolveType(ty, .direct); |
| 1640 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); | 1602 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); |
| ... | @@ -1655,7 +1617,8 @@ pub const DeclGen = struct { | ... | @@ -1655,7 +1617,8 @@ pub const DeclGen = struct { |
| 1655 | /// Convert representation from direct (in 'register) to direct (in memory) | 1617 | /// Convert representation from direct (in 'register) to direct (in memory) |
| 1656 | /// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect). | 1618 | /// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect). |
| 1657 | fn convertToIndirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef { | 1619 | fn convertToIndirect(self: *DeclGen, ty: Type, operand_id: IdRef) !IdRef { |
| 1658 | return switch (ty.zigTypeTag()) { | 1620 | const mod = self.module; |
| 1621 | return switch (ty.zigTypeTag(mod)) { | ||
| 1659 | .Bool => blk: { | 1622 | .Bool => blk: { |
| 1660 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); | 1623 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); |
| 1661 | break :blk self.boolToInt(indirect_bool_ty_ref, operand_id); | 1624 | break :blk self.boolToInt(indirect_bool_ty_ref, operand_id); |
| ... | @@ -1679,11 +1642,12 @@ pub const DeclGen = struct { | ... | @@ -1679,11 +1642,12 @@ pub const DeclGen = struct { |
| 1679 | } | 1642 | } |
| 1680 | 1643 | ||
| 1681 | fn load(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef) !IdRef { | 1644 | fn load(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef) !IdRef { |
| 1682 | const value_ty = ptr_ty.childType(); | 1645 | const mod = self.module; |
| 1646 | const value_ty = ptr_ty.childType(mod); | ||
| 1683 | const indirect_value_ty_ref = try self.resolveType(value_ty, .indirect); | 1647 | const indirect_value_ty_ref = try self.resolveType(value_ty, .indirect); |
| 1684 | const result_id = self.spv.allocId(); | 1648 | const result_id = self.spv.allocId(); |
| 1685 | const access = spec.MemoryAccess.Extended{ | 1649 | const access = spec.MemoryAccess.Extended{ |
| 1686 | .Volatile = ptr_ty.isVolatilePtr(), | 1650 | .Volatile = ptr_ty.isVolatilePtr(mod), |
| 1687 | }; | 1651 | }; |
| 1688 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ | 1652 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 1689 | .id_result_type = self.typeId(indirect_value_ty_ref), | 1653 | .id_result_type = self.typeId(indirect_value_ty_ref), |
| ... | @@ -1695,10 +1659,11 @@ pub const DeclGen = struct { | ... | @@ -1695,10 +1659,11 @@ pub const DeclGen = struct { |
| 1695 | } | 1659 | } |
| 1696 | 1660 | ||
| 1697 | fn store(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, value_id: IdRef) !void { | 1661 | fn store(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, value_id: IdRef) !void { |
| 1698 | const value_ty = ptr_ty.childType(); | 1662 | const mod = self.module; |
| 1663 | const value_ty = ptr_ty.childType(mod); | ||
| 1699 | const indirect_value_id = try self.convertToIndirect(value_ty, value_id); | 1664 | const indirect_value_id = try self.convertToIndirect(value_ty, value_id); |
| 1700 | const access = spec.MemoryAccess.Extended{ | 1665 | const access = spec.MemoryAccess.Extended{ |
| 1701 | .Volatile = ptr_ty.isVolatilePtr(), | 1666 | .Volatile = ptr_ty.isVolatilePtr(mod), |
| 1702 | }; | 1667 | }; |
| 1703 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 1668 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 1704 | .pointer = ptr_id, | 1669 | .pointer = ptr_id, |
| ... | @@ -1714,10 +1679,11 @@ pub const DeclGen = struct { | ... | @@ -1714,10 +1679,11 @@ pub const DeclGen = struct { |
| 1714 | } | 1679 | } |
| 1715 | 1680 | ||
| 1716 | fn genInst(self: *DeclGen, inst: Air.Inst.Index) !void { | 1681 | fn genInst(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 1682 | const mod = self.module; | ||
| 1683 | const ip = &mod.intern_pool; | ||
| 1717 | // TODO: remove now-redundant isUnused calls from AIR handler functions | 1684 | // TODO: remove now-redundant isUnused calls from AIR handler functions |
| 1718 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) { | 1685 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) |
| 1719 | return; | 1686 | return; |
| 1720 | } | ||
| 1721 | 1687 | ||
| 1722 | const air_tags = self.air.instructions.items(.tag); | 1688 | const air_tags = self.air.instructions.items(.tag); |
| 1723 | const maybe_result_id: ?IdRef = switch (air_tags[inst]) { | 1689 | const maybe_result_id: ?IdRef = switch (air_tags[inst]) { |
| ... | @@ -1794,8 +1760,6 @@ pub const DeclGen = struct { | ... | @@ -1794,8 +1760,6 @@ pub const DeclGen = struct { |
| 1794 | .br => return self.airBr(inst), | 1760 | .br => return self.airBr(inst), |
| 1795 | .breakpoint => return, | 1761 | .breakpoint => return, |
| 1796 | .cond_br => return self.airCondBr(inst), | 1762 | .cond_br => return self.airCondBr(inst), |
| 1797 | .constant => unreachable, | ||
| 1798 | .const_ty => unreachable, | ||
| 1799 | .dbg_stmt => return self.airDbgStmt(inst), | 1763 | .dbg_stmt => return self.airDbgStmt(inst), |
| 1800 | .loop => return self.airLoop(inst), | 1764 | .loop => return self.airLoop(inst), |
| 1801 | .ret => return self.airRet(inst), | 1765 | .ret => return self.airRet(inst), |
| ... | @@ -1841,7 +1805,7 @@ pub const DeclGen = struct { | ... | @@ -1841,7 +1805,7 @@ pub const DeclGen = struct { |
| 1841 | const lhs_id = try self.resolve(bin_op.lhs); | 1805 | const lhs_id = try self.resolve(bin_op.lhs); |
| 1842 | const rhs_id = try self.resolve(bin_op.rhs); | 1806 | const rhs_id = try self.resolve(bin_op.rhs); |
| 1843 | const result_id = self.spv.allocId(); | 1807 | const result_id = self.spv.allocId(); |
| 1844 | const result_type_id = try self.resolveTypeId(self.air.typeOfIndex(inst)); | 1808 | const result_type_id = try self.resolveTypeId(self.typeOfIndex(inst)); |
| 1845 | try self.func.body.emit(self.spv.gpa, opcode, .{ | 1809 | try self.func.body.emit(self.spv.gpa, opcode, .{ |
| 1846 | .id_result_type = result_type_id, | 1810 | .id_result_type = result_type_id, |
| 1847 | .id_result = result_id, | 1811 | .id_result = result_id, |
| ... | @@ -1856,7 +1820,7 @@ pub const DeclGen = struct { | ... | @@ -1856,7 +1820,7 @@ pub const DeclGen = struct { |
| 1856 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1820 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1857 | const lhs_id = try self.resolve(bin_op.lhs); | 1821 | const lhs_id = try self.resolve(bin_op.lhs); |
| 1858 | const rhs_id = try self.resolve(bin_op.rhs); | 1822 | const rhs_id = try self.resolve(bin_op.rhs); |
| 1859 | const result_type_id = try self.resolveTypeId(self.air.typeOfIndex(inst)); | 1823 | const result_type_id = try self.resolveTypeId(self.typeOfIndex(inst)); |
| 1860 | 1824 | ||
| 1861 | // the shift and the base must be the same type in SPIR-V, but in Zig the shift is a smaller int. | 1825 | // the shift and the base must be the same type in SPIR-V, but in Zig the shift is a smaller int. |
| 1862 | const shift_id = self.spv.allocId(); | 1826 | const shift_id = self.spv.allocId(); |
| ... | @@ -1901,15 +1865,15 @@ pub const DeclGen = struct { | ... | @@ -1901,15 +1865,15 @@ pub const DeclGen = struct { |
| 1901 | if (self.liveness.isUnused(inst)) return null; | 1865 | if (self.liveness.isUnused(inst)) return null; |
| 1902 | // LHS and RHS are guaranteed to have the same type, and AIR guarantees | 1866 | // LHS and RHS are guaranteed to have the same type, and AIR guarantees |
| 1903 | // the result to be the same as the LHS and RHS, which matches SPIR-V. | 1867 | // the result to be the same as the LHS and RHS, which matches SPIR-V. |
| 1904 | const ty = self.air.typeOfIndex(inst); | 1868 | const ty = self.typeOfIndex(inst); |
| 1905 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 1869 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 1906 | var lhs_id = try self.resolve(bin_op.lhs); | 1870 | var lhs_id = try self.resolve(bin_op.lhs); |
| 1907 | var rhs_id = try self.resolve(bin_op.rhs); | 1871 | var rhs_id = try self.resolve(bin_op.rhs); |
| 1908 | 1872 | ||
| 1909 | const result_ty_ref = try self.resolveType(ty, .direct); | 1873 | const result_ty_ref = try self.resolveType(ty, .direct); |
| 1910 | 1874 | ||
| 1911 | assert(self.air.typeOf(bin_op.lhs).eql(ty, self.module)); | 1875 | assert(self.typeOf(bin_op.lhs).eql(ty, self.module)); |
| 1912 | assert(self.air.typeOf(bin_op.rhs).eql(ty, self.module)); | 1876 | assert(self.typeOf(bin_op.rhs).eql(ty, self.module)); |
| 1913 | 1877 | ||
| 1914 | // Binary operations are generally applicable to both scalar and vector operations | 1878 | // Binary operations are generally applicable to both scalar and vector operations |
| 1915 | // in SPIR-V, but int and float versions of operations require different opcodes. | 1879 | // in SPIR-V, but int and float versions of operations require different opcodes. |
| ... | @@ -1965,8 +1929,8 @@ pub const DeclGen = struct { | ... | @@ -1965,8 +1929,8 @@ pub const DeclGen = struct { |
| 1965 | const lhs = try self.resolve(extra.lhs); | 1929 | const lhs = try self.resolve(extra.lhs); |
| 1966 | const rhs = try self.resolve(extra.rhs); | 1930 | const rhs = try self.resolve(extra.rhs); |
| 1967 | 1931 | ||
| 1968 | const operand_ty = self.air.typeOf(extra.lhs); | 1932 | const operand_ty = self.typeOf(extra.lhs); |
| 1969 | const result_ty = self.air.typeOfIndex(inst); | 1933 | const result_ty = self.typeOfIndex(inst); |
| 1970 | 1934 | ||
| 1971 | const info = try self.arithmeticTypeInfo(operand_ty); | 1935 | const info = try self.arithmeticTypeInfo(operand_ty); |
| 1972 | switch (info.class) { | 1936 | switch (info.class) { |
| ... | @@ -2056,15 +2020,16 @@ pub const DeclGen = struct { | ... | @@ -2056,15 +2020,16 @@ pub const DeclGen = struct { |
| 2056 | } | 2020 | } |
| 2057 | 2021 | ||
| 2058 | fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2022 | fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2023 | const mod = self.module; | ||
| 2059 | if (self.liveness.isUnused(inst)) return null; | 2024 | if (self.liveness.isUnused(inst)) return null; |
| 2060 | const ty = self.air.typeOfIndex(inst); | 2025 | const ty = self.typeOfIndex(inst); |
| 2061 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2026 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2062 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; | 2027 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 2063 | const a = try self.resolve(extra.a); | 2028 | const a = try self.resolve(extra.a); |
| 2064 | const b = try self.resolve(extra.b); | 2029 | const b = try self.resolve(extra.b); |
| 2065 | const mask = self.air.values[extra.mask]; | 2030 | const mask = extra.mask.toValue(); |
| 2066 | const mask_len = extra.mask_len; | 2031 | const mask_len = extra.mask_len; |
| 2067 | const a_len = self.air.typeOf(extra.a).vectorLen(); | 2032 | const a_len = self.typeOf(extra.a).vectorLen(mod); |
| 2068 | 2033 | ||
| 2069 | const result_id = self.spv.allocId(); | 2034 | const result_id = self.spv.allocId(); |
| 2070 | const result_type_id = try self.resolveTypeId(ty); | 2035 | const result_type_id = try self.resolveTypeId(ty); |
| ... | @@ -2078,12 +2043,11 @@ pub const DeclGen = struct { | ... | @@ -2078,12 +2043,11 @@ pub const DeclGen = struct { |
| 2078 | 2043 | ||
| 2079 | var i: usize = 0; | 2044 | var i: usize = 0; |
| 2080 | while (i < mask_len) : (i += 1) { | 2045 | while (i < mask_len) : (i += 1) { |
| 2081 | var buf: Value.ElemValueBuffer = undefined; | 2046 | const elem = try mask.elemValue(mod, i); |
| 2082 | const elem = mask.elemValueBuffer(self.module, i, &buf); | 2047 | if (elem.isUndef(mod)) { |
| 2083 | if (elem.isUndef()) { | ||
| 2084 | self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF); | 2048 | self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF); |
| 2085 | } else { | 2049 | } else { |
| 2086 | const int = elem.toSignedInt(self.getTarget()); | 2050 | const int = elem.toSignedInt(mod); |
| 2087 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); | 2051 | const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int + a_len); |
| 2088 | self.func.body.writeOperand(spec.LiteralInteger, unsigned); | 2052 | self.func.body.writeOperand(spec.LiteralInteger, unsigned); |
| 2089 | } | 2053 | } |
| ... | @@ -2130,9 +2094,10 @@ pub const DeclGen = struct { | ... | @@ -2130,9 +2094,10 @@ pub const DeclGen = struct { |
| 2130 | } | 2094 | } |
| 2131 | 2095 | ||
| 2132 | fn ptrAdd(self: *DeclGen, result_ty: Type, ptr_ty: Type, ptr_id: IdRef, offset_id: IdRef) !IdRef { | 2096 | fn ptrAdd(self: *DeclGen, result_ty: Type, ptr_ty: Type, ptr_id: IdRef, offset_id: IdRef) !IdRef { |
| 2097 | const mod = self.module; | ||
| 2133 | const result_ty_ref = try self.resolveType(result_ty, .direct); | 2098 | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 2134 | 2099 | ||
| 2135 | switch (ptr_ty.ptrSize()) { | 2100 | switch (ptr_ty.ptrSize(mod)) { |
| 2136 | .One => { | 2101 | .One => { |
| 2137 | // Pointer to array | 2102 | // Pointer to array |
| 2138 | // TODO: Is this correct? | 2103 | // TODO: Is this correct? |
| ... | @@ -2155,8 +2120,8 @@ pub const DeclGen = struct { | ... | @@ -2155,8 +2120,8 @@ pub const DeclGen = struct { |
| 2155 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2120 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2156 | const ptr_id = try self.resolve(bin_op.lhs); | 2121 | const ptr_id = try self.resolve(bin_op.lhs); |
| 2157 | const offset_id = try self.resolve(bin_op.rhs); | 2122 | const offset_id = try self.resolve(bin_op.rhs); |
| 2158 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2123 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2159 | const result_ty = self.air.typeOfIndex(inst); | 2124 | const result_ty = self.typeOfIndex(inst); |
| 2160 | 2125 | ||
| 2161 | return try self.ptrAdd(result_ty, ptr_ty, ptr_id, offset_id); | 2126 | return try self.ptrAdd(result_ty, ptr_ty, ptr_id, offset_id); |
| 2162 | } | 2127 | } |
| ... | @@ -2166,11 +2131,11 @@ pub const DeclGen = struct { | ... | @@ -2166,11 +2131,11 @@ pub const DeclGen = struct { |
| 2166 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2131 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2167 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2132 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2168 | const ptr_id = try self.resolve(bin_op.lhs); | 2133 | const ptr_id = try self.resolve(bin_op.lhs); |
| 2169 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2134 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2170 | const offset_id = try self.resolve(bin_op.rhs); | 2135 | const offset_id = try self.resolve(bin_op.rhs); |
| 2171 | const offset_ty = self.air.typeOf(bin_op.rhs); | 2136 | const offset_ty = self.typeOf(bin_op.rhs); |
| 2172 | const offset_ty_ref = try self.resolveType(offset_ty, .direct); | 2137 | const offset_ty_ref = try self.resolveType(offset_ty, .direct); |
| 2173 | const result_ty = self.air.typeOfIndex(inst); | 2138 | const result_ty = self.typeOfIndex(inst); |
| 2174 | 2139 | ||
| 2175 | const negative_offset_id = self.spv.allocId(); | 2140 | const negative_offset_id = self.spv.allocId(); |
| 2176 | try self.func.body.emit(self.spv.gpa, .OpSNegate, .{ | 2141 | try self.func.body.emit(self.spv.gpa, .OpSNegate, .{ |
| ... | @@ -2189,13 +2154,13 @@ pub const DeclGen = struct { | ... | @@ -2189,13 +2154,13 @@ pub const DeclGen = struct { |
| 2189 | lhs_id: IdRef, | 2154 | lhs_id: IdRef, |
| 2190 | rhs_id: IdRef, | 2155 | rhs_id: IdRef, |
| 2191 | ) !IdRef { | 2156 | ) !IdRef { |
| 2157 | const mod = self.module; | ||
| 2192 | var cmp_lhs_id = lhs_id; | 2158 | var cmp_lhs_id = lhs_id; |
| 2193 | var cmp_rhs_id = rhs_id; | 2159 | var cmp_rhs_id = rhs_id; |
| 2194 | const opcode: Opcode = opcode: { | 2160 | const opcode: Opcode = opcode: { |
| 2195 | var int_buffer: Type.Payload.Bits = undefined; | 2161 | const op_ty = switch (ty.zigTypeTag(mod)) { |
| 2196 | const op_ty = switch (ty.zigTypeTag()) { | ||
| 2197 | .Int, .Bool, .Float => ty, | 2162 | .Int, .Bool, .Float => ty, |
| 2198 | .Enum => ty.intTagType(&int_buffer), | 2163 | .Enum => ty.intTagType(), |
| 2199 | .ErrorSet => Type.u16, | 2164 | .ErrorSet => Type.u16, |
| 2200 | .Pointer => blk: { | 2165 | .Pointer => blk: { |
| 2201 | // Note that while SPIR-V offers OpPtrEqual and OpPtrNotEqual, they are | 2166 | // Note that while SPIR-V offers OpPtrEqual and OpPtrNotEqual, they are |
| ... | @@ -2291,8 +2256,8 @@ pub const DeclGen = struct { | ... | @@ -2291,8 +2256,8 @@ pub const DeclGen = struct { |
| 2291 | const lhs_id = try self.resolve(bin_op.lhs); | 2256 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2292 | const rhs_id = try self.resolve(bin_op.rhs); | 2257 | const rhs_id = try self.resolve(bin_op.rhs); |
| 2293 | const bool_ty_id = try self.resolveTypeId(Type.bool); | 2258 | const bool_ty_id = try self.resolveTypeId(Type.bool); |
| 2294 | const ty = self.air.typeOf(bin_op.lhs); | 2259 | const ty = self.typeOf(bin_op.lhs); |
| 2295 | assert(ty.eql(self.air.typeOf(bin_op.rhs), self.module)); | 2260 | assert(ty.eql(self.typeOf(bin_op.rhs), self.module)); |
| 2296 | 2261 | ||
| 2297 | return try self.cmp(op, bool_ty_id, ty, lhs_id, rhs_id); | 2262 | return try self.cmp(op, bool_ty_id, ty, lhs_id, rhs_id); |
| 2298 | } | 2263 | } |
| ... | @@ -2303,13 +2268,14 @@ pub const DeclGen = struct { | ... | @@ -2303,13 +2268,14 @@ pub const DeclGen = struct { |
| 2303 | src_ty: Type, | 2268 | src_ty: Type, |
| 2304 | src_id: IdRef, | 2269 | src_id: IdRef, |
| 2305 | ) !IdRef { | 2270 | ) !IdRef { |
| 2271 | const mod = self.module; | ||
| 2306 | const dst_ty_ref = try self.resolveType(dst_ty, .direct); | 2272 | const dst_ty_ref = try self.resolveType(dst_ty, .direct); |
| 2307 | const result_id = self.spv.allocId(); | 2273 | const result_id = self.spv.allocId(); |
| 2308 | 2274 | ||
| 2309 | // TODO: Some more cases are missing here | 2275 | // TODO: Some more cases are missing here |
| 2310 | // See fn bitCast in llvm.zig | 2276 | // See fn bitCast in llvm.zig |
| 2311 | 2277 | ||
| 2312 | if (src_ty.zigTypeTag() == .Int and dst_ty.isPtrAtRuntime()) { | 2278 | if (src_ty.zigTypeTag(mod) == .Int and dst_ty.isPtrAtRuntime(mod)) { |
| 2313 | try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{ | 2279 | try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{ |
| 2314 | .id_result_type = self.typeId(dst_ty_ref), | 2280 | .id_result_type = self.typeId(dst_ty_ref), |
| 2315 | .id_result = result_id, | 2281 | .id_result = result_id, |
| ... | @@ -2329,8 +2295,8 @@ pub const DeclGen = struct { | ... | @@ -2329,8 +2295,8 @@ pub const DeclGen = struct { |
| 2329 | if (self.liveness.isUnused(inst)) return null; | 2295 | if (self.liveness.isUnused(inst)) return null; |
| 2330 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2296 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2331 | const operand_id = try self.resolve(ty_op.operand); | 2297 | const operand_id = try self.resolve(ty_op.operand); |
| 2332 | const operand_ty = self.air.typeOf(ty_op.operand); | 2298 | const operand_ty = self.typeOf(ty_op.operand); |
| 2333 | const result_ty = self.air.typeOfIndex(inst); | 2299 | const result_ty = self.typeOfIndex(inst); |
| 2334 | return try self.bitCast(result_ty, operand_ty, operand_id); | 2300 | return try self.bitCast(result_ty, operand_ty, operand_id); |
| 2335 | } | 2301 | } |
| 2336 | 2302 | ||
| ... | @@ -2339,11 +2305,11 @@ pub const DeclGen = struct { | ... | @@ -2339,11 +2305,11 @@ pub const DeclGen = struct { |
| 2339 | 2305 | ||
| 2340 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2306 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2341 | const operand_id = try self.resolve(ty_op.operand); | 2307 | const operand_id = try self.resolve(ty_op.operand); |
| 2342 | const dest_ty = self.air.typeOfIndex(inst); | 2308 | const dest_ty = self.typeOfIndex(inst); |
| 2343 | const dest_ty_id = try self.resolveTypeId(dest_ty); | 2309 | const dest_ty_id = try self.resolveTypeId(dest_ty); |
| 2344 | 2310 | ||
| 2345 | const target = self.getTarget(); | 2311 | const mod = self.module; |
| 2346 | const dest_info = dest_ty.intInfo(target); | 2312 | const dest_info = dest_ty.intInfo(mod); |
| 2347 | 2313 | ||
| 2348 | // TODO: Masking? | 2314 | // TODO: Masking? |
| 2349 | 2315 | ||
| ... | @@ -2383,10 +2349,10 @@ pub const DeclGen = struct { | ... | @@ -2383,10 +2349,10 @@ pub const DeclGen = struct { |
| 2383 | if (self.liveness.isUnused(inst)) return null; | 2349 | if (self.liveness.isUnused(inst)) return null; |
| 2384 | 2350 | ||
| 2385 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2351 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2386 | const operand_ty = self.air.typeOf(ty_op.operand); | 2352 | const operand_ty = self.typeOf(ty_op.operand); |
| 2387 | const operand_id = try self.resolve(ty_op.operand); | 2353 | const operand_id = try self.resolve(ty_op.operand); |
| 2388 | const operand_info = try self.arithmeticTypeInfo(operand_ty); | 2354 | const operand_info = try self.arithmeticTypeInfo(operand_ty); |
| 2389 | const dest_ty = self.air.typeOfIndex(inst); | 2355 | const dest_ty = self.typeOfIndex(inst); |
| 2390 | const dest_ty_id = try self.resolveTypeId(dest_ty); | 2356 | const dest_ty_id = try self.resolveTypeId(dest_ty); |
| 2391 | 2357 | ||
| 2392 | const result_id = self.spv.allocId(); | 2358 | const result_id = self.spv.allocId(); |
| ... | @@ -2410,7 +2376,7 @@ pub const DeclGen = struct { | ... | @@ -2410,7 +2376,7 @@ pub const DeclGen = struct { |
| 2410 | 2376 | ||
| 2411 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2377 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2412 | const operand_id = try self.resolve(ty_op.operand); | 2378 | const operand_id = try self.resolve(ty_op.operand); |
| 2413 | const dest_ty = self.air.typeOfIndex(inst); | 2379 | const dest_ty = self.typeOfIndex(inst); |
| 2414 | const dest_info = try self.arithmeticTypeInfo(dest_ty); | 2380 | const dest_info = try self.arithmeticTypeInfo(dest_ty); |
| 2415 | const dest_ty_id = try self.resolveTypeId(dest_ty); | 2381 | const dest_ty_id = try self.resolveTypeId(dest_ty); |
| 2416 | 2382 | ||
| ... | @@ -2447,20 +2413,21 @@ pub const DeclGen = struct { | ... | @@ -2447,20 +2413,21 @@ pub const DeclGen = struct { |
| 2447 | fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef { | 2413 | fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef { |
| 2448 | if (self.liveness.isUnused(inst)) return null; | 2414 | if (self.liveness.isUnused(inst)) return null; |
| 2449 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2415 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2450 | const field_ty = self.air.typeOfIndex(inst); | 2416 | const field_ty = self.typeOfIndex(inst); |
| 2451 | const operand_id = try self.resolve(ty_op.operand); | 2417 | const operand_id = try self.resolve(ty_op.operand); |
| 2452 | return try self.extractField(field_ty, operand_id, field); | 2418 | return try self.extractField(field_ty, operand_id, field); |
| 2453 | } | 2419 | } |
| 2454 | 2420 | ||
| 2455 | fn airSliceElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2421 | fn airSliceElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2422 | const mod = self.module; | ||
| 2456 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2423 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2457 | const slice_ty = self.air.typeOf(bin_op.lhs); | 2424 | const slice_ty = self.typeOf(bin_op.lhs); |
| 2458 | if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null; | 2425 | if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) return null; |
| 2459 | 2426 | ||
| 2460 | const slice_id = try self.resolve(bin_op.lhs); | 2427 | const slice_id = try self.resolve(bin_op.lhs); |
| 2461 | const index_id = try self.resolve(bin_op.rhs); | 2428 | const index_id = try self.resolve(bin_op.rhs); |
| 2462 | 2429 | ||
| 2463 | const ptr_ty = self.air.typeOfIndex(inst); | 2430 | const ptr_ty = self.typeOfIndex(inst); |
| 2464 | const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); | 2431 | const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 2465 | 2432 | ||
| 2466 | const slice_ptr = try self.extractField(ptr_ty, slice_id, 0); | 2433 | const slice_ptr = try self.extractField(ptr_ty, slice_id, 0); |
| ... | @@ -2468,15 +2435,16 @@ pub const DeclGen = struct { | ... | @@ -2468,15 +2435,16 @@ pub const DeclGen = struct { |
| 2468 | } | 2435 | } |
| 2469 | 2436 | ||
| 2470 | fn airSliceElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2437 | fn airSliceElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2438 | const mod = self.module; | ||
| 2471 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2439 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2472 | const slice_ty = self.air.typeOf(bin_op.lhs); | 2440 | const slice_ty = self.typeOf(bin_op.lhs); |
| 2473 | if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null; | 2441 | if (!slice_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) return null; |
| 2474 | 2442 | ||
| 2475 | const slice_id = try self.resolve(bin_op.lhs); | 2443 | const slice_id = try self.resolve(bin_op.lhs); |
| 2476 | const index_id = try self.resolve(bin_op.rhs); | 2444 | const index_id = try self.resolve(bin_op.rhs); |
| 2477 | 2445 | ||
| 2478 | var slice_buf: Type.SlicePtrFieldTypeBuffer = undefined; | 2446 | var slice_buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 2479 | const ptr_ty = slice_ty.slicePtrFieldType(&slice_buf); | 2447 | const ptr_ty = slice_ty.slicePtrFieldType(&slice_buf, mod); |
| 2480 | const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); | 2448 | const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 2481 | 2449 | ||
| 2482 | const slice_ptr = try self.extractField(ptr_ty, slice_id, 0); | 2450 | const slice_ptr = try self.extractField(ptr_ty, slice_id, 0); |
| ... | @@ -2485,11 +2453,12 @@ pub const DeclGen = struct { | ... | @@ -2485,11 +2453,12 @@ pub const DeclGen = struct { |
| 2485 | } | 2453 | } |
| 2486 | 2454 | ||
| 2487 | fn ptrElemPtr(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, index_id: IdRef) !IdRef { | 2455 | fn ptrElemPtr(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, index_id: IdRef) !IdRef { |
| 2456 | const mod = self.module; | ||
| 2488 | // Construct new pointer type for the resulting pointer | 2457 | // Construct new pointer type for the resulting pointer |
| 2489 | const elem_ty = ptr_ty.elemType2(); // use elemType() so that we get T for *[N]T. | 2458 | const elem_ty = ptr_ty.elemType2(mod); // use elemType() so that we get T for *[N]T. |
| 2490 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); | 2459 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); |
| 2491 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(ptr_ty.ptrAddressSpace())); | 2460 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(ptr_ty.ptrAddressSpace(mod))); |
| 2492 | if (ptr_ty.isSinglePointer()) { | 2461 | if (ptr_ty.isSinglePointer(mod)) { |
| 2493 | // Pointer-to-array. In this case, the resulting pointer is not of the same type | 2462 | // Pointer-to-array. In this case, the resulting pointer is not of the same type |
| 2494 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. | 2463 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. |
| 2495 | return try self.accessChain(elem_ptr_ty_ref, ptr_id, &.{index_id}); | 2464 | return try self.accessChain(elem_ptr_ty_ref, ptr_id, &.{index_id}); |
| ... | @@ -2502,12 +2471,13 @@ pub const DeclGen = struct { | ... | @@ -2502,12 +2471,13 @@ pub const DeclGen = struct { |
| 2502 | fn airPtrElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2471 | fn airPtrElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2503 | if (self.liveness.isUnused(inst)) return null; | 2472 | if (self.liveness.isUnused(inst)) return null; |
| 2504 | 2473 | ||
| 2474 | const mod = self.module; | ||
| 2505 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2475 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2506 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2476 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2507 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2477 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2508 | const elem_ty = ptr_ty.childType(); | 2478 | const elem_ty = ptr_ty.childType(mod); |
| 2509 | // TODO: Make this return a null ptr or something | 2479 | // TODO: Make this return a null ptr or something |
| 2510 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) return null; | 2480 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; |
| 2511 | 2481 | ||
| 2512 | const ptr_id = try self.resolve(bin_op.lhs); | 2482 | const ptr_id = try self.resolve(bin_op.lhs); |
| 2513 | const index_id = try self.resolve(bin_op.rhs); | 2483 | const index_id = try self.resolve(bin_op.rhs); |
| ... | @@ -2515,8 +2485,9 @@ pub const DeclGen = struct { | ... | @@ -2515,8 +2485,9 @@ pub const DeclGen = struct { |
| 2515 | } | 2485 | } |
| 2516 | 2486 | ||
| 2517 | fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2487 | fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2488 | const mod = self.module; | ||
| 2518 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2489 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2519 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2490 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2520 | const ptr_id = try self.resolve(bin_op.lhs); | 2491 | const ptr_id = try self.resolve(bin_op.lhs); |
| 2521 | const index_id = try self.resolve(bin_op.rhs); | 2492 | const index_id = try self.resolve(bin_op.rhs); |
| 2522 | 2493 | ||
| ... | @@ -2525,19 +2496,19 @@ pub const DeclGen = struct { | ... | @@ -2525,19 +2496,19 @@ pub const DeclGen = struct { |
| 2525 | // If we have a pointer-to-array, construct an element pointer to use with load() | 2496 | // If we have a pointer-to-array, construct an element pointer to use with load() |
| 2526 | // If we pass ptr_ty directly, it will attempt to load the entire array rather than | 2497 | // If we pass ptr_ty directly, it will attempt to load the entire array rather than |
| 2527 | // just an element. | 2498 | // just an element. |
| 2528 | var elem_ptr_info = ptr_ty.ptrInfo(); | 2499 | var elem_ptr_info = ptr_ty.ptrInfo(mod); |
| 2529 | elem_ptr_info.data.size = .One; | 2500 | elem_ptr_info.size = .One; |
| 2530 | const elem_ptr_ty = Type.initPayload(&elem_ptr_info.base); | 2501 | const elem_ptr_ty = try Type.ptr(undefined, mod, elem_ptr_info); |
| 2531 | 2502 | ||
| 2532 | return try self.load(elem_ptr_ty, elem_ptr_id); | 2503 | return try self.load(elem_ptr_ty, elem_ptr_id); |
| 2533 | } | 2504 | } |
| 2534 | 2505 | ||
| 2535 | fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2506 | fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2536 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2507 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2537 | const un_ty = self.air.typeOf(ty_op.operand); | 2508 | const un_ty = self.typeOf(ty_op.operand); |
| 2538 | 2509 | ||
| 2539 | const target = self.module.getTarget(); | 2510 | const mod = self.module; |
| 2540 | const layout = un_ty.unionGetLayout(target); | 2511 | const layout = un_ty.unionGetLayout(mod); |
| 2541 | if (layout.tag_size == 0) return null; | 2512 | if (layout.tag_size == 0) return null; |
| 2542 | 2513 | ||
| 2543 | const union_handle = try self.resolve(ty_op.operand); | 2514 | const union_handle = try self.resolve(ty_op.operand); |
| ... | @@ -2551,17 +2522,18 @@ pub const DeclGen = struct { | ... | @@ -2551,17 +2522,18 @@ pub const DeclGen = struct { |
| 2551 | fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2522 | fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2552 | if (self.liveness.isUnused(inst)) return null; | 2523 | if (self.liveness.isUnused(inst)) return null; |
| 2553 | 2524 | ||
| 2525 | const mod = self.module; | ||
| 2554 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2526 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2555 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; | 2527 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 2556 | 2528 | ||
| 2557 | const struct_ty = self.air.typeOf(struct_field.struct_operand); | 2529 | const struct_ty = self.typeOf(struct_field.struct_operand); |
| 2558 | const object_id = try self.resolve(struct_field.struct_operand); | 2530 | const object_id = try self.resolve(struct_field.struct_operand); |
| 2559 | const field_index = struct_field.field_index; | 2531 | const field_index = struct_field.field_index; |
| 2560 | const field_ty = struct_ty.structFieldType(field_index); | 2532 | const field_ty = struct_ty.structFieldType(field_index, mod); |
| 2561 | 2533 | ||
| 2562 | if (!field_ty.hasRuntimeBitsIgnoreComptime()) return null; | 2534 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; |
| 2563 | 2535 | ||
| 2564 | assert(struct_ty.zigTypeTag() == .Struct); // Cannot do unions yet. | 2536 | assert(struct_ty.zigTypeTag(mod) == .Struct); // Cannot do unions yet. |
| 2565 | 2537 | ||
| 2566 | return try self.extractField(field_ty, object_id, field_index); | 2538 | return try self.extractField(field_ty, object_id, field_index); |
| 2567 | } | 2539 | } |
| ... | @@ -2573,9 +2545,10 @@ pub const DeclGen = struct { | ... | @@ -2573,9 +2545,10 @@ pub const DeclGen = struct { |
| 2573 | object_ptr: IdRef, | 2545 | object_ptr: IdRef, |
| 2574 | field_index: u32, | 2546 | field_index: u32, |
| 2575 | ) !?IdRef { | 2547 | ) !?IdRef { |
| 2576 | const object_ty = object_ptr_ty.childType(); | 2548 | const mod = self.module; |
| 2577 | switch (object_ty.zigTypeTag()) { | 2549 | const object_ty = object_ptr_ty.childType(mod); |
| 2578 | .Struct => switch (object_ty.containerLayout()) { | 2550 | switch (object_ty.zigTypeTag(mod)) { |
| 2551 | .Struct => switch (object_ty.containerLayout(mod)) { | ||
| 2579 | .Packed => unreachable, // TODO | 2552 | .Packed => unreachable, // TODO |
| 2580 | else => { | 2553 | else => { |
| 2581 | const field_index_ty_ref = try self.intType(.unsigned, 32); | 2554 | const field_index_ty_ref = try self.intType(.unsigned, 32); |
| ... | @@ -2592,8 +2565,8 @@ pub const DeclGen = struct { | ... | @@ -2592,8 +2565,8 @@ pub const DeclGen = struct { |
| 2592 | if (self.liveness.isUnused(inst)) return null; | 2565 | if (self.liveness.isUnused(inst)) return null; |
| 2593 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2566 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2594 | const struct_ptr = try self.resolve(ty_op.operand); | 2567 | const struct_ptr = try self.resolve(ty_op.operand); |
| 2595 | const struct_ptr_ty = self.air.typeOf(ty_op.operand); | 2568 | const struct_ptr_ty = self.typeOf(ty_op.operand); |
| 2596 | const result_ptr_ty = self.air.typeOfIndex(inst); | 2569 | const result_ptr_ty = self.typeOfIndex(inst); |
| 2597 | return try self.structFieldPtr(result_ptr_ty, struct_ptr_ty, struct_ptr, field_index); | 2570 | return try self.structFieldPtr(result_ptr_ty, struct_ptr_ty, struct_ptr, field_index); |
| 2598 | } | 2571 | } |
| 2599 | 2572 | ||
| ... | @@ -2649,9 +2622,10 @@ pub const DeclGen = struct { | ... | @@ -2649,9 +2622,10 @@ pub const DeclGen = struct { |
| 2649 | 2622 | ||
| 2650 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2623 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2651 | if (self.liveness.isUnused(inst)) return null; | 2624 | if (self.liveness.isUnused(inst)) return null; |
| 2652 | const ptr_ty = self.air.typeOfIndex(inst); | 2625 | const mod = self.module; |
| 2653 | assert(ptr_ty.ptrAddressSpace() == .generic); | 2626 | const ptr_ty = self.typeOfIndex(inst); |
| 2654 | const child_ty = ptr_ty.childType(); | 2627 | assert(ptr_ty.ptrAddressSpace(mod) == .generic); |
| 2628 | const child_ty = ptr_ty.childType(mod); | ||
| 2655 | const child_ty_ref = try self.resolveType(child_ty, .indirect); | 2629 | const child_ty_ref = try self.resolveType(child_ty, .indirect); |
| 2656 | return try self.alloc(child_ty_ref, null); | 2630 | return try self.alloc(child_ty_ref, null); |
| 2657 | } | 2631 | } |
| ... | @@ -2667,6 +2641,7 @@ pub const DeclGen = struct { | ... | @@ -2667,6 +2641,7 @@ pub const DeclGen = struct { |
| 2667 | // the current block by first generating the code of the block, then a label, and then generate the rest of the current | 2641 | // the current block by first generating the code of the block, then a label, and then generate the rest of the current |
| 2668 | // ir.Block in a different SPIR-V block. | 2642 | // ir.Block in a different SPIR-V block. |
| 2669 | 2643 | ||
| 2644 | const mod = self.module; | ||
| 2670 | const label_id = self.spv.allocId(); | 2645 | const label_id = self.spv.allocId(); |
| 2671 | 2646 | ||
| 2672 | // 4 chosen as arbitrary initial capacity. | 2647 | // 4 chosen as arbitrary initial capacity. |
| ... | @@ -2681,7 +2656,7 @@ pub const DeclGen = struct { | ... | @@ -2681,7 +2656,7 @@ pub const DeclGen = struct { |
| 2681 | incoming_blocks.deinit(self.gpa); | 2656 | incoming_blocks.deinit(self.gpa); |
| 2682 | } | 2657 | } |
| 2683 | 2658 | ||
| 2684 | const ty = self.air.typeOfIndex(inst); | 2659 | const ty = self.typeOfIndex(inst); |
| 2685 | const inst_datas = self.air.instructions.items(.data); | 2660 | const inst_datas = self.air.instructions.items(.data); |
| 2686 | const extra = self.air.extraData(Air.Block, inst_datas[inst].ty_pl.payload); | 2661 | const extra = self.air.extraData(Air.Block, inst_datas[inst].ty_pl.payload); |
| 2687 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 2662 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| ... | @@ -2690,7 +2665,7 @@ pub const DeclGen = struct { | ... | @@ -2690,7 +2665,7 @@ pub const DeclGen = struct { |
| 2690 | try self.beginSpvBlock(label_id); | 2665 | try self.beginSpvBlock(label_id); |
| 2691 | 2666 | ||
| 2692 | // If this block didn't produce a value, simply return here. | 2667 | // If this block didn't produce a value, simply return here. |
| 2693 | if (!ty.hasRuntimeBitsIgnoreComptime()) | 2668 | if (!ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 2694 | return null; | 2669 | return null; |
| 2695 | 2670 | ||
| 2696 | // Combine the result from the blocks using the Phi instruction. | 2671 | // Combine the result from the blocks using the Phi instruction. |
| ... | @@ -2714,9 +2689,10 @@ pub const DeclGen = struct { | ... | @@ -2714,9 +2689,10 @@ pub const DeclGen = struct { |
| 2714 | fn airBr(self: *DeclGen, inst: Air.Inst.Index) !void { | 2689 | fn airBr(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2715 | const br = self.air.instructions.items(.data)[inst].br; | 2690 | const br = self.air.instructions.items(.data)[inst].br; |
| 2716 | const block = self.blocks.get(br.block_inst).?; | 2691 | const block = self.blocks.get(br.block_inst).?; |
| 2717 | const operand_ty = self.air.typeOf(br.operand); | 2692 | const operand_ty = self.typeOf(br.operand); |
| 2718 | 2693 | ||
| 2719 | if (operand_ty.hasRuntimeBits()) { | 2694 | const mod = self.module; |
| 2695 | if (operand_ty.hasRuntimeBits(mod)) { | ||
| 2720 | const operand_id = try self.resolve(br.operand); | 2696 | const operand_id = try self.resolve(br.operand); |
| 2721 | // current_block_label_id should not be undefined here, lest there is a br or br_void in the function's body. | 2697 | // current_block_label_id should not be undefined here, lest there is a br or br_void in the function's body. |
| 2722 | try block.incoming_blocks.append(self.gpa, .{ .src_label_id = self.current_block_label_id, .break_value_id = operand_id }); | 2698 | try block.incoming_blocks.append(self.gpa, .{ .src_label_id = self.current_block_label_id, .break_value_id = operand_id }); |
| ... | @@ -2753,7 +2729,10 @@ pub const DeclGen = struct { | ... | @@ -2753,7 +2729,10 @@ pub const DeclGen = struct { |
| 2753 | 2729 | ||
| 2754 | fn airDbgStmt(self: *DeclGen, inst: Air.Inst.Index) !void { | 2730 | fn airDbgStmt(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2755 | const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt; | 2731 | const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt; |
| 2756 | const src_fname_id = try self.spv.resolveSourceFileName(self.module.declPtr(self.decl_index)); | 2732 | const src_fname_id = try self.spv.resolveSourceFileName( |
| 2733 | self.module, | ||
| 2734 | self.module.declPtr(self.decl_index), | ||
| 2735 | ); | ||
| 2757 | try self.func.body.emit(self.spv.gpa, .OpLine, .{ | 2736 | try self.func.body.emit(self.spv.gpa, .OpLine, .{ |
| 2758 | .file = src_fname_id, | 2737 | .file = src_fname_id, |
| 2759 | .line = dbg_stmt.line, | 2738 | .line = dbg_stmt.line, |
| ... | @@ -2762,22 +2741,24 @@ pub const DeclGen = struct { | ... | @@ -2762,22 +2741,24 @@ pub const DeclGen = struct { |
| 2762 | } | 2741 | } |
| 2763 | 2742 | ||
| 2764 | fn airLoad(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2743 | fn airLoad(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2744 | const mod = self.module; | ||
| 2765 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2745 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2766 | const ptr_ty = self.air.typeOf(ty_op.operand); | 2746 | const ptr_ty = self.typeOf(ty_op.operand); |
| 2767 | const operand = try self.resolve(ty_op.operand); | 2747 | const operand = try self.resolve(ty_op.operand); |
| 2768 | if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null; | 2748 | if (!ptr_ty.isVolatilePtr(mod) and self.liveness.isUnused(inst)) return null; |
| 2769 | 2749 | ||
| 2770 | return try self.load(ptr_ty, operand); | 2750 | return try self.load(ptr_ty, operand); |
| 2771 | } | 2751 | } |
| 2772 | 2752 | ||
| 2773 | fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { | 2753 | fn airStore(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2754 | const mod = self.module; | ||
| 2774 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; | 2755 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2775 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2756 | const ptr_ty = self.typeOf(bin_op.lhs); |
| 2776 | const ptr = try self.resolve(bin_op.lhs); | 2757 | const ptr = try self.resolve(bin_op.lhs); |
| 2777 | const value = try self.resolve(bin_op.rhs); | 2758 | const value = try self.resolve(bin_op.rhs); |
| 2778 | const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); | 2759 | const ptr_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 2779 | 2760 | ||
| 2780 | const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false; | 2761 | const val_is_undef = if (try self.air.value(bin_op.rhs, mod)) |val| val.isUndefDeep(mod) else false; |
| 2781 | if (val_is_undef) { | 2762 | if (val_is_undef) { |
| 2782 | const undef = try self.spv.constUndef(ptr_ty_ref); | 2763 | const undef = try self.spv.constUndef(ptr_ty_ref); |
| 2783 | try self.store(ptr_ty, ptr, undef); | 2764 | try self.store(ptr_ty, ptr, undef); |
| ... | @@ -2804,8 +2785,9 @@ pub const DeclGen = struct { | ... | @@ -2804,8 +2785,9 @@ pub const DeclGen = struct { |
| 2804 | 2785 | ||
| 2805 | fn airRet(self: *DeclGen, inst: Air.Inst.Index) !void { | 2786 | fn airRet(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2806 | const operand = self.air.instructions.items(.data)[inst].un_op; | 2787 | const operand = self.air.instructions.items(.data)[inst].un_op; |
| 2807 | const operand_ty = self.air.typeOf(operand); | 2788 | const operand_ty = self.typeOf(operand); |
| 2808 | if (operand_ty.hasRuntimeBits()) { | 2789 | const mod = self.module; |
| 2790 | if (operand_ty.hasRuntimeBits(mod)) { | ||
| 2809 | const operand_id = try self.resolve(operand); | 2791 | const operand_id = try self.resolve(operand); |
| 2810 | try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = operand_id }); | 2792 | try self.func.body.emit(self.spv.gpa, .OpReturnValue, .{ .value = operand_id }); |
| 2811 | } else { | 2793 | } else { |
| ... | @@ -2814,11 +2796,12 @@ pub const DeclGen = struct { | ... | @@ -2814,11 +2796,12 @@ pub const DeclGen = struct { |
| 2814 | } | 2796 | } |
| 2815 | 2797 | ||
| 2816 | fn airRetLoad(self: *DeclGen, inst: Air.Inst.Index) !void { | 2798 | fn airRetLoad(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2799 | const mod = self.module; | ||
| 2817 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2800 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2818 | const ptr_ty = self.air.typeOf(un_op); | 2801 | const ptr_ty = self.typeOf(un_op); |
| 2819 | const ret_ty = ptr_ty.childType(); | 2802 | const ret_ty = ptr_ty.childType(mod); |
| 2820 | 2803 | ||
| 2821 | if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { | 2804 | if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 2822 | try self.func.body.emit(self.spv.gpa, .OpReturn, {}); | 2805 | try self.func.body.emit(self.spv.gpa, .OpReturn, {}); |
| 2823 | return; | 2806 | return; |
| 2824 | } | 2807 | } |
| ... | @@ -2831,20 +2814,21 @@ pub const DeclGen = struct { | ... | @@ -2831,20 +2814,21 @@ pub const DeclGen = struct { |
| 2831 | } | 2814 | } |
| 2832 | 2815 | ||
| 2833 | fn airTry(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2816 | fn airTry(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2817 | const mod = self.module; | ||
| 2834 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 2818 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2835 | const err_union_id = try self.resolve(pl_op.operand); | 2819 | const err_union_id = try self.resolve(pl_op.operand); |
| 2836 | const extra = self.air.extraData(Air.Try, pl_op.payload); | 2820 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| 2837 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; | 2821 | const body = self.air.extra[extra.end..][0..extra.data.body_len]; |
| 2838 | 2822 | ||
| 2839 | const err_union_ty = self.air.typeOf(pl_op.operand); | 2823 | const err_union_ty = self.typeOf(pl_op.operand); |
| 2840 | const payload_ty = self.air.typeOfIndex(inst); | 2824 | const payload_ty = self.typeOfIndex(inst); |
| 2841 | 2825 | ||
| 2842 | const err_ty_ref = try self.resolveType(Type.anyerror, .direct); | 2826 | const err_ty_ref = try self.resolveType(Type.anyerror, .direct); |
| 2843 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); | 2827 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| 2844 | 2828 | ||
| 2845 | const eu_layout = self.errorUnionLayout(payload_ty); | 2829 | const eu_layout = self.errorUnionLayout(payload_ty); |
| 2846 | 2830 | ||
| 2847 | if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 2831 | if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 2848 | const err_id = if (eu_layout.payload_has_bits) | 2832 | const err_id = if (eu_layout.payload_has_bits) |
| 2849 | try self.extractField(Type.anyerror, err_union_id, eu_layout.errorFieldIndex()) | 2833 | try self.extractField(Type.anyerror, err_union_id, eu_layout.errorFieldIndex()) |
| 2850 | else | 2834 | else |
| ... | @@ -2892,17 +2876,18 @@ pub const DeclGen = struct { | ... | @@ -2892,17 +2876,18 @@ pub const DeclGen = struct { |
| 2892 | fn airErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2876 | fn airErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2893 | if (self.liveness.isUnused(inst)) return null; | 2877 | if (self.liveness.isUnused(inst)) return null; |
| 2894 | 2878 | ||
| 2879 | const mod = self.module; | ||
| 2895 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2880 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2896 | const operand_id = try self.resolve(ty_op.operand); | 2881 | const operand_id = try self.resolve(ty_op.operand); |
| 2897 | const err_union_ty = self.air.typeOf(ty_op.operand); | 2882 | const err_union_ty = self.typeOf(ty_op.operand); |
| 2898 | const err_ty_ref = try self.resolveType(Type.anyerror, .direct); | 2883 | const err_ty_ref = try self.resolveType(Type.anyerror, .direct); |
| 2899 | 2884 | ||
| 2900 | if (err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 2885 | if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) { |
| 2901 | // No error possible, so just return undefined. | 2886 | // No error possible, so just return undefined. |
| 2902 | return try self.spv.constUndef(err_ty_ref); | 2887 | return try self.spv.constUndef(err_ty_ref); |
| 2903 | } | 2888 | } |
| 2904 | 2889 | ||
| 2905 | const payload_ty = err_union_ty.errorUnionPayload(); | 2890 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 2906 | const eu_layout = self.errorUnionLayout(payload_ty); | 2891 | const eu_layout = self.errorUnionLayout(payload_ty); |
| 2907 | 2892 | ||
| 2908 | if (!eu_layout.payload_has_bits) { | 2893 | if (!eu_layout.payload_has_bits) { |
| ... | @@ -2916,9 +2901,10 @@ pub const DeclGen = struct { | ... | @@ -2916,9 +2901,10 @@ pub const DeclGen = struct { |
| 2916 | fn airWrapErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2901 | fn airWrapErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2917 | if (self.liveness.isUnused(inst)) return null; | 2902 | if (self.liveness.isUnused(inst)) return null; |
| 2918 | 2903 | ||
| 2904 | const mod = self.module; | ||
| 2919 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2905 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2920 | const err_union_ty = self.air.typeOfIndex(inst); | 2906 | const err_union_ty = self.typeOfIndex(inst); |
| 2921 | const payload_ty = err_union_ty.errorUnionPayload(); | 2907 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 2922 | const operand_id = try self.resolve(ty_op.operand); | 2908 | const operand_id = try self.resolve(ty_op.operand); |
| 2923 | const eu_layout = self.errorUnionLayout(payload_ty); | 2909 | const eu_layout = self.errorUnionLayout(payload_ty); |
| 2924 | 2910 | ||
| ... | @@ -2946,25 +2932,24 @@ pub const DeclGen = struct { | ... | @@ -2946,25 +2932,24 @@ pub const DeclGen = struct { |
| 2946 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { | 2932 | fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { |
| 2947 | if (self.liveness.isUnused(inst)) return null; | 2933 | if (self.liveness.isUnused(inst)) return null; |
| 2948 | 2934 | ||
| 2935 | const mod = self.module; | ||
| 2949 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 2936 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 2950 | const operand_id = try self.resolve(un_op); | 2937 | const operand_id = try self.resolve(un_op); |
| 2951 | const optional_ty = self.air.typeOf(un_op); | 2938 | const optional_ty = self.typeOf(un_op); |
| 2952 | 2939 | ||
| 2953 | var buf: Type.Payload.ElemType = undefined; | 2940 | const payload_ty = optional_ty.optionalChild(mod); |
| 2954 | const payload_ty = optional_ty.optionalChild(&buf); | ||
| 2955 | 2941 | ||
| 2956 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); | 2942 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| 2957 | 2943 | ||
| 2958 | if (optional_ty.optionalReprIsPayload()) { | 2944 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 2959 | // Pointer payload represents nullability: pointer or slice. | 2945 | // Pointer payload represents nullability: pointer or slice. |
| 2960 | 2946 | ||
| 2961 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | 2947 | const ptr_ty = if (payload_ty.isSlice(mod)) |
| 2962 | const ptr_ty = if (payload_ty.isSlice()) | 2948 | payload_ty.slicePtrFieldType(mod) |
| 2963 | payload_ty.slicePtrFieldType(&ptr_buf) | ||
| 2964 | else | 2949 | else |
| 2965 | payload_ty; | 2950 | payload_ty; |
| 2966 | 2951 | ||
| 2967 | const ptr_id = if (payload_ty.isSlice()) | 2952 | const ptr_id = if (payload_ty.isSlice(mod)) |
| 2968 | try self.extractField(Type.bool, operand_id, 0) | 2953 | try self.extractField(Type.bool, operand_id, 0) |
| 2969 | else | 2954 | else |
| 2970 | operand_id; | 2955 | operand_id; |
| ... | @@ -2985,7 +2970,7 @@ pub const DeclGen = struct { | ... | @@ -2985,7 +2970,7 @@ pub const DeclGen = struct { |
| 2985 | return result_id; | 2970 | return result_id; |
| 2986 | } | 2971 | } |
| 2987 | 2972 | ||
| 2988 | const is_non_null_id = if (optional_ty.hasRuntimeBitsIgnoreComptime()) | 2973 | const is_non_null_id = if (optional_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 2989 | try self.extractField(Type.bool, operand_id, 1) | 2974 | try self.extractField(Type.bool, operand_id, 1) |
| 2990 | else | 2975 | else |
| 2991 | // Optional representation is bool indicating whether the optional is set | 2976 | // Optional representation is bool indicating whether the optional is set |
| ... | @@ -3009,14 +2994,15 @@ pub const DeclGen = struct { | ... | @@ -3009,14 +2994,15 @@ pub const DeclGen = struct { |
| 3009 | fn airUnwrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2994 | fn airUnwrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3010 | if (self.liveness.isUnused(inst)) return null; | 2995 | if (self.liveness.isUnused(inst)) return null; |
| 3011 | 2996 | ||
| 2997 | const mod = self.module; | ||
| 3012 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2998 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3013 | const operand_id = try self.resolve(ty_op.operand); | 2999 | const operand_id = try self.resolve(ty_op.operand); |
| 3014 | const optional_ty = self.air.typeOf(ty_op.operand); | 3000 | const optional_ty = self.typeOf(ty_op.operand); |
| 3015 | const payload_ty = self.air.typeOfIndex(inst); | 3001 | const payload_ty = self.typeOfIndex(inst); |
| 3016 | 3002 | ||
| 3017 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return null; | 3003 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) return null; |
| 3018 | 3004 | ||
| 3019 | if (optional_ty.optionalReprIsPayload()) { | 3005 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 3020 | return operand_id; | 3006 | return operand_id; |
| 3021 | } | 3007 | } |
| 3022 | 3008 | ||
| ... | @@ -3026,16 +3012,17 @@ pub const DeclGen = struct { | ... | @@ -3026,16 +3012,17 @@ pub const DeclGen = struct { |
| 3026 | fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3012 | fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3027 | if (self.liveness.isUnused(inst)) return null; | 3013 | if (self.liveness.isUnused(inst)) return null; |
| 3028 | 3014 | ||
| 3015 | const mod = self.module; | ||
| 3029 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 3016 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 3030 | const payload_ty = self.air.typeOf(ty_op.operand); | 3017 | const payload_ty = self.typeOf(ty_op.operand); |
| 3031 | 3018 | ||
| 3032 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3019 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3033 | return try self.constBool(true, .direct); | 3020 | return try self.constBool(true, .direct); |
| 3034 | } | 3021 | } |
| 3035 | 3022 | ||
| 3036 | const operand_id = try self.resolve(ty_op.operand); | 3023 | const operand_id = try self.resolve(ty_op.operand); |
| 3037 | const optional_ty = self.air.typeOfIndex(inst); | 3024 | const optional_ty = self.typeOfIndex(inst); |
| 3038 | if (optional_ty.optionalReprIsPayload()) { | 3025 | if (optional_ty.optionalReprIsPayload(mod)) { |
| 3039 | return operand_id; | 3026 | return operand_id; |
| 3040 | } | 3027 | } |
| 3041 | 3028 | ||
| ... | @@ -3045,30 +3032,29 @@ pub const DeclGen = struct { | ... | @@ -3045,30 +3032,29 @@ pub const DeclGen = struct { |
| 3045 | } | 3032 | } |
| 3046 | 3033 | ||
| 3047 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { | 3034 | fn airSwitchBr(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 3048 | const target = self.getTarget(); | 3035 | const mod = self.module; |
| 3049 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 3036 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3050 | const cond = try self.resolve(pl_op.operand); | 3037 | const cond = try self.resolve(pl_op.operand); |
| 3051 | const cond_ty = self.air.typeOf(pl_op.operand); | 3038 | const cond_ty = self.typeOf(pl_op.operand); |
| 3052 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); | 3039 | const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload); |
| 3053 | 3040 | ||
| 3054 | const cond_words: u32 = switch (cond_ty.zigTypeTag()) { | 3041 | const cond_words: u32 = switch (cond_ty.zigTypeTag(mod)) { |
| 3055 | .Int => blk: { | 3042 | .Int => blk: { |
| 3056 | const bits = cond_ty.intInfo(target).bits; | 3043 | const bits = cond_ty.intInfo(mod).bits; |
| 3057 | const backing_bits = self.backingIntBits(bits) orelse { | 3044 | const backing_bits = self.backingIntBits(bits) orelse { |
| 3058 | return self.todo("implement composite int switch", .{}); | 3045 | return self.todo("implement composite int switch", .{}); |
| 3059 | }; | 3046 | }; |
| 3060 | break :blk if (backing_bits <= 32) @as(u32, 1) else 2; | 3047 | break :blk if (backing_bits <= 32) @as(u32, 1) else 2; |
| 3061 | }, | 3048 | }, |
| 3062 | .Enum => blk: { | 3049 | .Enum => blk: { |
| 3063 | var buffer: Type.Payload.Bits = undefined; | 3050 | const int_ty = cond_ty.intTagType(mod); |
| 3064 | const int_ty = cond_ty.intTagType(&buffer); | 3051 | const int_info = int_ty.intInfo(mod); |
| 3065 | const int_info = int_ty.intInfo(target); | ||
| 3066 | const backing_bits = self.backingIntBits(int_info.bits) orelse { | 3052 | const backing_bits = self.backingIntBits(int_info.bits) orelse { |
| 3067 | return self.todo("implement composite int switch", .{}); | 3053 | return self.todo("implement composite int switch", .{}); |
| 3068 | }; | 3054 | }; |
| 3069 | break :blk if (backing_bits <= 32) @as(u32, 1) else 2; | 3055 | break :blk if (backing_bits <= 32) @as(u32, 1) else 2; |
| 3070 | }, | 3056 | }, |
| 3071 | else => return self.todo("implement switch for type {s}", .{@tagName(cond_ty.zigTypeTag())}), // TODO: Figure out which types apply here, and work around them as we can only do integers. | 3057 | else => return self.todo("implement switch for type {s}", .{@tagName(cond_ty.zigTypeTag(mod))}), // TODO: Figure out which types apply here, and work around them as we can only do integers. |
| 3072 | }; | 3058 | }; |
| 3073 | 3059 | ||
| 3074 | const num_cases = switch_br.data.cases_len; | 3060 | const num_cases = switch_br.data.cases_len; |
| ... | @@ -3112,15 +3098,14 @@ pub const DeclGen = struct { | ... | @@ -3112,15 +3098,14 @@ pub const DeclGen = struct { |
| 3112 | const label = IdRef{ .id = first_case_label.id + case_i }; | 3098 | const label = IdRef{ .id = first_case_label.id + case_i }; |
| 3113 | 3099 | ||
| 3114 | for (items) |item| { | 3100 | for (items) |item| { |
| 3115 | const value = self.air.value(item) orelse { | 3101 | const value = (try self.air.value(item, mod)) orelse { |
| 3116 | return self.todo("switch on runtime value???", .{}); | 3102 | return self.todo("switch on runtime value???", .{}); |
| 3117 | }; | 3103 | }; |
| 3118 | const int_val = switch (cond_ty.zigTypeTag()) { | 3104 | const int_val = switch (cond_ty.zigTypeTag(mod)) { |
| 3119 | .Int => if (cond_ty.isSignedInt()) @bitCast(u64, value.toSignedInt(target)) else value.toUnsignedInt(target), | 3105 | .Int => if (cond_ty.isSignedInt(mod)) @bitCast(u64, value.toSignedInt(mod)) else value.toUnsignedInt(mod), |
| 3120 | .Enum => blk: { | 3106 | .Enum => blk: { |
| 3121 | var int_buffer: Value.Payload.U64 = undefined; | ||
| 3122 | // TODO: figure out of cond_ty is correct (something with enum literals) | 3107 | // TODO: figure out of cond_ty is correct (something with enum literals) |
| 3123 | break :blk value.enumToInt(cond_ty, &int_buffer).toUnsignedInt(target); // TODO: composite integer constants | 3108 | break :blk (try value.enumToInt(cond_ty, mod)).toUnsignedInt(mod); // TODO: composite integer constants |
| 3124 | }, | 3109 | }, |
| 3125 | else => unreachable, | 3110 | else => unreachable, |
| 3126 | }; | 3111 | }; |
| ... | @@ -3164,6 +3149,7 @@ pub const DeclGen = struct { | ... | @@ -3164,6 +3149,7 @@ pub const DeclGen = struct { |
| 3164 | } | 3149 | } |
| 3165 | 3150 | ||
| 3166 | fn airAssembly(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3151 | fn airAssembly(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3152 | const mod = self.module; | ||
| 3167 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 3153 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3168 | const extra = self.air.extraData(Air.Asm, ty_pl.payload); | 3154 | const extra = self.air.extraData(Air.Asm, ty_pl.payload); |
| 3169 | 3155 | ||
| ... | @@ -3246,7 +3232,7 @@ pub const DeclGen = struct { | ... | @@ -3246,7 +3232,7 @@ pub const DeclGen = struct { |
| 3246 | assert(as.errors.items.len != 0); | 3232 | assert(as.errors.items.len != 0); |
| 3247 | assert(self.error_msg == null); | 3233 | assert(self.error_msg == null); |
| 3248 | const loc = LazySrcLoc.nodeOffset(0); | 3234 | const loc = LazySrcLoc.nodeOffset(0); |
| 3249 | const src_loc = loc.toSrcLoc(self.module.declPtr(self.decl_index)); | 3235 | const src_loc = loc.toSrcLoc(self.module.declPtr(self.decl_index), mod); |
| 3250 | self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{}); | 3236 | self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{}); |
| 3251 | const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len); | 3237 | const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len); |
| 3252 | 3238 | ||
| ... | @@ -3294,19 +3280,20 @@ pub const DeclGen = struct { | ... | @@ -3294,19 +3280,20 @@ pub const DeclGen = struct { |
| 3294 | fn airCall(self: *DeclGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !?IdRef { | 3280 | fn airCall(self: *DeclGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !?IdRef { |
| 3295 | _ = modifier; | 3281 | _ = modifier; |
| 3296 | 3282 | ||
| 3283 | const mod = self.module; | ||
| 3297 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 3284 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3298 | const extra = self.air.extraData(Air.Call, pl_op.payload); | 3285 | const extra = self.air.extraData(Air.Call, pl_op.payload); |
| 3299 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); | 3286 | const args = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra.end..][0..extra.data.args_len]); |
| 3300 | const callee_ty = self.air.typeOf(pl_op.operand); | 3287 | const callee_ty = self.typeOf(pl_op.operand); |
| 3301 | const zig_fn_ty = switch (callee_ty.zigTypeTag()) { | 3288 | const zig_fn_ty = switch (callee_ty.zigTypeTag(mod)) { |
| 3302 | .Fn => callee_ty, | 3289 | .Fn => callee_ty, |
| 3303 | .Pointer => return self.fail("cannot call function pointers", .{}), | 3290 | .Pointer => return self.fail("cannot call function pointers", .{}), |
| 3304 | else => unreachable, | 3291 | else => unreachable, |
| 3305 | }; | 3292 | }; |
| 3306 | const fn_info = zig_fn_ty.fnInfo(); | 3293 | const fn_info = mod.typeToFunc(zig_fn_ty).?; |
| 3307 | const return_type = fn_info.return_type; | 3294 | const return_type = fn_info.return_type; |
| 3308 | 3295 | ||
| 3309 | const result_type_id = try self.resolveTypeId(return_type); | 3296 | const result_type_id = try self.resolveTypeId(return_type.toType()); |
| 3310 | const result_id = self.spv.allocId(); | 3297 | const result_id = self.spv.allocId(); |
| 3311 | const callee_id = try self.resolve(pl_op.operand); | 3298 | const callee_id = try self.resolve(pl_op.operand); |
| 3312 | 3299 | ||
| ... | @@ -3319,8 +3306,8 @@ pub const DeclGen = struct { | ... | @@ -3319,8 +3306,8 @@ pub const DeclGen = struct { |
| 3319 | // before starting to emit OpFunctionCall instructions. Hence the | 3306 | // before starting to emit OpFunctionCall instructions. Hence the |
| 3320 | // temporary params buffer. | 3307 | // temporary params buffer. |
| 3321 | const arg_id = try self.resolve(arg); | 3308 | const arg_id = try self.resolve(arg); |
| 3322 | const arg_ty = self.air.typeOf(arg); | 3309 | const arg_ty = self.typeOf(arg); |
| 3323 | if (!arg_ty.hasRuntimeBitsIgnoreComptime()) continue; | 3310 | if (!arg_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; |
| 3324 | 3311 | ||
| 3325 | params[n_params] = arg_id; | 3312 | params[n_params] = arg_id; |
| 3326 | n_params += 1; | 3313 | n_params += 1; |
| ... | @@ -3333,14 +3320,24 @@ pub const DeclGen = struct { | ... | @@ -3333,14 +3320,24 @@ pub const DeclGen = struct { |
| 3333 | .id_ref_3 = params[0..n_params], | 3320 | .id_ref_3 = params[0..n_params], |
| 3334 | }); | 3321 | }); |
| 3335 | 3322 | ||
| 3336 | if (return_type.isNoReturn()) { | 3323 | if (return_type == .noreturn_type) { |
| 3337 | try self.func.body.emit(self.spv.gpa, .OpUnreachable, {}); | 3324 | try self.func.body.emit(self.spv.gpa, .OpUnreachable, {}); |
| 3338 | } | 3325 | } |
| 3339 | 3326 | ||
| 3340 | if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBitsIgnoreComptime()) { | 3327 | if (self.liveness.isUnused(inst) or !return_type.toType().hasRuntimeBitsIgnoreComptime(mod)) { |
| 3341 | return null; | 3328 | return null; |
| 3342 | } | 3329 | } |
| 3343 | 3330 | ||
| 3344 | return result_id; | 3331 | return result_id; |
| 3345 | } | 3332 | } |
| 3333 | |||
| 3334 | fn typeOf(self: *DeclGen, inst: Air.Inst.Ref) Type { | ||
| 3335 | const mod = self.module; | ||
| 3336 | return self.air.typeOf(inst, &mod.intern_pool); | ||
| 3337 | } | ||
| 3338 | |||
| 3339 | fn typeOfIndex(self: *DeclGen, inst: Air.Inst.Index) Type { | ||
| 3340 | const mod = self.module; | ||
| 3341 | return self.air.typeOfIndex(inst, &mod.intern_pool); | ||
| 3342 | } | ||
| 3346 | }; | 3343 | }; |
src/codegen/spirv/Module.zig+4-3| ... | @@ -11,7 +11,8 @@ const std = @import("std"); | ... | @@ -11,7 +11,8 @@ const std = @import("std"); |
| 11 | const Allocator = std.mem.Allocator; | 11 | const Allocator = std.mem.Allocator; |
| 12 | const assert = std.debug.assert; | 12 | const assert = std.debug.assert; |
| 13 | 13 | ||
| 14 | const ZigDecl = @import("../../Module.zig").Decl; | 14 | const ZigModule = @import("../../Module.zig"); |
| 15 | const ZigDecl = ZigModule.Decl; | ||
| 15 | 16 | ||
| 16 | const spec = @import("spec.zig"); | 17 | const spec = @import("spec.zig"); |
| 17 | const Word = spec.Word; | 18 | const Word = spec.Word; |
| ... | @@ -389,8 +390,8 @@ pub fn addFunction(self: *Module, decl_index: Decl.Index, func: Fn) !void { | ... | @@ -389,8 +390,8 @@ pub fn addFunction(self: *Module, decl_index: Decl.Index, func: Fn) !void { |
| 389 | /// Fetch the result-id of an OpString instruction that encodes the path of the source | 390 | /// Fetch the result-id of an OpString instruction that encodes the path of the source |
| 390 | /// file of the decl. This function may also emit an OpSource with source-level information regarding | 391 | /// file of the decl. This function may also emit an OpSource with source-level information regarding |
| 391 | /// the decl. | 392 | /// the decl. |
| 392 | pub fn resolveSourceFileName(self: *Module, decl: *ZigDecl) !IdRef { | 393 | pub fn resolveSourceFileName(self: *Module, zig_module: *ZigModule, zig_decl: *ZigDecl) !IdRef { |
| 393 | const path = decl.getFileScope().sub_file_path; | 394 | const path = zig_decl.getFileScope(zig_module).sub_file_path; |
| 394 | const result = try self.source_file_names.getOrPut(self.gpa, path); | 395 | const result = try self.source_file_names.getOrPut(self.gpa, path); |
| 395 | if (!result.found_existing) { | 396 | if (!result.found_existing) { |
| 396 | const file_result_id = self.allocId(); | 397 | const file_result_id = self.allocId(); |
src/crash_report.zig+4-4| ... | @@ -99,7 +99,7 @@ fn dumpStatusReport() !void { | ... | @@ -99,7 +99,7 @@ fn dumpStatusReport() !void { |
| 99 | allocator, | 99 | allocator, |
| 100 | anal.body, | 100 | anal.body, |
| 101 | anal.body_index, | 101 | anal.body_index, |
| 102 | block.namespace.file_scope, | 102 | mod.namespacePtr(block.namespace).file_scope, |
| 103 | block_src_decl.src_node, | 103 | block_src_decl.src_node, |
| 104 | 6, // indent | 104 | 6, // indent |
| 105 | stderr, | 105 | stderr, |
| ... | @@ -108,7 +108,7 @@ fn dumpStatusReport() !void { | ... | @@ -108,7 +108,7 @@ fn dumpStatusReport() !void { |
| 108 | else => |e| return e, | 108 | else => |e| return e, |
| 109 | }; | 109 | }; |
| 110 | try stderr.writeAll(" For full context, use the command\n zig ast-check -t "); | 110 | try stderr.writeAll(" For full context, use the command\n zig ast-check -t "); |
| 111 | try writeFilePath(block.namespace.file_scope, stderr); | 111 | try writeFilePath(mod.namespacePtr(block.namespace).file_scope, stderr); |
| 112 | try stderr.writeAll("\n\n"); | 112 | try stderr.writeAll("\n\n"); |
| 113 | 113 | ||
| 114 | var parent = anal.parent; | 114 | var parent = anal.parent; |
| ... | @@ -121,7 +121,7 @@ fn dumpStatusReport() !void { | ... | @@ -121,7 +121,7 @@ fn dumpStatusReport() !void { |
| 121 | print_zir.renderSingleInstruction( | 121 | print_zir.renderSingleInstruction( |
| 122 | allocator, | 122 | allocator, |
| 123 | curr.body[curr.body_index], | 123 | curr.body[curr.body_index], |
| 124 | curr.block.namespace.file_scope, | 124 | mod.namespacePtr(curr.block.namespace).file_scope, |
| 125 | curr_block_src_decl.src_node, | 125 | curr_block_src_decl.src_node, |
| 126 | 6, // indent | 126 | 6, // indent |
| 127 | stderr, | 127 | stderr, |
| ... | @@ -148,7 +148,7 @@ fn writeFilePath(file: *Module.File, stream: anytype) !void { | ... | @@ -148,7 +148,7 @@ fn writeFilePath(file: *Module.File, stream: anytype) !void { |
| 148 | } | 148 | } |
| 149 | 149 | ||
| 150 | fn writeFullyQualifiedDeclWithFile(mod: *Module, decl: *Decl, stream: anytype) !void { | 150 | fn writeFullyQualifiedDeclWithFile(mod: *Module, decl: *Decl, stream: anytype) !void { |
| 151 | try writeFilePath(decl.getFileScope(), stream); | 151 | try writeFilePath(decl.getFileScope(mod), stream); |
| 152 | try stream.writeAll(": "); | 152 | try stream.writeAll(": "); |
| 153 | try decl.renderFullyQualifiedDebugName(mod, stream); | 153 | try decl.renderFullyQualifiedDebugName(mod, stream); |
| 154 | } | 154 | } |
src/link.zig+13-24| ... | @@ -502,8 +502,6 @@ pub const File = struct { | ... | @@ -502,8 +502,6 @@ pub const File = struct { |
| 502 | /// of the final binary. | 502 | /// of the final binary. |
| 503 | pub fn lowerUnnamedConst(base: *File, tv: TypedValue, decl_index: Module.Decl.Index) UpdateDeclError!u32 { | 503 | pub fn lowerUnnamedConst(base: *File, tv: TypedValue, decl_index: Module.Decl.Index) UpdateDeclError!u32 { |
| 504 | if (build_options.only_c) @compileError("unreachable"); | 504 | if (build_options.only_c) @compileError("unreachable"); |
| 505 | const decl = base.options.module.?.declPtr(decl_index); | ||
| 506 | log.debug("lowerUnnamedConst {*} ({s})", .{ decl, decl.name }); | ||
| 507 | switch (base.tag) { | 505 | switch (base.tag) { |
| 508 | // zig fmt: off | 506 | // zig fmt: off |
| 509 | .coff => return @fieldParentPtr(Coff, "base", base).lowerUnnamedConst(tv, decl_index), | 507 | .coff => return @fieldParentPtr(Coff, "base", base).lowerUnnamedConst(tv, decl_index), |
| ... | @@ -543,7 +541,6 @@ pub const File = struct { | ... | @@ -543,7 +541,6 @@ pub const File = struct { |
| 543 | /// May be called before or after updateDeclExports for any given Decl. | 541 | /// May be called before or after updateDeclExports for any given Decl. |
| 544 | pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { | 542 | pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { |
| 545 | const decl = module.declPtr(decl_index); | 543 | const decl = module.declPtr(decl_index); |
| 546 | log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmt(module) }); | ||
| 547 | assert(decl.has_tv); | 544 | assert(decl.has_tv); |
| 548 | if (build_options.only_c) { | 545 | if (build_options.only_c) { |
| 549 | assert(base.tag == .c); | 546 | assert(base.tag == .c); |
| ... | @@ -564,34 +561,27 @@ pub const File = struct { | ... | @@ -564,34 +561,27 @@ pub const File = struct { |
| 564 | } | 561 | } |
| 565 | 562 | ||
| 566 | /// May be called before or after updateDeclExports for any given Decl. | 563 | /// May be called before or after updateDeclExports for any given Decl. |
| 567 | pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) UpdateDeclError!void { | 564 | pub fn updateFunc(base: *File, module: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) UpdateDeclError!void { |
| 568 | const owner_decl = module.declPtr(func.owner_decl); | ||
| 569 | log.debug("updateFunc {*} ({s}), type={}", .{ | ||
| 570 | owner_decl, owner_decl.name, owner_decl.ty.fmt(module), | ||
| 571 | }); | ||
| 572 | if (build_options.only_c) { | 565 | if (build_options.only_c) { |
| 573 | assert(base.tag == .c); | 566 | assert(base.tag == .c); |
| 574 | return @fieldParentPtr(C, "base", base).updateFunc(module, func, air, liveness); | 567 | return @fieldParentPtr(C, "base", base).updateFunc(module, func_index, air, liveness); |
| 575 | } | 568 | } |
| 576 | switch (base.tag) { | 569 | switch (base.tag) { |
| 577 | // zig fmt: off | 570 | // zig fmt: off |
| 578 | .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func, air, liveness), | 571 | .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func_index, air, liveness), |
| 579 | .elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func, air, liveness), | 572 | .elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func_index, air, liveness), |
| 580 | .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func, air, liveness), | 573 | .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func_index, air, liveness), |
| 581 | .c => return @fieldParentPtr(C, "base", base).updateFunc(module, func, air, liveness), | 574 | .c => return @fieldParentPtr(C, "base", base).updateFunc(module, func_index, air, liveness), |
| 582 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func, air, liveness), | 575 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func_index, air, liveness), |
| 583 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func, air, liveness), | 576 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func_index, air, liveness), |
| 584 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func, air, liveness), | 577 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func_index, air, liveness), |
| 585 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateFunc(module, func, air, liveness), | 578 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateFunc(module, func_index, air, liveness), |
| 586 | // zig fmt: on | 579 | // zig fmt: on |
| 587 | } | 580 | } |
| 588 | } | 581 | } |
| 589 | 582 | ||
| 590 | pub fn updateDeclLineNumber(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { | 583 | pub fn updateDeclLineNumber(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { |
| 591 | const decl = module.declPtr(decl_index); | 584 | const decl = module.declPtr(decl_index); |
| 592 | log.debug("updateDeclLineNumber {*} ({s}), line={}", .{ | ||
| 593 | decl, decl.name, decl.src_line + 1, | ||
| 594 | }); | ||
| 595 | assert(decl.has_tv); | 585 | assert(decl.has_tv); |
| 596 | if (build_options.only_c) { | 586 | if (build_options.only_c) { |
| 597 | assert(base.tag == .c); | 587 | assert(base.tag == .c); |
| ... | @@ -867,7 +857,6 @@ pub const File = struct { | ... | @@ -867,7 +857,6 @@ pub const File = struct { |
| 867 | exports: []const *Module.Export, | 857 | exports: []const *Module.Export, |
| 868 | ) UpdateDeclExportsError!void { | 858 | ) UpdateDeclExportsError!void { |
| 869 | const decl = module.declPtr(decl_index); | 859 | const decl = module.declPtr(decl_index); |
| 870 | log.debug("updateDeclExports {*} ({s})", .{ decl, decl.name }); | ||
| 871 | assert(decl.has_tv); | 860 | assert(decl.has_tv); |
| 872 | if (build_options.only_c) { | 861 | if (build_options.only_c) { |
| 873 | assert(base.tag == .c); | 862 | assert(base.tag == .c); |
| ... | @@ -1124,13 +1113,13 @@ pub const File = struct { | ... | @@ -1124,13 +1113,13 @@ pub const File = struct { |
| 1124 | 1113 | ||
| 1125 | pub fn initDecl(kind: Kind, decl: ?Module.Decl.Index, mod: *Module) LazySymbol { | 1114 | pub fn initDecl(kind: Kind, decl: ?Module.Decl.Index, mod: *Module) LazySymbol { |
| 1126 | return .{ .kind = kind, .ty = if (decl) |decl_index| | 1115 | return .{ .kind = kind, .ty = if (decl) |decl_index| |
| 1127 | mod.declPtr(decl_index).val.castTag(.ty).?.data | 1116 | mod.declPtr(decl_index).val.toType() |
| 1128 | else | 1117 | else |
| 1129 | Type.anyerror }; | 1118 | Type.anyerror }; |
| 1130 | } | 1119 | } |
| 1131 | 1120 | ||
| 1132 | pub fn getDecl(self: LazySymbol) Module.Decl.OptionalIndex { | 1121 | pub fn getDecl(self: LazySymbol, mod: *Module) Module.Decl.OptionalIndex { |
| 1133 | return Module.Decl.OptionalIndex.init(self.ty.getOwnerDeclOrNull()); | 1122 | return Module.Decl.OptionalIndex.init(self.ty.getOwnerDeclOrNull(mod)); |
| 1134 | } | 1123 | } |
| 1135 | }; | 1124 | }; |
| 1136 | 1125 |
src/link/C.zig+10-7| ... | @@ -6,6 +6,7 @@ const fs = std.fs; | ... | @@ -6,6 +6,7 @@ const fs = std.fs; |
| 6 | 6 | ||
| 7 | const C = @This(); | 7 | const C = @This(); |
| 8 | const Module = @import("../Module.zig"); | 8 | const Module = @import("../Module.zig"); |
| 9 | const InternPool = @import("../InternPool.zig"); | ||
| 9 | const Compilation = @import("../Compilation.zig"); | 10 | const Compilation = @import("../Compilation.zig"); |
| 10 | const codegen = @import("../codegen/c.zig"); | 11 | const codegen = @import("../codegen/c.zig"); |
| 11 | const link = @import("../link.zig"); | 12 | const link = @import("../link.zig"); |
| ... | @@ -87,12 +88,13 @@ pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void { | ... | @@ -87,12 +88,13 @@ pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void { |
| 87 | } | 88 | } |
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 91 | pub fn updateFunc(self: *C, module: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { |
| 91 | const tracy = trace(@src()); | 92 | const tracy = trace(@src()); |
| 92 | defer tracy.end(); | 93 | defer tracy.end(); |
| 93 | 94 | ||
| 94 | const gpa = self.base.allocator; | 95 | const gpa = self.base.allocator; |
| 95 | 96 | ||
| 97 | const func = module.funcPtr(func_index); | ||
| 96 | const decl_index = func.owner_decl; | 98 | const decl_index = func.owner_decl; |
| 97 | const gop = try self.decl_table.getOrPut(gpa, decl_index); | 99 | const gop = try self.decl_table.getOrPut(gpa, decl_index); |
| 98 | if (!gop.found_existing) { | 100 | if (!gop.found_existing) { |
| ... | @@ -111,7 +113,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes | ... | @@ -111,7 +113,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes |
| 111 | .value_map = codegen.CValueMap.init(gpa), | 113 | .value_map = codegen.CValueMap.init(gpa), |
| 112 | .air = air, | 114 | .air = air, |
| 113 | .liveness = liveness, | 115 | .liveness = liveness, |
| 114 | .func = func, | 116 | .func_index = func_index, |
| 115 | .object = .{ | 117 | .object = .{ |
| 116 | .dg = .{ | 118 | .dg = .{ |
| 117 | .gpa = gpa, | 119 | .gpa = gpa, |
| ... | @@ -288,11 +290,11 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo | ... | @@ -288,11 +290,11 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo |
| 288 | } | 290 | } |
| 289 | 291 | ||
| 290 | { | 292 | { |
| 291 | var export_names = std.StringHashMapUnmanaged(void){}; | 293 | var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{}; |
| 292 | defer export_names.deinit(gpa); | 294 | defer export_names.deinit(gpa); |
| 293 | try export_names.ensureTotalCapacity(gpa, @intCast(u32, module.decl_exports.entries.len)); | 295 | try export_names.ensureTotalCapacity(gpa, @intCast(u32, module.decl_exports.entries.len)); |
| 294 | for (module.decl_exports.values()) |exports| for (exports.items) |@"export"| | 296 | for (module.decl_exports.values()) |exports| for (exports.items) |@"export"| |
| 295 | try export_names.put(gpa, @"export".options.name, {}); | 297 | try export_names.put(gpa, @"export".opts.name, {}); |
| 296 | 298 | ||
| 297 | while (f.remaining_decls.popOrNull()) |kv| { | 299 | while (f.remaining_decls.popOrNull()) |kv| { |
| 298 | const decl_index = kv.key; | 300 | const decl_index = kv.key; |
| ... | @@ -552,10 +554,11 @@ fn flushDecl( | ... | @@ -552,10 +554,11 @@ fn flushDecl( |
| 552 | self: *C, | 554 | self: *C, |
| 553 | f: *Flush, | 555 | f: *Flush, |
| 554 | decl_index: Module.Decl.Index, | 556 | decl_index: Module.Decl.Index, |
| 555 | export_names: std.StringHashMapUnmanaged(void), | 557 | export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void), |
| 556 | ) FlushDeclError!void { | 558 | ) FlushDeclError!void { |
| 557 | const gpa = self.base.allocator; | 559 | const gpa = self.base.allocator; |
| 558 | const decl = self.base.options.module.?.declPtr(decl_index); | 560 | const mod = self.base.options.module.?; |
| 561 | const decl = mod.declPtr(decl_index); | ||
| 559 | // Before flushing any particular Decl we must ensure its | 562 | // Before flushing any particular Decl we must ensure its |
| 560 | // dependencies are already flushed, so that the order in the .c | 563 | // dependencies are already flushed, so that the order in the .c |
| 561 | // file comes out correctly. | 564 | // file comes out correctly. |
| ... | @@ -569,7 +572,7 @@ fn flushDecl( | ... | @@ -569,7 +572,7 @@ fn flushDecl( |
| 569 | 572 | ||
| 570 | try self.flushLazyFns(f, decl_block.lazy_fns); | 573 | try self.flushLazyFns(f, decl_block.lazy_fns); |
| 571 | try f.all_buffers.ensureUnusedCapacity(gpa, 1); | 574 | try f.all_buffers.ensureUnusedCapacity(gpa, 1); |
| 572 | if (!(decl.isExtern() and export_names.contains(mem.span(decl.name)))) | 575 | if (!(decl.isExtern(mod) and export_names.contains(decl.name))) |
| 573 | f.appendBufAssumeCapacity(decl_block.fwd_decl.items); | 576 | f.appendBufAssumeCapacity(decl_block.fwd_decl.items); |
| 574 | } | 577 | } |
| 575 | 578 |
src/link/Coff.zig+71-66| ... | @@ -1032,20 +1032,21 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void { | ... | @@ -1032,20 +1032,21 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void { |
| 1032 | self.getAtomPtr(atom_index).sym_index = 0; | 1032 | self.getAtomPtr(atom_index).sym_index = 0; |
| 1033 | } | 1033 | } |
| 1034 | 1034 | ||
| 1035 | pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 1035 | pub fn updateFunc(self: *Coff, mod: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { |
| 1036 | if (build_options.skip_non_native and builtin.object_format != .coff) { | 1036 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1037 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1037 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1038 | } | 1038 | } |
| 1039 | if (build_options.have_llvm) { | 1039 | if (build_options.have_llvm) { |
| 1040 | if (self.llvm_object) |llvm_object| { | 1040 | if (self.llvm_object) |llvm_object| { |
| 1041 | return llvm_object.updateFunc(module, func, air, liveness); | 1041 | return llvm_object.updateFunc(mod, func_index, air, liveness); |
| 1042 | } | 1042 | } |
| 1043 | } | 1043 | } |
| 1044 | const tracy = trace(@src()); | 1044 | const tracy = trace(@src()); |
| 1045 | defer tracy.end(); | 1045 | defer tracy.end(); |
| 1046 | 1046 | ||
| 1047 | const func = mod.funcPtr(func_index); | ||
| 1047 | const decl_index = func.owner_decl; | 1048 | const decl_index = func.owner_decl; |
| 1048 | const decl = module.declPtr(decl_index); | 1049 | const decl = mod.declPtr(decl_index); |
| 1049 | 1050 | ||
| 1050 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); | 1051 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 1051 | self.freeUnnamedConsts(decl_index); | 1052 | self.freeUnnamedConsts(decl_index); |
| ... | @@ -1056,8 +1057,8 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live | ... | @@ -1056,8 +1057,8 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live |
| 1056 | 1057 | ||
| 1057 | const res = try codegen.generateFunction( | 1058 | const res = try codegen.generateFunction( |
| 1058 | &self.base, | 1059 | &self.base, |
| 1059 | decl.srcLoc(), | 1060 | decl.srcLoc(mod), |
| 1060 | func, | 1061 | func_index, |
| 1061 | air, | 1062 | air, |
| 1062 | liveness, | 1063 | liveness, |
| 1063 | &code_buffer, | 1064 | &code_buffer, |
| ... | @@ -1067,7 +1068,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live | ... | @@ -1067,7 +1068,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live |
| 1067 | .ok => code_buffer.items, | 1068 | .ok => code_buffer.items, |
| 1068 | .fail => |em| { | 1069 | .fail => |em| { |
| 1069 | decl.analysis = .codegen_failure; | 1070 | decl.analysis = .codegen_failure; |
| 1070 | try module.failed_decls.put(module.gpa, decl_index, em); | 1071 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1071 | return; | 1072 | return; |
| 1072 | }, | 1073 | }, |
| 1073 | }; | 1074 | }; |
| ... | @@ -1076,7 +1077,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live | ... | @@ -1076,7 +1077,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live |
| 1076 | 1077 | ||
| 1077 | // Since we updated the vaddr and the size, each corresponding export | 1078 | // Since we updated the vaddr and the size, each corresponding export |
| 1078 | // symbol also needs to be updated. | 1079 | // symbol also needs to be updated. |
| 1079 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 1080 | return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index)); |
| 1080 | } | 1081 | } |
| 1081 | 1082 | ||
| 1082 | pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { | 1083 | pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { |
| ... | @@ -1096,8 +1097,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1096,8 +1097,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In |
| 1096 | const atom_index = try self.createAtom(); | 1097 | const atom_index = try self.createAtom(); |
| 1097 | 1098 | ||
| 1098 | const sym_name = blk: { | 1099 | const sym_name = blk: { |
| 1099 | const decl_name = try decl.getFullyQualifiedName(mod); | 1100 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1100 | defer gpa.free(decl_name); | ||
| 1101 | 1101 | ||
| 1102 | const index = unnamed_consts.items.len; | 1102 | const index = unnamed_consts.items.len; |
| 1103 | break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); | 1103 | break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); |
| ... | @@ -1110,7 +1110,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1110,7 +1110,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In |
| 1110 | sym.section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1); | 1110 | sym.section_number = @intToEnum(coff.SectionNumber, self.rdata_section_index.? + 1); |
| 1111 | } | 1111 | } |
| 1112 | 1112 | ||
| 1113 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{ | 1113 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), tv, &code_buffer, .none, .{ |
| 1114 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, | 1114 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, |
| 1115 | }); | 1115 | }); |
| 1116 | var code = switch (res) { | 1116 | var code = switch (res) { |
| ... | @@ -1123,7 +1123,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1123,7 +1123,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In |
| 1123 | }, | 1123 | }, |
| 1124 | }; | 1124 | }; |
| 1125 | 1125 | ||
| 1126 | const required_alignment = tv.ty.abiAlignment(self.base.options.target); | 1126 | const required_alignment = tv.ty.abiAlignment(mod); |
| 1127 | const atom = self.getAtomPtr(atom_index); | 1127 | const atom = self.getAtomPtr(atom_index); |
| 1128 | atom.size = @intCast(u32, code.len); | 1128 | atom.size = @intCast(u32, code.len); |
| 1129 | atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment); | 1129 | atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment); |
| ... | @@ -1141,25 +1141,24 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1141,25 +1141,24 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In |
| 1141 | 1141 | ||
| 1142 | pub fn updateDecl( | 1142 | pub fn updateDecl( |
| 1143 | self: *Coff, | 1143 | self: *Coff, |
| 1144 | module: *Module, | 1144 | mod: *Module, |
| 1145 | decl_index: Module.Decl.Index, | 1145 | decl_index: Module.Decl.Index, |
| 1146 | ) link.File.UpdateDeclError!void { | 1146 | ) link.File.UpdateDeclError!void { |
| 1147 | if (build_options.skip_non_native and builtin.object_format != .coff) { | 1147 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1148 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1148 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1149 | } | 1149 | } |
| 1150 | if (build_options.have_llvm) { | 1150 | if (build_options.have_llvm) { |
| 1151 | if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl_index); | 1151 | if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index); |
| 1152 | } | 1152 | } |
| 1153 | const tracy = trace(@src()); | 1153 | const tracy = trace(@src()); |
| 1154 | defer tracy.end(); | 1154 | defer tracy.end(); |
| 1155 | 1155 | ||
| 1156 | const decl = module.declPtr(decl_index); | 1156 | const decl = mod.declPtr(decl_index); |
| 1157 | 1157 | ||
| 1158 | if (decl.val.tag() == .extern_fn) { | 1158 | if (decl.val.getExternFunc(mod)) |_| { |
| 1159 | return; // TODO Should we do more when front-end analyzed extern decl? | 1159 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1160 | } | 1160 | } |
| 1161 | if (decl.val.castTag(.variable)) |payload| { | 1161 | if (decl.val.getVariable(mod)) |variable| { |
| 1162 | const variable = payload.data; | ||
| 1163 | if (variable.is_extern) { | 1162 | if (variable.is_extern) { |
| 1164 | return; // TODO Should we do more when front-end analyzed extern decl? | 1163 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1165 | } | 1164 | } |
| ... | @@ -1172,8 +1171,8 @@ pub fn updateDecl( | ... | @@ -1172,8 +1171,8 @@ pub fn updateDecl( |
| 1172 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 1171 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 1173 | defer code_buffer.deinit(); | 1172 | defer code_buffer.deinit(); |
| 1174 | 1173 | ||
| 1175 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 1174 | const decl_val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val; |
| 1176 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 1175 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 1177 | .ty = decl.ty, | 1176 | .ty = decl.ty, |
| 1178 | .val = decl_val, | 1177 | .val = decl_val, |
| 1179 | }, &code_buffer, .none, .{ | 1178 | }, &code_buffer, .none, .{ |
| ... | @@ -1183,7 +1182,7 @@ pub fn updateDecl( | ... | @@ -1183,7 +1182,7 @@ pub fn updateDecl( |
| 1183 | .ok => code_buffer.items, | 1182 | .ok => code_buffer.items, |
| 1184 | .fail => |em| { | 1183 | .fail => |em| { |
| 1185 | decl.analysis = .codegen_failure; | 1184 | decl.analysis = .codegen_failure; |
| 1186 | try module.failed_decls.put(module.gpa, decl_index, em); | 1185 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1187 | return; | 1186 | return; |
| 1188 | }, | 1187 | }, |
| 1189 | }; | 1188 | }; |
| ... | @@ -1192,7 +1191,7 @@ pub fn updateDecl( | ... | @@ -1192,7 +1191,7 @@ pub fn updateDecl( |
| 1192 | 1191 | ||
| 1193 | // Since we updated the vaddr and the size, each corresponding export | 1192 | // Since we updated the vaddr and the size, each corresponding export |
| 1194 | // symbol also needs to be updated. | 1193 | // symbol also needs to be updated. |
| 1195 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 1194 | return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index)); |
| 1196 | } | 1195 | } |
| 1197 | 1196 | ||
| 1198 | fn updateLazySymbolAtom( | 1197 | fn updateLazySymbolAtom( |
| ... | @@ -1217,8 +1216,8 @@ fn updateLazySymbolAtom( | ... | @@ -1217,8 +1216,8 @@ fn updateLazySymbolAtom( |
| 1217 | const atom = self.getAtomPtr(atom_index); | 1216 | const atom = self.getAtomPtr(atom_index); |
| 1218 | const local_sym_index = atom.getSymbolIndex().?; | 1217 | const local_sym_index = atom.getSymbolIndex().?; |
| 1219 | 1218 | ||
| 1220 | const src = if (sym.ty.getOwnerDeclOrNull()) |owner_decl| | 1219 | const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| |
| 1221 | mod.declPtr(owner_decl).srcLoc() | 1220 | mod.declPtr(owner_decl).srcLoc(mod) |
| 1222 | else | 1221 | else |
| 1223 | Module.SrcLoc{ | 1222 | Module.SrcLoc{ |
| 1224 | .file_scope = undefined, | 1223 | .file_scope = undefined, |
| ... | @@ -1262,7 +1261,8 @@ fn updateLazySymbolAtom( | ... | @@ -1262,7 +1261,8 @@ fn updateLazySymbolAtom( |
| 1262 | } | 1261 | } |
| 1263 | 1262 | ||
| 1264 | pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Atom.Index { | 1263 | pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Atom.Index { |
| 1265 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); | 1264 | const mod = self.base.options.module.?; |
| 1265 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(mod)); | ||
| 1266 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); | 1266 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 1267 | if (!gop.found_existing) gop.value_ptr.* = .{}; | 1267 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 1268 | const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { | 1268 | const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { |
| ... | @@ -1277,7 +1277,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Ato | ... | @@ -1277,7 +1277,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Ato |
| 1277 | metadata.state.* = .pending_flush; | 1277 | metadata.state.* = .pending_flush; |
| 1278 | const atom = metadata.atom.*; | 1278 | const atom = metadata.atom.*; |
| 1279 | // anyerror needs to be deferred until flushModule | 1279 | // anyerror needs to be deferred until flushModule |
| 1280 | if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { | 1280 | if (sym.getDecl(mod) != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { |
| 1281 | .code => self.text_section_index.?, | 1281 | .code => self.text_section_index.?, |
| 1282 | .const_data => self.rdata_section_index.?, | 1282 | .const_data => self.rdata_section_index.?, |
| 1283 | }); | 1283 | }); |
| ... | @@ -1299,10 +1299,11 @@ pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom. | ... | @@ -1299,10 +1299,11 @@ pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom. |
| 1299 | fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { | 1299 | fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { |
| 1300 | const decl = self.base.options.module.?.declPtr(decl_index); | 1300 | const decl = self.base.options.module.?.declPtr(decl_index); |
| 1301 | const ty = decl.ty; | 1301 | const ty = decl.ty; |
| 1302 | const zig_ty = ty.zigTypeTag(); | 1302 | const mod = self.base.options.module.?; |
| 1303 | const zig_ty = ty.zigTypeTag(mod); | ||
| 1303 | const val = decl.val; | 1304 | const val = decl.val; |
| 1304 | const index: u16 = blk: { | 1305 | const index: u16 = blk: { |
| 1305 | if (val.isUndefDeep()) { | 1306 | if (val.isUndefDeep(mod)) { |
| 1306 | // TODO in release-fast and release-small, we should put undef in .bss | 1307 | // TODO in release-fast and release-small, we should put undef in .bss |
| 1307 | break :blk self.data_section_index.?; | 1308 | break :blk self.data_section_index.?; |
| 1308 | } | 1309 | } |
| ... | @@ -1311,7 +1312,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { | ... | @@ -1311,7 +1312,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { |
| 1311 | // TODO: what if this is a function pointer? | 1312 | // TODO: what if this is a function pointer? |
| 1312 | .Fn => break :blk self.text_section_index.?, | 1313 | .Fn => break :blk self.text_section_index.?, |
| 1313 | else => { | 1314 | else => { |
| 1314 | if (val.castTag(.variable)) |_| { | 1315 | if (val.getVariable(mod)) |_| { |
| 1315 | break :blk self.data_section_index.?; | 1316 | break :blk self.data_section_index.?; |
| 1316 | } | 1317 | } |
| 1317 | break :blk self.rdata_section_index.?; | 1318 | break :blk self.rdata_section_index.?; |
| ... | @@ -1322,15 +1323,13 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { | ... | @@ -1322,15 +1323,13 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { |
| 1322 | } | 1323 | } |
| 1323 | 1324 | ||
| 1324 | fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, complex_type: coff.ComplexType) !void { | 1325 | fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, complex_type: coff.ComplexType) !void { |
| 1325 | const gpa = self.base.allocator; | ||
| 1326 | const mod = self.base.options.module.?; | 1326 | const mod = self.base.options.module.?; |
| 1327 | const decl = mod.declPtr(decl_index); | 1327 | const decl = mod.declPtr(decl_index); |
| 1328 | 1328 | ||
| 1329 | const decl_name = try decl.getFullyQualifiedName(mod); | 1329 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1330 | defer gpa.free(decl_name); | ||
| 1331 | 1330 | ||
| 1332 | log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); | 1331 | log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); |
| 1333 | const required_alignment = decl.getAlignment(self.base.options.target); | 1332 | const required_alignment = decl.getAlignment(mod); |
| 1334 | 1333 | ||
| 1335 | const decl_metadata = self.decls.get(decl_index).?; | 1334 | const decl_metadata = self.decls.get(decl_index).?; |
| 1336 | const atom_index = decl_metadata.atom; | 1335 | const atom_index = decl_metadata.atom; |
| ... | @@ -1410,7 +1409,7 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { | ... | @@ -1410,7 +1409,7 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void { |
| 1410 | 1409 | ||
| 1411 | pub fn updateDeclExports( | 1410 | pub fn updateDeclExports( |
| 1412 | self: *Coff, | 1411 | self: *Coff, |
| 1413 | module: *Module, | 1412 | mod: *Module, |
| 1414 | decl_index: Module.Decl.Index, | 1413 | decl_index: Module.Decl.Index, |
| 1415 | exports: []const *Module.Export, | 1414 | exports: []const *Module.Export, |
| 1416 | ) link.File.UpdateDeclExportsError!void { | 1415 | ) link.File.UpdateDeclExportsError!void { |
| ... | @@ -1418,61 +1417,60 @@ pub fn updateDeclExports( | ... | @@ -1418,61 +1417,60 @@ pub fn updateDeclExports( |
| 1418 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1417 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1419 | } | 1418 | } |
| 1420 | 1419 | ||
| 1420 | const ip = &mod.intern_pool; | ||
| 1421 | |||
| 1421 | if (build_options.have_llvm) { | 1422 | if (build_options.have_llvm) { |
| 1422 | // Even in the case of LLVM, we need to notice certain exported symbols in order to | 1423 | // Even in the case of LLVM, we need to notice certain exported symbols in order to |
| 1423 | // detect the default subsystem. | 1424 | // detect the default subsystem. |
| 1424 | for (exports) |exp| { | 1425 | for (exports) |exp| { |
| 1425 | const exported_decl = module.declPtr(exp.exported_decl); | 1426 | const exported_decl = mod.declPtr(exp.exported_decl); |
| 1426 | if (exported_decl.getFunction() == null) continue; | 1427 | if (exported_decl.getOwnedFunctionIndex(mod) == .none) continue; |
| 1427 | const winapi_cc = switch (self.base.options.target.cpu.arch) { | 1428 | const winapi_cc = switch (self.base.options.target.cpu.arch) { |
| 1428 | .x86 => std.builtin.CallingConvention.Stdcall, | 1429 | .x86 => std.builtin.CallingConvention.Stdcall, |
| 1429 | else => std.builtin.CallingConvention.C, | 1430 | else => std.builtin.CallingConvention.C, |
| 1430 | }; | 1431 | }; |
| 1431 | const decl_cc = exported_decl.ty.fnCallingConvention(); | 1432 | const decl_cc = exported_decl.ty.fnCallingConvention(mod); |
| 1432 | if (decl_cc == .C and mem.eql(u8, exp.options.name, "main") and | 1433 | if (decl_cc == .C and ip.stringEqlSlice(exp.opts.name, "main") and |
| 1433 | self.base.options.link_libc) | 1434 | self.base.options.link_libc) |
| 1434 | { | 1435 | { |
| 1435 | module.stage1_flags.have_c_main = true; | 1436 | mod.stage1_flags.have_c_main = true; |
| 1436 | } else if (decl_cc == winapi_cc and self.base.options.target.os.tag == .windows) { | 1437 | } else if (decl_cc == winapi_cc and self.base.options.target.os.tag == .windows) { |
| 1437 | if (mem.eql(u8, exp.options.name, "WinMain")) { | 1438 | if (ip.stringEqlSlice(exp.opts.name, "WinMain")) { |
| 1438 | module.stage1_flags.have_winmain = true; | 1439 | mod.stage1_flags.have_winmain = true; |
| 1439 | } else if (mem.eql(u8, exp.options.name, "wWinMain")) { | 1440 | } else if (ip.stringEqlSlice(exp.opts.name, "wWinMain")) { |
| 1440 | module.stage1_flags.have_wwinmain = true; | 1441 | mod.stage1_flags.have_wwinmain = true; |
| 1441 | } else if (mem.eql(u8, exp.options.name, "WinMainCRTStartup")) { | 1442 | } else if (ip.stringEqlSlice(exp.opts.name, "WinMainCRTStartup")) { |
| 1442 | module.stage1_flags.have_winmain_crt_startup = true; | 1443 | mod.stage1_flags.have_winmain_crt_startup = true; |
| 1443 | } else if (mem.eql(u8, exp.options.name, "wWinMainCRTStartup")) { | 1444 | } else if (ip.stringEqlSlice(exp.opts.name, "wWinMainCRTStartup")) { |
| 1444 | module.stage1_flags.have_wwinmain_crt_startup = true; | 1445 | mod.stage1_flags.have_wwinmain_crt_startup = true; |
| 1445 | } else if (mem.eql(u8, exp.options.name, "DllMainCRTStartup")) { | 1446 | } else if (ip.stringEqlSlice(exp.opts.name, "DllMainCRTStartup")) { |
| 1446 | module.stage1_flags.have_dllmain_crt_startup = true; | 1447 | mod.stage1_flags.have_dllmain_crt_startup = true; |
| 1447 | } | 1448 | } |
| 1448 | } | 1449 | } |
| 1449 | } | 1450 | } |
| 1450 | 1451 | ||
| 1451 | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports); | 1452 | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports); |
| 1452 | } | 1453 | } |
| 1453 | 1454 | ||
| 1454 | const tracy = trace(@src()); | ||
| 1455 | defer tracy.end(); | ||
| 1456 | |||
| 1457 | const gpa = self.base.allocator; | 1455 | const gpa = self.base.allocator; |
| 1458 | 1456 | ||
| 1459 | const decl = module.declPtr(decl_index); | 1457 | const decl = mod.declPtr(decl_index); |
| 1460 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); | 1458 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 1461 | const atom = self.getAtom(atom_index); | 1459 | const atom = self.getAtom(atom_index); |
| 1462 | const decl_sym = atom.getSymbol(self); | 1460 | const decl_sym = atom.getSymbol(self); |
| 1463 | const decl_metadata = self.decls.getPtr(decl_index).?; | 1461 | const decl_metadata = self.decls.getPtr(decl_index).?; |
| 1464 | 1462 | ||
| 1465 | for (exports) |exp| { | 1463 | for (exports) |exp| { |
| 1466 | log.debug("adding new export '{s}'", .{exp.options.name}); | 1464 | log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)}); |
| 1467 | 1465 | ||
| 1468 | if (exp.options.section) |section_name| { | 1466 | if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section_name| { |
| 1469 | if (!mem.eql(u8, section_name, ".text")) { | 1467 | if (!mem.eql(u8, section_name, ".text")) { |
| 1470 | try module.failed_exports.putNoClobber( | 1468 | try mod.failed_exports.putNoClobber( |
| 1471 | module.gpa, | 1469 | gpa, |
| 1472 | exp, | 1470 | exp, |
| 1473 | try Module.ErrorMsg.create( | 1471 | try Module.ErrorMsg.create( |
| 1474 | gpa, | 1472 | gpa, |
| 1475 | decl.srcLoc(), | 1473 | decl.srcLoc(mod), |
| 1476 | "Unimplemented: ExportOptions.section", | 1474 | "Unimplemented: ExportOptions.section", |
| 1477 | .{}, | 1475 | .{}, |
| 1478 | ), | 1476 | ), |
| ... | @@ -1481,13 +1479,13 @@ pub fn updateDeclExports( | ... | @@ -1481,13 +1479,13 @@ pub fn updateDeclExports( |
| 1481 | } | 1479 | } |
| 1482 | } | 1480 | } |
| 1483 | 1481 | ||
| 1484 | if (exp.options.linkage == .LinkOnce) { | 1482 | if (exp.opts.linkage == .LinkOnce) { |
| 1485 | try module.failed_exports.putNoClobber( | 1483 | try mod.failed_exports.putNoClobber( |
| 1486 | module.gpa, | 1484 | gpa, |
| 1487 | exp, | 1485 | exp, |
| 1488 | try Module.ErrorMsg.create( | 1486 | try Module.ErrorMsg.create( |
| 1489 | gpa, | 1487 | gpa, |
| 1490 | decl.srcLoc(), | 1488 | decl.srcLoc(mod), |
| 1491 | "Unimplemented: GlobalLinkage.LinkOnce", | 1489 | "Unimplemented: GlobalLinkage.LinkOnce", |
| 1492 | .{}, | 1490 | .{}, |
| 1493 | ), | 1491 | ), |
| ... | @@ -1495,19 +1493,19 @@ pub fn updateDeclExports( | ... | @@ -1495,19 +1493,19 @@ pub fn updateDeclExports( |
| 1495 | continue; | 1493 | continue; |
| 1496 | } | 1494 | } |
| 1497 | 1495 | ||
| 1498 | const sym_index = decl_metadata.getExport(self, exp.options.name) orelse blk: { | 1496 | const sym_index = decl_metadata.getExport(self, mod.intern_pool.stringToSlice(exp.opts.name)) orelse blk: { |
| 1499 | const sym_index = try self.allocateSymbol(); | 1497 | const sym_index = try self.allocateSymbol(); |
| 1500 | try decl_metadata.exports.append(gpa, sym_index); | 1498 | try decl_metadata.exports.append(gpa, sym_index); |
| 1501 | break :blk sym_index; | 1499 | break :blk sym_index; |
| 1502 | }; | 1500 | }; |
| 1503 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; | 1501 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1504 | const sym = self.getSymbolPtr(sym_loc); | 1502 | const sym = self.getSymbolPtr(sym_loc); |
| 1505 | try self.setSymbolName(sym, exp.options.name); | 1503 | try self.setSymbolName(sym, mod.intern_pool.stringToSlice(exp.opts.name)); |
| 1506 | sym.value = decl_sym.value; | 1504 | sym.value = decl_sym.value; |
| 1507 | sym.section_number = @intToEnum(coff.SectionNumber, self.text_section_index.? + 1); | 1505 | sym.section_number = @intToEnum(coff.SectionNumber, self.text_section_index.? + 1); |
| 1508 | sym.type = .{ .complex_type = .FUNCTION, .base_type = .NULL }; | 1506 | sym.type = .{ .complex_type = .FUNCTION, .base_type = .NULL }; |
| 1509 | 1507 | ||
| 1510 | switch (exp.options.linkage) { | 1508 | switch (exp.opts.linkage) { |
| 1511 | .Strong => { | 1509 | .Strong => { |
| 1512 | sym.storage_class = .EXTERNAL; | 1510 | sym.storage_class = .EXTERNAL; |
| 1513 | }, | 1511 | }, |
| ... | @@ -1520,9 +1518,15 @@ pub fn updateDeclExports( | ... | @@ -1520,9 +1518,15 @@ pub fn updateDeclExports( |
| 1520 | } | 1518 | } |
| 1521 | } | 1519 | } |
| 1522 | 1520 | ||
| 1523 | pub fn deleteDeclExport(self: *Coff, decl_index: Module.Decl.Index, name: []const u8) void { | 1521 | pub fn deleteDeclExport( |
| 1522 | self: *Coff, | ||
| 1523 | decl_index: Module.Decl.Index, | ||
| 1524 | name_ip: InternPool.NullTerminatedString, | ||
| 1525 | ) void { | ||
| 1524 | if (self.llvm_object) |_| return; | 1526 | if (self.llvm_object) |_| return; |
| 1525 | const metadata = self.decls.getPtr(decl_index) orelse return; | 1527 | const metadata = self.decls.getPtr(decl_index) orelse return; |
| 1528 | const mod = self.base.options.module.?; | ||
| 1529 | const name = mod.intern_pool.stringToSlice(name_ip); | ||
| 1526 | const sym_index = metadata.getExportPtr(self, name) orelse return; | 1530 | const sym_index = metadata.getExportPtr(self, name) orelse return; |
| 1527 | 1531 | ||
| 1528 | const gpa = self.base.allocator; | 1532 | const gpa = self.base.allocator; |
| ... | @@ -2538,6 +2542,7 @@ const ImportTable = @import("Coff/ImportTable.zig"); | ... | @@ -2538,6 +2542,7 @@ const ImportTable = @import("Coff/ImportTable.zig"); |
| 2538 | const Liveness = @import("../Liveness.zig"); | 2542 | const Liveness = @import("../Liveness.zig"); |
| 2539 | const LlvmObject = @import("../codegen/llvm.zig").Object; | 2543 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 2540 | const Module = @import("../Module.zig"); | 2544 | const Module = @import("../Module.zig"); |
| 2545 | const InternPool = @import("../InternPool.zig"); | ||
| 2541 | const Object = @import("Coff/Object.zig"); | 2546 | const Object = @import("Coff/Object.zig"); |
| 2542 | const Relocation = @import("Coff/Relocation.zig"); | 2547 | const Relocation = @import("Coff/Relocation.zig"); |
| 2543 | const TableSection = @import("table_section.zig").TableSection; | 2548 | const TableSection = @import("table_section.zig").TableSection; |
src/link/Dwarf.zig+119-136| ... | @@ -18,6 +18,7 @@ const LinkBlock = File.LinkBlock; | ... | @@ -18,6 +18,7 @@ const LinkBlock = File.LinkBlock; |
| 18 | const LinkFn = File.LinkFn; | 18 | const LinkFn = File.LinkFn; |
| 19 | const LinkerLoad = @import("../codegen.zig").LinkerLoad; | 19 | const LinkerLoad = @import("../codegen.zig").LinkerLoad; |
| 20 | const Module = @import("../Module.zig"); | 20 | const Module = @import("../Module.zig"); |
| 21 | const InternPool = @import("../InternPool.zig"); | ||
| 21 | const StringTable = @import("strtab.zig").StringTable; | 22 | const StringTable = @import("strtab.zig").StringTable; |
| 22 | const Type = @import("../type.zig").Type; | 23 | const Type = @import("../type.zig").Type; |
| 23 | const Value = @import("../value.zig").Value; | 24 | const Value = @import("../value.zig").Value; |
| ... | @@ -86,12 +87,7 @@ pub const DeclState = struct { | ... | @@ -86,12 +87,7 @@ pub const DeclState = struct { |
| 86 | dbg_info: std.ArrayList(u8), | 87 | dbg_info: std.ArrayList(u8), |
| 87 | abbrev_type_arena: std.heap.ArenaAllocator, | 88 | abbrev_type_arena: std.heap.ArenaAllocator, |
| 88 | abbrev_table: std.ArrayListUnmanaged(AbbrevEntry) = .{}, | 89 | abbrev_table: std.ArrayListUnmanaged(AbbrevEntry) = .{}, |
| 89 | abbrev_resolver: std.HashMapUnmanaged( | 90 | abbrev_resolver: std.AutoHashMapUnmanaged(InternPool.Index, u32) = .{}, |
| 90 | Type, | ||
| 91 | u32, | ||
| 92 | Type.HashContext64, | ||
| 93 | std.hash_map.default_max_load_percentage, | ||
| 94 | ) = .{}, | ||
| 95 | abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, | 91 | abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{}, |
| 96 | exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{}, | 92 | exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{}, |
| 97 | 93 | ||
| ... | @@ -141,9 +137,7 @@ pub const DeclState = struct { | ... | @@ -141,9 +137,7 @@ pub const DeclState = struct { |
| 141 | /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section | 137 | /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section |
| 142 | /// which we use as our target of the relocation. | 138 | /// which we use as our target of the relocation. |
| 143 | fn addTypeRelocGlobal(self: *DeclState, atom_index: Atom.Index, ty: Type, offset: u32) !void { | 139 | fn addTypeRelocGlobal(self: *DeclState, atom_index: Atom.Index, ty: Type, offset: u32) !void { |
| 144 | const resolv = self.abbrev_resolver.getContext(ty, .{ | 140 | const resolv = self.abbrev_resolver.get(ty.toIntern()) orelse blk: { |
| 145 | .mod = self.mod, | ||
| 146 | }) orelse blk: { | ||
| 147 | const sym_index = @intCast(u32, self.abbrev_table.items.len); | 141 | const sym_index = @intCast(u32, self.abbrev_table.items.len); |
| 148 | try self.abbrev_table.append(self.gpa, .{ | 142 | try self.abbrev_table.append(self.gpa, .{ |
| 149 | .atom_index = atom_index, | 143 | .atom_index = atom_index, |
| ... | @@ -151,12 +145,8 @@ pub const DeclState = struct { | ... | @@ -151,12 +145,8 @@ pub const DeclState = struct { |
| 151 | .offset = undefined, | 145 | .offset = undefined, |
| 152 | }); | 146 | }); |
| 153 | log.debug("%{d}: {}", .{ sym_index, ty.fmt(self.mod) }); | 147 | log.debug("%{d}: {}", .{ sym_index, ty.fmt(self.mod) }); |
| 154 | try self.abbrev_resolver.putNoClobberContext(self.gpa, ty, sym_index, .{ | 148 | try self.abbrev_resolver.putNoClobber(self.gpa, ty.toIntern(), sym_index); |
| 155 | .mod = self.mod, | 149 | break :blk sym_index; |
| 156 | }); | ||
| 157 | break :blk self.abbrev_resolver.getContext(ty, .{ | ||
| 158 | .mod = self.mod, | ||
| 159 | }).?; | ||
| 160 | }; | 150 | }; |
| 161 | log.debug("{x}: %{d} + 0", .{ offset, resolv }); | 151 | log.debug("{x}: %{d} + 0", .{ offset, resolv }); |
| 162 | try self.abbrev_relocs.append(self.gpa, .{ | 152 | try self.abbrev_relocs.append(self.gpa, .{ |
| ... | @@ -169,16 +159,16 @@ pub const DeclState = struct { | ... | @@ -169,16 +159,16 @@ pub const DeclState = struct { |
| 169 | 159 | ||
| 170 | fn addDbgInfoType( | 160 | fn addDbgInfoType( |
| 171 | self: *DeclState, | 161 | self: *DeclState, |
| 172 | module: *Module, | 162 | mod: *Module, |
| 173 | atom_index: Atom.Index, | 163 | atom_index: Atom.Index, |
| 174 | ty: Type, | 164 | ty: Type, |
| 175 | ) error{OutOfMemory}!void { | 165 | ) error{OutOfMemory}!void { |
| 176 | const arena = self.abbrev_type_arena.allocator(); | 166 | const arena = self.abbrev_type_arena.allocator(); |
| 177 | const dbg_info_buffer = &self.dbg_info; | 167 | const dbg_info_buffer = &self.dbg_info; |
| 178 | const target = module.getTarget(); | 168 | const target = mod.getTarget(); |
| 179 | const target_endian = target.cpu.arch.endian(); | 169 | const target_endian = target.cpu.arch.endian(); |
| 180 | 170 | ||
| 181 | switch (ty.zigTypeTag()) { | 171 | switch (ty.zigTypeTag(mod)) { |
| 182 | .NoReturn => unreachable, | 172 | .NoReturn => unreachable, |
| 183 | .Void => { | 173 | .Void => { |
| 184 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.pad1)); | 174 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.pad1)); |
| ... | @@ -189,12 +179,12 @@ pub const DeclState = struct { | ... | @@ -189,12 +179,12 @@ pub const DeclState = struct { |
| 189 | // DW.AT.encoding, DW.FORM.data1 | 179 | // DW.AT.encoding, DW.FORM.data1 |
| 190 | dbg_info_buffer.appendAssumeCapacity(DW.ATE.boolean); | 180 | dbg_info_buffer.appendAssumeCapacity(DW.ATE.boolean); |
| 191 | // DW.AT.byte_size, DW.FORM.udata | 181 | // DW.AT.byte_size, DW.FORM.udata |
| 192 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(target)); | 182 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod)); |
| 193 | // DW.AT.name, DW.FORM.string | 183 | // DW.AT.name, DW.FORM.string |
| 194 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(module)}); | 184 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); |
| 195 | }, | 185 | }, |
| 196 | .Int => { | 186 | .Int => { |
| 197 | const info = ty.intInfo(target); | 187 | const info = ty.intInfo(mod); |
| 198 | try dbg_info_buffer.ensureUnusedCapacity(12); | 188 | try dbg_info_buffer.ensureUnusedCapacity(12); |
| 199 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.base_type)); | 189 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.base_type)); |
| 200 | // DW.AT.encoding, DW.FORM.data1 | 190 | // DW.AT.encoding, DW.FORM.data1 |
| ... | @@ -203,31 +193,30 @@ pub const DeclState = struct { | ... | @@ -203,31 +193,30 @@ pub const DeclState = struct { |
| 203 | .unsigned => DW.ATE.unsigned, | 193 | .unsigned => DW.ATE.unsigned, |
| 204 | }); | 194 | }); |
| 205 | // DW.AT.byte_size, DW.FORM.udata | 195 | // DW.AT.byte_size, DW.FORM.udata |
| 206 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(target)); | 196 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod)); |
| 207 | // DW.AT.name, DW.FORM.string | 197 | // DW.AT.name, DW.FORM.string |
| 208 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(module)}); | 198 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); |
| 209 | }, | 199 | }, |
| 210 | .Optional => { | 200 | .Optional => { |
| 211 | if (ty.isPtrLikeOptional()) { | 201 | if (ty.isPtrLikeOptional(mod)) { |
| 212 | try dbg_info_buffer.ensureUnusedCapacity(12); | 202 | try dbg_info_buffer.ensureUnusedCapacity(12); |
| 213 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.base_type)); | 203 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.base_type)); |
| 214 | // DW.AT.encoding, DW.FORM.data1 | 204 | // DW.AT.encoding, DW.FORM.data1 |
| 215 | dbg_info_buffer.appendAssumeCapacity(DW.ATE.address); | 205 | dbg_info_buffer.appendAssumeCapacity(DW.ATE.address); |
| 216 | // DW.AT.byte_size, DW.FORM.udata | 206 | // DW.AT.byte_size, DW.FORM.udata |
| 217 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(target)); | 207 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod)); |
| 218 | // DW.AT.name, DW.FORM.string | 208 | // DW.AT.name, DW.FORM.string |
| 219 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(module)}); | 209 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); |
| 220 | } else { | 210 | } else { |
| 221 | // Non-pointer optionals are structs: struct { .maybe = *, .val = * } | 211 | // Non-pointer optionals are structs: struct { .maybe = *, .val = * } |
| 222 | var buf = try arena.create(Type.Payload.ElemType); | 212 | const payload_ty = ty.optionalChild(mod); |
| 223 | const payload_ty = ty.optionalChild(buf); | ||
| 224 | // DW.AT.structure_type | 213 | // DW.AT.structure_type |
| 225 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type)); | 214 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type)); |
| 226 | // DW.AT.byte_size, DW.FORM.udata | 215 | // DW.AT.byte_size, DW.FORM.udata |
| 227 | const abi_size = ty.abiSize(target); | 216 | const abi_size = ty.abiSize(mod); |
| 228 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); | 217 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); |
| 229 | // DW.AT.name, DW.FORM.string | 218 | // DW.AT.name, DW.FORM.string |
| 230 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(module)}); | 219 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); |
| 231 | // DW.AT.member | 220 | // DW.AT.member |
| 232 | try dbg_info_buffer.ensureUnusedCapacity(7); | 221 | try dbg_info_buffer.ensureUnusedCapacity(7); |
| 233 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); | 222 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); |
| ... | @@ -251,14 +240,14 @@ pub const DeclState = struct { | ... | @@ -251,14 +240,14 @@ pub const DeclState = struct { |
| 251 | try dbg_info_buffer.resize(index + 4); | 240 | try dbg_info_buffer.resize(index + 4); |
| 252 | try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index)); | 241 | try self.addTypeRelocGlobal(atom_index, payload_ty, @intCast(u32, index)); |
| 253 | // DW.AT.data_member_location, DW.FORM.udata | 242 | // DW.AT.data_member_location, DW.FORM.udata |
| 254 | const offset = abi_size - payload_ty.abiSize(target); | 243 | const offset = abi_size - payload_ty.abiSize(mod); |
| 255 | try leb128.writeULEB128(dbg_info_buffer.writer(), offset); | 244 | try leb128.writeULEB128(dbg_info_buffer.writer(), offset); |
| 256 | // DW.AT.structure_type delimit children | 245 | // DW.AT.structure_type delimit children |
| 257 | try dbg_info_buffer.append(0); | 246 | try dbg_info_buffer.append(0); |
| 258 | } | 247 | } |
| 259 | }, | 248 | }, |
| 260 | .Pointer => { | 249 | .Pointer => { |
| 261 | if (ty.isSlice()) { | 250 | if (ty.isSlice(mod)) { |
| 262 | // Slices are structs: struct { .ptr = *, .len = N } | 251 | // Slices are structs: struct { .ptr = *, .len = N } |
| 263 | const ptr_bits = target.ptrBitWidth(); | 252 | const ptr_bits = target.ptrBitWidth(); |
| 264 | const ptr_bytes = @intCast(u8, @divExact(ptr_bits, 8)); | 253 | const ptr_bytes = @intCast(u8, @divExact(ptr_bits, 8)); |
| ... | @@ -266,9 +255,9 @@ pub const DeclState = struct { | ... | @@ -266,9 +255,9 @@ pub const DeclState = struct { |
| 266 | try dbg_info_buffer.ensureUnusedCapacity(2); | 255 | try dbg_info_buffer.ensureUnusedCapacity(2); |
| 267 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_type)); | 256 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_type)); |
| 268 | // DW.AT.byte_size, DW.FORM.udata | 257 | // DW.AT.byte_size, DW.FORM.udata |
| 269 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(target)); | 258 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod)); |
| 270 | // DW.AT.name, DW.FORM.string | 259 | // DW.AT.name, DW.FORM.string |
| 271 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(module)}); | 260 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); |
| 272 | // DW.AT.member | 261 | // DW.AT.member |
| 273 | try dbg_info_buffer.ensureUnusedCapacity(5); | 262 | try dbg_info_buffer.ensureUnusedCapacity(5); |
| 274 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); | 263 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); |
| ... | @@ -278,8 +267,7 @@ pub const DeclState = struct { | ... | @@ -278,8 +267,7 @@ pub const DeclState = struct { |
| 278 | // DW.AT.type, DW.FORM.ref4 | 267 | // DW.AT.type, DW.FORM.ref4 |
| 279 | var index = dbg_info_buffer.items.len; | 268 | var index = dbg_info_buffer.items.len; |
| 280 | try dbg_info_buffer.resize(index + 4); | 269 | try dbg_info_buffer.resize(index + 4); |
| 281 | var buf = try arena.create(Type.SlicePtrFieldTypeBuffer); | 270 | const ptr_ty = ty.slicePtrFieldType(mod); |
| 282 | const ptr_ty = ty.slicePtrFieldType(buf); | ||
| 283 | try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(u32, index)); | 271 | try self.addTypeRelocGlobal(atom_index, ptr_ty, @intCast(u32, index)); |
| 284 | // DW.AT.data_member_location, DW.FORM.udata | 272 | // DW.AT.data_member_location, DW.FORM.udata |
| 285 | try dbg_info_buffer.ensureUnusedCapacity(6); | 273 | try dbg_info_buffer.ensureUnusedCapacity(6); |
| ... | @@ -304,18 +292,18 @@ pub const DeclState = struct { | ... | @@ -304,18 +292,18 @@ pub const DeclState = struct { |
| 304 | // DW.AT.type, DW.FORM.ref4 | 292 | // DW.AT.type, DW.FORM.ref4 |
| 305 | const index = dbg_info_buffer.items.len; | 293 | const index = dbg_info_buffer.items.len; |
| 306 | try dbg_info_buffer.resize(index + 4); | 294 | try dbg_info_buffer.resize(index + 4); |
| 307 | try self.addTypeRelocGlobal(atom_index, ty.childType(), @intCast(u32, index)); | 295 | try self.addTypeRelocGlobal(atom_index, ty.childType(mod), @intCast(u32, index)); |
| 308 | } | 296 | } |
| 309 | }, | 297 | }, |
| 310 | .Array => { | 298 | .Array => { |
| 311 | // DW.AT.array_type | 299 | // DW.AT.array_type |
| 312 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_type)); | 300 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_type)); |
| 313 | // DW.AT.name, DW.FORM.string | 301 | // DW.AT.name, DW.FORM.string |
| 314 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(module)}); | 302 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); |
| 315 | // DW.AT.type, DW.FORM.ref4 | 303 | // DW.AT.type, DW.FORM.ref4 |
| 316 | var index = dbg_info_buffer.items.len; | 304 | var index = dbg_info_buffer.items.len; |
| 317 | try dbg_info_buffer.resize(index + 4); | 305 | try dbg_info_buffer.resize(index + 4); |
| 318 | try self.addTypeRelocGlobal(atom_index, ty.childType(), @intCast(u32, index)); | 306 | try self.addTypeRelocGlobal(atom_index, ty.childType(mod), @intCast(u32, index)); |
| 319 | // DW.AT.subrange_type | 307 | // DW.AT.subrange_type |
| 320 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim)); | 308 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim)); |
| 321 | // DW.AT.type, DW.FORM.ref4 | 309 | // DW.AT.type, DW.FORM.ref4 |
| ... | @@ -323,7 +311,7 @@ pub const DeclState = struct { | ... | @@ -323,7 +311,7 @@ pub const DeclState = struct { |
| 323 | try dbg_info_buffer.resize(index + 4); | 311 | try dbg_info_buffer.resize(index + 4); |
| 324 | try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(u32, index)); | 312 | try self.addTypeRelocGlobal(atom_index, Type.usize, @intCast(u32, index)); |
| 325 | // DW.AT.count, DW.FORM.udata | 313 | // DW.AT.count, DW.FORM.udata |
| 326 | const len = ty.arrayLenIncludingSentinel(); | 314 | const len = ty.arrayLenIncludingSentinel(mod); |
| 327 | try leb128.writeULEB128(dbg_info_buffer.writer(), len); | 315 | try leb128.writeULEB128(dbg_info_buffer.writer(), len); |
| 328 | // DW.AT.array_type delimit children | 316 | // DW.AT.array_type delimit children |
| 329 | try dbg_info_buffer.append(0); | 317 | try dbg_info_buffer.append(0); |
| ... | @@ -332,15 +320,14 @@ pub const DeclState = struct { | ... | @@ -332,15 +320,14 @@ pub const DeclState = struct { |
| 332 | // DW.AT.structure_type | 320 | // DW.AT.structure_type |
| 333 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type)); | 321 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type)); |
| 334 | // DW.AT.byte_size, DW.FORM.udata | 322 | // DW.AT.byte_size, DW.FORM.udata |
| 335 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(target)); | 323 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod)); |
| 336 | 324 | ||
| 337 | switch (ty.tag()) { | 325 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 338 | .tuple, .anon_struct => { | 326 | .anon_struct_type => |fields| { |
| 339 | // DW.AT.name, DW.FORM.string | 327 | // DW.AT.name, DW.FORM.string |
| 340 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(module)}); | 328 | try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(mod)}); |
| 341 | 329 | ||
| 342 | const fields = ty.tupleFields(); | 330 | for (fields.types, 0..) |field_ty, field_index| { |
| 343 | for (fields.types, 0..) |field, field_index| { | ||
| 344 | // DW.AT.member | 331 | // DW.AT.member |
| 345 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member)); | 332 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member)); |
| 346 | // DW.AT.name, DW.FORM.string | 333 | // DW.AT.name, DW.FORM.string |
| ... | @@ -348,29 +335,32 @@ pub const DeclState = struct { | ... | @@ -348,29 +335,32 @@ pub const DeclState = struct { |
| 348 | // DW.AT.type, DW.FORM.ref4 | 335 | // DW.AT.type, DW.FORM.ref4 |
| 349 | var index = dbg_info_buffer.items.len; | 336 | var index = dbg_info_buffer.items.len; |
| 350 | try dbg_info_buffer.resize(index + 4); | 337 | try dbg_info_buffer.resize(index + 4); |
| 351 | try self.addTypeRelocGlobal(atom_index, field, @intCast(u32, index)); | 338 | try self.addTypeRelocGlobal(atom_index, field_ty.toType(), @intCast(u32, index)); |
| 352 | // DW.AT.data_member_location, DW.FORM.udata | 339 | // DW.AT.data_member_location, DW.FORM.udata |
| 353 | const field_off = ty.structFieldOffset(field_index, target); | 340 | const field_off = ty.structFieldOffset(field_index, mod); |
| 354 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | 341 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| 355 | } | 342 | } |
| 356 | }, | 343 | }, |
| 357 | else => { | 344 | .struct_type => |struct_type| s: { |
| 345 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :s; | ||
| 358 | // DW.AT.name, DW.FORM.string | 346 | // DW.AT.name, DW.FORM.string |
| 359 | const struct_name = try ty.nameAllocArena(arena, module); | 347 | const struct_name = try ty.nameAllocArena(arena, mod); |
| 360 | try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); | 348 | try dbg_info_buffer.ensureUnusedCapacity(struct_name.len + 1); |
| 361 | dbg_info_buffer.appendSliceAssumeCapacity(struct_name); | 349 | dbg_info_buffer.appendSliceAssumeCapacity(struct_name); |
| 362 | dbg_info_buffer.appendAssumeCapacity(0); | 350 | dbg_info_buffer.appendAssumeCapacity(0); |
| 363 | 351 | ||
| 364 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 365 | if (struct_obj.layout == .Packed) { | 352 | if (struct_obj.layout == .Packed) { |
| 366 | log.debug("TODO implement .debug_info for packed structs", .{}); | 353 | log.debug("TODO implement .debug_info for packed structs", .{}); |
| 367 | break :blk; | 354 | break :blk; |
| 368 | } | 355 | } |
| 369 | 356 | ||
| 370 | const fields = ty.structFields(); | 357 | for ( |
| 371 | for (fields.keys(), 0..) |field_name, field_index| { | 358 | struct_obj.fields.keys(), |
| 372 | const field = fields.get(field_name).?; | 359 | struct_obj.fields.values(), |
| 373 | if (!field.ty.hasRuntimeBits()) continue; | 360 | 0.., |
| 361 | ) |field_name_ip, field, field_index| { | ||
| 362 | if (!field.ty.hasRuntimeBits(mod)) continue; | ||
| 363 | const field_name = mod.intern_pool.stringToSlice(field_name_ip); | ||
| 374 | // DW.AT.member | 364 | // DW.AT.member |
| 375 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); | 365 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); |
| 376 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); | 366 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); |
| ... | @@ -382,10 +372,11 @@ pub const DeclState = struct { | ... | @@ -382,10 +372,11 @@ pub const DeclState = struct { |
| 382 | try dbg_info_buffer.resize(index + 4); | 372 | try dbg_info_buffer.resize(index + 4); |
| 383 | try self.addTypeRelocGlobal(atom_index, field.ty, @intCast(u32, index)); | 373 | try self.addTypeRelocGlobal(atom_index, field.ty, @intCast(u32, index)); |
| 384 | // DW.AT.data_member_location, DW.FORM.udata | 374 | // DW.AT.data_member_location, DW.FORM.udata |
| 385 | const field_off = ty.structFieldOffset(field_index, target); | 375 | const field_off = ty.structFieldOffset(field_index, mod); |
| 386 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); | 376 | try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); |
| 387 | } | 377 | } |
| 388 | }, | 378 | }, |
| 379 | else => unreachable, | ||
| 389 | } | 380 | } |
| 390 | 381 | ||
| 391 | // DW.AT.structure_type delimit children | 382 | // DW.AT.structure_type delimit children |
| ... | @@ -395,21 +386,16 @@ pub const DeclState = struct { | ... | @@ -395,21 +386,16 @@ pub const DeclState = struct { |
| 395 | // DW.AT.enumeration_type | 386 | // DW.AT.enumeration_type |
| 396 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type)); | 387 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type)); |
| 397 | // DW.AT.byte_size, DW.FORM.udata | 388 | // DW.AT.byte_size, DW.FORM.udata |
| 398 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(target)); | 389 | try leb128.writeULEB128(dbg_info_buffer.writer(), ty.abiSize(mod)); |
| 399 | // DW.AT.name, DW.FORM.string | 390 | // DW.AT.name, DW.FORM.string |
| 400 | const enum_name = try ty.nameAllocArena(arena, module); | 391 | const enum_name = try ty.nameAllocArena(arena, mod); |
| 401 | try dbg_info_buffer.ensureUnusedCapacity(enum_name.len + 1); | 392 | try dbg_info_buffer.ensureUnusedCapacity(enum_name.len + 1); |
| 402 | dbg_info_buffer.appendSliceAssumeCapacity(enum_name); | 393 | dbg_info_buffer.appendSliceAssumeCapacity(enum_name); |
| 403 | dbg_info_buffer.appendAssumeCapacity(0); | 394 | dbg_info_buffer.appendAssumeCapacity(0); |
| 404 | 395 | ||
| 405 | const fields = ty.enumFields(); | 396 | const enum_type = mod.intern_pool.indexToKey(ty.ip_index).enum_type; |
| 406 | const values: ?Module.EnumFull.ValueMap = switch (ty.tag()) { | 397 | for (enum_type.names, 0..) |field_name_index, field_i| { |
| 407 | .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.values, | 398 | const field_name = mod.intern_pool.stringToSlice(field_name_index); |
| 408 | .enum_simple => null, | ||
| 409 | .enum_numbered => ty.castTag(.enum_numbered).?.data.values, | ||
| 410 | else => unreachable, | ||
| 411 | }; | ||
| 412 | for (fields.keys(), 0..) |field_name, field_i| { | ||
| 413 | // DW.AT.enumerator | 399 | // DW.AT.enumerator |
| 414 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64)); | 400 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2 + @sizeOf(u64)); |
| 415 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant)); | 401 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant)); |
| ... | @@ -417,15 +403,14 @@ pub const DeclState = struct { | ... | @@ -417,15 +403,14 @@ pub const DeclState = struct { |
| 417 | dbg_info_buffer.appendSliceAssumeCapacity(field_name); | 403 | dbg_info_buffer.appendSliceAssumeCapacity(field_name); |
| 418 | dbg_info_buffer.appendAssumeCapacity(0); | 404 | dbg_info_buffer.appendAssumeCapacity(0); |
| 419 | // DW.AT.const_value, DW.FORM.data8 | 405 | // DW.AT.const_value, DW.FORM.data8 |
| 420 | const value: u64 = if (values) |vals| value: { | 406 | const value: u64 = value: { |
| 421 | if (vals.count() == 0) break :value @intCast(u64, field_i); // auto-numbered | 407 | if (enum_type.values.len == 0) break :value field_i; // auto-numbered |
| 422 | const value = vals.keys()[field_i]; | 408 | const value = enum_type.values[field_i]; |
| 423 | // TODO do not assume a 64bit enum value - could be bigger. | 409 | // TODO do not assume a 64bit enum value - could be bigger. |
| 424 | // See https://github.com/ziglang/zig/issues/645 | 410 | // See https://github.com/ziglang/zig/issues/645 |
| 425 | var int_buffer: Value.Payload.U64 = undefined; | 411 | const field_int_val = try value.toValue().enumToInt(ty, mod); |
| 426 | const field_int_val = value.enumToInt(ty, &int_buffer); | 412 | break :value @bitCast(u64, field_int_val.toSignedInt(mod)); |
| 427 | break :value @bitCast(u64, field_int_val.toSignedInt(target)); | 413 | }; |
| 428 | } else @intCast(u64, field_i); | ||
| 429 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); | 414 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), value, target_endian); |
| 430 | } | 415 | } |
| 431 | 416 | ||
| ... | @@ -433,12 +418,12 @@ pub const DeclState = struct { | ... | @@ -433,12 +418,12 @@ pub const DeclState = struct { |
| 433 | try dbg_info_buffer.append(0); | 418 | try dbg_info_buffer.append(0); |
| 434 | }, | 419 | }, |
| 435 | .Union => { | 420 | .Union => { |
| 436 | const layout = ty.unionGetLayout(target); | 421 | const layout = ty.unionGetLayout(mod); |
| 437 | const union_obj = ty.cast(Type.Payload.Union).?.data; | 422 | const union_obj = mod.typeToUnion(ty).?; |
| 438 | const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0; | 423 | const payload_offset = if (layout.tag_align >= layout.payload_align) layout.tag_size else 0; |
| 439 | const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size; | 424 | const tag_offset = if (layout.tag_align >= layout.payload_align) 0 else layout.payload_size; |
| 440 | const is_tagged = layout.tag_size > 0; | 425 | const is_tagged = layout.tag_size > 0; |
| 441 | const union_name = try ty.nameAllocArena(arena, module); | 426 | const union_name = try ty.nameAllocArena(arena, mod); |
| 442 | 427 | ||
| 443 | // TODO this is temporary to match current state of unions in Zig - we don't yet have | 428 | // TODO this is temporary to match current state of unions in Zig - we don't yet have |
| 444 | // safety checks implemented meaning the implicit tag is not yet stored and generated | 429 | // safety checks implemented meaning the implicit tag is not yet stored and generated |
| ... | @@ -478,14 +463,15 @@ pub const DeclState = struct { | ... | @@ -478,14 +463,15 @@ pub const DeclState = struct { |
| 478 | try dbg_info_buffer.writer().print("{s}\x00", .{union_name}); | 463 | try dbg_info_buffer.writer().print("{s}\x00", .{union_name}); |
| 479 | } | 464 | } |
| 480 | 465 | ||
| 481 | const fields = ty.unionFields(); | 466 | const fields = ty.unionFields(mod); |
| 482 | for (fields.keys()) |field_name| { | 467 | for (fields.keys()) |field_name| { |
| 483 | const field = fields.get(field_name).?; | 468 | const field = fields.get(field_name).?; |
| 484 | if (!field.ty.hasRuntimeBits()) continue; | 469 | if (!field.ty.hasRuntimeBits(mod)) continue; |
| 485 | // DW.AT.member | 470 | // DW.AT.member |
| 486 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member)); | 471 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member)); |
| 487 | // DW.AT.name, DW.FORM.string | 472 | // DW.AT.name, DW.FORM.string |
| 488 | try dbg_info_buffer.writer().print("{s}\x00", .{field_name}); | 473 | try dbg_info_buffer.appendSlice(mod.intern_pool.stringToSlice(field_name)); |
| 474 | try dbg_info_buffer.append(0); | ||
| 489 | // DW.AT.type, DW.FORM.ref4 | 475 | // DW.AT.type, DW.FORM.ref4 |
| 490 | const index = dbg_info_buffer.items.len; | 476 | const index = dbg_info_buffer.items.len; |
| 491 | try dbg_info_buffer.resize(index + 4); | 477 | try dbg_info_buffer.resize(index + 4); |
| ... | @@ -517,30 +503,30 @@ pub const DeclState = struct { | ... | @@ -517,30 +503,30 @@ pub const DeclState = struct { |
| 517 | .ErrorSet => { | 503 | .ErrorSet => { |
| 518 | try addDbgInfoErrorSet( | 504 | try addDbgInfoErrorSet( |
| 519 | self.abbrev_type_arena.allocator(), | 505 | self.abbrev_type_arena.allocator(), |
| 520 | module, | 506 | mod, |
| 521 | ty, | 507 | ty, |
| 522 | target, | 508 | target, |
| 523 | &self.dbg_info, | 509 | &self.dbg_info, |
| 524 | ); | 510 | ); |
| 525 | }, | 511 | }, |
| 526 | .ErrorUnion => { | 512 | .ErrorUnion => { |
| 527 | const error_ty = ty.errorUnionSet(); | 513 | const error_ty = ty.errorUnionSet(mod); |
| 528 | const payload_ty = ty.errorUnionPayload(); | 514 | const payload_ty = ty.errorUnionPayload(mod); |
| 529 | const payload_align = if (payload_ty.isNoReturn()) 0 else payload_ty.abiAlignment(target); | 515 | const payload_align = if (payload_ty.isNoReturn(mod)) 0 else payload_ty.abiAlignment(mod); |
| 530 | const error_align = Type.anyerror.abiAlignment(target); | 516 | const error_align = Type.anyerror.abiAlignment(mod); |
| 531 | const abi_size = ty.abiSize(target); | 517 | const abi_size = ty.abiSize(mod); |
| 532 | const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(target) else 0; | 518 | const payload_off = if (error_align >= payload_align) Type.anyerror.abiSize(mod) else 0; |
| 533 | const error_off = if (error_align >= payload_align) 0 else payload_ty.abiSize(target); | 519 | const error_off = if (error_align >= payload_align) 0 else payload_ty.abiSize(mod); |
| 534 | 520 | ||
| 535 | // DW.AT.structure_type | 521 | // DW.AT.structure_type |
| 536 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type)); | 522 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type)); |
| 537 | // DW.AT.byte_size, DW.FORM.udata | 523 | // DW.AT.byte_size, DW.FORM.udata |
| 538 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); | 524 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); |
| 539 | // DW.AT.name, DW.FORM.string | 525 | // DW.AT.name, DW.FORM.string |
| 540 | const name = try ty.nameAllocArena(arena, module); | 526 | const name = try ty.nameAllocArena(arena, mod); |
| 541 | try dbg_info_buffer.writer().print("{s}\x00", .{name}); | 527 | try dbg_info_buffer.writer().print("{s}\x00", .{name}); |
| 542 | 528 | ||
| 543 | if (!payload_ty.isNoReturn()) { | 529 | if (!payload_ty.isNoReturn(mod)) { |
| 544 | // DW.AT.member | 530 | // DW.AT.member |
| 545 | try dbg_info_buffer.ensureUnusedCapacity(7); | 531 | try dbg_info_buffer.ensureUnusedCapacity(7); |
| 546 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); | 532 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); |
| ... | @@ -685,9 +671,10 @@ pub const DeclState = struct { | ... | @@ -685,9 +671,10 @@ pub const DeclState = struct { |
| 685 | const atom_index = self.di_atom_decls.get(owner_decl).?; | 671 | const atom_index = self.di_atom_decls.get(owner_decl).?; |
| 686 | const name_with_null = name.ptr[0 .. name.len + 1]; | 672 | const name_with_null = name.ptr[0 .. name.len + 1]; |
| 687 | try dbg_info.append(@enumToInt(AbbrevKind.variable)); | 673 | try dbg_info.append(@enumToInt(AbbrevKind.variable)); |
| 688 | const target = self.mod.getTarget(); | 674 | const mod = self.mod; |
| 675 | const target = mod.getTarget(); | ||
| 689 | const endian = target.cpu.arch.endian(); | 676 | const endian = target.cpu.arch.endian(); |
| 690 | const child_ty = if (is_ptr) ty.childType() else ty; | 677 | const child_ty = if (is_ptr) ty.childType(mod) else ty; |
| 691 | 678 | ||
| 692 | switch (loc) { | 679 | switch (loc) { |
| 693 | .register => |reg| { | 680 | .register => |reg| { |
| ... | @@ -790,9 +777,9 @@ pub const DeclState = struct { | ... | @@ -790,9 +777,9 @@ pub const DeclState = struct { |
| 790 | const fixup = dbg_info.items.len; | 777 | const fixup = dbg_info.items.len; |
| 791 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc | 778 | dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc |
| 792 | 1, | 779 | 1, |
| 793 | if (child_ty.isSignedInt()) DW.OP.consts else DW.OP.constu, | 780 | if (child_ty.isSignedInt(mod)) DW.OP.consts else DW.OP.constu, |
| 794 | }); | 781 | }); |
| 795 | if (child_ty.isSignedInt()) { | 782 | if (child_ty.isSignedInt(mod)) { |
| 796 | try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)); | 783 | try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x)); |
| 797 | } else { | 784 | } else { |
| 798 | try leb128.writeULEB128(dbg_info.writer(), x); | 785 | try leb128.writeULEB128(dbg_info.writer(), x); |
| ... | @@ -805,7 +792,7 @@ pub const DeclState = struct { | ... | @@ -805,7 +792,7 @@ pub const DeclState = struct { |
| 805 | // DW.AT.location, DW.FORM.exprloc | 792 | // DW.AT.location, DW.FORM.exprloc |
| 806 | // uleb128(exprloc_len) | 793 | // uleb128(exprloc_len) |
| 807 | // DW.OP.implicit_value uleb128(len_of_bytes) bytes | 794 | // DW.OP.implicit_value uleb128(len_of_bytes) bytes |
| 808 | const abi_size = @intCast(u32, child_ty.abiSize(target)); | 795 | const abi_size = @intCast(u32, child_ty.abiSize(mod)); |
| 809 | var implicit_value_len = std.ArrayList(u8).init(self.gpa); | 796 | var implicit_value_len = std.ArrayList(u8).init(self.gpa); |
| 810 | defer implicit_value_len.deinit(); | 797 | defer implicit_value_len.deinit(); |
| 811 | try leb128.writeULEB128(implicit_value_len.writer(), abi_size); | 798 | try leb128.writeULEB128(implicit_value_len.writer(), abi_size); |
| ... | @@ -964,8 +951,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) | ... | @@ -964,8 +951,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) |
| 964 | defer tracy.end(); | 951 | defer tracy.end(); |
| 965 | 952 | ||
| 966 | const decl = mod.declPtr(decl_index); | 953 | const decl = mod.declPtr(decl_index); |
| 967 | const decl_name = try decl.getFullyQualifiedName(mod); | 954 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 968 | defer self.allocator.free(decl_name); | ||
| 969 | 955 | ||
| 970 | log.debug("initDeclState {s}{*}", .{ decl_name, decl }); | 956 | log.debug("initDeclState {s}{*}", .{ decl_name, decl }); |
| 971 | 957 | ||
| ... | @@ -979,14 +965,14 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) | ... | @@ -979,14 +965,14 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) |
| 979 | 965 | ||
| 980 | assert(decl.has_tv); | 966 | assert(decl.has_tv); |
| 981 | 967 | ||
| 982 | switch (decl.ty.zigTypeTag()) { | 968 | switch (decl.ty.zigTypeTag(mod)) { |
| 983 | .Fn => { | 969 | .Fn => { |
| 984 | _ = try self.getOrCreateAtomForDecl(.src_fn, decl_index); | 970 | _ = try self.getOrCreateAtomForDecl(.src_fn, decl_index); |
| 985 | 971 | ||
| 986 | // For functions we need to add a prologue to the debug line program. | 972 | // For functions we need to add a prologue to the debug line program. |
| 987 | try dbg_line_buffer.ensureTotalCapacity(26); | 973 | try dbg_line_buffer.ensureTotalCapacity(26); |
| 988 | 974 | ||
| 989 | const func = decl.val.castTag(.function).?.data; | 975 | const func = decl.val.getFunction(mod).?; |
| 990 | log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ | 976 | log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ |
| 991 | decl.src_line, | 977 | decl.src_line, |
| 992 | func.lbrace_line, | 978 | func.lbrace_line, |
| ... | @@ -1026,8 +1012,8 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) | ... | @@ -1026,8 +1012,8 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) |
| 1026 | const decl_name_with_null = decl_name[0 .. decl_name.len + 1]; | 1012 | const decl_name_with_null = decl_name[0 .. decl_name.len + 1]; |
| 1027 | try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len); | 1013 | try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len); |
| 1028 | 1014 | ||
| 1029 | const fn_ret_type = decl.ty.fnReturnType(); | 1015 | const fn_ret_type = decl.ty.fnReturnType(mod); |
| 1030 | const fn_ret_has_bits = fn_ret_type.hasRuntimeBits(); | 1016 | const fn_ret_has_bits = fn_ret_type.hasRuntimeBits(mod); |
| 1031 | if (fn_ret_has_bits) { | 1017 | if (fn_ret_has_bits) { |
| 1032 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.subprogram)); | 1018 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.subprogram)); |
| 1033 | } else { | 1019 | } else { |
| ... | @@ -1059,7 +1045,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) | ... | @@ -1059,7 +1045,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) |
| 1059 | 1045 | ||
| 1060 | pub fn commitDeclState( | 1046 | pub fn commitDeclState( |
| 1061 | self: *Dwarf, | 1047 | self: *Dwarf, |
| 1062 | module: *Module, | 1048 | mod: *Module, |
| 1063 | decl_index: Module.Decl.Index, | 1049 | decl_index: Module.Decl.Index, |
| 1064 | sym_addr: u64, | 1050 | sym_addr: u64, |
| 1065 | sym_size: u64, | 1051 | sym_size: u64, |
| ... | @@ -1071,12 +1057,12 @@ pub fn commitDeclState( | ... | @@ -1071,12 +1057,12 @@ pub fn commitDeclState( |
| 1071 | const gpa = self.allocator; | 1057 | const gpa = self.allocator; |
| 1072 | var dbg_line_buffer = &decl_state.dbg_line; | 1058 | var dbg_line_buffer = &decl_state.dbg_line; |
| 1073 | var dbg_info_buffer = &decl_state.dbg_info; | 1059 | var dbg_info_buffer = &decl_state.dbg_info; |
| 1074 | const decl = module.declPtr(decl_index); | 1060 | const decl = mod.declPtr(decl_index); |
| 1075 | 1061 | ||
| 1076 | const target_endian = self.target.cpu.arch.endian(); | 1062 | const target_endian = self.target.cpu.arch.endian(); |
| 1077 | 1063 | ||
| 1078 | assert(decl.has_tv); | 1064 | assert(decl.has_tv); |
| 1079 | switch (decl.ty.zigTypeTag()) { | 1065 | switch (decl.ty.zigTypeTag(mod)) { |
| 1080 | .Fn => { | 1066 | .Fn => { |
| 1081 | // Since the Decl is a function, we need to update the .debug_line program. | 1067 | // Since the Decl is a function, we need to update the .debug_line program. |
| 1082 | // Perform the relocations based on vaddr. | 1068 | // Perform the relocations based on vaddr. |
| ... | @@ -1271,10 +1257,11 @@ pub fn commitDeclState( | ... | @@ -1271,10 +1257,11 @@ pub fn commitDeclState( |
| 1271 | const symbol = &decl_state.abbrev_table.items[sym_index]; | 1257 | const symbol = &decl_state.abbrev_table.items[sym_index]; |
| 1272 | const ty = symbol.type; | 1258 | const ty = symbol.type; |
| 1273 | const deferred: bool = blk: { | 1259 | const deferred: bool = blk: { |
| 1274 | if (ty.isAnyError()) break :blk true; | 1260 | if (ty.isAnyError(mod)) break :blk true; |
| 1275 | switch (ty.tag()) { | 1261 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 1276 | .error_set_inferred => { | 1262 | .inferred_error_set_type => |ies_index| { |
| 1277 | if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true; | 1263 | const ies = mod.inferredErrorSetPtr(ies_index); |
| 1264 | if (!ies.is_resolved) break :blk true; | ||
| 1278 | }, | 1265 | }, |
| 1279 | else => {}, | 1266 | else => {}, |
| 1280 | } | 1267 | } |
| ... | @@ -1283,11 +1270,10 @@ pub fn commitDeclState( | ... | @@ -1283,11 +1270,10 @@ pub fn commitDeclState( |
| 1283 | if (deferred) continue; | 1270 | if (deferred) continue; |
| 1284 | 1271 | ||
| 1285 | symbol.offset = @intCast(u32, dbg_info_buffer.items.len); | 1272 | symbol.offset = @intCast(u32, dbg_info_buffer.items.len); |
| 1286 | try decl_state.addDbgInfoType(module, di_atom_index, ty); | 1273 | try decl_state.addDbgInfoType(mod, di_atom_index, ty); |
| 1287 | } | 1274 | } |
| 1288 | } | 1275 | } |
| 1289 | 1276 | ||
| 1290 | log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name}); | ||
| 1291 | try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(u32, dbg_info_buffer.items.len)); | 1277 | try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(u32, dbg_info_buffer.items.len)); |
| 1292 | 1278 | ||
| 1293 | while (decl_state.abbrev_relocs.popOrNull()) |reloc| { | 1279 | while (decl_state.abbrev_relocs.popOrNull()) |reloc| { |
| ... | @@ -1295,10 +1281,11 @@ pub fn commitDeclState( | ... | @@ -1295,10 +1281,11 @@ pub fn commitDeclState( |
| 1295 | const symbol = decl_state.abbrev_table.items[target]; | 1281 | const symbol = decl_state.abbrev_table.items[target]; |
| 1296 | const ty = symbol.type; | 1282 | const ty = symbol.type; |
| 1297 | const deferred: bool = blk: { | 1283 | const deferred: bool = blk: { |
| 1298 | if (ty.isAnyError()) break :blk true; | 1284 | if (ty.isAnyError(mod)) break :blk true; |
| 1299 | switch (ty.tag()) { | 1285 | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 1300 | .error_set_inferred => { | 1286 | .inferred_error_set_type => |ies_index| { |
| 1301 | if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true; | 1287 | const ies = mod.inferredErrorSetPtr(ies_index); |
| 1288 | if (!ies.is_resolved) break :blk true; | ||
| 1302 | }, | 1289 | }, |
| 1303 | else => {}, | 1290 | else => {}, |
| 1304 | } | 1291 | } |
| ... | @@ -1319,7 +1306,7 @@ pub fn commitDeclState( | ... | @@ -1319,7 +1306,7 @@ pub fn commitDeclState( |
| 1319 | reloc.offset, | 1306 | reloc.offset, |
| 1320 | value, | 1307 | value, |
| 1321 | target, | 1308 | target, |
| 1322 | ty.fmt(module), | 1309 | ty.fmt(mod), |
| 1323 | }); | 1310 | }); |
| 1324 | mem.writeInt( | 1311 | mem.writeInt( |
| 1325 | u32, | 1312 | u32, |
| ... | @@ -1358,7 +1345,6 @@ pub fn commitDeclState( | ... | @@ -1358,7 +1345,6 @@ pub fn commitDeclState( |
| 1358 | } | 1345 | } |
| 1359 | } | 1346 | } |
| 1360 | 1347 | ||
| 1361 | log.debug("writeDeclDebugInfo for '{s}", .{decl.name}); | ||
| 1362 | try self.writeDeclDebugInfo(di_atom_index, dbg_info_buffer.items); | 1348 | try self.writeDeclDebugInfo(di_atom_index, dbg_info_buffer.items); |
| 1363 | } | 1349 | } |
| 1364 | 1350 | ||
| ... | @@ -1527,7 +1513,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons | ... | @@ -1527,7 +1513,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons |
| 1527 | } | 1513 | } |
| 1528 | } | 1514 | } |
| 1529 | 1515 | ||
| 1530 | pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.Decl.Index) !void { | 1516 | pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) !void { |
| 1531 | const tracy = trace(@src()); | 1517 | const tracy = trace(@src()); |
| 1532 | defer tracy.end(); | 1518 | defer tracy.end(); |
| 1533 | 1519 | ||
| ... | @@ -1535,8 +1521,8 @@ pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.De | ... | @@ -1535,8 +1521,8 @@ pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.De |
| 1535 | const atom = self.getAtom(.src_fn, atom_index); | 1521 | const atom = self.getAtom(.src_fn, atom_index); |
| 1536 | if (atom.len == 0) return; | 1522 | if (atom.len == 0) return; |
| 1537 | 1523 | ||
| 1538 | const decl = module.declPtr(decl_index); | 1524 | const decl = mod.declPtr(decl_index); |
| 1539 | const func = decl.val.castTag(.function).?.data; | 1525 | const func = decl.val.getFunction(mod).?; |
| 1540 | log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ | 1526 | log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ |
| 1541 | decl.src_line, | 1527 | decl.src_line, |
| 1542 | func.lbrace_line, | 1528 | func.lbrace_line, |
| ... | @@ -2534,18 +2520,14 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { | ... | @@ -2534,18 +2520,14 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { |
| 2534 | defer arena_alloc.deinit(); | 2520 | defer arena_alloc.deinit(); |
| 2535 | const arena = arena_alloc.allocator(); | 2521 | const arena = arena_alloc.allocator(); |
| 2536 | 2522 | ||
| 2537 | const error_set = try arena.create(Module.ErrorSet); | 2523 | // TODO: don't create a zig type for this, just make the dwarf info |
| 2538 | const error_ty = try Type.Tag.error_set.create(arena, error_set); | 2524 | // without touching the zig type system. |
| 2539 | var names = Module.ErrorSet.NameMap{}; | 2525 | const names = try arena.dupe(InternPool.NullTerminatedString, module.global_error_set.keys()); |
| 2540 | try names.ensureUnusedCapacity(arena, module.global_error_set.count()); | 2526 | std.mem.sort(InternPool.NullTerminatedString, names, {}, InternPool.NullTerminatedString.indexLessThan); |
| 2541 | var it = module.global_error_set.keyIterator(); | ||
| 2542 | while (it.next()) |key| { | ||
| 2543 | names.putAssumeCapacityNoClobber(key.*, {}); | ||
| 2544 | } | ||
| 2545 | error_set.names = names; | ||
| 2546 | 2527 | ||
| 2528 | const error_ty = try module.intern(.{ .error_set_type = .{ .names = names } }); | ||
| 2547 | var dbg_info_buffer = std.ArrayList(u8).init(arena); | 2529 | var dbg_info_buffer = std.ArrayList(u8).init(arena); |
| 2548 | try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer); | 2530 | try addDbgInfoErrorSet(arena, module, error_ty.toType(), self.target, &dbg_info_buffer); |
| 2549 | 2531 | ||
| 2550 | const di_atom_index = try self.createAtom(.di_atom); | 2532 | const di_atom_index = try self.createAtom(.di_atom); |
| 2551 | log.debug("updateDeclDebugInfoAllocation in flushModule", .{}); | 2533 | log.debug("updateDeclDebugInfoAllocation in flushModule", .{}); |
| ... | @@ -2598,7 +2580,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { | ... | @@ -2598,7 +2580,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { |
| 2598 | 2580 | ||
| 2599 | fn addDIFile(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) !u28 { | 2581 | fn addDIFile(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) !u28 { |
| 2600 | const decl = mod.declPtr(decl_index); | 2582 | const decl = mod.declPtr(decl_index); |
| 2601 | const file_scope = decl.getFileScope(); | 2583 | const file_scope = decl.getFileScope(mod); |
| 2602 | const gop = try self.di_files.getOrPut(self.allocator, file_scope); | 2584 | const gop = try self.di_files.getOrPut(self.allocator, file_scope); |
| 2603 | if (!gop.found_existing) { | 2585 | if (!gop.found_existing) { |
| 2604 | switch (self.bin_file.tag) { | 2586 | switch (self.bin_file.tag) { |
| ... | @@ -2663,7 +2645,7 @@ fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct { | ... | @@ -2663,7 +2645,7 @@ fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct { |
| 2663 | 2645 | ||
| 2664 | fn addDbgInfoErrorSet( | 2646 | fn addDbgInfoErrorSet( |
| 2665 | arena: Allocator, | 2647 | arena: Allocator, |
| 2666 | module: *Module, | 2648 | mod: *Module, |
| 2667 | ty: Type, | 2649 | ty: Type, |
| 2668 | target: std.Target, | 2650 | target: std.Target, |
| 2669 | dbg_info_buffer: *std.ArrayList(u8), | 2651 | dbg_info_buffer: *std.ArrayList(u8), |
| ... | @@ -2673,10 +2655,10 @@ fn addDbgInfoErrorSet( | ... | @@ -2673,10 +2655,10 @@ fn addDbgInfoErrorSet( |
| 2673 | // DW.AT.enumeration_type | 2655 | // DW.AT.enumeration_type |
| 2674 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type)); | 2656 | try dbg_info_buffer.append(@enumToInt(AbbrevKind.enum_type)); |
| 2675 | // DW.AT.byte_size, DW.FORM.udata | 2657 | // DW.AT.byte_size, DW.FORM.udata |
| 2676 | const abi_size = Type.anyerror.abiSize(target); | 2658 | const abi_size = Type.anyerror.abiSize(mod); |
| 2677 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); | 2659 | try leb128.writeULEB128(dbg_info_buffer.writer(), abi_size); |
| 2678 | // DW.AT.name, DW.FORM.string | 2660 | // DW.AT.name, DW.FORM.string |
| 2679 | const name = try ty.nameAllocArena(arena, module); | 2661 | const name = try ty.nameAllocArena(arena, mod); |
| 2680 | try dbg_info_buffer.writer().print("{s}\x00", .{name}); | 2662 | try dbg_info_buffer.writer().print("{s}\x00", .{name}); |
| 2681 | 2663 | ||
| 2682 | // DW.AT.enumerator | 2664 | // DW.AT.enumerator |
| ... | @@ -2689,9 +2671,10 @@ fn addDbgInfoErrorSet( | ... | @@ -2689,9 +2671,10 @@ fn addDbgInfoErrorSet( |
| 2689 | // DW.AT.const_value, DW.FORM.data8 | 2671 | // DW.AT.const_value, DW.FORM.data8 |
| 2690 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian); | 2672 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), 0, target_endian); |
| 2691 | 2673 | ||
| 2692 | const error_names = ty.errorSetNames(); | 2674 | const error_names = ty.errorSetNames(mod); |
| 2693 | for (error_names) |error_name| { | 2675 | for (error_names) |error_name_ip| { |
| 2694 | const kv = module.getErrorValue(error_name) catch unreachable; | 2676 | const int = try mod.getErrorValue(error_name_ip); |
| 2677 | const error_name = mod.intern_pool.stringToSlice(error_name_ip); | ||
| 2695 | // DW.AT.enumerator | 2678 | // DW.AT.enumerator |
| 2696 | try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64)); | 2679 | try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64)); |
| 2697 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant)); | 2680 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant)); |
| ... | @@ -2699,7 +2682,7 @@ fn addDbgInfoErrorSet( | ... | @@ -2699,7 +2682,7 @@ fn addDbgInfoErrorSet( |
| 2699 | dbg_info_buffer.appendSliceAssumeCapacity(error_name); | 2682 | dbg_info_buffer.appendSliceAssumeCapacity(error_name); |
| 2700 | dbg_info_buffer.appendAssumeCapacity(0); | 2683 | dbg_info_buffer.appendAssumeCapacity(0); |
| 2701 | // DW.AT.const_value, DW.FORM.data8 | 2684 | // DW.AT.const_value, DW.FORM.data8 |
| 2702 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), kv.value, target_endian); | 2685 | mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), int, target_endian); |
| 2703 | } | 2686 | } |
| 2704 | 2687 | ||
| 2705 | // DW.AT.enumeration_type delimit children | 2688 | // DW.AT.enumeration_type delimit children |
src/link/Elf.zig+63-58| ... | @@ -28,6 +28,7 @@ const File = link.File; | ... | @@ -28,6 +28,7 @@ const File = link.File; |
| 28 | const Liveness = @import("../Liveness.zig"); | 28 | const Liveness = @import("../Liveness.zig"); |
| 29 | const LlvmObject = @import("../codegen/llvm.zig").Object; | 29 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 30 | const Module = @import("../Module.zig"); | 30 | const Module = @import("../Module.zig"); |
| 31 | const InternPool = @import("../InternPool.zig"); | ||
| 31 | const Package = @import("../Package.zig"); | 32 | const Package = @import("../Package.zig"); |
| 32 | const StringTable = @import("strtab.zig").StringTable; | 33 | const StringTable = @import("strtab.zig").StringTable; |
| 33 | const TableSection = @import("table_section.zig").TableSection; | 34 | const TableSection = @import("table_section.zig").TableSection; |
| ... | @@ -2414,7 +2415,8 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { | ... | @@ -2414,7 +2415,8 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { |
| 2414 | } | 2415 | } |
| 2415 | 2416 | ||
| 2416 | pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Index { | 2417 | pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Index { |
| 2417 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); | 2418 | const mod = self.base.options.module.?; |
| 2419 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(mod)); | ||
| 2418 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); | 2420 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 2419 | if (!gop.found_existing) gop.value_ptr.* = .{}; | 2421 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 2420 | const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { | 2422 | const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { |
| ... | @@ -2429,7 +2431,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Inde | ... | @@ -2429,7 +2431,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Inde |
| 2429 | metadata.state.* = .pending_flush; | 2431 | metadata.state.* = .pending_flush; |
| 2430 | const atom = metadata.atom.*; | 2432 | const atom = metadata.atom.*; |
| 2431 | // anyerror needs to be deferred until flushModule | 2433 | // anyerror needs to be deferred until flushModule |
| 2432 | if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { | 2434 | if (sym.getDecl(mod) != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { |
| 2433 | .code => self.text_section_index.?, | 2435 | .code => self.text_section_index.?, |
| 2434 | .const_data => self.rodata_section_index.?, | 2436 | .const_data => self.rodata_section_index.?, |
| 2435 | }); | 2437 | }); |
| ... | @@ -2449,12 +2451,13 @@ pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.I | ... | @@ -2449,12 +2451,13 @@ pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.I |
| 2449 | } | 2451 | } |
| 2450 | 2452 | ||
| 2451 | fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 { | 2453 | fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 { |
| 2452 | const decl = self.base.options.module.?.declPtr(decl_index); | 2454 | const mod = self.base.options.module.?; |
| 2455 | const decl = mod.declPtr(decl_index); | ||
| 2453 | const ty = decl.ty; | 2456 | const ty = decl.ty; |
| 2454 | const zig_ty = ty.zigTypeTag(); | 2457 | const zig_ty = ty.zigTypeTag(mod); |
| 2455 | const val = decl.val; | 2458 | const val = decl.val; |
| 2456 | const shdr_index: u16 = blk: { | 2459 | const shdr_index: u16 = blk: { |
| 2457 | if (val.isUndefDeep()) { | 2460 | if (val.isUndefDeep(mod)) { |
| 2458 | // TODO in release-fast and release-small, we should put undef in .bss | 2461 | // TODO in release-fast and release-small, we should put undef in .bss |
| 2459 | break :blk self.data_section_index.?; | 2462 | break :blk self.data_section_index.?; |
| 2460 | } | 2463 | } |
| ... | @@ -2463,7 +2466,7 @@ fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 { | ... | @@ -2463,7 +2466,7 @@ fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 { |
| 2463 | // TODO: what if this is a function pointer? | 2466 | // TODO: what if this is a function pointer? |
| 2464 | .Fn => break :blk self.text_section_index.?, | 2467 | .Fn => break :blk self.text_section_index.?, |
| 2465 | else => { | 2468 | else => { |
| 2466 | if (val.castTag(.variable)) |_| { | 2469 | if (val.getVariable(mod)) |_| { |
| 2467 | break :blk self.data_section_index.?; | 2470 | break :blk self.data_section_index.?; |
| 2468 | } | 2471 | } |
| 2469 | break :blk self.rodata_section_index.?; | 2472 | break :blk self.rodata_section_index.?; |
| ... | @@ -2478,11 +2481,10 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s | ... | @@ -2478,11 +2481,10 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s |
| 2478 | const mod = self.base.options.module.?; | 2481 | const mod = self.base.options.module.?; |
| 2479 | const decl = mod.declPtr(decl_index); | 2482 | const decl = mod.declPtr(decl_index); |
| 2480 | 2483 | ||
| 2481 | const decl_name = try decl.getFullyQualifiedName(mod); | 2484 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 2482 | defer self.base.allocator.free(decl_name); | ||
| 2483 | 2485 | ||
| 2484 | log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); | 2486 | log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); |
| 2485 | const required_alignment = decl.getAlignment(self.base.options.target); | 2487 | const required_alignment = decl.getAlignment(mod); |
| 2486 | 2488 | ||
| 2487 | const decl_metadata = self.decls.get(decl_index).?; | 2489 | const decl_metadata = self.decls.get(decl_index).?; |
| 2488 | const atom_index = decl_metadata.atom; | 2490 | const atom_index = decl_metadata.atom; |
| ... | @@ -2572,19 +2574,20 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s | ... | @@ -2572,19 +2574,20 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s |
| 2572 | return local_sym; | 2574 | return local_sym; |
| 2573 | } | 2575 | } |
| 2574 | 2576 | ||
| 2575 | pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 2577 | pub fn updateFunc(self: *Elf, mod: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { |
| 2576 | if (build_options.skip_non_native and builtin.object_format != .elf) { | 2578 | if (build_options.skip_non_native and builtin.object_format != .elf) { |
| 2577 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 2579 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 2578 | } | 2580 | } |
| 2579 | if (build_options.have_llvm) { | 2581 | if (build_options.have_llvm) { |
| 2580 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness); | 2582 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness); |
| 2581 | } | 2583 | } |
| 2582 | 2584 | ||
| 2583 | const tracy = trace(@src()); | 2585 | const tracy = trace(@src()); |
| 2584 | defer tracy.end(); | 2586 | defer tracy.end(); |
| 2585 | 2587 | ||
| 2588 | const func = mod.funcPtr(func_index); | ||
| 2586 | const decl_index = func.owner_decl; | 2589 | const decl_index = func.owner_decl; |
| 2587 | const decl = module.declPtr(decl_index); | 2590 | const decl = mod.declPtr(decl_index); |
| 2588 | 2591 | ||
| 2589 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); | 2592 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 2590 | self.freeUnnamedConsts(decl_index); | 2593 | self.freeUnnamedConsts(decl_index); |
| ... | @@ -2593,28 +2596,28 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven | ... | @@ -2593,28 +2596,28 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven |
| 2593 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 2596 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2594 | defer code_buffer.deinit(); | 2597 | defer code_buffer.deinit(); |
| 2595 | 2598 | ||
| 2596 | var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; | 2599 | var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null; |
| 2597 | defer if (decl_state) |*ds| ds.deinit(); | 2600 | defer if (decl_state) |*ds| ds.deinit(); |
| 2598 | 2601 | ||
| 2599 | const res = if (decl_state) |*ds| | 2602 | const res = if (decl_state) |*ds| |
| 2600 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ | 2603 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .{ |
| 2601 | .dwarf = ds, | 2604 | .dwarf = ds, |
| 2602 | }) | 2605 | }) |
| 2603 | else | 2606 | else |
| 2604 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); | 2607 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .none); |
| 2605 | 2608 | ||
| 2606 | const code = switch (res) { | 2609 | const code = switch (res) { |
| 2607 | .ok => code_buffer.items, | 2610 | .ok => code_buffer.items, |
| 2608 | .fail => |em| { | 2611 | .fail => |em| { |
| 2609 | decl.analysis = .codegen_failure; | 2612 | decl.analysis = .codegen_failure; |
| 2610 | try module.failed_decls.put(module.gpa, decl_index, em); | 2613 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 2611 | return; | 2614 | return; |
| 2612 | }, | 2615 | }, |
| 2613 | }; | 2616 | }; |
| 2614 | const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC); | 2617 | const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC); |
| 2615 | if (decl_state) |*ds| { | 2618 | if (decl_state) |*ds| { |
| 2616 | try self.dwarf.?.commitDeclState( | 2619 | try self.dwarf.?.commitDeclState( |
| 2617 | module, | 2620 | mod, |
| 2618 | decl_index, | 2621 | decl_index, |
| 2619 | local_sym.st_value, | 2622 | local_sym.st_value, |
| 2620 | local_sym.st_size, | 2623 | local_sym.st_size, |
| ... | @@ -2624,31 +2627,30 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven | ... | @@ -2624,31 +2627,30 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven |
| 2624 | 2627 | ||
| 2625 | // Since we updated the vaddr and the size, each corresponding export | 2628 | // Since we updated the vaddr and the size, each corresponding export |
| 2626 | // symbol also needs to be updated. | 2629 | // symbol also needs to be updated. |
| 2627 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 2630 | return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index)); |
| 2628 | } | 2631 | } |
| 2629 | 2632 | ||
| 2630 | pub fn updateDecl( | 2633 | pub fn updateDecl( |
| 2631 | self: *Elf, | 2634 | self: *Elf, |
| 2632 | module: *Module, | 2635 | mod: *Module, |
| 2633 | decl_index: Module.Decl.Index, | 2636 | decl_index: Module.Decl.Index, |
| 2634 | ) File.UpdateDeclError!void { | 2637 | ) File.UpdateDeclError!void { |
| 2635 | if (build_options.skip_non_native and builtin.object_format != .elf) { | 2638 | if (build_options.skip_non_native and builtin.object_format != .elf) { |
| 2636 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 2639 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 2637 | } | 2640 | } |
| 2638 | if (build_options.have_llvm) { | 2641 | if (build_options.have_llvm) { |
| 2639 | if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl_index); | 2642 | if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index); |
| 2640 | } | 2643 | } |
| 2641 | 2644 | ||
| 2642 | const tracy = trace(@src()); | 2645 | const tracy = trace(@src()); |
| 2643 | defer tracy.end(); | 2646 | defer tracy.end(); |
| 2644 | 2647 | ||
| 2645 | const decl = module.declPtr(decl_index); | 2648 | const decl = mod.declPtr(decl_index); |
| 2646 | 2649 | ||
| 2647 | if (decl.val.tag() == .extern_fn) { | 2650 | if (decl.val.getExternFunc(mod)) |_| { |
| 2648 | return; // TODO Should we do more when front-end analyzed extern decl? | 2651 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 2649 | } | 2652 | } |
| 2650 | if (decl.val.castTag(.variable)) |payload| { | 2653 | if (decl.val.getVariable(mod)) |variable| { |
| 2651 | const variable = payload.data; | ||
| 2652 | if (variable.is_extern) { | 2654 | if (variable.is_extern) { |
| 2653 | return; // TODO Should we do more when front-end analyzed extern decl? | 2655 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 2654 | } | 2656 | } |
| ... | @@ -2661,13 +2663,13 @@ pub fn updateDecl( | ... | @@ -2661,13 +2663,13 @@ pub fn updateDecl( |
| 2661 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 2663 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 2662 | defer code_buffer.deinit(); | 2664 | defer code_buffer.deinit(); |
| 2663 | 2665 | ||
| 2664 | var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null; | 2666 | var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null; |
| 2665 | defer if (decl_state) |*ds| ds.deinit(); | 2667 | defer if (decl_state) |*ds| ds.deinit(); |
| 2666 | 2668 | ||
| 2667 | // TODO implement .debug_info for global variables | 2669 | // TODO implement .debug_info for global variables |
| 2668 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 2670 | const decl_val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val; |
| 2669 | const res = if (decl_state) |*ds| | 2671 | const res = if (decl_state) |*ds| |
| 2670 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 2672 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 2671 | .ty = decl.ty, | 2673 | .ty = decl.ty, |
| 2672 | .val = decl_val, | 2674 | .val = decl_val, |
| 2673 | }, &code_buffer, .{ | 2675 | }, &code_buffer, .{ |
| ... | @@ -2676,7 +2678,7 @@ pub fn updateDecl( | ... | @@ -2676,7 +2678,7 @@ pub fn updateDecl( |
| 2676 | .parent_atom_index = atom.getSymbolIndex().?, | 2678 | .parent_atom_index = atom.getSymbolIndex().?, |
| 2677 | }) | 2679 | }) |
| 2678 | else | 2680 | else |
| 2679 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 2681 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 2680 | .ty = decl.ty, | 2682 | .ty = decl.ty, |
| 2681 | .val = decl_val, | 2683 | .val = decl_val, |
| 2682 | }, &code_buffer, .none, .{ | 2684 | }, &code_buffer, .none, .{ |
| ... | @@ -2687,7 +2689,7 @@ pub fn updateDecl( | ... | @@ -2687,7 +2689,7 @@ pub fn updateDecl( |
| 2687 | .ok => code_buffer.items, | 2689 | .ok => code_buffer.items, |
| 2688 | .fail => |em| { | 2690 | .fail => |em| { |
| 2689 | decl.analysis = .codegen_failure; | 2691 | decl.analysis = .codegen_failure; |
| 2690 | try module.failed_decls.put(module.gpa, decl_index, em); | 2692 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 2691 | return; | 2693 | return; |
| 2692 | }, | 2694 | }, |
| 2693 | }; | 2695 | }; |
| ... | @@ -2695,7 +2697,7 @@ pub fn updateDecl( | ... | @@ -2695,7 +2697,7 @@ pub fn updateDecl( |
| 2695 | const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT); | 2697 | const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT); |
| 2696 | if (decl_state) |*ds| { | 2698 | if (decl_state) |*ds| { |
| 2697 | try self.dwarf.?.commitDeclState( | 2699 | try self.dwarf.?.commitDeclState( |
| 2698 | module, | 2700 | mod, |
| 2699 | decl_index, | 2701 | decl_index, |
| 2700 | local_sym.st_value, | 2702 | local_sym.st_value, |
| 2701 | local_sym.st_size, | 2703 | local_sym.st_size, |
| ... | @@ -2705,7 +2707,7 @@ pub fn updateDecl( | ... | @@ -2705,7 +2707,7 @@ pub fn updateDecl( |
| 2705 | 2707 | ||
| 2706 | // Since we updated the vaddr and the size, each corresponding export | 2708 | // Since we updated the vaddr and the size, each corresponding export |
| 2707 | // symbol also needs to be updated. | 2709 | // symbol also needs to be updated. |
| 2708 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 2710 | return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index)); |
| 2709 | } | 2711 | } |
| 2710 | 2712 | ||
| 2711 | fn updateLazySymbolAtom( | 2713 | fn updateLazySymbolAtom( |
| ... | @@ -2734,8 +2736,8 @@ fn updateLazySymbolAtom( | ... | @@ -2734,8 +2736,8 @@ fn updateLazySymbolAtom( |
| 2734 | const atom = self.getAtom(atom_index); | 2736 | const atom = self.getAtom(atom_index); |
| 2735 | const local_sym_index = atom.getSymbolIndex().?; | 2737 | const local_sym_index = atom.getSymbolIndex().?; |
| 2736 | 2738 | ||
| 2737 | const src = if (sym.ty.getOwnerDeclOrNull()) |owner_decl| | 2739 | const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| |
| 2738 | mod.declPtr(owner_decl).srcLoc() | 2740 | mod.declPtr(owner_decl).srcLoc(mod) |
| 2739 | else | 2741 | else |
| 2740 | Module.SrcLoc{ | 2742 | Module.SrcLoc{ |
| 2741 | .file_scope = undefined, | 2743 | .file_scope = undefined, |
| ... | @@ -2800,8 +2802,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2800,8 +2802,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2800 | 2802 | ||
| 2801 | const decl = mod.declPtr(decl_index); | 2803 | const decl = mod.declPtr(decl_index); |
| 2802 | const name_str_index = blk: { | 2804 | const name_str_index = blk: { |
| 2803 | const decl_name = try decl.getFullyQualifiedName(mod); | 2805 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 2804 | defer gpa.free(decl_name); | ||
| 2805 | const index = unnamed_consts.items.len; | 2806 | const index = unnamed_consts.items.len; |
| 2806 | const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); | 2807 | const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); |
| 2807 | defer gpa.free(name); | 2808 | defer gpa.free(name); |
| ... | @@ -2811,7 +2812,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2811,7 +2812,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2811 | 2812 | ||
| 2812 | const atom_index = try self.createAtom(); | 2813 | const atom_index = try self.createAtom(); |
| 2813 | 2814 | ||
| 2814 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ | 2815 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .{ |
| 2815 | .none = {}, | 2816 | .none = {}, |
| 2816 | }, .{ | 2817 | }, .{ |
| 2817 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, | 2818 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, |
| ... | @@ -2826,7 +2827,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2826,7 +2827,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2826 | }, | 2827 | }, |
| 2827 | }; | 2828 | }; |
| 2828 | 2829 | ||
| 2829 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | 2830 | const required_alignment = typed_value.ty.abiAlignment(mod); |
| 2830 | const shdr_index = self.rodata_section_index.?; | 2831 | const shdr_index = self.rodata_section_index.?; |
| 2831 | const phdr_index = self.sections.items(.phdr_index)[shdr_index]; | 2832 | const phdr_index = self.sections.items(.phdr_index)[shdr_index]; |
| 2832 | const local_sym = self.getAtom(atom_index).getSymbolPtr(self); | 2833 | const local_sym = self.getAtom(atom_index).getSymbolPtr(self); |
| ... | @@ -2852,7 +2853,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module | ... | @@ -2852,7 +2853,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2852 | 2853 | ||
| 2853 | pub fn updateDeclExports( | 2854 | pub fn updateDeclExports( |
| 2854 | self: *Elf, | 2855 | self: *Elf, |
| 2855 | module: *Module, | 2856 | mod: *Module, |
| 2856 | decl_index: Module.Decl.Index, | 2857 | decl_index: Module.Decl.Index, |
| 2857 | exports: []const *Module.Export, | 2858 | exports: []const *Module.Export, |
| 2858 | ) File.UpdateDeclExportsError!void { | 2859 | ) File.UpdateDeclExportsError!void { |
| ... | @@ -2860,7 +2861,7 @@ pub fn updateDeclExports( | ... | @@ -2860,7 +2861,7 @@ pub fn updateDeclExports( |
| 2860 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 2861 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 2861 | } | 2862 | } |
| 2862 | if (build_options.have_llvm) { | 2863 | if (build_options.have_llvm) { |
| 2863 | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports); | 2864 | if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports); |
| 2864 | } | 2865 | } |
| 2865 | 2866 | ||
| 2866 | const tracy = trace(@src()); | 2867 | const tracy = trace(@src()); |
| ... | @@ -2868,7 +2869,7 @@ pub fn updateDeclExports( | ... | @@ -2868,7 +2869,7 @@ pub fn updateDeclExports( |
| 2868 | 2869 | ||
| 2869 | const gpa = self.base.allocator; | 2870 | const gpa = self.base.allocator; |
| 2870 | 2871 | ||
| 2871 | const decl = module.declPtr(decl_index); | 2872 | const decl = mod.declPtr(decl_index); |
| 2872 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); | 2873 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 2873 | const atom = self.getAtom(atom_index); | 2874 | const atom = self.getAtom(atom_index); |
| 2874 | const decl_sym = atom.getSymbol(self); | 2875 | const decl_sym = atom.getSymbol(self); |
| ... | @@ -2878,40 +2879,41 @@ pub fn updateDeclExports( | ... | @@ -2878,40 +2879,41 @@ pub fn updateDeclExports( |
| 2878 | try self.global_symbols.ensureUnusedCapacity(gpa, exports.len); | 2879 | try self.global_symbols.ensureUnusedCapacity(gpa, exports.len); |
| 2879 | 2880 | ||
| 2880 | for (exports) |exp| { | 2881 | for (exports) |exp| { |
| 2881 | if (exp.options.section) |section_name| { | 2882 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); |
| 2882 | if (!mem.eql(u8, section_name, ".text")) { | 2883 | if (exp.opts.section.unwrap()) |section_name| { |
| 2883 | try module.failed_exports.ensureUnusedCapacity(module.gpa, 1); | 2884 | if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) { |
| 2884 | module.failed_exports.putAssumeCapacityNoClobber( | 2885 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); |
| 2886 | mod.failed_exports.putAssumeCapacityNoClobber( | ||
| 2885 | exp, | 2887 | exp, |
| 2886 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: ExportOptions.section", .{}), | 2888 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(mod), "Unimplemented: ExportOptions.section", .{}), |
| 2887 | ); | 2889 | ); |
| 2888 | continue; | 2890 | continue; |
| 2889 | } | 2891 | } |
| 2890 | } | 2892 | } |
| 2891 | const stb_bits: u8 = switch (exp.options.linkage) { | 2893 | const stb_bits: u8 = switch (exp.opts.linkage) { |
| 2892 | .Internal => elf.STB_LOCAL, | 2894 | .Internal => elf.STB_LOCAL, |
| 2893 | .Strong => blk: { | 2895 | .Strong => blk: { |
| 2894 | const entry_name = self.base.options.entry orelse "_start"; | 2896 | const entry_name = self.base.options.entry orelse "_start"; |
| 2895 | if (mem.eql(u8, exp.options.name, entry_name)) { | 2897 | if (mem.eql(u8, exp_name, entry_name)) { |
| 2896 | self.entry_addr = decl_sym.st_value; | 2898 | self.entry_addr = decl_sym.st_value; |
| 2897 | } | 2899 | } |
| 2898 | break :blk elf.STB_GLOBAL; | 2900 | break :blk elf.STB_GLOBAL; |
| 2899 | }, | 2901 | }, |
| 2900 | .Weak => elf.STB_WEAK, | 2902 | .Weak => elf.STB_WEAK, |
| 2901 | .LinkOnce => { | 2903 | .LinkOnce => { |
| 2902 | try module.failed_exports.ensureUnusedCapacity(module.gpa, 1); | 2904 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); |
| 2903 | module.failed_exports.putAssumeCapacityNoClobber( | 2905 | mod.failed_exports.putAssumeCapacityNoClobber( |
| 2904 | exp, | 2906 | exp, |
| 2905 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: GlobalLinkage.LinkOnce", .{}), | 2907 | try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(mod), "Unimplemented: GlobalLinkage.LinkOnce", .{}), |
| 2906 | ); | 2908 | ); |
| 2907 | continue; | 2909 | continue; |
| 2908 | }, | 2910 | }, |
| 2909 | }; | 2911 | }; |
| 2910 | const stt_bits: u8 = @truncate(u4, decl_sym.st_info); | 2912 | const stt_bits: u8 = @truncate(u4, decl_sym.st_info); |
| 2911 | if (decl_metadata.getExport(self, exp.options.name)) |i| { | 2913 | if (decl_metadata.getExport(self, exp_name)) |i| { |
| 2912 | const sym = &self.global_symbols.items[i]; | 2914 | const sym = &self.global_symbols.items[i]; |
| 2913 | sym.* = .{ | 2915 | sym.* = .{ |
| 2914 | .st_name = try self.shstrtab.insert(gpa, exp.options.name), | 2916 | .st_name = try self.shstrtab.insert(gpa, exp_name), |
| 2915 | .st_info = (stb_bits << 4) | stt_bits, | 2917 | .st_info = (stb_bits << 4) | stt_bits, |
| 2916 | .st_other = 0, | 2918 | .st_other = 0, |
| 2917 | .st_shndx = shdr_index, | 2919 | .st_shndx = shdr_index, |
| ... | @@ -2925,7 +2927,7 @@ pub fn updateDeclExports( | ... | @@ -2925,7 +2927,7 @@ pub fn updateDeclExports( |
| 2925 | }; | 2927 | }; |
| 2926 | try decl_metadata.exports.append(gpa, @intCast(u32, i)); | 2928 | try decl_metadata.exports.append(gpa, @intCast(u32, i)); |
| 2927 | self.global_symbols.items[i] = .{ | 2929 | self.global_symbols.items[i] = .{ |
| 2928 | .st_name = try self.shstrtab.insert(gpa, exp.options.name), | 2930 | .st_name = try self.shstrtab.insert(gpa, exp_name), |
| 2929 | .st_info = (stb_bits << 4) | stt_bits, | 2931 | .st_info = (stb_bits << 4) | stt_bits, |
| 2930 | .st_other = 0, | 2932 | .st_other = 0, |
| 2931 | .st_shndx = shdr_index, | 2933 | .st_shndx = shdr_index, |
| ... | @@ -2942,8 +2944,7 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.In | ... | @@ -2942,8 +2944,7 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.In |
| 2942 | defer tracy.end(); | 2944 | defer tracy.end(); |
| 2943 | 2945 | ||
| 2944 | const decl = mod.declPtr(decl_index); | 2946 | const decl = mod.declPtr(decl_index); |
| 2945 | const decl_name = try decl.getFullyQualifiedName(mod); | 2947 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 2946 | defer self.base.allocator.free(decl_name); | ||
| 2947 | 2948 | ||
| 2948 | log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); | 2949 | log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); |
| 2949 | 2950 | ||
| ... | @@ -2953,11 +2954,15 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.In | ... | @@ -2953,11 +2954,15 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.In |
| 2953 | } | 2954 | } |
| 2954 | } | 2955 | } |
| 2955 | 2956 | ||
| 2956 | pub fn deleteDeclExport(self: *Elf, decl_index: Module.Decl.Index, name: []const u8) void { | 2957 | pub fn deleteDeclExport( |
| 2958 | self: *Elf, | ||
| 2959 | decl_index: Module.Decl.Index, | ||
| 2960 | name: InternPool.NullTerminatedString, | ||
| 2961 | ) void { | ||
| 2957 | if (self.llvm_object) |_| return; | 2962 | if (self.llvm_object) |_| return; |
| 2958 | const metadata = self.decls.getPtr(decl_index) orelse return; | 2963 | const metadata = self.decls.getPtr(decl_index) orelse return; |
| 2959 | const sym_index = metadata.getExportPtr(self, name) orelse return; | 2964 | const mod = self.base.options.module.?; |
| 2960 | log.debug("deleting export '{s}'", .{name}); | 2965 | const sym_index = metadata.getExportPtr(self, mod.intern_pool.stringToSlice(name)) orelse return; |
| 2961 | self.global_symbol_free_list.append(self.base.allocator, sym_index.*) catch {}; | 2966 | self.global_symbol_free_list.append(self.base.allocator, sym_index.*) catch {}; |
| 2962 | self.global_symbols.items[sym_index.*].st_info = 0; | 2967 | self.global_symbols.items[sym_index.*].st_info = 0; |
| 2963 | sym_index.* = 0; | 2968 | sym_index.* = 0; |
src/link/MachO.zig+76-68| ... | @@ -40,6 +40,7 @@ const Liveness = @import("../Liveness.zig"); | ... | @@ -40,6 +40,7 @@ const Liveness = @import("../Liveness.zig"); |
| 40 | const LlvmObject = @import("../codegen/llvm.zig").Object; | 40 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 41 | const Md5 = std.crypto.hash.Md5; | 41 | const Md5 = std.crypto.hash.Md5; |
| 42 | const Module = @import("../Module.zig"); | 42 | const Module = @import("../Module.zig"); |
| 43 | const InternPool = @import("../InternPool.zig"); | ||
| 43 | const Relocation = @import("MachO/Relocation.zig"); | 44 | const Relocation = @import("MachO/Relocation.zig"); |
| 44 | const StringTable = @import("strtab.zig").StringTable; | 45 | const StringTable = @import("strtab.zig").StringTable; |
| 45 | const TableSection = @import("table_section.zig").TableSection; | 46 | const TableSection = @import("table_section.zig").TableSection; |
| ... | @@ -1847,18 +1848,19 @@ fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { | ... | @@ -1847,18 +1848,19 @@ fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { |
| 1847 | self.markRelocsDirtyByTarget(target); | 1848 | self.markRelocsDirtyByTarget(target); |
| 1848 | } | 1849 | } |
| 1849 | 1850 | ||
| 1850 | pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 1851 | pub fn updateFunc(self: *MachO, mod: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { |
| 1851 | if (build_options.skip_non_native and builtin.object_format != .macho) { | 1852 | if (build_options.skip_non_native and builtin.object_format != .macho) { |
| 1852 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1853 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1853 | } | 1854 | } |
| 1854 | if (build_options.have_llvm) { | 1855 | if (build_options.have_llvm) { |
| 1855 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness); | 1856 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness); |
| 1856 | } | 1857 | } |
| 1857 | const tracy = trace(@src()); | 1858 | const tracy = trace(@src()); |
| 1858 | defer tracy.end(); | 1859 | defer tracy.end(); |
| 1859 | 1860 | ||
| 1861 | const func = mod.funcPtr(func_index); | ||
| 1860 | const decl_index = func.owner_decl; | 1862 | const decl_index = func.owner_decl; |
| 1861 | const decl = module.declPtr(decl_index); | 1863 | const decl = mod.declPtr(decl_index); |
| 1862 | 1864 | ||
| 1863 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); | 1865 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 1864 | self.freeUnnamedConsts(decl_index); | 1866 | self.freeUnnamedConsts(decl_index); |
| ... | @@ -1868,23 +1870,23 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -1868,23 +1870,23 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 1868 | defer code_buffer.deinit(); | 1870 | defer code_buffer.deinit(); |
| 1869 | 1871 | ||
| 1870 | var decl_state = if (self.d_sym) |*d_sym| | 1872 | var decl_state = if (self.d_sym) |*d_sym| |
| 1871 | try d_sym.dwarf.initDeclState(module, decl_index) | 1873 | try d_sym.dwarf.initDeclState(mod, decl_index) |
| 1872 | else | 1874 | else |
| 1873 | null; | 1875 | null; |
| 1874 | defer if (decl_state) |*ds| ds.deinit(); | 1876 | defer if (decl_state) |*ds| ds.deinit(); |
| 1875 | 1877 | ||
| 1876 | const res = if (decl_state) |*ds| | 1878 | const res = if (decl_state) |*ds| |
| 1877 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ | 1879 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .{ |
| 1878 | .dwarf = ds, | 1880 | .dwarf = ds, |
| 1879 | }) | 1881 | }) |
| 1880 | else | 1882 | else |
| 1881 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none); | 1883 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .none); |
| 1882 | 1884 | ||
| 1883 | var code = switch (res) { | 1885 | var code = switch (res) { |
| 1884 | .ok => code_buffer.items, | 1886 | .ok => code_buffer.items, |
| 1885 | .fail => |em| { | 1887 | .fail => |em| { |
| 1886 | decl.analysis = .codegen_failure; | 1888 | decl.analysis = .codegen_failure; |
| 1887 | try module.failed_decls.put(module.gpa, decl_index, em); | 1889 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1888 | return; | 1890 | return; |
| 1889 | }, | 1891 | }, |
| 1890 | }; | 1892 | }; |
| ... | @@ -1893,7 +1895,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -1893,7 +1895,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 1893 | 1895 | ||
| 1894 | if (decl_state) |*ds| { | 1896 | if (decl_state) |*ds| { |
| 1895 | try self.d_sym.?.dwarf.commitDeclState( | 1897 | try self.d_sym.?.dwarf.commitDeclState( |
| 1896 | module, | 1898 | mod, |
| 1897 | decl_index, | 1899 | decl_index, |
| 1898 | addr, | 1900 | addr, |
| 1899 | self.getAtom(atom_index).size, | 1901 | self.getAtom(atom_index).size, |
| ... | @@ -1903,7 +1905,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -1903,7 +1905,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 1903 | 1905 | ||
| 1904 | // Since we updated the vaddr and the size, each corresponding export symbol also | 1906 | // Since we updated the vaddr and the size, each corresponding export symbol also |
| 1905 | // needs to be updated. | 1907 | // needs to be updated. |
| 1906 | try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 1908 | try self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index)); |
| 1907 | } | 1909 | } |
| 1908 | 1910 | ||
| 1909 | pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 { | 1911 | pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 { |
| ... | @@ -1912,16 +1914,15 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu | ... | @@ -1912,16 +1914,15 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 1912 | var code_buffer = std.ArrayList(u8).init(gpa); | 1914 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1913 | defer code_buffer.deinit(); | 1915 | defer code_buffer.deinit(); |
| 1914 | 1916 | ||
| 1915 | const module = self.base.options.module.?; | 1917 | const mod = self.base.options.module.?; |
| 1916 | const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index); | 1918 | const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index); |
| 1917 | if (!gop.found_existing) { | 1919 | if (!gop.found_existing) { |
| 1918 | gop.value_ptr.* = .{}; | 1920 | gop.value_ptr.* = .{}; |
| 1919 | } | 1921 | } |
| 1920 | const unnamed_consts = gop.value_ptr; | 1922 | const unnamed_consts = gop.value_ptr; |
| 1921 | 1923 | ||
| 1922 | const decl = module.declPtr(decl_index); | 1924 | const decl = mod.declPtr(decl_index); |
| 1923 | const decl_name = try decl.getFullyQualifiedName(module); | 1925 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1924 | defer gpa.free(decl_name); | ||
| 1925 | 1926 | ||
| 1926 | const name_str_index = blk: { | 1927 | const name_str_index = blk: { |
| 1927 | const index = unnamed_consts.items.len; | 1928 | const index = unnamed_consts.items.len; |
| ... | @@ -1935,20 +1936,20 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu | ... | @@ -1935,20 +1936,20 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 1935 | 1936 | ||
| 1936 | const atom_index = try self.createAtom(); | 1937 | const atom_index = try self.createAtom(); |
| 1937 | 1938 | ||
| 1938 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none, .{ | 1939 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .none, .{ |
| 1939 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, | 1940 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, |
| 1940 | }); | 1941 | }); |
| 1941 | var code = switch (res) { | 1942 | var code = switch (res) { |
| 1942 | .ok => code_buffer.items, | 1943 | .ok => code_buffer.items, |
| 1943 | .fail => |em| { | 1944 | .fail => |em| { |
| 1944 | decl.analysis = .codegen_failure; | 1945 | decl.analysis = .codegen_failure; |
| 1945 | try module.failed_decls.put(module.gpa, decl_index, em); | 1946 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1946 | log.err("{s}", .{em.msg}); | 1947 | log.err("{s}", .{em.msg}); |
| 1947 | return error.CodegenFail; | 1948 | return error.CodegenFail; |
| 1948 | }, | 1949 | }, |
| 1949 | }; | 1950 | }; |
| 1950 | 1951 | ||
| 1951 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | 1952 | const required_alignment = typed_value.ty.abiAlignment(mod); |
| 1952 | const atom = self.getAtomPtr(atom_index); | 1953 | const atom = self.getAtomPtr(atom_index); |
| 1953 | atom.size = code.len; | 1954 | atom.size = code.len; |
| 1954 | // TODO: work out logic for disambiguating functions from function pointers | 1955 | // TODO: work out logic for disambiguating functions from function pointers |
| ... | @@ -1971,33 +1972,32 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu | ... | @@ -1971,33 +1972,32 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 1971 | return atom.getSymbolIndex().?; | 1972 | return atom.getSymbolIndex().?; |
| 1972 | } | 1973 | } |
| 1973 | 1974 | ||
| 1974 | pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { | 1975 | pub fn updateDecl(self: *MachO, mod: *Module, decl_index: Module.Decl.Index) !void { |
| 1975 | if (build_options.skip_non_native and builtin.object_format != .macho) { | 1976 | if (build_options.skip_non_native and builtin.object_format != .macho) { |
| 1976 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1977 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1977 | } | 1978 | } |
| 1978 | if (build_options.have_llvm) { | 1979 | if (build_options.have_llvm) { |
| 1979 | if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl_index); | 1980 | if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index); |
| 1980 | } | 1981 | } |
| 1981 | const tracy = trace(@src()); | 1982 | const tracy = trace(@src()); |
| 1982 | defer tracy.end(); | 1983 | defer tracy.end(); |
| 1983 | 1984 | ||
| 1984 | const decl = module.declPtr(decl_index); | 1985 | const decl = mod.declPtr(decl_index); |
| 1985 | 1986 | ||
| 1986 | if (decl.val.tag() == .extern_fn) { | 1987 | if (decl.val.getExternFunc(mod)) |_| { |
| 1987 | return; // TODO Should we do more when front-end analyzed extern decl? | 1988 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1988 | } | 1989 | } |
| 1989 | if (decl.val.castTag(.variable)) |payload| { | 1990 | if (decl.val.getVariable(mod)) |variable| { |
| 1990 | const variable = payload.data; | ||
| 1991 | if (variable.is_extern) { | 1991 | if (variable.is_extern) { |
| 1992 | return; // TODO Should we do more when front-end analyzed extern decl? | 1992 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1993 | } | 1993 | } |
| 1994 | } | 1994 | } |
| 1995 | 1995 | ||
| 1996 | const is_threadlocal = if (decl.val.castTag(.variable)) |payload| | 1996 | const is_threadlocal = if (decl.val.getVariable(mod)) |variable| |
| 1997 | payload.data.is_threadlocal and !self.base.options.single_threaded | 1997 | variable.is_threadlocal and !self.base.options.single_threaded |
| 1998 | else | 1998 | else |
| 1999 | false; | 1999 | false; |
| 2000 | if (is_threadlocal) return self.updateThreadlocalVariable(module, decl_index); | 2000 | if (is_threadlocal) return self.updateThreadlocalVariable(mod, decl_index); |
| 2001 | 2001 | ||
| 2002 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); | 2002 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 2003 | const sym_index = self.getAtom(atom_index).getSymbolIndex().?; | 2003 | const sym_index = self.getAtom(atom_index).getSymbolIndex().?; |
| ... | @@ -2007,14 +2007,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -2007,14 +2007,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2007 | defer code_buffer.deinit(); | 2007 | defer code_buffer.deinit(); |
| 2008 | 2008 | ||
| 2009 | var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym| | 2009 | var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym| |
| 2010 | try d_sym.dwarf.initDeclState(module, decl_index) | 2010 | try d_sym.dwarf.initDeclState(mod, decl_index) |
| 2011 | else | 2011 | else |
| 2012 | null; | 2012 | null; |
| 2013 | defer if (decl_state) |*ds| ds.deinit(); | 2013 | defer if (decl_state) |*ds| ds.deinit(); |
| 2014 | 2014 | ||
| 2015 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 2015 | const decl_val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val; |
| 2016 | const res = if (decl_state) |*ds| | 2016 | const res = if (decl_state) |*ds| |
| 2017 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 2017 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 2018 | .ty = decl.ty, | 2018 | .ty = decl.ty, |
| 2019 | .val = decl_val, | 2019 | .val = decl_val, |
| 2020 | }, &code_buffer, .{ | 2020 | }, &code_buffer, .{ |
| ... | @@ -2023,7 +2023,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -2023,7 +2023,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2023 | .parent_atom_index = sym_index, | 2023 | .parent_atom_index = sym_index, |
| 2024 | }) | 2024 | }) |
| 2025 | else | 2025 | else |
| 2026 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 2026 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 2027 | .ty = decl.ty, | 2027 | .ty = decl.ty, |
| 2028 | .val = decl_val, | 2028 | .val = decl_val, |
| 2029 | }, &code_buffer, .none, .{ | 2029 | }, &code_buffer, .none, .{ |
| ... | @@ -2034,7 +2034,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -2034,7 +2034,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2034 | .ok => code_buffer.items, | 2034 | .ok => code_buffer.items, |
| 2035 | .fail => |em| { | 2035 | .fail => |em| { |
| 2036 | decl.analysis = .codegen_failure; | 2036 | decl.analysis = .codegen_failure; |
| 2037 | try module.failed_decls.put(module.gpa, decl_index, em); | 2037 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 2038 | return; | 2038 | return; |
| 2039 | }, | 2039 | }, |
| 2040 | }; | 2040 | }; |
| ... | @@ -2042,7 +2042,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -2042,7 +2042,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2042 | 2042 | ||
| 2043 | if (decl_state) |*ds| { | 2043 | if (decl_state) |*ds| { |
| 2044 | try self.d_sym.?.dwarf.commitDeclState( | 2044 | try self.d_sym.?.dwarf.commitDeclState( |
| 2045 | module, | 2045 | mod, |
| 2046 | decl_index, | 2046 | decl_index, |
| 2047 | addr, | 2047 | addr, |
| 2048 | self.getAtom(atom_index).size, | 2048 | self.getAtom(atom_index).size, |
| ... | @@ -2052,7 +2052,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -2052,7 +2052,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2052 | 2052 | ||
| 2053 | // Since we updated the vaddr and the size, each corresponding export symbol also | 2053 | // Since we updated the vaddr and the size, each corresponding export symbol also |
| 2054 | // needs to be updated. | 2054 | // needs to be updated. |
| 2055 | try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 2055 | try self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index)); |
| 2056 | } | 2056 | } |
| 2057 | 2057 | ||
| 2058 | fn updateLazySymbolAtom( | 2058 | fn updateLazySymbolAtom( |
| ... | @@ -2081,8 +2081,8 @@ fn updateLazySymbolAtom( | ... | @@ -2081,8 +2081,8 @@ fn updateLazySymbolAtom( |
| 2081 | const atom = self.getAtomPtr(atom_index); | 2081 | const atom = self.getAtomPtr(atom_index); |
| 2082 | const local_sym_index = atom.getSymbolIndex().?; | 2082 | const local_sym_index = atom.getSymbolIndex().?; |
| 2083 | 2083 | ||
| 2084 | const src = if (sym.ty.getOwnerDeclOrNull()) |owner_decl| | 2084 | const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| |
| 2085 | mod.declPtr(owner_decl).srcLoc() | 2085 | mod.declPtr(owner_decl).srcLoc(mod) |
| 2086 | else | 2086 | else |
| 2087 | Module.SrcLoc{ | 2087 | Module.SrcLoc{ |
| 2088 | .file_scope = undefined, | 2088 | .file_scope = undefined, |
| ... | @@ -2126,7 +2126,8 @@ fn updateLazySymbolAtom( | ... | @@ -2126,7 +2126,8 @@ fn updateLazySymbolAtom( |
| 2126 | } | 2126 | } |
| 2127 | 2127 | ||
| 2128 | pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.Index { | 2128 | pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.Index { |
| 2129 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); | 2129 | const mod = self.base.options.module.?; |
| 2130 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(mod)); | ||
| 2130 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); | 2131 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 2131 | if (!gop.found_existing) gop.value_ptr.* = .{}; | 2132 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 2132 | const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { | 2133 | const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { |
| ... | @@ -2144,7 +2145,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.In | ... | @@ -2144,7 +2145,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.In |
| 2144 | metadata.state.* = .pending_flush; | 2145 | metadata.state.* = .pending_flush; |
| 2145 | const atom = metadata.atom.*; | 2146 | const atom = metadata.atom.*; |
| 2146 | // anyerror needs to be deferred until flushModule | 2147 | // anyerror needs to be deferred until flushModule |
| 2147 | if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { | 2148 | if (sym.getDecl(mod) != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { |
| 2148 | .code => self.text_section_index.?, | 2149 | .code => self.text_section_index.?, |
| 2149 | .const_data => self.data_const_section_index.?, | 2150 | .const_data => self.data_const_section_index.?, |
| 2150 | }); | 2151 | }); |
| ... | @@ -2152,6 +2153,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.In | ... | @@ -2152,6 +2153,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.In |
| 2152 | } | 2153 | } |
| 2153 | 2154 | ||
| 2154 | fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { | 2155 | fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { |
| 2156 | const mod = self.base.options.module.?; | ||
| 2155 | // Lowering a TLV on macOS involves two stages: | 2157 | // Lowering a TLV on macOS involves two stages: |
| 2156 | // 1. first we lower the initializer into appopriate section (__thread_data or __thread_bss) | 2158 | // 1. first we lower the initializer into appopriate section (__thread_data or __thread_bss) |
| 2157 | // 2. next, we create a corresponding threadlocal variable descriptor in __thread_vars | 2159 | // 2. next, we create a corresponding threadlocal variable descriptor in __thread_vars |
| ... | @@ -2175,9 +2177,9 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D | ... | @@ -2175,9 +2177,9 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D |
| 2175 | 2177 | ||
| 2176 | const decl = module.declPtr(decl_index); | 2178 | const decl = module.declPtr(decl_index); |
| 2177 | const decl_metadata = self.decls.get(decl_index).?; | 2179 | const decl_metadata = self.decls.get(decl_index).?; |
| 2178 | const decl_val = decl.val.castTag(.variable).?.data.init; | 2180 | const decl_val = decl.val.getVariable(mod).?.init.toValue(); |
| 2179 | const res = if (decl_state) |*ds| | 2181 | const res = if (decl_state) |*ds| |
| 2180 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 2182 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 2181 | .ty = decl.ty, | 2183 | .ty = decl.ty, |
| 2182 | .val = decl_val, | 2184 | .val = decl_val, |
| 2183 | }, &code_buffer, .{ | 2185 | }, &code_buffer, .{ |
| ... | @@ -2186,7 +2188,7 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D | ... | @@ -2186,7 +2188,7 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D |
| 2186 | .parent_atom_index = init_sym_index, | 2188 | .parent_atom_index = init_sym_index, |
| 2187 | }) | 2189 | }) |
| 2188 | else | 2190 | else |
| 2189 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 2191 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 2190 | .ty = decl.ty, | 2192 | .ty = decl.ty, |
| 2191 | .val = decl_val, | 2193 | .val = decl_val, |
| 2192 | }, &code_buffer, .none, .{ | 2194 | }, &code_buffer, .none, .{ |
| ... | @@ -2202,10 +2204,9 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D | ... | @@ -2202,10 +2204,9 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D |
| 2202 | }, | 2204 | }, |
| 2203 | }; | 2205 | }; |
| 2204 | 2206 | ||
| 2205 | const required_alignment = decl.getAlignment(self.base.options.target); | 2207 | const required_alignment = decl.getAlignment(mod); |
| 2206 | 2208 | ||
| 2207 | const decl_name = try decl.getFullyQualifiedName(module); | 2209 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(module)); |
| 2208 | defer gpa.free(decl_name); | ||
| 2209 | 2210 | ||
| 2210 | const init_sym_name = try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{decl_name}); | 2211 | const init_sym_name = try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{decl_name}); |
| 2211 | defer gpa.free(init_sym_name); | 2212 | defer gpa.free(init_sym_name); |
| ... | @@ -2262,12 +2263,13 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { | ... | @@ -2262,12 +2263,13 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { |
| 2262 | const decl = self.base.options.module.?.declPtr(decl_index); | 2263 | const decl = self.base.options.module.?.declPtr(decl_index); |
| 2263 | const ty = decl.ty; | 2264 | const ty = decl.ty; |
| 2264 | const val = decl.val; | 2265 | const val = decl.val; |
| 2265 | const zig_ty = ty.zigTypeTag(); | 2266 | const mod = self.base.options.module.?; |
| 2267 | const zig_ty = ty.zigTypeTag(mod); | ||
| 2266 | const mode = self.base.options.optimize_mode; | 2268 | const mode = self.base.options.optimize_mode; |
| 2267 | const single_threaded = self.base.options.single_threaded; | 2269 | const single_threaded = self.base.options.single_threaded; |
| 2268 | const sect_id: u8 = blk: { | 2270 | const sect_id: u8 = blk: { |
| 2269 | // TODO finish and audit this function | 2271 | // TODO finish and audit this function |
| 2270 | if (val.isUndefDeep()) { | 2272 | if (val.isUndefDeep(mod)) { |
| 2271 | if (mode == .ReleaseFast or mode == .ReleaseSmall) { | 2273 | if (mode == .ReleaseFast or mode == .ReleaseSmall) { |
| 2272 | @panic("TODO __DATA,__bss"); | 2274 | @panic("TODO __DATA,__bss"); |
| 2273 | } else { | 2275 | } else { |
| ... | @@ -2275,8 +2277,8 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { | ... | @@ -2275,8 +2277,8 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { |
| 2275 | } | 2277 | } |
| 2276 | } | 2278 | } |
| 2277 | 2279 | ||
| 2278 | if (val.castTag(.variable)) |variable| { | 2280 | if (val.getVariable(mod)) |variable| { |
| 2279 | if (variable.data.is_threadlocal and !single_threaded) { | 2281 | if (variable.is_threadlocal and !single_threaded) { |
| 2280 | break :blk self.thread_data_section_index.?; | 2282 | break :blk self.thread_data_section_index.?; |
| 2281 | } | 2283 | } |
| 2282 | break :blk self.data_section_index.?; | 2284 | break :blk self.data_section_index.?; |
| ... | @@ -2286,7 +2288,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { | ... | @@ -2286,7 +2288,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { |
| 2286 | // TODO: what if this is a function pointer? | 2288 | // TODO: what if this is a function pointer? |
| 2287 | .Fn => break :blk self.text_section_index.?, | 2289 | .Fn => break :blk self.text_section_index.?, |
| 2288 | else => { | 2290 | else => { |
| 2289 | if (val.castTag(.variable)) |_| { | 2291 | if (val.getVariable(mod)) |_| { |
| 2290 | break :blk self.data_section_index.?; | 2292 | break :blk self.data_section_index.?; |
| 2291 | } | 2293 | } |
| 2292 | break :blk self.data_const_section_index.?; | 2294 | break :blk self.data_const_section_index.?; |
| ... | @@ -2301,10 +2303,9 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 | ... | @@ -2301,10 +2303,9 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 |
| 2301 | const mod = self.base.options.module.?; | 2303 | const mod = self.base.options.module.?; |
| 2302 | const decl = mod.declPtr(decl_index); | 2304 | const decl = mod.declPtr(decl_index); |
| 2303 | 2305 | ||
| 2304 | const required_alignment = decl.getAlignment(self.base.options.target); | 2306 | const required_alignment = decl.getAlignment(mod); |
| 2305 | 2307 | ||
| 2306 | const decl_name = try decl.getFullyQualifiedName(mod); | 2308 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 2307 | defer gpa.free(decl_name); | ||
| 2308 | 2309 | ||
| 2309 | const decl_metadata = self.decls.get(decl_index).?; | 2310 | const decl_metadata = self.decls.get(decl_index).?; |
| 2310 | const atom_index = decl_metadata.atom; | 2311 | const atom_index = decl_metadata.atom; |
| ... | @@ -2376,7 +2377,7 @@ pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: Module.De | ... | @@ -2376,7 +2377,7 @@ pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: Module.De |
| 2376 | 2377 | ||
| 2377 | pub fn updateDeclExports( | 2378 | pub fn updateDeclExports( |
| 2378 | self: *MachO, | 2379 | self: *MachO, |
| 2379 | module: *Module, | 2380 | mod: *Module, |
| 2380 | decl_index: Module.Decl.Index, | 2381 | decl_index: Module.Decl.Index, |
| 2381 | exports: []const *Module.Export, | 2382 | exports: []const *Module.Export, |
| 2382 | ) File.UpdateDeclExportsError!void { | 2383 | ) File.UpdateDeclExportsError!void { |
| ... | @@ -2385,7 +2386,7 @@ pub fn updateDeclExports( | ... | @@ -2385,7 +2386,7 @@ pub fn updateDeclExports( |
| 2385 | } | 2386 | } |
| 2386 | if (build_options.have_llvm) { | 2387 | if (build_options.have_llvm) { |
| 2387 | if (self.llvm_object) |llvm_object| | 2388 | if (self.llvm_object) |llvm_object| |
| 2388 | return llvm_object.updateDeclExports(module, decl_index, exports); | 2389 | return llvm_object.updateDeclExports(mod, decl_index, exports); |
| 2389 | } | 2390 | } |
| 2390 | 2391 | ||
| 2391 | const tracy = trace(@src()); | 2392 | const tracy = trace(@src()); |
| ... | @@ -2393,26 +2394,28 @@ pub fn updateDeclExports( | ... | @@ -2393,26 +2394,28 @@ pub fn updateDeclExports( |
| 2393 | 2394 | ||
| 2394 | const gpa = self.base.allocator; | 2395 | const gpa = self.base.allocator; |
| 2395 | 2396 | ||
| 2396 | const decl = module.declPtr(decl_index); | 2397 | const decl = mod.declPtr(decl_index); |
| 2397 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); | 2398 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| 2398 | const atom = self.getAtom(atom_index); | 2399 | const atom = self.getAtom(atom_index); |
| 2399 | const decl_sym = atom.getSymbol(self); | 2400 | const decl_sym = atom.getSymbol(self); |
| 2400 | const decl_metadata = self.decls.getPtr(decl_index).?; | 2401 | const decl_metadata = self.decls.getPtr(decl_index).?; |
| 2401 | 2402 | ||
| 2402 | for (exports) |exp| { | 2403 | for (exports) |exp| { |
| 2403 | const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name}); | 2404 | const exp_name = try std.fmt.allocPrint(gpa, "_{}", .{ |
| 2405 | exp.opts.name.fmt(&mod.intern_pool), | ||
| 2406 | }); | ||
| 2404 | defer gpa.free(exp_name); | 2407 | defer gpa.free(exp_name); |
| 2405 | 2408 | ||
| 2406 | log.debug("adding new export '{s}'", .{exp_name}); | 2409 | log.debug("adding new export '{s}'", .{exp_name}); |
| 2407 | 2410 | ||
| 2408 | if (exp.options.section) |section_name| { | 2411 | if (exp.opts.section.unwrap()) |section_name| { |
| 2409 | if (!mem.eql(u8, section_name, "__text")) { | 2412 | if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) { |
| 2410 | try module.failed_exports.putNoClobber( | 2413 | try mod.failed_exports.putNoClobber( |
| 2411 | module.gpa, | 2414 | mod.gpa, |
| 2412 | exp, | 2415 | exp, |
| 2413 | try Module.ErrorMsg.create( | 2416 | try Module.ErrorMsg.create( |
| 2414 | gpa, | 2417 | gpa, |
| 2415 | decl.srcLoc(), | 2418 | decl.srcLoc(mod), |
| 2416 | "Unimplemented: ExportOptions.section", | 2419 | "Unimplemented: ExportOptions.section", |
| 2417 | .{}, | 2420 | .{}, |
| 2418 | ), | 2421 | ), |
| ... | @@ -2421,13 +2424,13 @@ pub fn updateDeclExports( | ... | @@ -2421,13 +2424,13 @@ pub fn updateDeclExports( |
| 2421 | } | 2424 | } |
| 2422 | } | 2425 | } |
| 2423 | 2426 | ||
| 2424 | if (exp.options.linkage == .LinkOnce) { | 2427 | if (exp.opts.linkage == .LinkOnce) { |
| 2425 | try module.failed_exports.putNoClobber( | 2428 | try mod.failed_exports.putNoClobber( |
| 2426 | module.gpa, | 2429 | mod.gpa, |
| 2427 | exp, | 2430 | exp, |
| 2428 | try Module.ErrorMsg.create( | 2431 | try Module.ErrorMsg.create( |
| 2429 | gpa, | 2432 | gpa, |
| 2430 | decl.srcLoc(), | 2433 | decl.srcLoc(mod), |
| 2431 | "Unimplemented: GlobalLinkage.LinkOnce", | 2434 | "Unimplemented: GlobalLinkage.LinkOnce", |
| 2432 | .{}, | 2435 | .{}, |
| 2433 | ), | 2436 | ), |
| ... | @@ -2450,7 +2453,7 @@ pub fn updateDeclExports( | ... | @@ -2450,7 +2453,7 @@ pub fn updateDeclExports( |
| 2450 | .n_value = decl_sym.n_value, | 2453 | .n_value = decl_sym.n_value, |
| 2451 | }; | 2454 | }; |
| 2452 | 2455 | ||
| 2453 | switch (exp.options.linkage) { | 2456 | switch (exp.opts.linkage) { |
| 2454 | .Internal => { | 2457 | .Internal => { |
| 2455 | // Symbol should be hidden, or in MachO lingo, private extern. | 2458 | // Symbol should be hidden, or in MachO lingo, private extern. |
| 2456 | // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF. | 2459 | // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF. |
| ... | @@ -2471,9 +2474,9 @@ pub fn updateDeclExports( | ... | @@ -2471,9 +2474,9 @@ pub fn updateDeclExports( |
| 2471 | // TODO: this needs rethinking | 2474 | // TODO: this needs rethinking |
| 2472 | const global = self.getGlobal(exp_name).?; | 2475 | const global = self.getGlobal(exp_name).?; |
| 2473 | if (sym_loc.sym_index != global.sym_index and global.file != null) { | 2476 | if (sym_loc.sym_index != global.sym_index and global.file != null) { |
| 2474 | _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create( | 2477 | _ = try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create( |
| 2475 | gpa, | 2478 | gpa, |
| 2476 | decl.srcLoc(), | 2479 | decl.srcLoc(mod), |
| 2477 | \\LinkError: symbol '{s}' defined multiple times | 2480 | \\LinkError: symbol '{s}' defined multiple times |
| 2478 | , | 2481 | , |
| 2479 | .{exp_name}, | 2482 | .{exp_name}, |
| ... | @@ -2485,12 +2488,17 @@ pub fn updateDeclExports( | ... | @@ -2485,12 +2488,17 @@ pub fn updateDeclExports( |
| 2485 | } | 2488 | } |
| 2486 | } | 2489 | } |
| 2487 | 2490 | ||
| 2488 | pub fn deleteDeclExport(self: *MachO, decl_index: Module.Decl.Index, name: []const u8) Allocator.Error!void { | 2491 | pub fn deleteDeclExport( |
| 2492 | self: *MachO, | ||
| 2493 | decl_index: Module.Decl.Index, | ||
| 2494 | name: InternPool.NullTerminatedString, | ||
| 2495 | ) Allocator.Error!void { | ||
| 2489 | if (self.llvm_object) |_| return; | 2496 | if (self.llvm_object) |_| return; |
| 2490 | const metadata = self.decls.getPtr(decl_index) orelse return; | 2497 | const metadata = self.decls.getPtr(decl_index) orelse return; |
| 2491 | 2498 | ||
| 2492 | const gpa = self.base.allocator; | 2499 | const gpa = self.base.allocator; |
| 2493 | const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{name}); | 2500 | const mod = self.base.options.module.?; |
| 2501 | const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{mod.intern_pool.stringToSlice(name)}); | ||
| 2494 | defer gpa.free(exp_name); | 2502 | defer gpa.free(exp_name); |
| 2495 | const sym_index = metadata.getExportPtr(self, exp_name) orelse return; | 2503 | const sym_index = metadata.getExportPtr(self, exp_name) orelse return; |
| 2496 | 2504 |
src/link/NvPtx.zig+2-2| ... | @@ -68,9 +68,9 @@ pub fn deinit(self: *NvPtx) void { | ... | @@ -68,9 +68,9 @@ pub fn deinit(self: *NvPtx) void { |
| 68 | self.base.allocator.free(self.ptx_file_name); | 68 | self.base.allocator.free(self.ptx_file_name); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | pub fn updateFunc(self: *NvPtx, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 71 | pub fn updateFunc(self: *NvPtx, module: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { |
| 72 | if (!build_options.have_llvm) return; | 72 | if (!build_options.have_llvm) return; |
| 73 | try self.llvm_object.updateFunc(module, func, air, liveness); | 73 | try self.llvm_object.updateFunc(module, func_index, air, liveness); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | pub fn updateDecl(self: *NvPtx, module: *Module, decl_index: Module.Decl.Index) !void { | 76 | pub fn updateDecl(self: *NvPtx, module: *Module, decl_index: Module.Decl.Index) !void { |
src/link/Plan9.zig+39-46| ... | @@ -213,14 +213,14 @@ fn putFn(self: *Plan9, decl_index: Module.Decl.Index, out: FnDeclOutput) !void { | ... | @@ -213,14 +213,14 @@ fn putFn(self: *Plan9, decl_index: Module.Decl.Index, out: FnDeclOutput) !void { |
| 213 | const gpa = self.base.allocator; | 213 | const gpa = self.base.allocator; |
| 214 | const mod = self.base.options.module.?; | 214 | const mod = self.base.options.module.?; |
| 215 | const decl = mod.declPtr(decl_index); | 215 | const decl = mod.declPtr(decl_index); |
| 216 | const fn_map_res = try self.fn_decl_table.getOrPut(gpa, decl.getFileScope()); | 216 | const fn_map_res = try self.fn_decl_table.getOrPut(gpa, decl.getFileScope(mod)); |
| 217 | if (fn_map_res.found_existing) { | 217 | if (fn_map_res.found_existing) { |
| 218 | if (try fn_map_res.value_ptr.functions.fetchPut(gpa, decl_index, out)) |old_entry| { | 218 | if (try fn_map_res.value_ptr.functions.fetchPut(gpa, decl_index, out)) |old_entry| { |
| 219 | gpa.free(old_entry.value.code); | 219 | gpa.free(old_entry.value.code); |
| 220 | gpa.free(old_entry.value.lineinfo); | 220 | gpa.free(old_entry.value.lineinfo); |
| 221 | } | 221 | } |
| 222 | } else { | 222 | } else { |
| 223 | const file = decl.getFileScope(); | 223 | const file = decl.getFileScope(mod); |
| 224 | const arena = self.path_arena.allocator(); | 224 | const arena = self.path_arena.allocator(); |
| 225 | // each file gets a symbol | 225 | // each file gets a symbol |
| 226 | fn_map_res.value_ptr.* = .{ | 226 | fn_map_res.value_ptr.* = .{ |
| ... | @@ -276,17 +276,17 @@ fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !voi | ... | @@ -276,17 +276,17 @@ fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !voi |
| 276 | } | 276 | } |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 279 | pub fn updateFunc(self: *Plan9, mod: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { |
| 280 | if (build_options.skip_non_native and builtin.object_format != .plan9) { | 280 | if (build_options.skip_non_native and builtin.object_format != .plan9) { |
| 281 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 281 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | const func = mod.funcPtr(func_index); | ||
| 284 | const decl_index = func.owner_decl; | 285 | const decl_index = func.owner_decl; |
| 285 | const decl = module.declPtr(decl_index); | 286 | const decl = mod.declPtr(decl_index); |
| 286 | self.freeUnnamedConsts(decl_index); | 287 | self.freeUnnamedConsts(decl_index); |
| 287 | 288 | ||
| 288 | _ = try self.seeDecl(decl_index); | 289 | _ = try self.seeDecl(decl_index); |
| 289 | log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); | ||
| 290 | 290 | ||
| 291 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 291 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 292 | defer code_buffer.deinit(); | 292 | defer code_buffer.deinit(); |
| ... | @@ -298,8 +298,8 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -298,8 +298,8 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 298 | 298 | ||
| 299 | const res = try codegen.generateFunction( | 299 | const res = try codegen.generateFunction( |
| 300 | &self.base, | 300 | &self.base, |
| 301 | decl.srcLoc(), | 301 | decl.srcLoc(mod), |
| 302 | func, | 302 | func_index, |
| 303 | air, | 303 | air, |
| 304 | liveness, | 304 | liveness, |
| 305 | &code_buffer, | 305 | &code_buffer, |
| ... | @@ -316,7 +316,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -316,7 +316,7 @@ pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liv |
| 316 | .ok => try code_buffer.toOwnedSlice(), | 316 | .ok => try code_buffer.toOwnedSlice(), |
| 317 | .fail => |em| { | 317 | .fail => |em| { |
| 318 | decl.analysis = .codegen_failure; | 318 | decl.analysis = .codegen_failure; |
| 319 | try module.failed_decls.put(module.gpa, decl_index, em); | 319 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 320 | return; | 320 | return; |
| 321 | }, | 321 | }, |
| 322 | }; | 322 | }; |
| ... | @@ -344,8 +344,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I | ... | @@ -344,8 +344,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 344 | } | 344 | } |
| 345 | const unnamed_consts = gop.value_ptr; | 345 | const unnamed_consts = gop.value_ptr; |
| 346 | 346 | ||
| 347 | const decl_name = try decl.getFullyQualifiedName(mod); | 347 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 348 | defer self.base.allocator.free(decl_name); | ||
| 349 | 348 | ||
| 350 | const index = unnamed_consts.items.len; | 349 | const index = unnamed_consts.items.len; |
| 351 | // name is freed when the unnamed const is freed | 350 | // name is freed when the unnamed const is freed |
| ... | @@ -366,7 +365,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I | ... | @@ -366,7 +365,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 366 | }; | 365 | }; |
| 367 | self.syms.items[info.sym_index.?] = sym; | 366 | self.syms.items[info.sym_index.?] = sym; |
| 368 | 367 | ||
| 369 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .{ | 368 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), tv, &code_buffer, .{ |
| 370 | .none = {}, | 369 | .none = {}, |
| 371 | }, .{ | 370 | }, .{ |
| 372 | .parent_atom_index = @enumToInt(decl_index), | 371 | .parent_atom_index = @enumToInt(decl_index), |
| ... | @@ -388,14 +387,13 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I | ... | @@ -388,14 +387,13 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 388 | return @intCast(u32, info.got_index.?); | 387 | return @intCast(u32, info.got_index.?); |
| 389 | } | 388 | } |
| 390 | 389 | ||
| 391 | pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) !void { | 390 | pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void { |
| 392 | const decl = module.declPtr(decl_index); | 391 | const decl = mod.declPtr(decl_index); |
| 393 | 392 | ||
| 394 | if (decl.val.tag() == .extern_fn) { | 393 | if (decl.val.getExternFunc(mod)) |_| { |
| 395 | return; // TODO Should we do more when front-end analyzed extern decl? | 394 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 396 | } | 395 | } |
| 397 | if (decl.val.castTag(.variable)) |payload| { | 396 | if (decl.val.getVariable(mod)) |variable| { |
| 398 | const variable = payload.data; | ||
| 399 | if (variable.is_extern) { | 397 | if (variable.is_extern) { |
| 400 | return; // TODO Should we do more when front-end analyzed extern decl? | 398 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 401 | } | 399 | } |
| ... | @@ -403,13 +401,11 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -403,13 +401,11 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) |
| 403 | 401 | ||
| 404 | _ = try self.seeDecl(decl_index); | 402 | _ = try self.seeDecl(decl_index); |
| 405 | 403 | ||
| 406 | log.debug("codegen decl {*} ({s}) ({d})", .{ decl, decl.name, decl_index }); | ||
| 407 | |||
| 408 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 404 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 409 | defer code_buffer.deinit(); | 405 | defer code_buffer.deinit(); |
| 410 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 406 | const decl_val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val; |
| 411 | // TODO we need the symbol index for symbol in the table of locals for the containing atom | 407 | // TODO we need the symbol index for symbol in the table of locals for the containing atom |
| 412 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 408 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 413 | .ty = decl.ty, | 409 | .ty = decl.ty, |
| 414 | .val = decl_val, | 410 | .val = decl_val, |
| 415 | }, &code_buffer, .{ .none = {} }, .{ | 411 | }, &code_buffer, .{ .none = {} }, .{ |
| ... | @@ -419,7 +415,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -419,7 +415,7 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) |
| 419 | .ok => code_buffer.items, | 415 | .ok => code_buffer.items, |
| 420 | .fail => |em| { | 416 | .fail => |em| { |
| 421 | decl.analysis = .codegen_failure; | 417 | decl.analysis = .codegen_failure; |
| 422 | try module.failed_decls.put(module.gpa, decl_index, em); | 418 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 423 | return; | 419 | return; |
| 424 | }, | 420 | }, |
| 425 | }; | 421 | }; |
| ... | @@ -432,9 +428,9 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -432,9 +428,9 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl_index: Module.Decl.Index) |
| 432 | } | 428 | } |
| 433 | /// called at the end of update{Decl,Func} | 429 | /// called at the end of update{Decl,Func} |
| 434 | fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void { | 430 | fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void { |
| 435 | const decl = self.base.options.module.?.declPtr(decl_index); | 431 | const mod = self.base.options.module.?; |
| 436 | const is_fn = (decl.ty.zigTypeTag() == .Fn); | 432 | const decl = mod.declPtr(decl_index); |
| 437 | log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name }); | 433 | const is_fn = (decl.ty.zigTypeTag(mod) == .Fn); |
| 438 | const sym_t: aout.Sym.Type = if (is_fn) .t else .d; | 434 | const sym_t: aout.Sym.Type = if (is_fn) .t else .d; |
| 439 | 435 | ||
| 440 | const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); | 436 | const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); |
| ... | @@ -445,7 +441,7 @@ fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void { | ... | @@ -445,7 +441,7 @@ fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void { |
| 445 | const sym: aout.Sym = .{ | 441 | const sym: aout.Sym = .{ |
| 446 | .value = undefined, // the value of stuff gets filled in in flushModule | 442 | .value = undefined, // the value of stuff gets filled in in flushModule |
| 447 | .type = decl_block.type, | 443 | .type = decl_block.type, |
| 448 | .name = mem.span(decl.name), | 444 | .name = try self.base.allocator.dupe(u8, mod.intern_pool.stringToSlice(decl.name)), |
| 449 | }; | 445 | }; |
| 450 | 446 | ||
| 451 | if (decl_block.sym_index) |s| { | 447 | if (decl_block.sym_index) |s| { |
| ... | @@ -566,10 +562,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -566,10 +562,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 566 | var it = fentry.value_ptr.functions.iterator(); | 562 | var it = fentry.value_ptr.functions.iterator(); |
| 567 | while (it.next()) |entry| { | 563 | while (it.next()) |entry| { |
| 568 | const decl_index = entry.key_ptr.*; | 564 | const decl_index = entry.key_ptr.*; |
| 569 | const decl = mod.declPtr(decl_index); | ||
| 570 | const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); | 565 | const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); |
| 571 | const out = entry.value_ptr.*; | 566 | const out = entry.value_ptr.*; |
| 572 | log.debug("write text decl {*} ({s}), lines {d} to {d}", .{ decl, decl.name, out.start_line + 1, out.end_line }); | ||
| 573 | { | 567 | { |
| 574 | // connect the previous decl to the next | 568 | // connect the previous decl to the next |
| 575 | const delta_line = @intCast(i32, out.start_line) - @intCast(i32, linecount); | 569 | const delta_line = @intCast(i32, out.start_line) - @intCast(i32, linecount); |
| ... | @@ -615,10 +609,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -615,10 +609,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 615 | var it = self.data_decl_table.iterator(); | 609 | var it = self.data_decl_table.iterator(); |
| 616 | while (it.next()) |entry| { | 610 | while (it.next()) |entry| { |
| 617 | const decl_index = entry.key_ptr.*; | 611 | const decl_index = entry.key_ptr.*; |
| 618 | const decl = mod.declPtr(decl_index); | ||
| 619 | const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); | 612 | const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); |
| 620 | const code = entry.value_ptr.*; | 613 | const code = entry.value_ptr.*; |
| 621 | log.debug("write data decl {*} ({s})", .{ decl, decl.name }); | ||
| 622 | 614 | ||
| 623 | foff += code.len; | 615 | foff += code.len; |
| 624 | iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; | 616 | iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; |
| ... | @@ -694,19 +686,16 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -694,19 +686,16 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 694 | const source_decl = mod.declPtr(source_decl_index); | 686 | const source_decl = mod.declPtr(source_decl_index); |
| 695 | for (kv.value_ptr.items) |reloc| { | 687 | for (kv.value_ptr.items) |reloc| { |
| 696 | const target_decl_index = reloc.target; | 688 | const target_decl_index = reloc.target; |
| 697 | const target_decl = mod.declPtr(target_decl_index); | ||
| 698 | const target_decl_block = self.getDeclBlock(self.decls.get(target_decl_index).?.index); | 689 | const target_decl_block = self.getDeclBlock(self.decls.get(target_decl_index).?.index); |
| 699 | const target_decl_offset = target_decl_block.offset.?; | 690 | const target_decl_offset = target_decl_block.offset.?; |
| 700 | 691 | ||
| 701 | const offset = reloc.offset; | 692 | const offset = reloc.offset; |
| 702 | const addend = reloc.addend; | 693 | const addend = reloc.addend; |
| 703 | 694 | ||
| 704 | log.debug("relocating the address of '{s}' + {d} into '{s}' + {d}", .{ target_decl.name, addend, source_decl.name, offset }); | ||
| 705 | |||
| 706 | const code = blk: { | 695 | const code = blk: { |
| 707 | const is_fn = source_decl.ty.zigTypeTag() == .Fn; | 696 | const is_fn = source_decl.ty.zigTypeTag(mod) == .Fn; |
| 708 | if (is_fn) { | 697 | if (is_fn) { |
| 709 | const table = self.fn_decl_table.get(source_decl.getFileScope()).?.functions; | 698 | const table = self.fn_decl_table.get(source_decl.getFileScope(mod)).?.functions; |
| 710 | const output = table.get(source_decl_index).?; | 699 | const output = table.get(source_decl_index).?; |
| 711 | break :blk output.code; | 700 | break :blk output.code; |
| 712 | } else { | 701 | } else { |
| ... | @@ -728,7 +717,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -728,7 +717,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 728 | } | 717 | } |
| 729 | fn addDeclExports( | 718 | fn addDeclExports( |
| 730 | self: *Plan9, | 719 | self: *Plan9, |
| 731 | module: *Module, | 720 | mod: *Module, |
| 732 | decl_index: Module.Decl.Index, | 721 | decl_index: Module.Decl.Index, |
| 733 | exports: []const *Module.Export, | 722 | exports: []const *Module.Export, |
| 734 | ) !void { | 723 | ) !void { |
| ... | @@ -736,12 +725,13 @@ fn addDeclExports( | ... | @@ -736,12 +725,13 @@ fn addDeclExports( |
| 736 | const decl_block = self.getDeclBlock(metadata.index); | 725 | const decl_block = self.getDeclBlock(metadata.index); |
| 737 | 726 | ||
| 738 | for (exports) |exp| { | 727 | for (exports) |exp| { |
| 728 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); | ||
| 739 | // plan9 does not support custom sections | 729 | // plan9 does not support custom sections |
| 740 | if (exp.options.section) |section_name| { | 730 | if (exp.opts.section.unwrap()) |section_name| { |
| 741 | if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) { | 731 | if (!mod.intern_pool.stringEqlSlice(section_name, ".text") and !mod.intern_pool.stringEqlSlice(section_name, ".data")) { |
| 742 | try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create( | 732 | try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create( |
| 743 | self.base.allocator, | 733 | self.base.allocator, |
| 744 | module.declPtr(decl_index).srcLoc(), | 734 | mod.declPtr(decl_index).srcLoc(mod), |
| 745 | "plan9 does not support extra sections", | 735 | "plan9 does not support extra sections", |
| 746 | .{}, | 736 | .{}, |
| 747 | )); | 737 | )); |
| ... | @@ -751,10 +741,10 @@ fn addDeclExports( | ... | @@ -751,10 +741,10 @@ fn addDeclExports( |
| 751 | const sym = .{ | 741 | const sym = .{ |
| 752 | .value = decl_block.offset.?, | 742 | .value = decl_block.offset.?, |
| 753 | .type = decl_block.type.toGlobal(), | 743 | .type = decl_block.type.toGlobal(), |
| 754 | .name = exp.options.name, | 744 | .name = try self.base.allocator.dupe(u8, exp_name), |
| 755 | }; | 745 | }; |
| 756 | 746 | ||
| 757 | if (metadata.getExport(self, exp.options.name)) |i| { | 747 | if (metadata.getExport(self, exp_name)) |i| { |
| 758 | self.syms.items[i] = sym; | 748 | self.syms.items[i] = sym; |
| 759 | } else { | 749 | } else { |
| 760 | try self.syms.append(self.base.allocator, sym); | 750 | try self.syms.append(self.base.allocator, sym); |
| ... | @@ -770,9 +760,9 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { | ... | @@ -770,9 +760,9 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { |
| 770 | // in the deleteUnusedDecl function. | 760 | // in the deleteUnusedDecl function. |
| 771 | const mod = self.base.options.module.?; | 761 | const mod = self.base.options.module.?; |
| 772 | const decl = mod.declPtr(decl_index); | 762 | const decl = mod.declPtr(decl_index); |
| 773 | const is_fn = (decl.val.tag() == .function); | 763 | const is_fn = decl.val.getFunctionIndex(mod) != .none; |
| 774 | if (is_fn) { | 764 | if (is_fn) { |
| 775 | var symidx_and_submap = self.fn_decl_table.get(decl.getFileScope()).?; | 765 | var symidx_and_submap = self.fn_decl_table.get(decl.getFileScope(mod)).?; |
| 776 | var submap = symidx_and_submap.functions; | 766 | var submap = symidx_and_submap.functions; |
| 777 | if (submap.fetchSwapRemove(decl_index)) |removed_entry| { | 767 | if (submap.fetchSwapRemove(decl_index)) |removed_entry| { |
| 778 | self.base.allocator.free(removed_entry.value.code); | 768 | self.base.allocator.free(removed_entry.value.code); |
| ... | @@ -955,7 +945,10 @@ pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void { | ... | @@ -955,7 +945,10 @@ pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void { |
| 955 | try w.writeAll(sym.name); | 945 | try w.writeAll(sym.name); |
| 956 | try w.writeByte(0); | 946 | try w.writeByte(0); |
| 957 | } | 947 | } |
| 948 | |||
| 958 | pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { | 949 | pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 950 | const mod = self.base.options.module.?; | ||
| 951 | const ip = &mod.intern_pool; | ||
| 959 | const writer = buf.writer(); | 952 | const writer = buf.writer(); |
| 960 | // write the f symbols | 953 | // write the f symbols |
| 961 | { | 954 | { |
| ... | @@ -979,7 +972,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { | ... | @@ -979,7 +972,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 979 | const sym = self.syms.items[decl_block.sym_index.?]; | 972 | const sym = self.syms.items[decl_block.sym_index.?]; |
| 980 | try self.writeSym(writer, sym); | 973 | try self.writeSym(writer, sym); |
| 981 | if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| { | 974 | if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| { |
| 982 | for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| { | 975 | for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.opts.name))) |exp_i| { |
| 983 | try self.writeSym(writer, self.syms.items[exp_i]); | 976 | try self.writeSym(writer, self.syms.items[exp_i]); |
| 984 | }; | 977 | }; |
| 985 | } | 978 | } |
| ... | @@ -1005,7 +998,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { | ... | @@ -1005,7 +998,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 1005 | const sym = self.syms.items[decl_block.sym_index.?]; | 998 | const sym = self.syms.items[decl_block.sym_index.?]; |
| 1006 | try self.writeSym(writer, sym); | 999 | try self.writeSym(writer, sym); |
| 1007 | if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| { | 1000 | if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| { |
| 1008 | for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| { | 1001 | for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.opts.name))) |exp_i| { |
| 1009 | const s = self.syms.items[exp_i]; | 1002 | const s = self.syms.items[exp_i]; |
| 1010 | if (mem.eql(u8, s.name, "_start")) | 1003 | if (mem.eql(u8, s.name, "_start")) |
| 1011 | self.entry_val = s.value; | 1004 | self.entry_val = s.value; |
| ... | @@ -1031,7 +1024,7 @@ pub fn getDeclVAddr( | ... | @@ -1031,7 +1024,7 @@ pub fn getDeclVAddr( |
| 1031 | ) !u64 { | 1024 | ) !u64 { |
| 1032 | const mod = self.base.options.module.?; | 1025 | const mod = self.base.options.module.?; |
| 1033 | const decl = mod.declPtr(decl_index); | 1026 | const decl = mod.declPtr(decl_index); |
| 1034 | if (decl.ty.zigTypeTag() == .Fn) { | 1027 | if (decl.ty.zigTypeTag(mod) == .Fn) { |
| 1035 | var start = self.bases.text; | 1028 | var start = self.bases.text; |
| 1036 | var it_file = self.fn_decl_table.iterator(); | 1029 | var it_file = self.fn_decl_table.iterator(); |
| 1037 | while (it_file.next()) |fentry| { | 1030 | while (it_file.next()) |fentry| { |
src/link/SpirV.zig+9-6| ... | @@ -103,11 +103,13 @@ pub fn deinit(self: *SpirV) void { | ... | @@ -103,11 +103,13 @@ pub fn deinit(self: *SpirV) void { |
| 103 | self.decl_link.deinit(); | 103 | self.decl_link.deinit(); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | pub fn updateFunc(self: *SpirV, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 106 | pub fn updateFunc(self: *SpirV, module: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { |
| 107 | if (build_options.skip_non_native) { | 107 | if (build_options.skip_non_native) { |
| 108 | @panic("Attempted to compile for architecture that was disabled by build configuration"); | 108 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | const func = module.funcPtr(func_index); | ||
| 112 | |||
| 111 | var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_link); | 113 | var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_link); |
| 112 | defer decl_gen.deinit(); | 114 | defer decl_gen.deinit(); |
| 113 | 115 | ||
| ... | @@ -131,12 +133,12 @@ pub fn updateDecl(self: *SpirV, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -131,12 +133,12 @@ pub fn updateDecl(self: *SpirV, module: *Module, decl_index: Module.Decl.Index) |
| 131 | 133 | ||
| 132 | pub fn updateDeclExports( | 134 | pub fn updateDeclExports( |
| 133 | self: *SpirV, | 135 | self: *SpirV, |
| 134 | module: *Module, | 136 | mod: *Module, |
| 135 | decl_index: Module.Decl.Index, | 137 | decl_index: Module.Decl.Index, |
| 136 | exports: []const *Module.Export, | 138 | exports: []const *Module.Export, |
| 137 | ) !void { | 139 | ) !void { |
| 138 | const decl = module.declPtr(decl_index); | 140 | const decl = mod.declPtr(decl_index); |
| 139 | if (decl.val.tag() == .function and decl.ty.fnCallingConvention() == .Kernel) { | 141 | if (decl.val.getFunctionIndex(mod) != .none and decl.ty.fnCallingConvention(mod) == .Kernel) { |
| 140 | // TODO: Unify with resolveDecl in spirv.zig. | 142 | // TODO: Unify with resolveDecl in spirv.zig. |
| 141 | const entry = try self.decl_link.getOrPut(decl_index); | 143 | const entry = try self.decl_link.getOrPut(decl_index); |
| 142 | if (!entry.found_existing) { | 144 | if (!entry.found_existing) { |
| ... | @@ -145,7 +147,7 @@ pub fn updateDeclExports( | ... | @@ -145,7 +147,7 @@ pub fn updateDeclExports( |
| 145 | const spv_decl_index = entry.value_ptr.*; | 147 | const spv_decl_index = entry.value_ptr.*; |
| 146 | 148 | ||
| 147 | for (exports) |exp| { | 149 | for (exports) |exp| { |
| 148 | try self.spv.declareEntryPoint(spv_decl_index, exp.options.name); | 150 | try self.spv.declareEntryPoint(spv_decl_index, mod.intern_pool.stringToSlice(exp.opts.name)); |
| 149 | } | 151 | } |
| 150 | } | 152 | } |
| 151 | 153 | ||
| ... | @@ -188,7 +190,8 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -188,7 +190,8 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No |
| 188 | var error_info = std.ArrayList(u8).init(self.spv.arena); | 190 | var error_info = std.ArrayList(u8).init(self.spv.arena); |
| 189 | try error_info.appendSlice("zig_errors"); | 191 | try error_info.appendSlice("zig_errors"); |
| 190 | const module = self.base.options.module.?; | 192 | const module = self.base.options.module.?; |
| 191 | for (module.error_name_list.items) |name| { | 193 | for (module.global_error_set.keys()) |name_nts| { |
| 194 | const name = module.intern_pool.stringToSlice(name_nts); | ||
| 192 | // Errors can contain pretty much any character - to encode them in a string we must escape | 195 | // Errors can contain pretty much any character - to encode them in a string we must escape |
| 193 | // them somehow. Easiest here is to use some established scheme, one which also preseves the | 196 | // them somehow. Easiest here is to use some established scheme, one which also preseves the |
| 194 | // name if it contains no strange characters is nice for debugging. URI encoding fits the bill. | 197 | // name if it contains no strange characters is nice for debugging. URI encoding fits the bill. |
src/link/Wasm.zig+96-79| ... | @@ -149,7 +149,8 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, | ... | @@ -149,7 +149,8 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, |
| 149 | /// into the final binary. | 149 | /// into the final binary. |
| 150 | resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .{}, | 150 | resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .{}, |
| 151 | /// Symbols that remain undefined after symbol resolution. | 151 | /// Symbols that remain undefined after symbol resolution. |
| 152 | undefs: std.StringArrayHashMapUnmanaged(SymbolLoc) = .{}, | 152 | /// Note: The key represents an offset into the string table, rather than the actual string. |
| 153 | undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .{}, | ||
| 153 | /// Maps a symbol's location to an atom. This can be used to find meta | 154 | /// Maps a symbol's location to an atom. This can be used to find meta |
| 154 | /// data of a symbol, such as its size, or its offset to perform a relocation. | 155 | /// data of a symbol, such as its size, or its offset to perform a relocation. |
| 155 | /// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped. | 156 | /// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped. |
| ... | @@ -514,6 +515,10 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { | ... | @@ -514,6 +515,10 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { |
| 514 | /// Leaves index undefined and the default flags (0). | 515 | /// Leaves index undefined and the default flags (0). |
| 515 | fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc { | 516 | fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc { |
| 516 | const name_offset = try wasm.string_table.put(wasm.base.allocator, name); | 517 | const name_offset = try wasm.string_table.put(wasm.base.allocator, name); |
| 518 | return wasm.createSyntheticSymbolOffset(name_offset, tag); | ||
| 519 | } | ||
| 520 | |||
| 521 | fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc { | ||
| 517 | const sym_index = @intCast(u32, wasm.symbols.items.len); | 522 | const sym_index = @intCast(u32, wasm.symbols.items.len); |
| 518 | const loc: SymbolLoc = .{ .index = sym_index, .file = null }; | 523 | const loc: SymbolLoc = .{ .index = sym_index, .file = null }; |
| 519 | try wasm.symbols.append(wasm.base.allocator, .{ | 524 | try wasm.symbols.append(wasm.base.allocator, .{ |
| ... | @@ -691,7 +696,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { | ... | @@ -691,7 +696,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { |
| 691 | try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {}); | 696 | try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, location, {}); |
| 692 | 697 | ||
| 693 | if (symbol.isUndefined()) { | 698 | if (symbol.isUndefined()) { |
| 694 | try wasm.undefs.putNoClobber(wasm.base.allocator, sym_name, location); | 699 | try wasm.undefs.putNoClobber(wasm.base.allocator, sym_name_index, location); |
| 695 | } | 700 | } |
| 696 | continue; | 701 | continue; |
| 697 | } | 702 | } |
| ... | @@ -801,7 +806,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { | ... | @@ -801,7 +806,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_index: u16) !void { |
| 801 | try wasm.resolved_symbols.put(wasm.base.allocator, location, {}); | 806 | try wasm.resolved_symbols.put(wasm.base.allocator, location, {}); |
| 802 | assert(wasm.resolved_symbols.swapRemove(existing_loc)); | 807 | assert(wasm.resolved_symbols.swapRemove(existing_loc)); |
| 803 | if (existing_sym.isUndefined()) { | 808 | if (existing_sym.isUndefined()) { |
| 804 | _ = wasm.undefs.swapRemove(sym_name); | 809 | _ = wasm.undefs.swapRemove(sym_name_index); |
| 805 | } | 810 | } |
| 806 | } | 811 | } |
| 807 | } | 812 | } |
| ... | @@ -812,15 +817,16 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { | ... | @@ -812,15 +817,16 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { |
| 812 | log.debug("Resolving symbols in archives", .{}); | 817 | log.debug("Resolving symbols in archives", .{}); |
| 813 | var index: u32 = 0; | 818 | var index: u32 = 0; |
| 814 | undef_loop: while (index < wasm.undefs.count()) { | 819 | undef_loop: while (index < wasm.undefs.count()) { |
| 815 | const sym_name = wasm.undefs.keys()[index]; | 820 | const sym_name_index = wasm.undefs.keys()[index]; |
| 816 | 821 | ||
| 817 | for (wasm.archives.items) |archive| { | 822 | for (wasm.archives.items) |archive| { |
| 823 | const sym_name = wasm.string_table.get(sym_name_index); | ||
| 824 | log.debug("Detected symbol '{s}' in archive '{s}', parsing objects..", .{ sym_name, archive.name }); | ||
| 818 | const offset = archive.toc.get(sym_name) orelse { | 825 | const offset = archive.toc.get(sym_name) orelse { |
| 819 | // symbol does not exist in this archive | 826 | // symbol does not exist in this archive |
| 820 | continue; | 827 | continue; |
| 821 | }; | 828 | }; |
| 822 | 829 | ||
| 823 | log.debug("Detected symbol '{s}' in archive '{s}', parsing objects..", .{ sym_name, archive.name }); | ||
| 824 | // Symbol is found in unparsed object file within current archive. | 830 | // Symbol is found in unparsed object file within current archive. |
| 825 | // Parse object and and resolve symbols again before we check remaining | 831 | // Parse object and and resolve symbols again before we check remaining |
| 826 | // undefined symbols. | 832 | // undefined symbols. |
| ... | @@ -1191,28 +1197,36 @@ fn validateFeatures( | ... | @@ -1191,28 +1197,36 @@ fn validateFeatures( |
| 1191 | /// if one or multiple undefined references exist. When none exist, the symbol will | 1197 | /// if one or multiple undefined references exist. When none exist, the symbol will |
| 1192 | /// not be created, ensuring we don't unneccesarily emit unreferenced symbols. | 1198 | /// not be created, ensuring we don't unneccesarily emit unreferenced symbols. |
| 1193 | fn resolveLazySymbols(wasm: *Wasm) !void { | 1199 | fn resolveLazySymbols(wasm: *Wasm) !void { |
| 1194 | if (wasm.undefs.fetchSwapRemove("__heap_base")) |kv| { | 1200 | if (wasm.string_table.getOffset("__heap_base")) |name_offset| { |
| 1195 | const loc = try wasm.createSyntheticSymbol("__heap_base", .data); | 1201 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1196 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | 1202 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); |
| 1197 | _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations. | 1203 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); |
| 1204 | _ = wasm.resolved_symbols.swapRemove(loc); // we don't want to emit this symbol, only use it for relocations. | ||
| 1205 | } | ||
| 1198 | } | 1206 | } |
| 1199 | 1207 | ||
| 1200 | if (wasm.undefs.fetchSwapRemove("__heap_end")) |kv| { | 1208 | if (wasm.string_table.getOffset("__heap_end")) |name_offset| { |
| 1201 | const loc = try wasm.createSyntheticSymbol("__heap_end", .data); | 1209 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1202 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | 1210 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); |
| 1203 | _ = wasm.resolved_symbols.swapRemove(loc); | 1211 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); |
| 1212 | _ = wasm.resolved_symbols.swapRemove(loc); | ||
| 1213 | } | ||
| 1204 | } | 1214 | } |
| 1205 | 1215 | ||
| 1206 | if (!wasm.base.options.shared_memory) { | 1216 | if (!wasm.base.options.shared_memory) { |
| 1207 | if (wasm.undefs.fetchSwapRemove("__tls_base")) |kv| { | 1217 | if (wasm.string_table.getOffset("__tls_base")) |name_offset| { |
| 1208 | const loc = try wasm.createSyntheticSymbol("__tls_base", .global); | 1218 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1209 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | 1219 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global); |
| 1220 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | ||
| 1221 | } | ||
| 1210 | } | 1222 | } |
| 1211 | } | 1223 | } |
| 1212 | if (wasm.undefs.fetchSwapRemove("__zig_errors_len")) |kv| { | 1224 | if (wasm.string_table.getOffset("__zig_errors_len")) |name_offset| { |
| 1213 | const loc = try wasm.createSyntheticSymbol("__zig_errors_len", .data); | 1225 | if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| { |
| 1214 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); | 1226 | const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data); |
| 1215 | _ = wasm.resolved_symbols.swapRemove(kv.value); | 1227 | try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc); |
| 1228 | _ = wasm.resolved_symbols.swapRemove(kv.value); | ||
| 1229 | } | ||
| 1216 | } | 1230 | } |
| 1217 | } | 1231 | } |
| 1218 | 1232 | ||
| ... | @@ -1324,17 +1338,18 @@ pub fn allocateSymbol(wasm: *Wasm) !u32 { | ... | @@ -1324,17 +1338,18 @@ pub fn allocateSymbol(wasm: *Wasm) !u32 { |
| 1324 | return index; | 1338 | return index; |
| 1325 | } | 1339 | } |
| 1326 | 1340 | ||
| 1327 | pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 1341 | pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { |
| 1328 | if (build_options.skip_non_native and builtin.object_format != .wasm) { | 1342 | if (build_options.skip_non_native and builtin.object_format != .wasm) { |
| 1329 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1343 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1330 | } | 1344 | } |
| 1331 | if (build_options.have_llvm) { | 1345 | if (build_options.have_llvm) { |
| 1332 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func, air, liveness); | 1346 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness); |
| 1333 | } | 1347 | } |
| 1334 | 1348 | ||
| 1335 | const tracy = trace(@src()); | 1349 | const tracy = trace(@src()); |
| 1336 | defer tracy.end(); | 1350 | defer tracy.end(); |
| 1337 | 1351 | ||
| 1352 | const func = mod.funcPtr(func_index); | ||
| 1338 | const decl_index = func.owner_decl; | 1353 | const decl_index = func.owner_decl; |
| 1339 | const decl = mod.declPtr(decl_index); | 1354 | const decl = mod.declPtr(decl_index); |
| 1340 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); | 1355 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| ... | @@ -1348,7 +1363,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes | ... | @@ -1348,7 +1363,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes |
| 1348 | defer code_writer.deinit(); | 1363 | defer code_writer.deinit(); |
| 1349 | // const result = try codegen.generateFunction( | 1364 | // const result = try codegen.generateFunction( |
| 1350 | // &wasm.base, | 1365 | // &wasm.base, |
| 1351 | // decl.srcLoc(), | 1366 | // decl.srcLoc(mod), |
| 1352 | // func, | 1367 | // func, |
| 1353 | // air, | 1368 | // air, |
| 1354 | // liveness, | 1369 | // liveness, |
| ... | @@ -1357,8 +1372,8 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes | ... | @@ -1357,8 +1372,8 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes |
| 1357 | // ); | 1372 | // ); |
| 1358 | const result = try codegen.generateFunction( | 1373 | const result = try codegen.generateFunction( |
| 1359 | &wasm.base, | 1374 | &wasm.base, |
| 1360 | decl.srcLoc(), | 1375 | decl.srcLoc(mod), |
| 1361 | func, | 1376 | func_index, |
| 1362 | air, | 1377 | air, |
| 1363 | liveness, | 1378 | liveness, |
| 1364 | &code_writer, | 1379 | &code_writer, |
| ... | @@ -1403,9 +1418,9 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi | ... | @@ -1403,9 +1418,9 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi |
| 1403 | defer tracy.end(); | 1418 | defer tracy.end(); |
| 1404 | 1419 | ||
| 1405 | const decl = mod.declPtr(decl_index); | 1420 | const decl = mod.declPtr(decl_index); |
| 1406 | if (decl.val.castTag(.function)) |_| { | 1421 | if (decl.val.getFunction(mod)) |_| { |
| 1407 | return; | 1422 | return; |
| 1408 | } else if (decl.val.castTag(.extern_fn)) |_| { | 1423 | } else if (decl.val.getExternFunc(mod)) |_| { |
| 1409 | return; | 1424 | return; |
| 1410 | } | 1425 | } |
| 1411 | 1426 | ||
| ... | @@ -1413,19 +1428,20 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi | ... | @@ -1413,19 +1428,20 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi |
| 1413 | const atom = wasm.getAtomPtr(atom_index); | 1428 | const atom = wasm.getAtomPtr(atom_index); |
| 1414 | atom.clear(); | 1429 | atom.clear(); |
| 1415 | 1430 | ||
| 1416 | if (decl.isExtern()) { | 1431 | if (decl.isExtern(mod)) { |
| 1417 | const variable = decl.getVariable().?; | 1432 | const variable = decl.getOwnedVariable(mod).?; |
| 1418 | const name = mem.sliceTo(decl.name, 0); | 1433 | const name = mod.intern_pool.stringToSlice(decl.name); |
| 1419 | return wasm.addOrUpdateImport(name, atom.sym_index, variable.lib_name, null); | 1434 | const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name); |
| 1435 | return wasm.addOrUpdateImport(name, atom.sym_index, lib_name, null); | ||
| 1420 | } | 1436 | } |
| 1421 | const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 1437 | const val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val; |
| 1422 | 1438 | ||
| 1423 | var code_writer = std.ArrayList(u8).init(wasm.base.allocator); | 1439 | var code_writer = std.ArrayList(u8).init(wasm.base.allocator); |
| 1424 | defer code_writer.deinit(); | 1440 | defer code_writer.deinit(); |
| 1425 | 1441 | ||
| 1426 | const res = try codegen.generateSymbol( | 1442 | const res = try codegen.generateSymbol( |
| 1427 | &wasm.base, | 1443 | &wasm.base, |
| 1428 | decl.srcLoc(), | 1444 | decl.srcLoc(mod), |
| 1429 | .{ .ty = decl.ty, .val = val }, | 1445 | .{ .ty = decl.ty, .val = val }, |
| 1430 | &code_writer, | 1446 | &code_writer, |
| 1431 | .none, | 1447 | .none, |
| ... | @@ -1451,8 +1467,7 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.I | ... | @@ -1451,8 +1467,7 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.I |
| 1451 | defer tracy.end(); | 1467 | defer tracy.end(); |
| 1452 | 1468 | ||
| 1453 | const decl = mod.declPtr(decl_index); | 1469 | const decl = mod.declPtr(decl_index); |
| 1454 | const decl_name = try decl.getFullyQualifiedName(mod); | 1470 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1455 | defer wasm.base.allocator.free(decl_name); | ||
| 1456 | 1471 | ||
| 1457 | log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); | 1472 | log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); |
| 1458 | try dw.updateDeclLineNumber(mod, decl_index); | 1473 | try dw.updateDeclLineNumber(mod, decl_index); |
| ... | @@ -1465,15 +1480,14 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8 | ... | @@ -1465,15 +1480,14 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8 |
| 1465 | const atom_index = wasm.decls.get(decl_index).?; | 1480 | const atom_index = wasm.decls.get(decl_index).?; |
| 1466 | const atom = wasm.getAtomPtr(atom_index); | 1481 | const atom = wasm.getAtomPtr(atom_index); |
| 1467 | const symbol = &wasm.symbols.items[atom.sym_index]; | 1482 | const symbol = &wasm.symbols.items[atom.sym_index]; |
| 1468 | const full_name = try decl.getFullyQualifiedName(mod); | 1483 | const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1469 | defer wasm.base.allocator.free(full_name); | ||
| 1470 | symbol.name = try wasm.string_table.put(wasm.base.allocator, full_name); | 1484 | symbol.name = try wasm.string_table.put(wasm.base.allocator, full_name); |
| 1471 | try atom.code.appendSlice(wasm.base.allocator, code); | 1485 | try atom.code.appendSlice(wasm.base.allocator, code); |
| 1472 | try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); | 1486 | try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); |
| 1473 | 1487 | ||
| 1474 | atom.size = @intCast(u32, code.len); | 1488 | atom.size = @intCast(u32, code.len); |
| 1475 | if (code.len == 0) return; | 1489 | if (code.len == 0) return; |
| 1476 | atom.alignment = decl.ty.abiAlignment(wasm.base.options.target); | 1490 | atom.alignment = decl.ty.abiAlignment(mod); |
| 1477 | } | 1491 | } |
| 1478 | 1492 | ||
| 1479 | /// From a given symbol location, returns its `wasm.GlobalType`. | 1493 | /// From a given symbol location, returns its `wasm.GlobalType`. |
| ... | @@ -1523,9 +1537,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { | ... | @@ -1523,9 +1537,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type { |
| 1523 | /// Returns the symbol index of the local | 1537 | /// Returns the symbol index of the local |
| 1524 | /// The given `decl` is the parent decl whom owns the constant. | 1538 | /// The given `decl` is the parent decl whom owns the constant. |
| 1525 | pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { | 1539 | pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { |
| 1526 | assert(tv.ty.zigTypeTag() != .Fn); // cannot create local symbols for functions | ||
| 1527 | |||
| 1528 | const mod = wasm.base.options.module.?; | 1540 | const mod = wasm.base.options.module.?; |
| 1541 | assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions | ||
| 1529 | const decl = mod.declPtr(decl_index); | 1542 | const decl = mod.declPtr(decl_index); |
| 1530 | 1543 | ||
| 1531 | // Create and initialize a new local symbol and atom | 1544 | // Create and initialize a new local symbol and atom |
| ... | @@ -1534,16 +1547,17 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1534,16 +1547,17 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1534 | const parent_atom = wasm.getAtomPtr(parent_atom_index); | 1547 | const parent_atom = wasm.getAtomPtr(parent_atom_index); |
| 1535 | const local_index = parent_atom.locals.items.len; | 1548 | const local_index = parent_atom.locals.items.len; |
| 1536 | try parent_atom.locals.append(wasm.base.allocator, atom_index); | 1549 | try parent_atom.locals.append(wasm.base.allocator, atom_index); |
| 1537 | const fqdn = try decl.getFullyQualifiedName(mod); | 1550 | const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1538 | defer wasm.base.allocator.free(fqdn); | 1551 | const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ |
| 1539 | const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index }); | 1552 | fqn, local_index, |
| 1553 | }); | ||
| 1540 | defer wasm.base.allocator.free(name); | 1554 | defer wasm.base.allocator.free(name); |
| 1541 | var value_bytes = std.ArrayList(u8).init(wasm.base.allocator); | 1555 | var value_bytes = std.ArrayList(u8).init(wasm.base.allocator); |
| 1542 | defer value_bytes.deinit(); | 1556 | defer value_bytes.deinit(); |
| 1543 | 1557 | ||
| 1544 | const code = code: { | 1558 | const code = code: { |
| 1545 | const atom = wasm.getAtomPtr(atom_index); | 1559 | const atom = wasm.getAtomPtr(atom_index); |
| 1546 | atom.alignment = tv.ty.abiAlignment(wasm.base.options.target); | 1560 | atom.alignment = tv.ty.abiAlignment(mod); |
| 1547 | wasm.symbols.items[atom.sym_index] = .{ | 1561 | wasm.symbols.items[atom.sym_index] = .{ |
| 1548 | .name = try wasm.string_table.put(wasm.base.allocator, name), | 1562 | .name = try wasm.string_table.put(wasm.base.allocator, name), |
| 1549 | .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), | 1563 | .flags = @enumToInt(Symbol.Flag.WASM_SYM_BINDING_LOCAL), |
| ... | @@ -1555,7 +1569,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1555,7 +1569,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1555 | 1569 | ||
| 1556 | const result = try codegen.generateSymbol( | 1570 | const result = try codegen.generateSymbol( |
| 1557 | &wasm.base, | 1571 | &wasm.base, |
| 1558 | decl.srcLoc(), | 1572 | decl.srcLoc(mod), |
| 1559 | tv, | 1573 | tv, |
| 1560 | &value_bytes, | 1574 | &value_bytes, |
| 1561 | .none, | 1575 | .none, |
| ... | @@ -1611,7 +1625,7 @@ pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u3 | ... | @@ -1611,7 +1625,7 @@ pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !u3 |
| 1611 | wasm.symbols.items[sym_index] = symbol; | 1625 | wasm.symbols.items[sym_index] = symbol; |
| 1612 | gop.value_ptr.* = .{ .index = sym_index, .file = null }; | 1626 | gop.value_ptr.* = .{ .index = sym_index, .file = null }; |
| 1613 | try wasm.resolved_symbols.put(wasm.base.allocator, gop.value_ptr.*, {}); | 1627 | try wasm.resolved_symbols.put(wasm.base.allocator, gop.value_ptr.*, {}); |
| 1614 | try wasm.undefs.putNoClobber(wasm.base.allocator, name, gop.value_ptr.*); | 1628 | try wasm.undefs.putNoClobber(wasm.base.allocator, name_index, gop.value_ptr.*); |
| 1615 | return sym_index; | 1629 | return sym_index; |
| 1616 | } | 1630 | } |
| 1617 | 1631 | ||
| ... | @@ -1632,7 +1646,7 @@ pub fn getDeclVAddr( | ... | @@ -1632,7 +1646,7 @@ pub fn getDeclVAddr( |
| 1632 | const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; | 1646 | const atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?; |
| 1633 | const atom = wasm.getAtomPtr(atom_index); | 1647 | const atom = wasm.getAtomPtr(atom_index); |
| 1634 | const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32; | 1648 | const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32; |
| 1635 | if (decl.ty.zigTypeTag() == .Fn) { | 1649 | if (decl.ty.zigTypeTag(mod) == .Fn) { |
| 1636 | assert(reloc_info.addend == 0); // addend not allowed for function relocations | 1650 | assert(reloc_info.addend == 0); // addend not allowed for function relocations |
| 1637 | // We found a function pointer, so add it to our table, | 1651 | // We found a function pointer, so add it to our table, |
| 1638 | // as function pointers are not allowed to be stored inside the data section. | 1652 | // as function pointers are not allowed to be stored inside the data section. |
| ... | @@ -1689,36 +1703,37 @@ pub fn updateDeclExports( | ... | @@ -1689,36 +1703,37 @@ pub fn updateDeclExports( |
| 1689 | const decl = mod.declPtr(decl_index); | 1703 | const decl = mod.declPtr(decl_index); |
| 1690 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); | 1704 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| 1691 | const atom = wasm.getAtom(atom_index); | 1705 | const atom = wasm.getAtom(atom_index); |
| 1706 | const gpa = mod.gpa; | ||
| 1692 | 1707 | ||
| 1693 | for (exports) |exp| { | 1708 | for (exports) |exp| { |
| 1694 | if (exp.options.section) |section| { | 1709 | if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section| { |
| 1695 | try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create( | 1710 | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( |
| 1696 | mod.gpa, | 1711 | gpa, |
| 1697 | decl.srcLoc(), | 1712 | decl.srcLoc(mod), |
| 1698 | "Unimplemented: ExportOptions.section '{s}'", | 1713 | "Unimplemented: ExportOptions.section '{s}'", |
| 1699 | .{section}, | 1714 | .{section}, |
| 1700 | )); | 1715 | )); |
| 1701 | continue; | 1716 | continue; |
| 1702 | } | 1717 | } |
| 1703 | 1718 | ||
| 1704 | const export_name = try wasm.string_table.put(wasm.base.allocator, exp.options.name); | 1719 | const export_name = try wasm.string_table.put(wasm.base.allocator, mod.intern_pool.stringToSlice(exp.opts.name)); |
| 1705 | if (wasm.globals.getPtr(export_name)) |existing_loc| { | 1720 | if (wasm.globals.getPtr(export_name)) |existing_loc| { |
| 1706 | if (existing_loc.index == atom.sym_index) continue; | 1721 | if (existing_loc.index == atom.sym_index) continue; |
| 1707 | const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; | 1722 | const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; |
| 1708 | 1723 | ||
| 1709 | const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak; | 1724 | const exp_is_weak = exp.opts.linkage == .Internal or exp.opts.linkage == .Weak; |
| 1710 | // When both the to-be-exported symbol and the already existing symbol | 1725 | // When both the to-be-exported symbol and the already existing symbol |
| 1711 | // are strong symbols, we have a linker error. | 1726 | // are strong symbols, we have a linker error. |
| 1712 | // In the other case we replace one with the other. | 1727 | // In the other case we replace one with the other. |
| 1713 | if (!exp_is_weak and !existing_sym.isWeak()) { | 1728 | if (!exp_is_weak and !existing_sym.isWeak()) { |
| 1714 | try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create( | 1729 | try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( |
| 1715 | mod.gpa, | 1730 | gpa, |
| 1716 | decl.srcLoc(), | 1731 | decl.srcLoc(mod), |
| 1717 | \\LinkError: symbol '{s}' defined multiple times | 1732 | \\LinkError: symbol '{}' defined multiple times |
| 1718 | \\ first definition in '{s}' | 1733 | \\ first definition in '{s}' |
| 1719 | \\ next definition in '{s}' | 1734 | \\ next definition in '{s}' |
| 1720 | , | 1735 | , |
| 1721 | .{ exp.options.name, wasm.name, wasm.name }, | 1736 | .{ exp.opts.name.fmt(&mod.intern_pool), wasm.name, wasm.name }, |
| 1722 | )); | 1737 | )); |
| 1723 | continue; | 1738 | continue; |
| 1724 | } else if (exp_is_weak) { | 1739 | } else if (exp_is_weak) { |
| ... | @@ -1735,7 +1750,7 @@ pub fn updateDeclExports( | ... | @@ -1735,7 +1750,7 @@ pub fn updateDeclExports( |
| 1735 | const exported_atom = wasm.getAtom(exported_atom_index); | 1750 | const exported_atom = wasm.getAtom(exported_atom_index); |
| 1736 | const sym_loc = exported_atom.symbolLoc(); | 1751 | const sym_loc = exported_atom.symbolLoc(); |
| 1737 | const symbol = sym_loc.getSymbol(wasm); | 1752 | const symbol = sym_loc.getSymbol(wasm); |
| 1738 | switch (exp.options.linkage) { | 1753 | switch (exp.opts.linkage) { |
| 1739 | .Internal => { | 1754 | .Internal => { |
| 1740 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 1755 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 1741 | }, | 1756 | }, |
| ... | @@ -1744,9 +1759,9 @@ pub fn updateDeclExports( | ... | @@ -1744,9 +1759,9 @@ pub fn updateDeclExports( |
| 1744 | }, | 1759 | }, |
| 1745 | .Strong => {}, // symbols are strong by default | 1760 | .Strong => {}, // symbols are strong by default |
| 1746 | .LinkOnce => { | 1761 | .LinkOnce => { |
| 1747 | try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create( | 1762 | try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( |
| 1748 | mod.gpa, | 1763 | gpa, |
| 1749 | decl.srcLoc(), | 1764 | decl.srcLoc(mod), |
| 1750 | "Unimplemented: LinkOnce", | 1765 | "Unimplemented: LinkOnce", |
| 1751 | .{}, | 1766 | .{}, |
| 1752 | )); | 1767 | )); |
| ... | @@ -1754,7 +1769,7 @@ pub fn updateDeclExports( | ... | @@ -1754,7 +1769,7 @@ pub fn updateDeclExports( |
| 1754 | }, | 1769 | }, |
| 1755 | } | 1770 | } |
| 1756 | // Ensure the symbol will be exported using the given name | 1771 | // Ensure the symbol will be exported using the given name |
| 1757 | if (!mem.eql(u8, exp.options.name, sym_loc.getName(wasm))) { | 1772 | if (!mod.intern_pool.stringEqlSlice(exp.opts.name, sym_loc.getName(wasm))) { |
| 1758 | try wasm.export_names.put(wasm.base.allocator, sym_loc, export_name); | 1773 | try wasm.export_names.put(wasm.base.allocator, sym_loc, export_name); |
| 1759 | } | 1774 | } |
| 1760 | 1775 | ||
| ... | @@ -1768,7 +1783,7 @@ pub fn updateDeclExports( | ... | @@ -1768,7 +1783,7 @@ pub fn updateDeclExports( |
| 1768 | 1783 | ||
| 1769 | // if the symbol was previously undefined, remove it as an import | 1784 | // if the symbol was previously undefined, remove it as an import |
| 1770 | _ = wasm.imports.remove(sym_loc); | 1785 | _ = wasm.imports.remove(sym_loc); |
| 1771 | _ = wasm.undefs.swapRemove(exp.options.name); | 1786 | _ = wasm.undefs.swapRemove(export_name); |
| 1772 | } | 1787 | } |
| 1773 | } | 1788 | } |
| 1774 | 1789 | ||
| ... | @@ -1792,7 +1807,7 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void { | ... | @@ -1792,7 +1807,7 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void { |
| 1792 | assert(wasm.symbol_atom.remove(local_atom.symbolLoc())); | 1807 | assert(wasm.symbol_atom.remove(local_atom.symbolLoc())); |
| 1793 | } | 1808 | } |
| 1794 | 1809 | ||
| 1795 | if (decl.isExtern()) { | 1810 | if (decl.isExtern(mod)) { |
| 1796 | _ = wasm.imports.remove(atom.symbolLoc()); | 1811 | _ = wasm.imports.remove(atom.symbolLoc()); |
| 1797 | } | 1812 | } |
| 1798 | _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc()); | 1813 | _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc()); |
| ... | @@ -1853,7 +1868,7 @@ pub fn addOrUpdateImport( | ... | @@ -1853,7 +1868,7 @@ pub fn addOrUpdateImport( |
| 1853 | /// Symbol index that is external | 1868 | /// Symbol index that is external |
| 1854 | symbol_index: u32, | 1869 | symbol_index: u32, |
| 1855 | /// Optional library name (i.e. `extern "c" fn foo() void` | 1870 | /// Optional library name (i.e. `extern "c" fn foo() void` |
| 1856 | lib_name: ?[*:0]const u8, | 1871 | lib_name: ?[:0]const u8, |
| 1857 | /// The index of the type that represents the function signature | 1872 | /// The index of the type that represents the function signature |
| 1858 | /// when the extern is a function. When this is null, a data-symbol | 1873 | /// when the extern is a function. When this is null, a data-symbol |
| 1859 | /// is asserted instead. | 1874 | /// is asserted instead. |
| ... | @@ -1864,7 +1879,7 @@ pub fn addOrUpdateImport( | ... | @@ -1864,7 +1879,7 @@ pub fn addOrUpdateImport( |
| 1864 | // Also mangle the name when the lib name is set and not equal to "C" so imports with the same | 1879 | // Also mangle the name when the lib name is set and not equal to "C" so imports with the same |
| 1865 | // name but different module can be resolved correctly. | 1880 | // name but different module can be resolved correctly. |
| 1866 | const mangle_name = lib_name != null and | 1881 | const mangle_name = lib_name != null and |
| 1867 | !std.mem.eql(u8, std.mem.sliceTo(lib_name.?, 0), "c"); | 1882 | !std.mem.eql(u8, lib_name.?, "c"); |
| 1868 | const full_name = if (mangle_name) full_name: { | 1883 | const full_name = if (mangle_name) full_name: { |
| 1869 | break :full_name try std.fmt.allocPrint(wasm.base.allocator, "{s}|{s}", .{ name, lib_name.? }); | 1884 | break :full_name try std.fmt.allocPrint(wasm.base.allocator, "{s}|{s}", .{ name, lib_name.? }); |
| 1870 | } else name; | 1885 | } else name; |
| ... | @@ -1884,13 +1899,13 @@ pub fn addOrUpdateImport( | ... | @@ -1884,13 +1899,13 @@ pub fn addOrUpdateImport( |
| 1884 | const loc: SymbolLoc = .{ .file = null, .index = symbol_index }; | 1899 | const loc: SymbolLoc = .{ .file = null, .index = symbol_index }; |
| 1885 | global_gop.value_ptr.* = loc; | 1900 | global_gop.value_ptr.* = loc; |
| 1886 | try wasm.resolved_symbols.put(wasm.base.allocator, loc, {}); | 1901 | try wasm.resolved_symbols.put(wasm.base.allocator, loc, {}); |
| 1887 | try wasm.undefs.putNoClobber(wasm.base.allocator, full_name, loc); | 1902 | try wasm.undefs.putNoClobber(wasm.base.allocator, decl_name_index, loc); |
| 1888 | } | 1903 | } |
| 1889 | 1904 | ||
| 1890 | if (type_index) |ty_index| { | 1905 | if (type_index) |ty_index| { |
| 1891 | const gop = try wasm.imports.getOrPut(wasm.base.allocator, .{ .index = symbol_index, .file = null }); | 1906 | const gop = try wasm.imports.getOrPut(wasm.base.allocator, .{ .index = symbol_index, .file = null }); |
| 1892 | const module_name = if (lib_name) |l_name| blk: { | 1907 | const module_name = if (lib_name) |l_name| blk: { |
| 1893 | break :blk mem.sliceTo(l_name, 0); | 1908 | break :blk l_name; |
| 1894 | } else wasm.host_name; | 1909 | } else wasm.host_name; |
| 1895 | if (!gop.found_existing) { | 1910 | if (!gop.found_existing) { |
| 1896 | gop.value_ptr.* = .{ | 1911 | gop.value_ptr.* = .{ |
| ... | @@ -2932,8 +2947,9 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { | ... | @@ -2932,8 +2947,9 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { |
| 2932 | 2947 | ||
| 2933 | const atom_index = try wasm.createAtom(); | 2948 | const atom_index = try wasm.createAtom(); |
| 2934 | const atom = wasm.getAtomPtr(atom_index); | 2949 | const atom = wasm.getAtomPtr(atom_index); |
| 2935 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | 2950 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 2936 | atom.alignment = slice_ty.abiAlignment(wasm.base.options.target); | 2951 | const mod = wasm.base.options.module.?; |
| 2952 | atom.alignment = slice_ty.abiAlignment(mod); | ||
| 2937 | const sym_index = atom.sym_index; | 2953 | const sym_index = atom.sym_index; |
| 2938 | 2954 | ||
| 2939 | const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_name_table"); | 2955 | const sym_name = try wasm.string_table.put(wasm.base.allocator, "__zig_err_name_table"); |
| ... | @@ -2985,10 +3001,11 @@ fn populateErrorNameTable(wasm: *Wasm) !void { | ... | @@ -2985,10 +3001,11 @@ fn populateErrorNameTable(wasm: *Wasm) !void { |
| 2985 | // Addend for each relocation to the table | 3001 | // Addend for each relocation to the table |
| 2986 | var addend: u32 = 0; | 3002 | var addend: u32 = 0; |
| 2987 | const mod = wasm.base.options.module.?; | 3003 | const mod = wasm.base.options.module.?; |
| 2988 | for (mod.error_name_list.items) |error_name| { | 3004 | for (mod.global_error_set.keys()) |error_name_nts| { |
| 3005 | const error_name = mod.intern_pool.stringToSlice(error_name_nts); | ||
| 2989 | const len = @intCast(u32, error_name.len + 1); // names are 0-termianted | 3006 | const len = @intCast(u32, error_name.len + 1); // names are 0-termianted |
| 2990 | 3007 | ||
| 2991 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); | 3008 | const slice_ty = Type.slice_const_u8_sentinel_0; |
| 2992 | const offset = @intCast(u32, atom.code.items.len); | 3009 | const offset = @intCast(u32, atom.code.items.len); |
| 2993 | // first we create the data for the slice of the name | 3010 | // first we create the data for the slice of the name |
| 2994 | try atom.code.appendNTimes(wasm.base.allocator, 0, 4); // ptr to name, will be relocated | 3011 | try atom.code.appendNTimes(wasm.base.allocator, 0, 4); // ptr to name, will be relocated |
| ... | @@ -3000,7 +3017,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { | ... | @@ -3000,7 +3017,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { |
| 3000 | .offset = offset, | 3017 | .offset = offset, |
| 3001 | .addend = @intCast(i32, addend), | 3018 | .addend = @intCast(i32, addend), |
| 3002 | }); | 3019 | }); |
| 3003 | atom.size += @intCast(u32, slice_ty.abiSize(wasm.base.options.target)); | 3020 | atom.size += @intCast(u32, slice_ty.abiSize(mod)); |
| 3004 | addend += len; | 3021 | addend += len; |
| 3005 | 3022 | ||
| 3006 | // as we updated the error name table, we now store the actual name within the names atom | 3023 | // as we updated the error name table, we now store the actual name within the names atom |
| ... | @@ -3366,15 +3383,15 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -3366,15 +3383,15 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 3366 | var decl_it = wasm.decls.iterator(); | 3383 | var decl_it = wasm.decls.iterator(); |
| 3367 | while (decl_it.next()) |entry| { | 3384 | while (decl_it.next()) |entry| { |
| 3368 | const decl = mod.declPtr(entry.key_ptr.*); | 3385 | const decl = mod.declPtr(entry.key_ptr.*); |
| 3369 | if (decl.isExtern()) continue; | 3386 | if (decl.isExtern(mod)) continue; |
| 3370 | const atom_index = entry.value_ptr.*; | 3387 | const atom_index = entry.value_ptr.*; |
| 3371 | const atom = wasm.getAtomPtr(atom_index); | 3388 | const atom = wasm.getAtomPtr(atom_index); |
| 3372 | if (decl.ty.zigTypeTag() == .Fn) { | 3389 | if (decl.ty.zigTypeTag(mod) == .Fn) { |
| 3373 | try wasm.parseAtom(atom_index, .function); | 3390 | try wasm.parseAtom(atom_index, .function); |
| 3374 | } else if (decl.getVariable()) |variable| { | 3391 | } else if (decl.getOwnedVariable(mod)) |variable| { |
| 3375 | if (!variable.is_mutable) { | 3392 | if (variable.is_const) { |
| 3376 | try wasm.parseAtom(atom_index, .{ .data = .read_only }); | 3393 | try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 3377 | } else if (variable.init.isUndefDeep()) { | 3394 | } else if (variable.init.toValue().isUndefDeep(mod)) { |
| 3378 | // for safe build modes, we store the atom in the data segment, | 3395 | // for safe build modes, we store the atom in the data segment, |
| 3379 | // whereas for unsafe build modes we store it in bss. | 3396 | // whereas for unsafe build modes we store it in bss. |
| 3380 | const is_initialized = wasm.base.options.optimize_mode == .Debug or | 3397 | const is_initialized = wasm.base.options.optimize_mode == .Debug or |
src/main.zig+5| ... | @@ -569,6 +569,7 @@ const usage_build_generic = | ... | @@ -569,6 +569,7 @@ const usage_build_generic = |
| 569 | \\ --verbose-link Display linker invocations | 569 | \\ --verbose-link Display linker invocations |
| 570 | \\ --verbose-cc Display C compiler invocations | 570 | \\ --verbose-cc Display C compiler invocations |
| 571 | \\ --verbose-air Enable compiler debug output for Zig AIR | 571 | \\ --verbose-air Enable compiler debug output for Zig AIR |
| 572 | \\ --verbose-intern-pool Enable compiler debug output for InternPool | ||
| 572 | \\ --verbose-llvm-ir[=path] Enable compiler debug output for unoptimized LLVM IR | 573 | \\ --verbose-llvm-ir[=path] Enable compiler debug output for unoptimized LLVM IR |
| 573 | \\ --verbose-llvm-bc=[path] Enable compiler debug output for unoptimized LLVM BC | 574 | \\ --verbose-llvm-bc=[path] Enable compiler debug output for unoptimized LLVM BC |
| 574 | \\ --verbose-cimport Enable compiler debug output for C imports | 575 | \\ --verbose-cimport Enable compiler debug output for C imports |
| ... | @@ -735,6 +736,7 @@ fn buildOutputType( | ... | @@ -735,6 +736,7 @@ fn buildOutputType( |
| 735 | var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK"); | 736 | var verbose_link = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_LINK"); |
| 736 | var verbose_cc = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_CC"); | 737 | var verbose_cc = (builtin.os.tag != .wasi or builtin.link_libc) and std.process.hasEnvVarConstant("ZIG_VERBOSE_CC"); |
| 737 | var verbose_air = false; | 738 | var verbose_air = false; |
| 739 | var verbose_intern_pool = false; | ||
| 738 | var verbose_llvm_ir: ?[]const u8 = null; | 740 | var verbose_llvm_ir: ?[]const u8 = null; |
| 739 | var verbose_llvm_bc: ?[]const u8 = null; | 741 | var verbose_llvm_bc: ?[]const u8 = null; |
| 740 | var verbose_cimport = false; | 742 | var verbose_cimport = false; |
| ... | @@ -1460,6 +1462,8 @@ fn buildOutputType( | ... | @@ -1460,6 +1462,8 @@ fn buildOutputType( |
| 1460 | verbose_cc = true; | 1462 | verbose_cc = true; |
| 1461 | } else if (mem.eql(u8, arg, "--verbose-air")) { | 1463 | } else if (mem.eql(u8, arg, "--verbose-air")) { |
| 1462 | verbose_air = true; | 1464 | verbose_air = true; |
| 1465 | } else if (mem.eql(u8, arg, "--verbose-intern-pool")) { | ||
| 1466 | verbose_intern_pool = true; | ||
| 1463 | } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { | 1467 | } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { |
| 1464 | verbose_llvm_ir = "-"; | 1468 | verbose_llvm_ir = "-"; |
| 1465 | } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) { | 1469 | } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) { |
| ... | @@ -3156,6 +3160,7 @@ fn buildOutputType( | ... | @@ -3156,6 +3160,7 @@ fn buildOutputType( |
| 3156 | .verbose_cc = verbose_cc, | 3160 | .verbose_cc = verbose_cc, |
| 3157 | .verbose_link = verbose_link, | 3161 | .verbose_link = verbose_link, |
| 3158 | .verbose_air = verbose_air, | 3162 | .verbose_air = verbose_air, |
| 3163 | .verbose_intern_pool = verbose_intern_pool, | ||
| 3159 | .verbose_llvm_ir = verbose_llvm_ir, | 3164 | .verbose_llvm_ir = verbose_llvm_ir, |
| 3160 | .verbose_llvm_bc = verbose_llvm_bc, | 3165 | .verbose_llvm_bc = verbose_llvm_bc, |
| 3161 | .verbose_cimport = verbose_cimport, | 3166 | .verbose_cimport = verbose_cimport, |
src/print_air.zig+32-37| ... | @@ -7,6 +7,7 @@ const Value = @import("value.zig").Value; | ... | @@ -7,6 +7,7 @@ const Value = @import("value.zig").Value; |
| 7 | const Type = @import("type.zig").Type; | 7 | const Type = @import("type.zig").Type; |
| 8 | const Air = @import("Air.zig"); | 8 | const Air = @import("Air.zig"); |
| 9 | const Liveness = @import("Liveness.zig"); | 9 | const Liveness = @import("Liveness.zig"); |
| 10 | const InternPool = @import("InternPool.zig"); | ||
| 10 | 11 | ||
| 11 | pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) void { | 12 | pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) void { |
| 12 | const instruction_bytes = air.instructions.len * | 13 | const instruction_bytes = air.instructions.len * |
| ... | @@ -14,12 +15,11 @@ pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) vo | ... | @@ -14,12 +15,11 @@ pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) vo |
| 14 | // the debug safety tag but we want to measure release size. | 15 | // the debug safety tag but we want to measure release size. |
| 15 | (@sizeOf(Air.Inst.Tag) + 8); | 16 | (@sizeOf(Air.Inst.Tag) + 8); |
| 16 | const extra_bytes = air.extra.len * @sizeOf(u32); | 17 | const extra_bytes = air.extra.len * @sizeOf(u32); |
| 17 | const values_bytes = air.values.len * @sizeOf(Value); | ||
| 18 | const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0; | 18 | const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0; |
| 19 | const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0; | 19 | const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0; |
| 20 | const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0; | 20 | const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0; |
| 21 | const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes + | 21 | const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes + |
| 22 | values_bytes + @sizeOf(Liveness) + liveness_extra_bytes + | 22 | @sizeOf(Liveness) + liveness_extra_bytes + |
| 23 | liveness_special_bytes + tomb_bytes; | 23 | liveness_special_bytes + tomb_bytes; |
| 24 | 24 | ||
| 25 | // zig fmt: off | 25 | // zig fmt: off |
| ... | @@ -27,7 +27,6 @@ pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) vo | ... | @@ -27,7 +27,6 @@ pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) vo |
| 27 | \\# Total AIR+Liveness bytes: {} | 27 | \\# Total AIR+Liveness bytes: {} |
| 28 | \\# AIR Instructions: {d} ({}) | 28 | \\# AIR Instructions: {d} ({}) |
| 29 | \\# AIR Extra Data: {d} ({}) | 29 | \\# AIR Extra Data: {d} ({}) |
| 30 | \\# AIR Values Bytes: {d} ({}) | ||
| 31 | \\# Liveness tomb_bits: {} | 30 | \\# Liveness tomb_bits: {} |
| 32 | \\# Liveness Extra Data: {d} ({}) | 31 | \\# Liveness Extra Data: {d} ({}) |
| 33 | \\# Liveness special table: {d} ({}) | 32 | \\# Liveness special table: {d} ({}) |
| ... | @@ -36,7 +35,6 @@ pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) vo | ... | @@ -36,7 +35,6 @@ pub fn write(stream: anytype, module: *Module, air: Air, liveness: ?Liveness) vo |
| 36 | fmtIntSizeBin(total_bytes), | 35 | fmtIntSizeBin(total_bytes), |
| 37 | air.instructions.len, fmtIntSizeBin(instruction_bytes), | 36 | air.instructions.len, fmtIntSizeBin(instruction_bytes), |
| 38 | air.extra.len, fmtIntSizeBin(extra_bytes), | 37 | air.extra.len, fmtIntSizeBin(extra_bytes), |
| 39 | air.values.len, fmtIntSizeBin(values_bytes), | ||
| 40 | fmtIntSizeBin(tomb_bytes), | 38 | fmtIntSizeBin(tomb_bytes), |
| 41 | if (liveness) |l| l.extra.len else 0, fmtIntSizeBin(liveness_extra_bytes), | 39 | if (liveness) |l| l.extra.len else 0, fmtIntSizeBin(liveness_extra_bytes), |
| 42 | if (liveness) |l| l.special.count() else 0, fmtIntSizeBin(liveness_special_bytes), | 40 | if (liveness) |l| l.special.count() else 0, fmtIntSizeBin(liveness_special_bytes), |
| ... | @@ -92,14 +90,10 @@ const Writer = struct { | ... | @@ -92,14 +90,10 @@ const Writer = struct { |
| 92 | 90 | ||
| 93 | fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void { | 91 | fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void { |
| 94 | for (w.air.instructions.items(.tag), 0..) |tag, i| { | 92 | for (w.air.instructions.items(.tag), 0..) |tag, i| { |
| 93 | if (tag != .interned) continue; | ||
| 95 | const inst = @intCast(Air.Inst.Index, i); | 94 | const inst = @intCast(Air.Inst.Index, i); |
| 96 | switch (tag) { | 95 | try w.writeInst(s, inst); |
| 97 | .constant, .const_ty => { | 96 | try s.writeByte('\n'); |
| 98 | try w.writeInst(s, inst); | ||
| 99 | try s.writeByte('\n'); | ||
| 100 | }, | ||
| 101 | else => continue, | ||
| 102 | } | ||
| 103 | } | 97 | } |
| 104 | } | 98 | } |
| 105 | 99 | ||
| ... | @@ -225,7 +219,6 @@ const Writer = struct { | ... | @@ -225,7 +219,6 @@ const Writer = struct { |
| 225 | .save_err_return_trace_index, | 219 | .save_err_return_trace_index, |
| 226 | => try w.writeNoOp(s, inst), | 220 | => try w.writeNoOp(s, inst), |
| 227 | 221 | ||
| 228 | .const_ty, | ||
| 229 | .alloc, | 222 | .alloc, |
| 230 | .ret_ptr, | 223 | .ret_ptr, |
| 231 | .err_return_trace, | 224 | .err_return_trace, |
| ... | @@ -304,7 +297,9 @@ const Writer = struct { | ... | @@ -304,7 +297,9 @@ const Writer = struct { |
| 304 | 297 | ||
| 305 | .struct_field_ptr => try w.writeStructField(s, inst), | 298 | .struct_field_ptr => try w.writeStructField(s, inst), |
| 306 | .struct_field_val => try w.writeStructField(s, inst), | 299 | .struct_field_val => try w.writeStructField(s, inst), |
| 307 | .constant => try w.writeConstant(s, inst), | 300 | .inferred_alloc => @panic("TODO"), |
| 301 | .inferred_alloc_comptime => @panic("TODO"), | ||
| 302 | .interned => try w.writeInterned(s, inst), | ||
| 308 | .assembly => try w.writeAssembly(s, inst), | 303 | .assembly => try w.writeAssembly(s, inst), |
| 309 | .dbg_stmt => try w.writeDbgStmt(s, inst), | 304 | .dbg_stmt => try w.writeDbgStmt(s, inst), |
| 310 | 305 | ||
| ... | @@ -364,13 +359,7 @@ const Writer = struct { | ... | @@ -364,13 +359,7 @@ const Writer = struct { |
| 364 | } | 359 | } |
| 365 | 360 | ||
| 366 | fn writeType(w: *Writer, s: anytype, ty: Type) !void { | 361 | fn writeType(w: *Writer, s: anytype, ty: Type) !void { |
| 367 | const t = ty.tag(); | 362 | return ty.print(s, w.module); |
| 368 | switch (t) { | ||
| 369 | .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"), | ||
| 370 | .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"), | ||
| 371 | .generic_poison => try s.writeAll("(generic_poison)"), | ||
| 372 | else => try ty.print(s, w.module), | ||
| 373 | } | ||
| 374 | } | 363 | } |
| 375 | 364 | ||
| 376 | fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 365 | fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| ... | @@ -432,9 +421,10 @@ const Writer = struct { | ... | @@ -432,9 +421,10 @@ const Writer = struct { |
| 432 | } | 421 | } |
| 433 | 422 | ||
| 434 | fn writeAggregateInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 423 | fn writeAggregateInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 424 | const mod = w.module; | ||
| 435 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; | 425 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; |
| 436 | const vector_ty = w.air.getRefType(ty_pl.ty); | 426 | const vector_ty = w.air.getRefType(ty_pl.ty); |
| 437 | const len = @intCast(usize, vector_ty.arrayLen()); | 427 | const len = @intCast(usize, vector_ty.arrayLen(mod)); |
| 438 | const elements = @ptrCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]); | 428 | const elements = @ptrCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]); |
| 439 | 429 | ||
| 440 | try w.writeType(s, vector_ty); | 430 | try w.writeType(s, vector_ty); |
| ... | @@ -511,10 +501,11 @@ const Writer = struct { | ... | @@ -511,10 +501,11 @@ const Writer = struct { |
| 511 | } | 501 | } |
| 512 | 502 | ||
| 513 | fn writeSelect(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 503 | fn writeSelect(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 504 | const mod = w.module; | ||
| 514 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; | 505 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 515 | const extra = w.air.extraData(Air.Bin, pl_op.payload).data; | 506 | const extra = w.air.extraData(Air.Bin, pl_op.payload).data; |
| 516 | 507 | ||
| 517 | const elem_ty = w.air.typeOfIndex(inst).childType(); | 508 | const elem_ty = w.typeOfIndex(inst).childType(mod); |
| 518 | try w.writeType(s, elem_ty); | 509 | try w.writeType(s, elem_ty); |
| 519 | try s.writeAll(", "); | 510 | try s.writeAll(", "); |
| 520 | try w.writeOperand(s, inst, 0, pl_op.operand); | 511 | try w.writeOperand(s, inst, 0, pl_op.operand); |
| ... | @@ -605,12 +596,12 @@ const Writer = struct { | ... | @@ -605,12 +596,12 @@ const Writer = struct { |
| 605 | try s.print(", {d}", .{extra.field_index}); | 596 | try s.print(", {d}", .{extra.field_index}); |
| 606 | } | 597 | } |
| 607 | 598 | ||
| 608 | fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 599 | fn writeInterned(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 609 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; | 600 | const mod = w.module; |
| 610 | const val = w.air.values[ty_pl.payload]; | 601 | const ip_index = w.air.instructions.items(.data)[inst].interned; |
| 611 | const ty = w.air.getRefType(ty_pl.ty); | 602 | const ty = mod.intern_pool.indexToKey(ip_index).typeOf().toType(); |
| 612 | try w.writeType(s, ty); | 603 | try w.writeType(s, ty); |
| 613 | try s.print(", {}", .{val.fmtValue(ty, w.module)}); | 604 | try s.print(", {}", .{ip_index.toValue().fmtValue(ty, mod)}); |
| 614 | } | 605 | } |
| 615 | 606 | ||
| 616 | fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 607 | fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| ... | @@ -621,7 +612,7 @@ const Writer = struct { | ... | @@ -621,7 +612,7 @@ const Writer = struct { |
| 621 | var extra_i: usize = extra.end; | 612 | var extra_i: usize = extra.end; |
| 622 | var op_index: usize = 0; | 613 | var op_index: usize = 0; |
| 623 | 614 | ||
| 624 | const ret_ty = w.air.typeOfIndex(inst); | 615 | const ret_ty = w.typeOfIndex(inst); |
| 625 | try w.writeType(s, ret_ty); | 616 | try w.writeType(s, ret_ty); |
| 626 | 617 | ||
| 627 | if (is_volatile) { | 618 | if (is_volatile) { |
| ... | @@ -692,17 +683,17 @@ const Writer = struct { | ... | @@ -692,17 +683,17 @@ const Writer = struct { |
| 692 | } | 683 | } |
| 693 | 684 | ||
| 694 | fn writeDbgInline(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 685 | fn writeDbgInline(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 695 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; | 686 | const ty_fn = w.air.instructions.items(.data)[inst].ty_fn; |
| 696 | const function = w.air.values[ty_pl.payload].castTag(.function).?.data; | 687 | const func_index = ty_fn.func; |
| 697 | const owner_decl = w.module.declPtr(function.owner_decl); | 688 | const owner_decl = w.module.declPtr(w.module.funcPtr(func_index).owner_decl); |
| 698 | try s.print("{s}", .{owner_decl.name}); | 689 | try s.print("{}", .{owner_decl.name.fmt(&w.module.intern_pool)}); |
| 699 | } | 690 | } |
| 700 | 691 | ||
| 701 | fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 692 | fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 702 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; | 693 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 703 | try w.writeOperand(s, inst, 0, pl_op.operand); | 694 | try w.writeOperand(s, inst, 0, pl_op.operand); |
| 704 | const name = w.air.nullTerminatedString(pl_op.payload); | 695 | const name = w.air.nullTerminatedString(pl_op.payload); |
| 705 | try s.print(", {s}", .{name}); | 696 | try s.print(", \"{}\"", .{std.zig.fmtEscapes(name)}); |
| 706 | } | 697 | } |
| 707 | 698 | ||
| 708 | fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 699 | fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| ... | @@ -965,14 +956,13 @@ const Writer = struct { | ... | @@ -965,14 +956,13 @@ const Writer = struct { |
| 965 | operand: Air.Inst.Ref, | 956 | operand: Air.Inst.Ref, |
| 966 | dies: bool, | 957 | dies: bool, |
| 967 | ) @TypeOf(s).Error!void { | 958 | ) @TypeOf(s).Error!void { |
| 968 | var i: usize = @enumToInt(operand); | 959 | const i = @enumToInt(operand); |
| 969 | 960 | ||
| 970 | if (i < Air.Inst.Ref.typed_value_map.len) { | 961 | if (i < InternPool.static_len) { |
| 971 | return s.print("@{}", .{operand}); | 962 | return s.print("@{}", .{operand}); |
| 972 | } | 963 | } |
| 973 | i -= Air.Inst.Ref.typed_value_map.len; | ||
| 974 | 964 | ||
| 975 | return w.writeInstIndex(s, @intCast(Air.Inst.Index, i), dies); | 965 | return w.writeInstIndex(s, i - InternPool.static_len, dies); |
| 976 | } | 966 | } |
| 977 | 967 | ||
| 978 | fn writeInstIndex( | 968 | fn writeInstIndex( |
| ... | @@ -985,4 +975,9 @@ const Writer = struct { | ... | @@ -985,4 +975,9 @@ const Writer = struct { |
| 985 | try s.print("%{d}", .{inst}); | 975 | try s.print("%{d}", .{inst}); |
| 986 | if (dies) try s.writeByte('!'); | 976 | if (dies) try s.writeByte('!'); |
| 987 | } | 977 | } |
| 978 | |||
| 979 | fn typeOfIndex(w: *Writer, inst: Air.Inst.Index) Type { | ||
| 980 | const mod = w.module; | ||
| 981 | return w.air.typeOfIndex(inst, &mod.intern_pool); | ||
| 982 | } | ||
| 988 | }; | 983 | }; |
src/print_zir.zig+5-9| ... | @@ -3,6 +3,7 @@ const mem = std.mem; | ... | @@ -3,6 +3,7 @@ const mem = std.mem; |
| 3 | const Allocator = std.mem.Allocator; | 3 | const Allocator = std.mem.Allocator; |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const Ast = std.zig.Ast; | 5 | const Ast = std.zig.Ast; |
| 6 | const InternPool = @import("InternPool.zig"); | ||
| 6 | 7 | ||
| 7 | const Zir = @import("Zir.zig"); | 8 | const Zir = @import("Zir.zig"); |
| 8 | const Module = @import("Module.zig"); | 9 | const Module = @import("Module.zig"); |
| ... | @@ -1191,7 +1192,7 @@ const Writer = struct { | ... | @@ -1191,7 +1192,7 @@ const Writer = struct { |
| 1191 | .field => { | 1192 | .field => { |
| 1192 | const field_name = self.code.nullTerminatedString(extra.data.field_name_start); | 1193 | const field_name = self.code.nullTerminatedString(extra.data.field_name_start); |
| 1193 | try self.writeInstRef(stream, extra.data.obj_ptr); | 1194 | try self.writeInstRef(stream, extra.data.obj_ptr); |
| 1194 | try stream.print(", {}", .{std.zig.fmtId(field_name)}); | 1195 | try stream.print(", \"{}\"", .{std.zig.fmtEscapes(field_name)}); |
| 1195 | }, | 1196 | }, |
| 1196 | } | 1197 | } |
| 1197 | try stream.writeAll(", ["); | 1198 | try stream.writeAll(", ["); |
| ... | @@ -2468,14 +2469,9 @@ const Writer = struct { | ... | @@ -2468,14 +2469,9 @@ const Writer = struct { |
| 2468 | } | 2469 | } |
| 2469 | 2470 | ||
| 2470 | fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void { | 2471 | fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void { |
| 2471 | var i: usize = @enumToInt(ref); | 2472 | const i = @enumToInt(ref); |
| 2472 | 2473 | if (i < InternPool.static_len) return stream.print("@{}", .{@intToEnum(InternPool.Index, i)}); | |
| 2473 | if (i < Zir.Inst.Ref.typed_value_map.len) { | 2474 | return self.writeInstIndex(stream, i - InternPool.static_len); |
| 2474 | return stream.print("@{}", .{ref}); | ||
| 2475 | } | ||
| 2476 | i -= Zir.Inst.Ref.typed_value_map.len; | ||
| 2477 | |||
| 2478 | return self.writeInstIndex(stream, @intCast(Zir.Inst.Index, i)); | ||
| 2479 | } | 2475 | } |
| 2480 | 2476 | ||
| 2481 | fn writeInstIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { | 2477 | fn writeInstIndex(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void { |
src/target.zig+11-128| ... | @@ -512,134 +512,6 @@ pub fn needUnwindTables(target: std.Target) bool { | ... | @@ -512,134 +512,6 @@ pub fn needUnwindTables(target: std.Target) bool { |
| 512 | return target.os.tag == .windows; | 512 | return target.os.tag == .windows; |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | pub const AtomicPtrAlignmentError = error{ | ||
| 516 | FloatTooBig, | ||
| 517 | IntTooBig, | ||
| 518 | BadType, | ||
| 519 | }; | ||
| 520 | |||
| 521 | pub const AtomicPtrAlignmentDiagnostics = struct { | ||
| 522 | bits: u16 = undefined, | ||
| 523 | max_bits: u16 = undefined, | ||
| 524 | }; | ||
| 525 | |||
| 526 | /// If ABI alignment of `ty` is OK for atomic operations, returns 0. | ||
| 527 | /// Otherwise returns the alignment required on a pointer for the target | ||
| 528 | /// to perform atomic operations. | ||
| 529 | // TODO this function does not take into account CPU features, which can affect | ||
| 530 | // this value. Audit this! | ||
| 531 | pub fn atomicPtrAlignment( | ||
| 532 | target: std.Target, | ||
| 533 | ty: Type, | ||
| 534 | diags: *AtomicPtrAlignmentDiagnostics, | ||
| 535 | ) AtomicPtrAlignmentError!u32 { | ||
| 536 | const max_atomic_bits: u16 = switch (target.cpu.arch) { | ||
| 537 | .avr, | ||
| 538 | .msp430, | ||
| 539 | .spu_2, | ||
| 540 | => 16, | ||
| 541 | |||
| 542 | .arc, | ||
| 543 | .arm, | ||
| 544 | .armeb, | ||
| 545 | .hexagon, | ||
| 546 | .m68k, | ||
| 547 | .le32, | ||
| 548 | .mips, | ||
| 549 | .mipsel, | ||
| 550 | .nvptx, | ||
| 551 | .powerpc, | ||
| 552 | .powerpcle, | ||
| 553 | .r600, | ||
| 554 | .riscv32, | ||
| 555 | .sparc, | ||
| 556 | .sparcel, | ||
| 557 | .tce, | ||
| 558 | .tcele, | ||
| 559 | .thumb, | ||
| 560 | .thumbeb, | ||
| 561 | .x86, | ||
| 562 | .xcore, | ||
| 563 | .amdil, | ||
| 564 | .hsail, | ||
| 565 | .spir, | ||
| 566 | .kalimba, | ||
| 567 | .lanai, | ||
| 568 | .shave, | ||
| 569 | .wasm32, | ||
| 570 | .renderscript32, | ||
| 571 | .csky, | ||
| 572 | .spirv32, | ||
| 573 | .dxil, | ||
| 574 | .loongarch32, | ||
| 575 | .xtensa, | ||
| 576 | => 32, | ||
| 577 | |||
| 578 | .amdgcn, | ||
| 579 | .bpfel, | ||
| 580 | .bpfeb, | ||
| 581 | .le64, | ||
| 582 | .mips64, | ||
| 583 | .mips64el, | ||
| 584 | .nvptx64, | ||
| 585 | .powerpc64, | ||
| 586 | .powerpc64le, | ||
| 587 | .riscv64, | ||
| 588 | .sparc64, | ||
| 589 | .s390x, | ||
| 590 | .amdil64, | ||
| 591 | .hsail64, | ||
| 592 | .spir64, | ||
| 593 | .wasm64, | ||
| 594 | .renderscript64, | ||
| 595 | .ve, | ||
| 596 | .spirv64, | ||
| 597 | .loongarch64, | ||
| 598 | => 64, | ||
| 599 | |||
| 600 | .aarch64, | ||
| 601 | .aarch64_be, | ||
| 602 | .aarch64_32, | ||
| 603 | => 128, | ||
| 604 | |||
| 605 | .x86_64 => if (std.Target.x86.featureSetHas(target.cpu.features, .cx16)) 128 else 64, | ||
| 606 | }; | ||
| 607 | |||
| 608 | var buffer: Type.Payload.Bits = undefined; | ||
| 609 | |||
| 610 | const int_ty = switch (ty.zigTypeTag()) { | ||
| 611 | .Int => ty, | ||
| 612 | .Enum => ty.intTagType(&buffer), | ||
| 613 | .Float => { | ||
| 614 | const bit_count = ty.floatBits(target); | ||
| 615 | if (bit_count > max_atomic_bits) { | ||
| 616 | diags.* = .{ | ||
| 617 | .bits = bit_count, | ||
| 618 | .max_bits = max_atomic_bits, | ||
| 619 | }; | ||
| 620 | return error.FloatTooBig; | ||
| 621 | } | ||
| 622 | return 0; | ||
| 623 | }, | ||
| 624 | .Bool => return 0, | ||
| 625 | else => { | ||
| 626 | if (ty.isPtrAtRuntime()) return 0; | ||
| 627 | return error.BadType; | ||
| 628 | }, | ||
| 629 | }; | ||
| 630 | |||
| 631 | const bit_count = int_ty.intInfo(target).bits; | ||
| 632 | if (bit_count > max_atomic_bits) { | ||
| 633 | diags.* = .{ | ||
| 634 | .bits = bit_count, | ||
| 635 | .max_bits = max_atomic_bits, | ||
| 636 | }; | ||
| 637 | return error.IntTooBig; | ||
| 638 | } | ||
| 639 | |||
| 640 | return 0; | ||
| 641 | } | ||
| 642 | |||
| 643 | pub fn defaultAddressSpace( | 515 | pub fn defaultAddressSpace( |
| 644 | target: std.Target, | 516 | target: std.Target, |
| 645 | context: enum { | 517 | context: enum { |
| ... | @@ -777,3 +649,14 @@ pub fn compilerRtIntAbbrev(bits: u16) []const u8 { | ... | @@ -777,3 +649,14 @@ pub fn compilerRtIntAbbrev(bits: u16) []const u8 { |
| 777 | else => "o", // Non-standard | 649 | else => "o", // Non-standard |
| 778 | }; | 650 | }; |
| 779 | } | 651 | } |
| 652 | |||
| 653 | pub fn fnCallConvAllowsZigTypes(target: std.Target, cc: std.builtin.CallingConvention) bool { | ||
| 654 | return switch (cc) { | ||
| 655 | .Unspecified, .Async, .Inline => true, | ||
| 656 | // For now we want to authorize PTX kernel to use zig objects, even if | ||
| 657 | // we end up exposing the ABI. The goal is to experiment with more | ||
| 658 | // integrated CPU/GPU code. | ||
| 659 | .Kernel => target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64, | ||
| 660 | else => false, | ||
| 661 | }; | ||
| 662 | } |
src/type.zig+2420-5687| ... | @@ -9,176 +9,42 @@ const log = std.log.scoped(.Type); | ... | @@ -9,176 +9,42 @@ const log = std.log.scoped(.Type); |
| 9 | const target_util = @import("target.zig"); | 9 | const target_util = @import("target.zig"); |
| 10 | const TypedValue = @import("TypedValue.zig"); | 10 | const TypedValue = @import("TypedValue.zig"); |
| 11 | const Sema = @import("Sema.zig"); | 11 | const Sema = @import("Sema.zig"); |
| 12 | const InternPool = @import("InternPool.zig"); | ||
| 12 | 13 | ||
| 13 | const file_struct = @This(); | 14 | /// Both types and values are canonically represented by a single 32-bit integer |
| 14 | 15 | /// which is an index into an `InternPool` data structure. | |
| 15 | /// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication. | 16 | /// This struct abstracts around this storage by providing methods only |
| 16 | /// It's important for this type to be small. | 17 | /// applicable to types rather than values in general. |
| 17 | /// Types are not de-duplicated, which helps with multi-threading since it obviates the requirement | 18 | pub const Type = struct { |
| 18 | /// of obtaining a lock on a global type table, as well as making the | 19 | ip_index: InternPool.Index, |
| 19 | /// garbage collection bookkeeping simpler. | 20 | |
| 20 | /// This union takes advantage of the fact that the first page of memory | 21 | pub fn zigTypeTag(ty: Type, mod: *const Module) std.builtin.TypeId { |
| 21 | /// is unmapped, giving us 4096 possible enum tags that have no payload. | 22 | return ty.zigTypeTagOrPoison(mod) catch unreachable; |
| 22 | pub const Type = extern union { | ||
| 23 | /// If the tag value is less than Tag.no_payload_count, then no pointer | ||
| 24 | /// dereference is needed. | ||
| 25 | tag_if_small_enough: Tag, | ||
| 26 | ptr_otherwise: *Payload, | ||
| 27 | |||
| 28 | pub fn zigTypeTag(ty: Type) std.builtin.TypeId { | ||
| 29 | return ty.zigTypeTagOrPoison() catch unreachable; | ||
| 30 | } | ||
| 31 | |||
| 32 | pub fn zigTypeTagOrPoison(ty: Type) error{GenericPoison}!std.builtin.TypeId { | ||
| 33 | switch (ty.tag()) { | ||
| 34 | .generic_poison => return error.GenericPoison, | ||
| 35 | |||
| 36 | .u1, | ||
| 37 | .u8, | ||
| 38 | .i8, | ||
| 39 | .u16, | ||
| 40 | .i16, | ||
| 41 | .u29, | ||
| 42 | .u32, | ||
| 43 | .i32, | ||
| 44 | .u64, | ||
| 45 | .i64, | ||
| 46 | .u128, | ||
| 47 | .i128, | ||
| 48 | .usize, | ||
| 49 | .isize, | ||
| 50 | .c_char, | ||
| 51 | .c_short, | ||
| 52 | .c_ushort, | ||
| 53 | .c_int, | ||
| 54 | .c_uint, | ||
| 55 | .c_long, | ||
| 56 | .c_ulong, | ||
| 57 | .c_longlong, | ||
| 58 | .c_ulonglong, | ||
| 59 | .int_signed, | ||
| 60 | .int_unsigned, | ||
| 61 | => return .Int, | ||
| 62 | |||
| 63 | .f16, | ||
| 64 | .f32, | ||
| 65 | .f64, | ||
| 66 | .f80, | ||
| 67 | .f128, | ||
| 68 | .c_longdouble, | ||
| 69 | => return .Float, | ||
| 70 | |||
| 71 | .error_set, | ||
| 72 | .error_set_single, | ||
| 73 | .anyerror, | ||
| 74 | .error_set_inferred, | ||
| 75 | .error_set_merged, | ||
| 76 | => return .ErrorSet, | ||
| 77 | |||
| 78 | .anyopaque, .@"opaque" => return .Opaque, | ||
| 79 | .bool => return .Bool, | ||
| 80 | .void => return .Void, | ||
| 81 | .type => return .Type, | ||
| 82 | .comptime_int => return .ComptimeInt, | ||
| 83 | .comptime_float => return .ComptimeFloat, | ||
| 84 | .noreturn => return .NoReturn, | ||
| 85 | .null => return .Null, | ||
| 86 | .undefined => return .Undefined, | ||
| 87 | |||
| 88 | .fn_noreturn_no_args => return .Fn, | ||
| 89 | .fn_void_no_args => return .Fn, | ||
| 90 | .fn_naked_noreturn_no_args => return .Fn, | ||
| 91 | .fn_ccc_void_no_args => return .Fn, | ||
| 92 | .function => return .Fn, | ||
| 93 | |||
| 94 | .array, | ||
| 95 | .array_u8_sentinel_0, | ||
| 96 | .array_u8, | ||
| 97 | .array_sentinel, | ||
| 98 | => return .Array, | ||
| 99 | |||
| 100 | .vector => return .Vector, | ||
| 101 | |||
| 102 | .single_const_pointer_to_comptime_int, | ||
| 103 | .const_slice_u8, | ||
| 104 | .const_slice_u8_sentinel_0, | ||
| 105 | .single_const_pointer, | ||
| 106 | .single_mut_pointer, | ||
| 107 | .many_const_pointer, | ||
| 108 | .many_mut_pointer, | ||
| 109 | .c_const_pointer, | ||
| 110 | .c_mut_pointer, | ||
| 111 | .const_slice, | ||
| 112 | .mut_slice, | ||
| 113 | .pointer, | ||
| 114 | .inferred_alloc_const, | ||
| 115 | .inferred_alloc_mut, | ||
| 116 | .manyptr_u8, | ||
| 117 | .manyptr_const_u8, | ||
| 118 | .manyptr_const_u8_sentinel_0, | ||
| 119 | => return .Pointer, | ||
| 120 | |||
| 121 | .optional, | ||
| 122 | .optional_single_const_pointer, | ||
| 123 | .optional_single_mut_pointer, | ||
| 124 | => return .Optional, | ||
| 125 | .enum_literal => return .EnumLiteral, | ||
| 126 | |||
| 127 | .anyerror_void_error_union, .error_union => return .ErrorUnion, | ||
| 128 | |||
| 129 | .anyframe_T, .@"anyframe" => return .AnyFrame, | ||
| 130 | |||
| 131 | .empty_struct, | ||
| 132 | .empty_struct_literal, | ||
| 133 | .@"struct", | ||
| 134 | .prefetch_options, | ||
| 135 | .export_options, | ||
| 136 | .extern_options, | ||
| 137 | .tuple, | ||
| 138 | .anon_struct, | ||
| 139 | => return .Struct, | ||
| 140 | |||
| 141 | .enum_full, | ||
| 142 | .enum_nonexhaustive, | ||
| 143 | .enum_simple, | ||
| 144 | .enum_numbered, | ||
| 145 | .atomic_order, | ||
| 146 | .atomic_rmw_op, | ||
| 147 | .calling_convention, | ||
| 148 | .address_space, | ||
| 149 | .float_mode, | ||
| 150 | .reduce_op, | ||
| 151 | .modifier, | ||
| 152 | => return .Enum, | ||
| 153 | |||
| 154 | .@"union", | ||
| 155 | .union_safety_tagged, | ||
| 156 | .union_tagged, | ||
| 157 | .type_info, | ||
| 158 | => return .Union, | ||
| 159 | } | ||
| 160 | } | 23 | } |
| 161 | 24 | ||
| 162 | pub fn baseZigTypeTag(self: Type) std.builtin.TypeId { | 25 | pub fn zigTypeTagOrPoison(ty: Type, mod: *const Module) error{GenericPoison}!std.builtin.TypeId { |
| 163 | return switch (self.zigTypeTag()) { | 26 | return mod.intern_pool.zigTypeTagOrPoison(ty.toIntern()); |
| 164 | .ErrorUnion => self.errorUnionPayload().baseZigTypeTag(), | 27 | } |
| 28 | |||
| 29 | pub fn baseZigTypeTag(self: Type, mod: *Module) std.builtin.TypeId { | ||
| 30 | return switch (self.zigTypeTag(mod)) { | ||
| 31 | .ErrorUnion => self.errorUnionPayload(mod).baseZigTypeTag(mod), | ||
| 165 | .Optional => { | 32 | .Optional => { |
| 166 | var buf: Payload.ElemType = undefined; | 33 | return self.optionalChild(mod).baseZigTypeTag(mod); |
| 167 | return self.optionalChild(&buf).baseZigTypeTag(); | ||
| 168 | }, | 34 | }, |
| 169 | else => |t| t, | 35 | else => |t| t, |
| 170 | }; | 36 | }; |
| 171 | } | 37 | } |
| 172 | 38 | ||
| 173 | pub fn isSelfComparable(ty: Type, is_equality_cmp: bool) bool { | 39 | pub fn isSelfComparable(ty: Type, mod: *const Module, is_equality_cmp: bool) bool { |
| 174 | return switch (ty.zigTypeTag()) { | 40 | return switch (ty.zigTypeTag(mod)) { |
| 175 | .Int, | 41 | .Int, |
| 176 | .Float, | 42 | .Float, |
| 177 | .ComptimeFloat, | 43 | .ComptimeFloat, |
| 178 | .ComptimeInt, | 44 | .ComptimeInt, |
| 179 | => true, | 45 | => true, |
| 180 | 46 | ||
| 181 | .Vector => ty.elemType2().isSelfComparable(is_equality_cmp), | 47 | .Vector => ty.elemType2(mod).isSelfComparable(mod, is_equality_cmp), |
| 182 | 48 | ||
| 183 | .Bool, | 49 | .Bool, |
| 184 | .Type, | 50 | .Type, |
| ... | @@ -201,1317 +67,70 @@ pub const Type = extern union { | ... | @@ -201,1317 +67,70 @@ pub const Type = extern union { |
| 201 | .Frame, | 67 | .Frame, |
| 202 | => false, | 68 | => false, |
| 203 | 69 | ||
| 204 | .Pointer => !ty.isSlice() and (is_equality_cmp or ty.isCPtr()), | 70 | .Pointer => !ty.isSlice(mod) and (is_equality_cmp or ty.isCPtr(mod)), |
| 205 | .Optional => { | 71 | .Optional => { |
| 206 | if (!is_equality_cmp) return false; | 72 | if (!is_equality_cmp) return false; |
| 207 | var buf: Payload.ElemType = undefined; | 73 | return ty.optionalChild(mod).isSelfComparable(mod, is_equality_cmp); |
| 208 | return ty.optionalChild(&buf).isSelfComparable(is_equality_cmp); | ||
| 209 | }, | 74 | }, |
| 210 | }; | 75 | }; |
| 211 | } | 76 | } |
| 212 | 77 | ||
| 213 | pub fn initTag(comptime small_tag: Tag) Type { | ||
| 214 | comptime assert(@enumToInt(small_tag) < Tag.no_payload_count); | ||
| 215 | return .{ .tag_if_small_enough = small_tag }; | ||
| 216 | } | ||
| 217 | |||
| 218 | pub fn initPayload(payload: *Payload) Type { | ||
| 219 | assert(@enumToInt(payload.tag) >= Tag.no_payload_count); | ||
| 220 | return .{ .ptr_otherwise = payload }; | ||
| 221 | } | ||
| 222 | |||
| 223 | pub fn tag(self: Type) Tag { | ||
| 224 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) { | ||
| 225 | return self.tag_if_small_enough; | ||
| 226 | } else { | ||
| 227 | return self.ptr_otherwise.tag; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | /// Prefer `castTag` to this. | ||
| 232 | pub fn cast(self: Type, comptime T: type) ?*T { | ||
| 233 | if (@hasField(T, "base_tag")) { | ||
| 234 | return self.castTag(T.base_tag); | ||
| 235 | } | ||
| 236 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) { | ||
| 237 | return null; | ||
| 238 | } | ||
| 239 | inline for (@typeInfo(Tag).Enum.fields) |field| { | ||
| 240 | if (field.value < Tag.no_payload_count) | ||
| 241 | continue; | ||
| 242 | const t = @intToEnum(Tag, field.value); | ||
| 243 | if (self.ptr_otherwise.tag == t) { | ||
| 244 | if (T == t.Type()) { | ||
| 245 | return @fieldParentPtr(T, "base", self.ptr_otherwise); | ||
| 246 | } | ||
| 247 | return null; | ||
| 248 | } | ||
| 249 | } | ||
| 250 | unreachable; | ||
| 251 | } | ||
| 252 | |||
| 253 | pub fn castTag(self: Type, comptime t: Tag) ?*t.Type() { | ||
| 254 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) | ||
| 255 | return null; | ||
| 256 | |||
| 257 | if (self.ptr_otherwise.tag == t) | ||
| 258 | return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise); | ||
| 259 | |||
| 260 | return null; | ||
| 261 | } | ||
| 262 | |||
| 263 | pub fn castPointer(self: Type) ?*Payload.ElemType { | ||
| 264 | return switch (self.tag()) { | ||
| 265 | .single_const_pointer, | ||
| 266 | .single_mut_pointer, | ||
| 267 | .many_const_pointer, | ||
| 268 | .many_mut_pointer, | ||
| 269 | .c_const_pointer, | ||
| 270 | .c_mut_pointer, | ||
| 271 | .const_slice, | ||
| 272 | .mut_slice, | ||
| 273 | .optional_single_const_pointer, | ||
| 274 | .optional_single_mut_pointer, | ||
| 275 | .manyptr_u8, | ||
| 276 | .manyptr_const_u8, | ||
| 277 | .manyptr_const_u8_sentinel_0, | ||
| 278 | => self.cast(Payload.ElemType), | ||
| 279 | |||
| 280 | .inferred_alloc_const => unreachable, | ||
| 281 | .inferred_alloc_mut => unreachable, | ||
| 282 | |||
| 283 | else => null, | ||
| 284 | }; | ||
| 285 | } | ||
| 286 | |||
| 287 | /// If it is a function pointer, returns the function type. Otherwise returns null. | 78 | /// If it is a function pointer, returns the function type. Otherwise returns null. |
| 288 | pub fn castPtrToFn(ty: Type) ?Type { | 79 | pub fn castPtrToFn(ty: Type, mod: *const Module) ?Type { |
| 289 | if (ty.zigTypeTag() != .Pointer) return null; | 80 | if (ty.zigTypeTag(mod) != .Pointer) return null; |
| 290 | const elem_ty = ty.childType(); | 81 | const elem_ty = ty.childType(mod); |
| 291 | if (elem_ty.zigTypeTag() != .Fn) return null; | 82 | if (elem_ty.zigTypeTag(mod) != .Fn) return null; |
| 292 | return elem_ty; | 83 | return elem_ty; |
| 293 | } | 84 | } |
| 294 | 85 | ||
| 295 | pub fn ptrIsMutable(ty: Type) bool { | 86 | /// Asserts the type is a pointer. |
| 296 | return switch (ty.tag()) { | 87 | pub fn ptrIsMutable(ty: Type, mod: *const Module) bool { |
| 297 | .single_const_pointer_to_comptime_int, | 88 | return !mod.intern_pool.indexToKey(ty.toIntern()).ptr_type.flags.is_const; |
| 298 | .const_slice_u8, | ||
| 299 | .const_slice_u8_sentinel_0, | ||
| 300 | .single_const_pointer, | ||
| 301 | .many_const_pointer, | ||
| 302 | .manyptr_const_u8, | ||
| 303 | .manyptr_const_u8_sentinel_0, | ||
| 304 | .c_const_pointer, | ||
| 305 | .const_slice, | ||
| 306 | => false, | ||
| 307 | |||
| 308 | .single_mut_pointer, | ||
| 309 | .many_mut_pointer, | ||
| 310 | .manyptr_u8, | ||
| 311 | .c_mut_pointer, | ||
| 312 | .mut_slice, | ||
| 313 | => true, | ||
| 314 | |||
| 315 | .pointer => ty.castTag(.pointer).?.data.mutable, | ||
| 316 | |||
| 317 | else => unreachable, | ||
| 318 | }; | ||
| 319 | } | ||
| 320 | |||
| 321 | pub const ArrayInfo = struct { elem_type: Type, sentinel: ?Value = null, len: u64 }; | ||
| 322 | pub fn arrayInfo(self: Type) ArrayInfo { | ||
| 323 | return .{ | ||
| 324 | .len = self.arrayLen(), | ||
| 325 | .sentinel = self.sentinel(), | ||
| 326 | .elem_type = self.elemType(), | ||
| 327 | }; | ||
| 328 | } | 89 | } |
| 329 | 90 | ||
| 330 | pub fn ptrInfo(self: Type) Payload.Pointer { | 91 | pub const ArrayInfo = struct { |
| 331 | switch (self.tag()) { | 92 | elem_type: Type, |
| 332 | .single_const_pointer_to_comptime_int => return .{ .data = .{ | 93 | sentinel: ?Value = null, |
| 333 | .pointee_type = Type.initTag(.comptime_int), | 94 | len: u64, |
| 334 | .sentinel = null, | ||
| 335 | .@"align" = 0, | ||
| 336 | .@"addrspace" = .generic, | ||
| 337 | .bit_offset = 0, | ||
| 338 | .host_size = 0, | ||
| 339 | .@"allowzero" = false, | ||
| 340 | .mutable = false, | ||
| 341 | .@"volatile" = false, | ||
| 342 | .size = .One, | ||
| 343 | } }, | ||
| 344 | .const_slice_u8 => return .{ .data = .{ | ||
| 345 | .pointee_type = Type.initTag(.u8), | ||
| 346 | .sentinel = null, | ||
| 347 | .@"align" = 0, | ||
| 348 | .@"addrspace" = .generic, | ||
| 349 | .bit_offset = 0, | ||
| 350 | .host_size = 0, | ||
| 351 | .@"allowzero" = false, | ||
| 352 | .mutable = false, | ||
| 353 | .@"volatile" = false, | ||
| 354 | .size = .Slice, | ||
| 355 | } }, | ||
| 356 | .const_slice_u8_sentinel_0 => return .{ .data = .{ | ||
| 357 | .pointee_type = Type.initTag(.u8), | ||
| 358 | .sentinel = Value.zero, | ||
| 359 | .@"align" = 0, | ||
| 360 | .@"addrspace" = .generic, | ||
| 361 | .bit_offset = 0, | ||
| 362 | .host_size = 0, | ||
| 363 | .@"allowzero" = false, | ||
| 364 | .mutable = false, | ||
| 365 | .@"volatile" = false, | ||
| 366 | .size = .Slice, | ||
| 367 | } }, | ||
| 368 | .single_const_pointer => return .{ .data = .{ | ||
| 369 | .pointee_type = self.castPointer().?.data, | ||
| 370 | .sentinel = null, | ||
| 371 | .@"align" = 0, | ||
| 372 | .@"addrspace" = .generic, | ||
| 373 | .bit_offset = 0, | ||
| 374 | .host_size = 0, | ||
| 375 | .@"allowzero" = false, | ||
| 376 | .mutable = false, | ||
| 377 | .@"volatile" = false, | ||
| 378 | .size = .One, | ||
| 379 | } }, | ||
| 380 | .single_mut_pointer => return .{ .data = .{ | ||
| 381 | .pointee_type = self.castPointer().?.data, | ||
| 382 | .sentinel = null, | ||
| 383 | .@"align" = 0, | ||
| 384 | .@"addrspace" = .generic, | ||
| 385 | .bit_offset = 0, | ||
| 386 | .host_size = 0, | ||
| 387 | .@"allowzero" = false, | ||
| 388 | .mutable = true, | ||
| 389 | .@"volatile" = false, | ||
| 390 | .size = .One, | ||
| 391 | } }, | ||
| 392 | .many_const_pointer => return .{ .data = .{ | ||
| 393 | .pointee_type = self.castPointer().?.data, | ||
| 394 | .sentinel = null, | ||
| 395 | .@"align" = 0, | ||
| 396 | .@"addrspace" = .generic, | ||
| 397 | .bit_offset = 0, | ||
| 398 | .host_size = 0, | ||
| 399 | .@"allowzero" = false, | ||
| 400 | .mutable = false, | ||
| 401 | .@"volatile" = false, | ||
| 402 | .size = .Many, | ||
| 403 | } }, | ||
| 404 | .manyptr_const_u8 => return .{ .data = .{ | ||
| 405 | .pointee_type = Type.initTag(.u8), | ||
| 406 | .sentinel = null, | ||
| 407 | .@"align" = 0, | ||
| 408 | .@"addrspace" = .generic, | ||
| 409 | .bit_offset = 0, | ||
| 410 | .host_size = 0, | ||
| 411 | .@"allowzero" = false, | ||
| 412 | .mutable = false, | ||
| 413 | .@"volatile" = false, | ||
| 414 | .size = .Many, | ||
| 415 | } }, | ||
| 416 | .manyptr_const_u8_sentinel_0 => return .{ .data = .{ | ||
| 417 | .pointee_type = Type.initTag(.u8), | ||
| 418 | .sentinel = Value.zero, | ||
| 419 | .@"align" = 0, | ||
| 420 | .@"addrspace" = .generic, | ||
| 421 | .bit_offset = 0, | ||
| 422 | .host_size = 0, | ||
| 423 | .@"allowzero" = false, | ||
| 424 | .mutable = false, | ||
| 425 | .@"volatile" = false, | ||
| 426 | .size = .Many, | ||
| 427 | } }, | ||
| 428 | .many_mut_pointer => return .{ .data = .{ | ||
| 429 | .pointee_type = self.castPointer().?.data, | ||
| 430 | .sentinel = null, | ||
| 431 | .@"align" = 0, | ||
| 432 | .@"addrspace" = .generic, | ||
| 433 | .bit_offset = 0, | ||
| 434 | .host_size = 0, | ||
| 435 | .@"allowzero" = false, | ||
| 436 | .mutable = true, | ||
| 437 | .@"volatile" = false, | ||
| 438 | .size = .Many, | ||
| 439 | } }, | ||
| 440 | .manyptr_u8 => return .{ .data = .{ | ||
| 441 | .pointee_type = Type.initTag(.u8), | ||
| 442 | .sentinel = null, | ||
| 443 | .@"align" = 0, | ||
| 444 | .@"addrspace" = .generic, | ||
| 445 | .bit_offset = 0, | ||
| 446 | .host_size = 0, | ||
| 447 | .@"allowzero" = false, | ||
| 448 | .mutable = true, | ||
| 449 | .@"volatile" = false, | ||
| 450 | .size = .Many, | ||
| 451 | } }, | ||
| 452 | .c_const_pointer => return .{ .data = .{ | ||
| 453 | .pointee_type = self.castPointer().?.data, | ||
| 454 | .sentinel = null, | ||
| 455 | .@"align" = 0, | ||
| 456 | .@"addrspace" = .generic, | ||
| 457 | .bit_offset = 0, | ||
| 458 | .host_size = 0, | ||
| 459 | .@"allowzero" = true, | ||
| 460 | .mutable = false, | ||
| 461 | .@"volatile" = false, | ||
| 462 | .size = .C, | ||
| 463 | } }, | ||
| 464 | .c_mut_pointer => return .{ .data = .{ | ||
| 465 | .pointee_type = self.castPointer().?.data, | ||
| 466 | .sentinel = null, | ||
| 467 | .@"align" = 0, | ||
| 468 | .@"addrspace" = .generic, | ||
| 469 | .bit_offset = 0, | ||
| 470 | .host_size = 0, | ||
| 471 | .@"allowzero" = true, | ||
| 472 | .mutable = true, | ||
| 473 | .@"volatile" = false, | ||
| 474 | .size = .C, | ||
| 475 | } }, | ||
| 476 | .const_slice => return .{ .data = .{ | ||
| 477 | .pointee_type = self.castPointer().?.data, | ||
| 478 | .sentinel = null, | ||
| 479 | .@"align" = 0, | ||
| 480 | .@"addrspace" = .generic, | ||
| 481 | .bit_offset = 0, | ||
| 482 | .host_size = 0, | ||
| 483 | .@"allowzero" = false, | ||
| 484 | .mutable = false, | ||
| 485 | .@"volatile" = false, | ||
| 486 | .size = .Slice, | ||
| 487 | } }, | ||
| 488 | .mut_slice => return .{ .data = .{ | ||
| 489 | .pointee_type = self.castPointer().?.data, | ||
| 490 | .sentinel = null, | ||
| 491 | .@"align" = 0, | ||
| 492 | .@"addrspace" = .generic, | ||
| 493 | .bit_offset = 0, | ||
| 494 | .host_size = 0, | ||
| 495 | .@"allowzero" = false, | ||
| 496 | .mutable = true, | ||
| 497 | .@"volatile" = false, | ||
| 498 | .size = .Slice, | ||
| 499 | } }, | ||
| 500 | |||
| 501 | .pointer => return self.castTag(.pointer).?.*, | ||
| 502 | |||
| 503 | .optional_single_mut_pointer => return .{ .data = .{ | ||
| 504 | .pointee_type = self.castPointer().?.data, | ||
| 505 | .sentinel = null, | ||
| 506 | .@"align" = 0, | ||
| 507 | .@"addrspace" = .generic, | ||
| 508 | .bit_offset = 0, | ||
| 509 | .host_size = 0, | ||
| 510 | .@"allowzero" = false, | ||
| 511 | .mutable = true, | ||
| 512 | .@"volatile" = false, | ||
| 513 | .size = .One, | ||
| 514 | } }, | ||
| 515 | .optional_single_const_pointer => return .{ .data = .{ | ||
| 516 | .pointee_type = self.castPointer().?.data, | ||
| 517 | .sentinel = null, | ||
| 518 | .@"align" = 0, | ||
| 519 | .@"addrspace" = .generic, | ||
| 520 | .bit_offset = 0, | ||
| 521 | .host_size = 0, | ||
| 522 | .@"allowzero" = false, | ||
| 523 | .mutable = false, | ||
| 524 | .@"volatile" = false, | ||
| 525 | .size = .One, | ||
| 526 | } }, | ||
| 527 | .optional => { | ||
| 528 | var buf: Payload.ElemType = undefined; | ||
| 529 | const child_type = self.optionalChild(&buf); | ||
| 530 | return child_type.ptrInfo(); | ||
| 531 | }, | ||
| 532 | |||
| 533 | else => unreachable, | ||
| 534 | } | ||
| 535 | } | ||
| 536 | |||
| 537 | pub fn eql(a: Type, b: Type, mod: *Module) bool { | ||
| 538 | // As a shortcut, if the small tags / addresses match, we're done. | ||
| 539 | if (a.tag_if_small_enough == b.tag_if_small_enough) return true; | ||
| 540 | |||
| 541 | switch (a.tag()) { | ||
| 542 | .generic_poison => unreachable, | ||
| 543 | |||
| 544 | // Detect that e.g. u64 != usize, even if the bits match on a particular target. | ||
| 545 | .usize, | ||
| 546 | .isize, | ||
| 547 | .c_char, | ||
| 548 | .c_short, | ||
| 549 | .c_ushort, | ||
| 550 | .c_int, | ||
| 551 | .c_uint, | ||
| 552 | .c_long, | ||
| 553 | .c_ulong, | ||
| 554 | .c_longlong, | ||
| 555 | .c_ulonglong, | ||
| 556 | |||
| 557 | .f16, | ||
| 558 | .f32, | ||
| 559 | .f64, | ||
| 560 | .f80, | ||
| 561 | .f128, | ||
| 562 | .c_longdouble, | ||
| 563 | |||
| 564 | .bool, | ||
| 565 | .void, | ||
| 566 | .type, | ||
| 567 | .comptime_int, | ||
| 568 | .comptime_float, | ||
| 569 | .noreturn, | ||
| 570 | .null, | ||
| 571 | .undefined, | ||
| 572 | .anyopaque, | ||
| 573 | .@"anyframe", | ||
| 574 | .enum_literal, | ||
| 575 | => |a_tag| { | ||
| 576 | assert(a_tag != b.tag()); // because of the comparison at the top of the function. | ||
| 577 | return false; | ||
| 578 | }, | ||
| 579 | |||
| 580 | .u1, | ||
| 581 | .u8, | ||
| 582 | .i8, | ||
| 583 | .u16, | ||
| 584 | .i16, | ||
| 585 | .u29, | ||
| 586 | .u32, | ||
| 587 | .i32, | ||
| 588 | .u64, | ||
| 589 | .i64, | ||
| 590 | .u128, | ||
| 591 | .i128, | ||
| 592 | .int_signed, | ||
| 593 | .int_unsigned, | ||
| 594 | => { | ||
| 595 | if (b.zigTypeTag() != .Int) return false; | ||
| 596 | if (b.isNamedInt()) return false; | ||
| 597 | |||
| 598 | // Arbitrary sized integers. The target will not be branched upon, | ||
| 599 | // because we handled target-dependent cases above. | ||
| 600 | const info_a = a.intInfo(@as(Target, undefined)); | ||
| 601 | const info_b = b.intInfo(@as(Target, undefined)); | ||
| 602 | return info_a.signedness == info_b.signedness and info_a.bits == info_b.bits; | ||
| 603 | }, | ||
| 604 | |||
| 605 | .error_set_inferred => { | ||
| 606 | // Inferred error sets are only equal if both are inferred | ||
| 607 | // and they share the same pointer. | ||
| 608 | const a_ies = a.castTag(.error_set_inferred).?.data; | ||
| 609 | const b_ies = (b.castTag(.error_set_inferred) orelse return false).data; | ||
| 610 | return a_ies == b_ies; | ||
| 611 | }, | ||
| 612 | |||
| 613 | .anyerror => { | ||
| 614 | return b.tag() == .anyerror; | ||
| 615 | }, | ||
| 616 | |||
| 617 | .error_set, | ||
| 618 | .error_set_single, | ||
| 619 | .error_set_merged, | ||
| 620 | => { | ||
| 621 | switch (b.tag()) { | ||
| 622 | .error_set, .error_set_single, .error_set_merged => {}, | ||
| 623 | else => return false, | ||
| 624 | } | ||
| 625 | |||
| 626 | // Two resolved sets match if their error set names match. | ||
| 627 | // Since they are pre-sorted we compare them element-wise. | ||
| 628 | const a_set = a.errorSetNames(); | ||
| 629 | const b_set = b.errorSetNames(); | ||
| 630 | if (a_set.len != b_set.len) return false; | ||
| 631 | for (a_set, 0..) |a_item, i| { | ||
| 632 | const b_item = b_set[i]; | ||
| 633 | if (!std.mem.eql(u8, a_item, b_item)) return false; | ||
| 634 | } | ||
| 635 | return true; | ||
| 636 | }, | ||
| 637 | |||
| 638 | .@"opaque" => { | ||
| 639 | const opaque_obj_a = a.castTag(.@"opaque").?.data; | ||
| 640 | const opaque_obj_b = (b.castTag(.@"opaque") orelse return false).data; | ||
| 641 | return opaque_obj_a == opaque_obj_b; | ||
| 642 | }, | ||
| 643 | |||
| 644 | .fn_noreturn_no_args, | ||
| 645 | .fn_void_no_args, | ||
| 646 | .fn_naked_noreturn_no_args, | ||
| 647 | .fn_ccc_void_no_args, | ||
| 648 | .function, | ||
| 649 | => { | ||
| 650 | if (b.zigTypeTag() != .Fn) return false; | ||
| 651 | |||
| 652 | const a_info = a.fnInfo(); | ||
| 653 | const b_info = b.fnInfo(); | ||
| 654 | |||
| 655 | if (a_info.return_type.tag() != .generic_poison and | ||
| 656 | b_info.return_type.tag() != .generic_poison and | ||
| 657 | !eql(a_info.return_type, b_info.return_type, mod)) | ||
| 658 | return false; | ||
| 659 | |||
| 660 | if (a_info.is_var_args != b_info.is_var_args) | ||
| 661 | return false; | ||
| 662 | |||
| 663 | if (a_info.is_generic != b_info.is_generic) | ||
| 664 | return false; | ||
| 665 | |||
| 666 | if (a_info.is_noinline != b_info.is_noinline) | ||
| 667 | return false; | ||
| 668 | |||
| 669 | if (a_info.noalias_bits != b_info.noalias_bits) | ||
| 670 | return false; | ||
| 671 | |||
| 672 | if (!a_info.cc_is_generic and a_info.cc != b_info.cc) | ||
| 673 | return false; | ||
| 674 | |||
| 675 | if (!a_info.align_is_generic and a_info.alignment != b_info.alignment) | ||
| 676 | return false; | ||
| 677 | |||
| 678 | if (a_info.param_types.len != b_info.param_types.len) | ||
| 679 | return false; | ||
| 680 | |||
| 681 | for (a_info.param_types, 0..) |a_param_ty, i| { | ||
| 682 | const b_param_ty = b_info.param_types[i]; | ||
| 683 | if (a_info.comptime_params[i] != b_info.comptime_params[i]) | ||
| 684 | return false; | ||
| 685 | |||
| 686 | if (a_param_ty.tag() == .generic_poison) continue; | ||
| 687 | if (b_param_ty.tag() == .generic_poison) continue; | ||
| 688 | |||
| 689 | if (!eql(a_param_ty, b_param_ty, mod)) | ||
| 690 | return false; | ||
| 691 | } | ||
| 692 | |||
| 693 | return true; | ||
| 694 | }, | ||
| 695 | |||
| 696 | .array, | ||
| 697 | .array_u8_sentinel_0, | ||
| 698 | .array_u8, | ||
| 699 | .array_sentinel, | ||
| 700 | .vector, | ||
| 701 | => { | ||
| 702 | if (a.zigTypeTag() != b.zigTypeTag()) return false; | ||
| 703 | |||
| 704 | if (a.arrayLen() != b.arrayLen()) | ||
| 705 | return false; | ||
| 706 | const elem_ty = a.elemType(); | ||
| 707 | if (!elem_ty.eql(b.elemType(), mod)) | ||
| 708 | return false; | ||
| 709 | const sentinel_a = a.sentinel(); | ||
| 710 | const sentinel_b = b.sentinel(); | ||
| 711 | if (sentinel_a) |sa| { | ||
| 712 | if (sentinel_b) |sb| { | ||
| 713 | return sa.eql(sb, elem_ty, mod); | ||
| 714 | } else { | ||
| 715 | return false; | ||
| 716 | } | ||
| 717 | } else { | ||
| 718 | return sentinel_b == null; | ||
| 719 | } | ||
| 720 | }, | ||
| 721 | |||
| 722 | .single_const_pointer_to_comptime_int, | ||
| 723 | .const_slice_u8, | ||
| 724 | .const_slice_u8_sentinel_0, | ||
| 725 | .single_const_pointer, | ||
| 726 | .single_mut_pointer, | ||
| 727 | .many_const_pointer, | ||
| 728 | .many_mut_pointer, | ||
| 729 | .c_const_pointer, | ||
| 730 | .c_mut_pointer, | ||
| 731 | .const_slice, | ||
| 732 | .mut_slice, | ||
| 733 | .pointer, | ||
| 734 | .inferred_alloc_const, | ||
| 735 | .inferred_alloc_mut, | ||
| 736 | .manyptr_u8, | ||
| 737 | .manyptr_const_u8, | ||
| 738 | .manyptr_const_u8_sentinel_0, | ||
| 739 | => { | ||
| 740 | if (b.zigTypeTag() != .Pointer) return false; | ||
| 741 | |||
| 742 | const info_a = a.ptrInfo().data; | ||
| 743 | const info_b = b.ptrInfo().data; | ||
| 744 | if (!info_a.pointee_type.eql(info_b.pointee_type, mod)) | ||
| 745 | return false; | ||
| 746 | if (info_a.@"align" != info_b.@"align") | ||
| 747 | return false; | ||
| 748 | if (info_a.@"addrspace" != info_b.@"addrspace") | ||
| 749 | return false; | ||
| 750 | if (info_a.bit_offset != info_b.bit_offset) | ||
| 751 | return false; | ||
| 752 | if (info_a.host_size != info_b.host_size) | ||
| 753 | return false; | ||
| 754 | if (info_a.vector_index != info_b.vector_index) | ||
| 755 | return false; | ||
| 756 | if (info_a.@"allowzero" != info_b.@"allowzero") | ||
| 757 | return false; | ||
| 758 | if (info_a.mutable != info_b.mutable) | ||
| 759 | return false; | ||
| 760 | if (info_a.@"volatile" != info_b.@"volatile") | ||
| 761 | return false; | ||
| 762 | if (info_a.size != info_b.size) | ||
| 763 | return false; | ||
| 764 | |||
| 765 | const sentinel_a = info_a.sentinel; | ||
| 766 | const sentinel_b = info_b.sentinel; | ||
| 767 | if (sentinel_a) |sa| { | ||
| 768 | if (sentinel_b) |sb| { | ||
| 769 | if (!sa.eql(sb, info_a.pointee_type, mod)) | ||
| 770 | return false; | ||
| 771 | } else { | ||
| 772 | return false; | ||
| 773 | } | ||
| 774 | } else { | ||
| 775 | if (sentinel_b != null) | ||
| 776 | return false; | ||
| 777 | } | ||
| 778 | |||
| 779 | return true; | ||
| 780 | }, | ||
| 781 | |||
| 782 | .optional, | ||
| 783 | .optional_single_const_pointer, | ||
| 784 | .optional_single_mut_pointer, | ||
| 785 | => { | ||
| 786 | if (b.zigTypeTag() != .Optional) return false; | ||
| 787 | |||
| 788 | var buf_a: Payload.ElemType = undefined; | ||
| 789 | var buf_b: Payload.ElemType = undefined; | ||
| 790 | return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b), mod); | ||
| 791 | }, | ||
| 792 | |||
| 793 | .anyerror_void_error_union, .error_union => { | ||
| 794 | if (b.zigTypeTag() != .ErrorUnion) return false; | ||
| 795 | |||
| 796 | const a_set = a.errorUnionSet(); | ||
| 797 | const b_set = b.errorUnionSet(); | ||
| 798 | if (!a_set.eql(b_set, mod)) return false; | ||
| 799 | |||
| 800 | const a_payload = a.errorUnionPayload(); | ||
| 801 | const b_payload = b.errorUnionPayload(); | ||
| 802 | if (!a_payload.eql(b_payload, mod)) return false; | ||
| 803 | |||
| 804 | return true; | ||
| 805 | }, | ||
| 806 | |||
| 807 | .anyframe_T => { | ||
| 808 | if (b.zigTypeTag() != .AnyFrame) return false; | ||
| 809 | return a.elemType2().eql(b.elemType2(), mod); | ||
| 810 | }, | ||
| 811 | |||
| 812 | .empty_struct => { | ||
| 813 | const a_namespace = a.castTag(.empty_struct).?.data; | ||
| 814 | const b_namespace = (b.castTag(.empty_struct) orelse return false).data; | ||
| 815 | return a_namespace == b_namespace; | ||
| 816 | }, | ||
| 817 | .@"struct" => { | ||
| 818 | const a_struct_obj = a.castTag(.@"struct").?.data; | ||
| 819 | const b_struct_obj = (b.castTag(.@"struct") orelse return false).data; | ||
| 820 | return a_struct_obj == b_struct_obj; | ||
| 821 | }, | ||
| 822 | .tuple, .empty_struct_literal => { | ||
| 823 | if (!b.isSimpleTuple()) return false; | ||
| 824 | |||
| 825 | const a_tuple = a.tupleFields(); | ||
| 826 | const b_tuple = b.tupleFields(); | ||
| 827 | |||
| 828 | if (a_tuple.types.len != b_tuple.types.len) return false; | ||
| 829 | |||
| 830 | for (a_tuple.types, 0..) |a_ty, i| { | ||
| 831 | const b_ty = b_tuple.types[i]; | ||
| 832 | if (!eql(a_ty, b_ty, mod)) return false; | ||
| 833 | } | ||
| 834 | |||
| 835 | for (a_tuple.values, 0..) |a_val, i| { | ||
| 836 | const ty = a_tuple.types[i]; | ||
| 837 | const b_val = b_tuple.values[i]; | ||
| 838 | if (a_val.tag() == .unreachable_value) { | ||
| 839 | if (b_val.tag() == .unreachable_value) { | ||
| 840 | continue; | ||
| 841 | } else { | ||
| 842 | return false; | ||
| 843 | } | ||
| 844 | } else { | ||
| 845 | if (b_val.tag() == .unreachable_value) { | ||
| 846 | return false; | ||
| 847 | } else { | ||
| 848 | if (!Value.eql(a_val, b_val, ty, mod)) return false; | ||
| 849 | } | ||
| 850 | } | ||
| 851 | } | ||
| 852 | |||
| 853 | return true; | ||
| 854 | }, | ||
| 855 | .anon_struct => { | ||
| 856 | const a_struct_obj = a.castTag(.anon_struct).?.data; | ||
| 857 | const b_struct_obj = (b.castTag(.anon_struct) orelse return false).data; | ||
| 858 | |||
| 859 | if (a_struct_obj.types.len != b_struct_obj.types.len) return false; | ||
| 860 | |||
| 861 | for (a_struct_obj.names, 0..) |a_name, i| { | ||
| 862 | const b_name = b_struct_obj.names[i]; | ||
| 863 | if (!std.mem.eql(u8, a_name, b_name)) return false; | ||
| 864 | } | ||
| 865 | |||
| 866 | for (a_struct_obj.types, 0..) |a_ty, i| { | ||
| 867 | const b_ty = b_struct_obj.types[i]; | ||
| 868 | if (!eql(a_ty, b_ty, mod)) return false; | ||
| 869 | } | ||
| 870 | |||
| 871 | for (a_struct_obj.values, 0..) |a_val, i| { | ||
| 872 | const ty = a_struct_obj.types[i]; | ||
| 873 | const b_val = b_struct_obj.values[i]; | ||
| 874 | if (a_val.tag() == .unreachable_value) { | ||
| 875 | if (b_val.tag() == .unreachable_value) { | ||
| 876 | continue; | ||
| 877 | } else { | ||
| 878 | return false; | ||
| 879 | } | ||
| 880 | } else { | ||
| 881 | if (b_val.tag() == .unreachable_value) { | ||
| 882 | return false; | ||
| 883 | } else { | ||
| 884 | if (!Value.eql(a_val, b_val, ty, mod)) return false; | ||
| 885 | } | ||
| 886 | } | ||
| 887 | } | ||
| 888 | |||
| 889 | return true; | ||
| 890 | }, | ||
| 891 | |||
| 892 | // we can't compare these based on tags because it wouldn't detect if, | ||
| 893 | // for example, a was resolved into .@"struct" but b was one of these tags. | ||
| 894 | .prefetch_options, | ||
| 895 | .export_options, | ||
| 896 | .extern_options, | ||
| 897 | => unreachable, // needed to resolve the type before now | ||
| 898 | |||
| 899 | .enum_full, .enum_nonexhaustive => { | ||
| 900 | const a_enum_obj = a.cast(Payload.EnumFull).?.data; | ||
| 901 | const b_enum_obj = (b.cast(Payload.EnumFull) orelse return false).data; | ||
| 902 | return a_enum_obj == b_enum_obj; | ||
| 903 | }, | ||
| 904 | .enum_simple => { | ||
| 905 | const a_enum_obj = a.cast(Payload.EnumSimple).?.data; | ||
| 906 | const b_enum_obj = (b.cast(Payload.EnumSimple) orelse return false).data; | ||
| 907 | return a_enum_obj == b_enum_obj; | ||
| 908 | }, | ||
| 909 | .enum_numbered => { | ||
| 910 | const a_enum_obj = a.cast(Payload.EnumNumbered).?.data; | ||
| 911 | const b_enum_obj = (b.cast(Payload.EnumNumbered) orelse return false).data; | ||
| 912 | return a_enum_obj == b_enum_obj; | ||
| 913 | }, | ||
| 914 | // we can't compare these based on tags because it wouldn't detect if, | ||
| 915 | // for example, a was resolved into .enum_simple but b was one of these tags. | ||
| 916 | .atomic_order, | ||
| 917 | .atomic_rmw_op, | ||
| 918 | .calling_convention, | ||
| 919 | .address_space, | ||
| 920 | .float_mode, | ||
| 921 | .reduce_op, | ||
| 922 | .modifier, | ||
| 923 | => unreachable, // needed to resolve the type before now | ||
| 924 | |||
| 925 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 926 | const a_union_obj = a.cast(Payload.Union).?.data; | ||
| 927 | const b_union_obj = (b.cast(Payload.Union) orelse return false).data; | ||
| 928 | return a_union_obj == b_union_obj; | ||
| 929 | }, | ||
| 930 | // we can't compare these based on tags because it wouldn't detect if, | ||
| 931 | // for example, a was resolved into .union_tagged but b was one of these tags. | ||
| 932 | .type_info => unreachable, // needed to resolve the type before now | ||
| 933 | |||
| 934 | } | ||
| 935 | } | ||
| 936 | |||
| 937 | pub fn hash(self: Type, mod: *Module) u64 { | ||
| 938 | var hasher = std.hash.Wyhash.init(0); | ||
| 939 | self.hashWithHasher(&hasher, mod); | ||
| 940 | return hasher.final(); | ||
| 941 | } | ||
| 942 | |||
| 943 | pub fn hashWithHasher(ty: Type, hasher: *std.hash.Wyhash, mod: *Module) void { | ||
| 944 | switch (ty.tag()) { | ||
| 945 | .generic_poison => unreachable, | ||
| 946 | |||
| 947 | .usize, | ||
| 948 | .isize, | ||
| 949 | .c_char, | ||
| 950 | .c_short, | ||
| 951 | .c_ushort, | ||
| 952 | .c_int, | ||
| 953 | .c_uint, | ||
| 954 | .c_long, | ||
| 955 | .c_ulong, | ||
| 956 | .c_longlong, | ||
| 957 | .c_ulonglong, | ||
| 958 | => |ty_tag| { | ||
| 959 | std.hash.autoHash(hasher, std.builtin.TypeId.Int); | ||
| 960 | std.hash.autoHash(hasher, ty_tag); | ||
| 961 | }, | ||
| 962 | |||
| 963 | .f16, | ||
| 964 | .f32, | ||
| 965 | .f64, | ||
| 966 | .f80, | ||
| 967 | .f128, | ||
| 968 | .c_longdouble, | ||
| 969 | => |ty_tag| { | ||
| 970 | std.hash.autoHash(hasher, std.builtin.TypeId.Float); | ||
| 971 | std.hash.autoHash(hasher, ty_tag); | ||
| 972 | }, | ||
| 973 | |||
| 974 | .bool => std.hash.autoHash(hasher, std.builtin.TypeId.Bool), | ||
| 975 | .void => std.hash.autoHash(hasher, std.builtin.TypeId.Void), | ||
| 976 | .type => std.hash.autoHash(hasher, std.builtin.TypeId.Type), | ||
| 977 | .comptime_int => std.hash.autoHash(hasher, std.builtin.TypeId.ComptimeInt), | ||
| 978 | .comptime_float => std.hash.autoHash(hasher, std.builtin.TypeId.ComptimeFloat), | ||
| 979 | .noreturn => std.hash.autoHash(hasher, std.builtin.TypeId.NoReturn), | ||
| 980 | .null => std.hash.autoHash(hasher, std.builtin.TypeId.Null), | ||
| 981 | .undefined => std.hash.autoHash(hasher, std.builtin.TypeId.Undefined), | ||
| 982 | |||
| 983 | .anyopaque => { | ||
| 984 | std.hash.autoHash(hasher, std.builtin.TypeId.Opaque); | ||
| 985 | std.hash.autoHash(hasher, Tag.anyopaque); | ||
| 986 | }, | ||
| 987 | |||
| 988 | .@"anyframe" => { | ||
| 989 | std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame); | ||
| 990 | std.hash.autoHash(hasher, Tag.@"anyframe"); | ||
| 991 | }, | ||
| 992 | |||
| 993 | .enum_literal => { | ||
| 994 | std.hash.autoHash(hasher, std.builtin.TypeId.EnumLiteral); | ||
| 995 | std.hash.autoHash(hasher, Tag.enum_literal); | ||
| 996 | }, | ||
| 997 | |||
| 998 | .u1, | ||
| 999 | .u8, | ||
| 1000 | .i8, | ||
| 1001 | .u16, | ||
| 1002 | .i16, | ||
| 1003 | .u29, | ||
| 1004 | .u32, | ||
| 1005 | .i32, | ||
| 1006 | .u64, | ||
| 1007 | .i64, | ||
| 1008 | .u128, | ||
| 1009 | .i128, | ||
| 1010 | .int_signed, | ||
| 1011 | .int_unsigned, | ||
| 1012 | => { | ||
| 1013 | // Arbitrary sized integers. The target will not be branched upon, | ||
| 1014 | // because we handled target-dependent cases above. | ||
| 1015 | std.hash.autoHash(hasher, std.builtin.TypeId.Int); | ||
| 1016 | const info = ty.intInfo(@as(Target, undefined)); | ||
| 1017 | std.hash.autoHash(hasher, info.signedness); | ||
| 1018 | std.hash.autoHash(hasher, info.bits); | ||
| 1019 | }, | ||
| 1020 | |||
| 1021 | .error_set, | ||
| 1022 | .error_set_single, | ||
| 1023 | .error_set_merged, | ||
| 1024 | => { | ||
| 1025 | // all are treated like an "error set" for hashing | ||
| 1026 | std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet); | ||
| 1027 | std.hash.autoHash(hasher, Tag.error_set); | ||
| 1028 | |||
| 1029 | const names = ty.errorSetNames(); | ||
| 1030 | std.hash.autoHash(hasher, names.len); | ||
| 1031 | assert(std.sort.isSorted([]const u8, names, u8, std.mem.lessThan)); | ||
| 1032 | for (names) |name| hasher.update(name); | ||
| 1033 | }, | ||
| 1034 | |||
| 1035 | .anyerror => { | ||
| 1036 | // anyerror is distinct from other error sets | ||
| 1037 | std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet); | ||
| 1038 | std.hash.autoHash(hasher, Tag.anyerror); | ||
| 1039 | }, | ||
| 1040 | |||
| 1041 | .error_set_inferred => { | ||
| 1042 | // inferred error sets are compared using their data pointer | ||
| 1043 | const ies: *Module.Fn.InferredErrorSet = ty.castTag(.error_set_inferred).?.data; | ||
| 1044 | std.hash.autoHash(hasher, std.builtin.TypeId.ErrorSet); | ||
| 1045 | std.hash.autoHash(hasher, Tag.error_set_inferred); | ||
| 1046 | std.hash.autoHash(hasher, ies); | ||
| 1047 | }, | ||
| 1048 | |||
| 1049 | .@"opaque" => { | ||
| 1050 | std.hash.autoHash(hasher, std.builtin.TypeId.Opaque); | ||
| 1051 | const opaque_obj = ty.castTag(.@"opaque").?.data; | ||
| 1052 | std.hash.autoHash(hasher, opaque_obj); | ||
| 1053 | }, | ||
| 1054 | |||
| 1055 | .fn_noreturn_no_args, | ||
| 1056 | .fn_void_no_args, | ||
| 1057 | .fn_naked_noreturn_no_args, | ||
| 1058 | .fn_ccc_void_no_args, | ||
| 1059 | .function, | ||
| 1060 | => { | ||
| 1061 | std.hash.autoHash(hasher, std.builtin.TypeId.Fn); | ||
| 1062 | |||
| 1063 | const fn_info = ty.fnInfo(); | ||
| 1064 | if (fn_info.return_type.tag() != .generic_poison) { | ||
| 1065 | hashWithHasher(fn_info.return_type, hasher, mod); | ||
| 1066 | } | ||
| 1067 | if (!fn_info.align_is_generic) { | ||
| 1068 | std.hash.autoHash(hasher, fn_info.alignment); | ||
| 1069 | } | ||
| 1070 | if (!fn_info.cc_is_generic) { | ||
| 1071 | std.hash.autoHash(hasher, fn_info.cc); | ||
| 1072 | } | ||
| 1073 | std.hash.autoHash(hasher, fn_info.is_var_args); | ||
| 1074 | std.hash.autoHash(hasher, fn_info.is_generic); | ||
| 1075 | std.hash.autoHash(hasher, fn_info.is_noinline); | ||
| 1076 | std.hash.autoHash(hasher, fn_info.noalias_bits); | ||
| 1077 | |||
| 1078 | std.hash.autoHash(hasher, fn_info.param_types.len); | ||
| 1079 | for (fn_info.param_types, 0..) |param_ty, i| { | ||
| 1080 | std.hash.autoHash(hasher, fn_info.paramIsComptime(i)); | ||
| 1081 | if (param_ty.tag() == .generic_poison) continue; | ||
| 1082 | hashWithHasher(param_ty, hasher, mod); | ||
| 1083 | } | ||
| 1084 | }, | ||
| 1085 | |||
| 1086 | .array, | ||
| 1087 | .array_u8_sentinel_0, | ||
| 1088 | .array_u8, | ||
| 1089 | .array_sentinel, | ||
| 1090 | => { | ||
| 1091 | std.hash.autoHash(hasher, std.builtin.TypeId.Array); | ||
| 1092 | |||
| 1093 | const elem_ty = ty.elemType(); | ||
| 1094 | std.hash.autoHash(hasher, ty.arrayLen()); | ||
| 1095 | hashWithHasher(elem_ty, hasher, mod); | ||
| 1096 | hashSentinel(ty.sentinel(), elem_ty, hasher, mod); | ||
| 1097 | }, | ||
| 1098 | |||
| 1099 | .vector => { | ||
| 1100 | std.hash.autoHash(hasher, std.builtin.TypeId.Vector); | ||
| 1101 | |||
| 1102 | const elem_ty = ty.elemType(); | ||
| 1103 | std.hash.autoHash(hasher, ty.vectorLen()); | ||
| 1104 | hashWithHasher(elem_ty, hasher, mod); | ||
| 1105 | }, | ||
| 1106 | |||
| 1107 | .single_const_pointer_to_comptime_int, | ||
| 1108 | .const_slice_u8, | ||
| 1109 | .const_slice_u8_sentinel_0, | ||
| 1110 | .single_const_pointer, | ||
| 1111 | .single_mut_pointer, | ||
| 1112 | .many_const_pointer, | ||
| 1113 | .many_mut_pointer, | ||
| 1114 | .c_const_pointer, | ||
| 1115 | .c_mut_pointer, | ||
| 1116 | .const_slice, | ||
| 1117 | .mut_slice, | ||
| 1118 | .pointer, | ||
| 1119 | .inferred_alloc_const, | ||
| 1120 | .inferred_alloc_mut, | ||
| 1121 | .manyptr_u8, | ||
| 1122 | .manyptr_const_u8, | ||
| 1123 | .manyptr_const_u8_sentinel_0, | ||
| 1124 | => { | ||
| 1125 | std.hash.autoHash(hasher, std.builtin.TypeId.Pointer); | ||
| 1126 | |||
| 1127 | const info = ty.ptrInfo().data; | ||
| 1128 | hashWithHasher(info.pointee_type, hasher, mod); | ||
| 1129 | hashSentinel(info.sentinel, info.pointee_type, hasher, mod); | ||
| 1130 | std.hash.autoHash(hasher, info.@"align"); | ||
| 1131 | std.hash.autoHash(hasher, info.@"addrspace"); | ||
| 1132 | std.hash.autoHash(hasher, info.bit_offset); | ||
| 1133 | std.hash.autoHash(hasher, info.host_size); | ||
| 1134 | std.hash.autoHash(hasher, info.vector_index); | ||
| 1135 | std.hash.autoHash(hasher, info.@"allowzero"); | ||
| 1136 | std.hash.autoHash(hasher, info.mutable); | ||
| 1137 | std.hash.autoHash(hasher, info.@"volatile"); | ||
| 1138 | std.hash.autoHash(hasher, info.size); | ||
| 1139 | }, | ||
| 1140 | |||
| 1141 | .optional, | ||
| 1142 | .optional_single_const_pointer, | ||
| 1143 | .optional_single_mut_pointer, | ||
| 1144 | => { | ||
| 1145 | std.hash.autoHash(hasher, std.builtin.TypeId.Optional); | ||
| 1146 | |||
| 1147 | var buf: Payload.ElemType = undefined; | ||
| 1148 | hashWithHasher(ty.optionalChild(&buf), hasher, mod); | ||
| 1149 | }, | ||
| 1150 | |||
| 1151 | .anyerror_void_error_union, .error_union => { | ||
| 1152 | std.hash.autoHash(hasher, std.builtin.TypeId.ErrorUnion); | ||
| 1153 | |||
| 1154 | const set_ty = ty.errorUnionSet(); | ||
| 1155 | hashWithHasher(set_ty, hasher, mod); | ||
| 1156 | |||
| 1157 | const payload_ty = ty.errorUnionPayload(); | ||
| 1158 | hashWithHasher(payload_ty, hasher, mod); | ||
| 1159 | }, | ||
| 1160 | |||
| 1161 | .anyframe_T => { | ||
| 1162 | std.hash.autoHash(hasher, std.builtin.TypeId.AnyFrame); | ||
| 1163 | hashWithHasher(ty.childType(), hasher, mod); | ||
| 1164 | }, | ||
| 1165 | |||
| 1166 | .empty_struct => { | ||
| 1167 | std.hash.autoHash(hasher, std.builtin.TypeId.Struct); | ||
| 1168 | const namespace: *const Module.Namespace = ty.castTag(.empty_struct).?.data; | ||
| 1169 | std.hash.autoHash(hasher, namespace); | ||
| 1170 | }, | ||
| 1171 | .@"struct" => { | ||
| 1172 | const struct_obj: *const Module.Struct = ty.castTag(.@"struct").?.data; | ||
| 1173 | std.hash.autoHash(hasher, struct_obj); | ||
| 1174 | }, | ||
| 1175 | .tuple, .empty_struct_literal => { | ||
| 1176 | std.hash.autoHash(hasher, std.builtin.TypeId.Struct); | ||
| 1177 | |||
| 1178 | const tuple = ty.tupleFields(); | ||
| 1179 | std.hash.autoHash(hasher, tuple.types.len); | ||
| 1180 | |||
| 1181 | for (tuple.types, 0..) |field_ty, i| { | ||
| 1182 | hashWithHasher(field_ty, hasher, mod); | ||
| 1183 | const field_val = tuple.values[i]; | ||
| 1184 | if (field_val.tag() == .unreachable_value) continue; | ||
| 1185 | field_val.hash(field_ty, hasher, mod); | ||
| 1186 | } | ||
| 1187 | }, | ||
| 1188 | .anon_struct => { | ||
| 1189 | const struct_obj = ty.castTag(.anon_struct).?.data; | ||
| 1190 | std.hash.autoHash(hasher, std.builtin.TypeId.Struct); | ||
| 1191 | std.hash.autoHash(hasher, struct_obj.types.len); | ||
| 1192 | |||
| 1193 | for (struct_obj.types, 0..) |field_ty, i| { | ||
| 1194 | const field_name = struct_obj.names[i]; | ||
| 1195 | const field_val = struct_obj.values[i]; | ||
| 1196 | hasher.update(field_name); | ||
| 1197 | hashWithHasher(field_ty, hasher, mod); | ||
| 1198 | if (field_val.tag() == .unreachable_value) continue; | ||
| 1199 | field_val.hash(field_ty, hasher, mod); | ||
| 1200 | } | ||
| 1201 | }, | ||
| 1202 | |||
| 1203 | // we can't hash these based on tags because they wouldn't match the expanded version. | ||
| 1204 | .prefetch_options, | ||
| 1205 | .export_options, | ||
| 1206 | .extern_options, | ||
| 1207 | => unreachable, // needed to resolve the type before now | ||
| 1208 | |||
| 1209 | .enum_full, .enum_nonexhaustive => { | ||
| 1210 | const enum_obj: *const Module.EnumFull = ty.cast(Payload.EnumFull).?.data; | ||
| 1211 | std.hash.autoHash(hasher, std.builtin.TypeId.Enum); | ||
| 1212 | std.hash.autoHash(hasher, enum_obj); | ||
| 1213 | }, | ||
| 1214 | .enum_simple => { | ||
| 1215 | const enum_obj: *const Module.EnumSimple = ty.cast(Payload.EnumSimple).?.data; | ||
| 1216 | std.hash.autoHash(hasher, std.builtin.TypeId.Enum); | ||
| 1217 | std.hash.autoHash(hasher, enum_obj); | ||
| 1218 | }, | ||
| 1219 | .enum_numbered => { | ||
| 1220 | const enum_obj: *const Module.EnumNumbered = ty.cast(Payload.EnumNumbered).?.data; | ||
| 1221 | std.hash.autoHash(hasher, std.builtin.TypeId.Enum); | ||
| 1222 | std.hash.autoHash(hasher, enum_obj); | ||
| 1223 | }, | ||
| 1224 | // we can't hash these based on tags because they wouldn't match the expanded version. | ||
| 1225 | .atomic_order, | ||
| 1226 | .atomic_rmw_op, | ||
| 1227 | .calling_convention, | ||
| 1228 | .address_space, | ||
| 1229 | .float_mode, | ||
| 1230 | .reduce_op, | ||
| 1231 | .modifier, | ||
| 1232 | => unreachable, // needed to resolve the type before now | ||
| 1233 | |||
| 1234 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 1235 | const union_obj: *const Module.Union = ty.cast(Payload.Union).?.data; | ||
| 1236 | std.hash.autoHash(hasher, std.builtin.TypeId.Union); | ||
| 1237 | std.hash.autoHash(hasher, union_obj); | ||
| 1238 | }, | ||
| 1239 | // we can't hash these based on tags because they wouldn't match the expanded version. | ||
| 1240 | .type_info => unreachable, // needed to resolve the type before now | ||
| 1241 | |||
| 1242 | } | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | fn hashSentinel(opt_val: ?Value, ty: Type, hasher: *std.hash.Wyhash, mod: *Module) void { | ||
| 1246 | if (opt_val) |s| { | ||
| 1247 | std.hash.autoHash(hasher, true); | ||
| 1248 | s.hash(ty, hasher, mod); | ||
| 1249 | } else { | ||
| 1250 | std.hash.autoHash(hasher, false); | ||
| 1251 | } | ||
| 1252 | } | ||
| 1253 | |||
| 1254 | pub const HashContext64 = struct { | ||
| 1255 | mod: *Module, | ||
| 1256 | |||
| 1257 | pub fn hash(self: @This(), t: Type) u64 { | ||
| 1258 | return t.hash(self.mod); | ||
| 1259 | } | ||
| 1260 | pub fn eql(self: @This(), a: Type, b: Type) bool { | ||
| 1261 | return a.eql(b, self.mod); | ||
| 1262 | } | ||
| 1263 | }; | ||
| 1264 | |||
| 1265 | pub const HashContext32 = struct { | ||
| 1266 | mod: *Module, | ||
| 1267 | |||
| 1268 | pub fn hash(self: @This(), t: Type) u32 { | ||
| 1269 | return @truncate(u32, t.hash(self.mod)); | ||
| 1270 | } | ||
| 1271 | pub fn eql(self: @This(), a: Type, b: Type, b_index: usize) bool { | ||
| 1272 | _ = b_index; | ||
| 1273 | return a.eql(b, self.mod); | ||
| 1274 | } | ||
| 1275 | }; | 95 | }; |
| 1276 | 96 | ||
| 1277 | pub fn copy(self: Type, allocator: Allocator) error{OutOfMemory}!Type { | 97 | pub fn arrayInfo(self: Type, mod: *const Module) ArrayInfo { |
| 1278 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) { | 98 | return .{ |
| 1279 | return Type{ .tag_if_small_enough = self.tag_if_small_enough }; | 99 | .len = self.arrayLen(mod), |
| 1280 | } else switch (self.ptr_otherwise.tag) { | 100 | .sentinel = self.sentinel(mod), |
| 1281 | .u1, | 101 | .elem_type = self.childType(mod), |
| 1282 | .u8, | 102 | }; |
| 1283 | .i8, | 103 | } |
| 1284 | .u16, | 104 | |
| 1285 | .i16, | 105 | pub fn ptrInfoIp(ip: *const InternPool, ty: InternPool.Index) InternPool.Key.PtrType { |
| 1286 | .u29, | 106 | return switch (ip.indexToKey(ty)) { |
| 1287 | .u32, | 107 | .ptr_type => |p| p, |
| 1288 | .i32, | 108 | .opt_type => |child| switch (ip.indexToKey(child)) { |
| 1289 | .u64, | 109 | .ptr_type => |p| p, |
| 1290 | .i64, | 110 | else => unreachable, |
| 1291 | .u128, | ||
| 1292 | .i128, | ||
| 1293 | .usize, | ||
| 1294 | .isize, | ||
| 1295 | .c_char, | ||
| 1296 | .c_short, | ||
| 1297 | .c_ushort, | ||
| 1298 | .c_int, | ||
| 1299 | .c_uint, | ||
| 1300 | .c_long, | ||
| 1301 | .c_ulong, | ||
| 1302 | .c_longlong, | ||
| 1303 | .c_ulonglong, | ||
| 1304 | .c_longdouble, | ||
| 1305 | .anyopaque, | ||
| 1306 | .f16, | ||
| 1307 | .f32, | ||
| 1308 | .f64, | ||
| 1309 | .f80, | ||
| 1310 | .f128, | ||
| 1311 | .bool, | ||
| 1312 | .void, | ||
| 1313 | .type, | ||
| 1314 | .anyerror, | ||
| 1315 | .comptime_int, | ||
| 1316 | .comptime_float, | ||
| 1317 | .noreturn, | ||
| 1318 | .null, | ||
| 1319 | .undefined, | ||
| 1320 | .fn_noreturn_no_args, | ||
| 1321 | .fn_void_no_args, | ||
| 1322 | .fn_naked_noreturn_no_args, | ||
| 1323 | .fn_ccc_void_no_args, | ||
| 1324 | .single_const_pointer_to_comptime_int, | ||
| 1325 | .const_slice_u8, | ||
| 1326 | .const_slice_u8_sentinel_0, | ||
| 1327 | .enum_literal, | ||
| 1328 | .anyerror_void_error_union, | ||
| 1329 | .inferred_alloc_const, | ||
| 1330 | .inferred_alloc_mut, | ||
| 1331 | .empty_struct_literal, | ||
| 1332 | .manyptr_u8, | ||
| 1333 | .manyptr_const_u8, | ||
| 1334 | .manyptr_const_u8_sentinel_0, | ||
| 1335 | .atomic_order, | ||
| 1336 | .atomic_rmw_op, | ||
| 1337 | .calling_convention, | ||
| 1338 | .address_space, | ||
| 1339 | .float_mode, | ||
| 1340 | .reduce_op, | ||
| 1341 | .modifier, | ||
| 1342 | .prefetch_options, | ||
| 1343 | .export_options, | ||
| 1344 | .extern_options, | ||
| 1345 | .type_info, | ||
| 1346 | .@"anyframe", | ||
| 1347 | .generic_poison, | ||
| 1348 | => unreachable, | ||
| 1349 | |||
| 1350 | .array_u8, | ||
| 1351 | .array_u8_sentinel_0, | ||
| 1352 | => return self.copyPayloadShallow(allocator, Payload.Len), | ||
| 1353 | |||
| 1354 | .single_const_pointer, | ||
| 1355 | .single_mut_pointer, | ||
| 1356 | .many_const_pointer, | ||
| 1357 | .many_mut_pointer, | ||
| 1358 | .c_const_pointer, | ||
| 1359 | .c_mut_pointer, | ||
| 1360 | .const_slice, | ||
| 1361 | .mut_slice, | ||
| 1362 | .optional, | ||
| 1363 | .optional_single_mut_pointer, | ||
| 1364 | .optional_single_const_pointer, | ||
| 1365 | .anyframe_T, | ||
| 1366 | => { | ||
| 1367 | const payload = self.cast(Payload.ElemType).?; | ||
| 1368 | const new_payload = try allocator.create(Payload.ElemType); | ||
| 1369 | new_payload.* = .{ | ||
| 1370 | .base = .{ .tag = payload.base.tag }, | ||
| 1371 | .data = try payload.data.copy(allocator), | ||
| 1372 | }; | ||
| 1373 | return Type{ .ptr_otherwise = &new_payload.base }; | ||
| 1374 | }, | ||
| 1375 | |||
| 1376 | .int_signed, | ||
| 1377 | .int_unsigned, | ||
| 1378 | => return self.copyPayloadShallow(allocator, Payload.Bits), | ||
| 1379 | |||
| 1380 | .vector => { | ||
| 1381 | const payload = self.castTag(.vector).?.data; | ||
| 1382 | return Tag.vector.create(allocator, .{ | ||
| 1383 | .len = payload.len, | ||
| 1384 | .elem_type = try payload.elem_type.copy(allocator), | ||
| 1385 | }); | ||
| 1386 | }, | ||
| 1387 | .array => { | ||
| 1388 | const payload = self.castTag(.array).?.data; | ||
| 1389 | return Tag.array.create(allocator, .{ | ||
| 1390 | .len = payload.len, | ||
| 1391 | .elem_type = try payload.elem_type.copy(allocator), | ||
| 1392 | }); | ||
| 1393 | }, | ||
| 1394 | .array_sentinel => { | ||
| 1395 | const payload = self.castTag(.array_sentinel).?.data; | ||
| 1396 | return Tag.array_sentinel.create(allocator, .{ | ||
| 1397 | .len = payload.len, | ||
| 1398 | .sentinel = try payload.sentinel.copy(allocator), | ||
| 1399 | .elem_type = try payload.elem_type.copy(allocator), | ||
| 1400 | }); | ||
| 1401 | }, | ||
| 1402 | .tuple => { | ||
| 1403 | const payload = self.castTag(.tuple).?.data; | ||
| 1404 | const types = try allocator.alloc(Type, payload.types.len); | ||
| 1405 | const values = try allocator.alloc(Value, payload.values.len); | ||
| 1406 | for (payload.types, 0..) |ty, i| { | ||
| 1407 | types[i] = try ty.copy(allocator); | ||
| 1408 | } | ||
| 1409 | for (payload.values, 0..) |val, i| { | ||
| 1410 | values[i] = try val.copy(allocator); | ||
| 1411 | } | ||
| 1412 | return Tag.tuple.create(allocator, .{ | ||
| 1413 | .types = types, | ||
| 1414 | .values = values, | ||
| 1415 | }); | ||
| 1416 | }, | ||
| 1417 | .anon_struct => { | ||
| 1418 | const payload = self.castTag(.anon_struct).?.data; | ||
| 1419 | const names = try allocator.alloc([]const u8, payload.names.len); | ||
| 1420 | const types = try allocator.alloc(Type, payload.types.len); | ||
| 1421 | const values = try allocator.alloc(Value, payload.values.len); | ||
| 1422 | for (payload.names, 0..) |name, i| { | ||
| 1423 | names[i] = try allocator.dupe(u8, name); | ||
| 1424 | } | ||
| 1425 | for (payload.types, 0..) |ty, i| { | ||
| 1426 | types[i] = try ty.copy(allocator); | ||
| 1427 | } | ||
| 1428 | for (payload.values, 0..) |val, i| { | ||
| 1429 | values[i] = try val.copy(allocator); | ||
| 1430 | } | ||
| 1431 | return Tag.anon_struct.create(allocator, .{ | ||
| 1432 | .names = names, | ||
| 1433 | .types = types, | ||
| 1434 | .values = values, | ||
| 1435 | }); | ||
| 1436 | }, | ||
| 1437 | .function => { | ||
| 1438 | const payload = self.castTag(.function).?.data; | ||
| 1439 | const param_types = try allocator.alloc(Type, payload.param_types.len); | ||
| 1440 | for (payload.param_types, 0..) |param_ty, i| { | ||
| 1441 | param_types[i] = try param_ty.copy(allocator); | ||
| 1442 | } | ||
| 1443 | const other_comptime_params = payload.comptime_params[0..payload.param_types.len]; | ||
| 1444 | const comptime_params = try allocator.dupe(bool, other_comptime_params); | ||
| 1445 | return Tag.function.create(allocator, .{ | ||
| 1446 | .return_type = try payload.return_type.copy(allocator), | ||
| 1447 | .param_types = param_types, | ||
| 1448 | .cc = payload.cc, | ||
| 1449 | .alignment = payload.alignment, | ||
| 1450 | .is_var_args = payload.is_var_args, | ||
| 1451 | .is_generic = payload.is_generic, | ||
| 1452 | .is_noinline = payload.is_noinline, | ||
| 1453 | .comptime_params = comptime_params.ptr, | ||
| 1454 | .align_is_generic = payload.align_is_generic, | ||
| 1455 | .cc_is_generic = payload.cc_is_generic, | ||
| 1456 | .section_is_generic = payload.section_is_generic, | ||
| 1457 | .addrspace_is_generic = payload.addrspace_is_generic, | ||
| 1458 | .noalias_bits = payload.noalias_bits, | ||
| 1459 | }); | ||
| 1460 | }, | ||
| 1461 | .pointer => { | ||
| 1462 | const payload = self.castTag(.pointer).?.data; | ||
| 1463 | const sent: ?Value = if (payload.sentinel) |some| | ||
| 1464 | try some.copy(allocator) | ||
| 1465 | else | ||
| 1466 | null; | ||
| 1467 | return Tag.pointer.create(allocator, .{ | ||
| 1468 | .pointee_type = try payload.pointee_type.copy(allocator), | ||
| 1469 | .sentinel = sent, | ||
| 1470 | .@"align" = payload.@"align", | ||
| 1471 | .@"addrspace" = payload.@"addrspace", | ||
| 1472 | .bit_offset = payload.bit_offset, | ||
| 1473 | .host_size = payload.host_size, | ||
| 1474 | .vector_index = payload.vector_index, | ||
| 1475 | .@"allowzero" = payload.@"allowzero", | ||
| 1476 | .mutable = payload.mutable, | ||
| 1477 | .@"volatile" = payload.@"volatile", | ||
| 1478 | .size = payload.size, | ||
| 1479 | }); | ||
| 1480 | }, | ||
| 1481 | .error_union => { | ||
| 1482 | const payload = self.castTag(.error_union).?.data; | ||
| 1483 | return Tag.error_union.create(allocator, .{ | ||
| 1484 | .error_set = try payload.error_set.copy(allocator), | ||
| 1485 | .payload = try payload.payload.copy(allocator), | ||
| 1486 | }); | ||
| 1487 | }, | ||
| 1488 | .error_set_merged => { | ||
| 1489 | const names = self.castTag(.error_set_merged).?.data.keys(); | ||
| 1490 | var duped_names = Module.ErrorSet.NameMap{}; | ||
| 1491 | try duped_names.ensureTotalCapacity(allocator, names.len); | ||
| 1492 | for (names) |name| { | ||
| 1493 | duped_names.putAssumeCapacityNoClobber(name, {}); | ||
| 1494 | } | ||
| 1495 | return Tag.error_set_merged.create(allocator, duped_names); | ||
| 1496 | }, | 111 | }, |
| 1497 | .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), | 112 | else => unreachable, |
| 1498 | .error_set_inferred => return self.copyPayloadShallow(allocator, Payload.ErrorSetInferred), | 113 | }; |
| 1499 | .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name), | ||
| 1500 | .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope), | ||
| 1501 | .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct), | ||
| 1502 | .@"union", .union_safety_tagged, .union_tagged => return self.copyPayloadShallow(allocator, Payload.Union), | ||
| 1503 | .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple), | ||
| 1504 | .enum_numbered => return self.copyPayloadShallow(allocator, Payload.EnumNumbered), | ||
| 1505 | .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull), | ||
| 1506 | .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque), | ||
| 1507 | } | ||
| 1508 | } | 114 | } |
| 1509 | 115 | ||
| 1510 | fn copyPayloadShallow(self: Type, allocator: Allocator, comptime T: type) error{OutOfMemory}!Type { | 116 | pub fn ptrInfo(ty: Type, mod: *const Module) Payload.Pointer.Data { |
| 1511 | const payload = self.cast(T).?; | 117 | return Payload.Pointer.Data.fromKey(ptrInfoIp(&mod.intern_pool, ty.toIntern())); |
| 1512 | const new_payload = try allocator.create(T); | 118 | } |
| 1513 | new_payload.* = payload.*; | 119 | |
| 1514 | return Type{ .ptr_otherwise = &new_payload.base }; | 120 | pub fn eql(a: Type, b: Type, mod: *const Module) bool { |
| 121 | _ = mod; // TODO: remove this parameter | ||
| 122 | // The InternPool data structure hashes based on Key to make interned objects | ||
| 123 | // unique. An Index can be treated simply as u32 value for the | ||
| 124 | // purpose of Type/Value hashing and equality. | ||
| 125 | return a.toIntern() == b.toIntern(); | ||
| 126 | } | ||
| 127 | |||
| 128 | pub fn hash(ty: Type, mod: *const Module) u32 { | ||
| 129 | _ = mod; // TODO: remove this parameter | ||
| 130 | // The InternPool data structure hashes based on Key to make interned objects | ||
| 131 | // unique. An Index can be treated simply as u32 value for the | ||
| 132 | // purpose of Type/Value hashing and equality. | ||
| 133 | return std.hash.uint32(@enumToInt(ty.toIntern())); | ||
| 1515 | } | 134 | } |
| 1516 | 135 | ||
| 1517 | pub fn format(ty: Type, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | 136 | pub fn format(ty: Type, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| ... | @@ -1550,7 +169,7 @@ pub const Type = extern union { | ... | @@ -1550,7 +169,7 @@ pub const Type = extern union { |
| 1550 | } | 169 | } |
| 1551 | 170 | ||
| 1552 | /// This is a debug function. In order to print types in a meaningful way | 171 | /// This is a debug function. In order to print types in a meaningful way |
| 1553 | /// we also need access to the target. | 172 | /// we also need access to the module. |
| 1554 | pub fn dump( | 173 | pub fn dump( |
| 1555 | start_type: Type, | 174 | start_type: Type, |
| 1556 | comptime unused_format_string: []const u8, | 175 | comptime unused_format_string: []const u8, |
| ... | @@ -1559,372 +178,7 @@ pub const Type = extern union { | ... | @@ -1559,372 +178,7 @@ pub const Type = extern union { |
| 1559 | ) @TypeOf(writer).Error!void { | 178 | ) @TypeOf(writer).Error!void { |
| 1560 | _ = options; | 179 | _ = options; |
| 1561 | comptime assert(unused_format_string.len == 0); | 180 | comptime assert(unused_format_string.len == 0); |
| 1562 | if (true) { | 181 | return writer.print("{any}", .{start_type.ip_index}); |
| 1563 | // This is disabled to work around a bug where this function | ||
| 1564 | // recursively causes more generic function instantiations | ||
| 1565 | // resulting in an infinite loop in the compiler. | ||
| 1566 | try writer.writeAll("[TODO fix internal compiler bug regarding dump]"); | ||
| 1567 | return; | ||
| 1568 | } | ||
| 1569 | var ty = start_type; | ||
| 1570 | while (true) { | ||
| 1571 | const t = ty.tag(); | ||
| 1572 | switch (t) { | ||
| 1573 | .u1, | ||
| 1574 | .u8, | ||
| 1575 | .i8, | ||
| 1576 | .u16, | ||
| 1577 | .i16, | ||
| 1578 | .u29, | ||
| 1579 | .u32, | ||
| 1580 | .i32, | ||
| 1581 | .u64, | ||
| 1582 | .i64, | ||
| 1583 | .u128, | ||
| 1584 | .i128, | ||
| 1585 | .usize, | ||
| 1586 | .isize, | ||
| 1587 | .c_char, | ||
| 1588 | .c_short, | ||
| 1589 | .c_ushort, | ||
| 1590 | .c_int, | ||
| 1591 | .c_uint, | ||
| 1592 | .c_long, | ||
| 1593 | .c_ulong, | ||
| 1594 | .c_longlong, | ||
| 1595 | .c_ulonglong, | ||
| 1596 | .c_longdouble, | ||
| 1597 | .anyopaque, | ||
| 1598 | .f16, | ||
| 1599 | .f32, | ||
| 1600 | .f64, | ||
| 1601 | .f80, | ||
| 1602 | .f128, | ||
| 1603 | .bool, | ||
| 1604 | .void, | ||
| 1605 | .type, | ||
| 1606 | .anyerror, | ||
| 1607 | .@"anyframe", | ||
| 1608 | .comptime_int, | ||
| 1609 | .comptime_float, | ||
| 1610 | .noreturn, | ||
| 1611 | => return writer.writeAll(@tagName(t)), | ||
| 1612 | |||
| 1613 | .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"), | ||
| 1614 | .null => return writer.writeAll("@Type(.Null)"), | ||
| 1615 | .undefined => return writer.writeAll("@Type(.Undefined)"), | ||
| 1616 | |||
| 1617 | .empty_struct, .empty_struct_literal => return writer.writeAll("struct {}"), | ||
| 1618 | |||
| 1619 | .@"struct" => { | ||
| 1620 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 1621 | return writer.print("({s} decl={d})", .{ | ||
| 1622 | @tagName(t), struct_obj.owner_decl, | ||
| 1623 | }); | ||
| 1624 | }, | ||
| 1625 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 1626 | const union_obj = ty.cast(Payload.Union).?.data; | ||
| 1627 | return writer.print("({s} decl={d})", .{ | ||
| 1628 | @tagName(t), union_obj.owner_decl, | ||
| 1629 | }); | ||
| 1630 | }, | ||
| 1631 | .enum_full, .enum_nonexhaustive => { | ||
| 1632 | const enum_full = ty.cast(Payload.EnumFull).?.data; | ||
| 1633 | return writer.print("({s} decl={d})", .{ | ||
| 1634 | @tagName(t), enum_full.owner_decl, | ||
| 1635 | }); | ||
| 1636 | }, | ||
| 1637 | .enum_simple => { | ||
| 1638 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 1639 | return writer.print("({s} decl={d})", .{ | ||
| 1640 | @tagName(t), enum_simple.owner_decl, | ||
| 1641 | }); | ||
| 1642 | }, | ||
| 1643 | .enum_numbered => { | ||
| 1644 | const enum_numbered = ty.castTag(.enum_numbered).?.data; | ||
| 1645 | return writer.print("({s} decl={d})", .{ | ||
| 1646 | @tagName(t), enum_numbered.owner_decl, | ||
| 1647 | }); | ||
| 1648 | }, | ||
| 1649 | .@"opaque" => { | ||
| 1650 | const opaque_obj = ty.castTag(.@"opaque").?.data; | ||
| 1651 | return writer.print("({s} decl={d})", .{ | ||
| 1652 | @tagName(t), opaque_obj.owner_decl, | ||
| 1653 | }); | ||
| 1654 | }, | ||
| 1655 | |||
| 1656 | .anyerror_void_error_union => return writer.writeAll("anyerror!void"), | ||
| 1657 | .const_slice_u8 => return writer.writeAll("[]const u8"), | ||
| 1658 | .const_slice_u8_sentinel_0 => return writer.writeAll("[:0]const u8"), | ||
| 1659 | .fn_noreturn_no_args => return writer.writeAll("fn() noreturn"), | ||
| 1660 | .fn_void_no_args => return writer.writeAll("fn() void"), | ||
| 1661 | .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"), | ||
| 1662 | .fn_ccc_void_no_args => return writer.writeAll("fn() callconv(.C) void"), | ||
| 1663 | .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"), | ||
| 1664 | .manyptr_u8 => return writer.writeAll("[*]u8"), | ||
| 1665 | .manyptr_const_u8 => return writer.writeAll("[*]const u8"), | ||
| 1666 | .manyptr_const_u8_sentinel_0 => return writer.writeAll("[*:0]const u8"), | ||
| 1667 | .atomic_order => return writer.writeAll("std.builtin.AtomicOrder"), | ||
| 1668 | .atomic_rmw_op => return writer.writeAll("std.builtin.AtomicRmwOp"), | ||
| 1669 | .calling_convention => return writer.writeAll("std.builtin.CallingConvention"), | ||
| 1670 | .address_space => return writer.writeAll("std.builtin.AddressSpace"), | ||
| 1671 | .float_mode => return writer.writeAll("std.builtin.FloatMode"), | ||
| 1672 | .reduce_op => return writer.writeAll("std.builtin.ReduceOp"), | ||
| 1673 | .modifier => return writer.writeAll("std.builtin.CallModifier"), | ||
| 1674 | .prefetch_options => return writer.writeAll("std.builtin.PrefetchOptions"), | ||
| 1675 | .export_options => return writer.writeAll("std.builtin.ExportOptions"), | ||
| 1676 | .extern_options => return writer.writeAll("std.builtin.ExternOptions"), | ||
| 1677 | .type_info => return writer.writeAll("std.builtin.Type"), | ||
| 1678 | .function => { | ||
| 1679 | const payload = ty.castTag(.function).?.data; | ||
| 1680 | try writer.writeAll("fn("); | ||
| 1681 | for (payload.param_types, 0..) |param_type, i| { | ||
| 1682 | if (i != 0) try writer.writeAll(", "); | ||
| 1683 | try param_type.dump("", .{}, writer); | ||
| 1684 | } | ||
| 1685 | if (payload.is_var_args) { | ||
| 1686 | if (payload.param_types.len != 0) { | ||
| 1687 | try writer.writeAll(", "); | ||
| 1688 | } | ||
| 1689 | try writer.writeAll("..."); | ||
| 1690 | } | ||
| 1691 | try writer.writeAll(") "); | ||
| 1692 | if (payload.alignment != 0) { | ||
| 1693 | try writer.print("align({d}) ", .{payload.alignment}); | ||
| 1694 | } | ||
| 1695 | if (payload.cc != .Unspecified) { | ||
| 1696 | try writer.writeAll("callconv(."); | ||
| 1697 | try writer.writeAll(@tagName(payload.cc)); | ||
| 1698 | try writer.writeAll(") "); | ||
| 1699 | } | ||
| 1700 | ty = payload.return_type; | ||
| 1701 | continue; | ||
| 1702 | }, | ||
| 1703 | |||
| 1704 | .anyframe_T => { | ||
| 1705 | const return_type = ty.castTag(.anyframe_T).?.data; | ||
| 1706 | try writer.print("anyframe->", .{}); | ||
| 1707 | ty = return_type; | ||
| 1708 | continue; | ||
| 1709 | }, | ||
| 1710 | .array_u8 => { | ||
| 1711 | const len = ty.castTag(.array_u8).?.data; | ||
| 1712 | return writer.print("[{d}]u8", .{len}); | ||
| 1713 | }, | ||
| 1714 | .array_u8_sentinel_0 => { | ||
| 1715 | const len = ty.castTag(.array_u8_sentinel_0).?.data; | ||
| 1716 | return writer.print("[{d}:0]u8", .{len}); | ||
| 1717 | }, | ||
| 1718 | .vector => { | ||
| 1719 | const payload = ty.castTag(.vector).?.data; | ||
| 1720 | try writer.print("@Vector({d}, ", .{payload.len}); | ||
| 1721 | try payload.elem_type.dump("", .{}, writer); | ||
| 1722 | return writer.writeAll(")"); | ||
| 1723 | }, | ||
| 1724 | .array => { | ||
| 1725 | const payload = ty.castTag(.array).?.data; | ||
| 1726 | try writer.print("[{d}]", .{payload.len}); | ||
| 1727 | ty = payload.elem_type; | ||
| 1728 | continue; | ||
| 1729 | }, | ||
| 1730 | .array_sentinel => { | ||
| 1731 | const payload = ty.castTag(.array_sentinel).?.data; | ||
| 1732 | try writer.print("[{d}:{}]", .{ | ||
| 1733 | payload.len, | ||
| 1734 | payload.sentinel.fmtDebug(), | ||
| 1735 | }); | ||
| 1736 | ty = payload.elem_type; | ||
| 1737 | continue; | ||
| 1738 | }, | ||
| 1739 | .tuple => { | ||
| 1740 | const tuple = ty.castTag(.tuple).?.data; | ||
| 1741 | try writer.writeAll("tuple{"); | ||
| 1742 | for (tuple.types, 0..) |field_ty, i| { | ||
| 1743 | if (i != 0) try writer.writeAll(", "); | ||
| 1744 | const val = tuple.values[i]; | ||
| 1745 | if (val.tag() != .unreachable_value) { | ||
| 1746 | try writer.writeAll("comptime "); | ||
| 1747 | } | ||
| 1748 | try field_ty.dump("", .{}, writer); | ||
| 1749 | if (val.tag() != .unreachable_value) { | ||
| 1750 | try writer.print(" = {}", .{val.fmtDebug()}); | ||
| 1751 | } | ||
| 1752 | } | ||
| 1753 | try writer.writeAll("}"); | ||
| 1754 | return; | ||
| 1755 | }, | ||
| 1756 | .anon_struct => { | ||
| 1757 | const anon_struct = ty.castTag(.anon_struct).?.data; | ||
| 1758 | try writer.writeAll("struct{"); | ||
| 1759 | for (anon_struct.types, 0..) |field_ty, i| { | ||
| 1760 | if (i != 0) try writer.writeAll(", "); | ||
| 1761 | const val = anon_struct.values[i]; | ||
| 1762 | if (val.tag() != .unreachable_value) { | ||
| 1763 | try writer.writeAll("comptime "); | ||
| 1764 | } | ||
| 1765 | try writer.writeAll(anon_struct.names[i]); | ||
| 1766 | try writer.writeAll(": "); | ||
| 1767 | try field_ty.dump("", .{}, writer); | ||
| 1768 | if (val.tag() != .unreachable_value) { | ||
| 1769 | try writer.print(" = {}", .{val.fmtDebug()}); | ||
| 1770 | } | ||
| 1771 | } | ||
| 1772 | try writer.writeAll("}"); | ||
| 1773 | return; | ||
| 1774 | }, | ||
| 1775 | .single_const_pointer => { | ||
| 1776 | const pointee_type = ty.castTag(.single_const_pointer).?.data; | ||
| 1777 | try writer.writeAll("*const "); | ||
| 1778 | ty = pointee_type; | ||
| 1779 | continue; | ||
| 1780 | }, | ||
| 1781 | .single_mut_pointer => { | ||
| 1782 | const pointee_type = ty.castTag(.single_mut_pointer).?.data; | ||
| 1783 | try writer.writeAll("*"); | ||
| 1784 | ty = pointee_type; | ||
| 1785 | continue; | ||
| 1786 | }, | ||
| 1787 | .many_const_pointer => { | ||
| 1788 | const pointee_type = ty.castTag(.many_const_pointer).?.data; | ||
| 1789 | try writer.writeAll("[*]const "); | ||
| 1790 | ty = pointee_type; | ||
| 1791 | continue; | ||
| 1792 | }, | ||
| 1793 | .many_mut_pointer => { | ||
| 1794 | const pointee_type = ty.castTag(.many_mut_pointer).?.data; | ||
| 1795 | try writer.writeAll("[*]"); | ||
| 1796 | ty = pointee_type; | ||
| 1797 | continue; | ||
| 1798 | }, | ||
| 1799 | .c_const_pointer => { | ||
| 1800 | const pointee_type = ty.castTag(.c_const_pointer).?.data; | ||
| 1801 | try writer.writeAll("[*c]const "); | ||
| 1802 | ty = pointee_type; | ||
| 1803 | continue; | ||
| 1804 | }, | ||
| 1805 | .c_mut_pointer => { | ||
| 1806 | const pointee_type = ty.castTag(.c_mut_pointer).?.data; | ||
| 1807 | try writer.writeAll("[*c]"); | ||
| 1808 | ty = pointee_type; | ||
| 1809 | continue; | ||
| 1810 | }, | ||
| 1811 | .const_slice => { | ||
| 1812 | const pointee_type = ty.castTag(.const_slice).?.data; | ||
| 1813 | try writer.writeAll("[]const "); | ||
| 1814 | ty = pointee_type; | ||
| 1815 | continue; | ||
| 1816 | }, | ||
| 1817 | .mut_slice => { | ||
| 1818 | const pointee_type = ty.castTag(.mut_slice).?.data; | ||
| 1819 | try writer.writeAll("[]"); | ||
| 1820 | ty = pointee_type; | ||
| 1821 | continue; | ||
| 1822 | }, | ||
| 1823 | .int_signed => { | ||
| 1824 | const bits = ty.castTag(.int_signed).?.data; | ||
| 1825 | return writer.print("i{d}", .{bits}); | ||
| 1826 | }, | ||
| 1827 | .int_unsigned => { | ||
| 1828 | const bits = ty.castTag(.int_unsigned).?.data; | ||
| 1829 | return writer.print("u{d}", .{bits}); | ||
| 1830 | }, | ||
| 1831 | .optional => { | ||
| 1832 | const child_type = ty.castTag(.optional).?.data; | ||
| 1833 | try writer.writeByte('?'); | ||
| 1834 | ty = child_type; | ||
| 1835 | continue; | ||
| 1836 | }, | ||
| 1837 | .optional_single_const_pointer => { | ||
| 1838 | const pointee_type = ty.castTag(.optional_single_const_pointer).?.data; | ||
| 1839 | try writer.writeAll("?*const "); | ||
| 1840 | ty = pointee_type; | ||
| 1841 | continue; | ||
| 1842 | }, | ||
| 1843 | .optional_single_mut_pointer => { | ||
| 1844 | const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data; | ||
| 1845 | try writer.writeAll("?*"); | ||
| 1846 | ty = pointee_type; | ||
| 1847 | continue; | ||
| 1848 | }, | ||
| 1849 | |||
| 1850 | .pointer => { | ||
| 1851 | const payload = ty.castTag(.pointer).?.data; | ||
| 1852 | if (payload.sentinel) |some| switch (payload.size) { | ||
| 1853 | .One, .C => unreachable, | ||
| 1854 | .Many => try writer.print("[*:{}]", .{some.fmtDebug()}), | ||
| 1855 | .Slice => try writer.print("[:{}]", .{some.fmtDebug()}), | ||
| 1856 | } else switch (payload.size) { | ||
| 1857 | .One => try writer.writeAll("*"), | ||
| 1858 | .Many => try writer.writeAll("[*]"), | ||
| 1859 | .C => try writer.writeAll("[*c]"), | ||
| 1860 | .Slice => try writer.writeAll("[]"), | ||
| 1861 | } | ||
| 1862 | if (payload.@"align" != 0 or payload.host_size != 0 or payload.vector_index != .none) { | ||
| 1863 | try writer.print("align({d}", .{payload.@"align"}); | ||
| 1864 | |||
| 1865 | if (payload.bit_offset != 0 or payload.host_size != 0) { | ||
| 1866 | try writer.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size }); | ||
| 1867 | } | ||
| 1868 | if (payload.vector_index == .runtime) { | ||
| 1869 | try writer.writeAll(":?"); | ||
| 1870 | } else if (payload.vector_index != .none) { | ||
| 1871 | try writer.print(":{d}", .{@enumToInt(payload.vector_index)}); | ||
| 1872 | } | ||
| 1873 | try writer.writeAll(") "); | ||
| 1874 | } | ||
| 1875 | if (payload.@"addrspace" != .generic) { | ||
| 1876 | try writer.print("addrspace(.{s}) ", .{@tagName(payload.@"addrspace")}); | ||
| 1877 | } | ||
| 1878 | if (!payload.mutable) try writer.writeAll("const "); | ||
| 1879 | if (payload.@"volatile") try writer.writeAll("volatile "); | ||
| 1880 | if (payload.@"allowzero" and payload.size != .C) try writer.writeAll("allowzero "); | ||
| 1881 | |||
| 1882 | ty = payload.pointee_type; | ||
| 1883 | continue; | ||
| 1884 | }, | ||
| 1885 | .error_union => { | ||
| 1886 | const payload = ty.castTag(.error_union).?.data; | ||
| 1887 | try payload.error_set.dump("", .{}, writer); | ||
| 1888 | try writer.writeAll("!"); | ||
| 1889 | ty = payload.payload; | ||
| 1890 | continue; | ||
| 1891 | }, | ||
| 1892 | .error_set => { | ||
| 1893 | const names = ty.castTag(.error_set).?.data.names.keys(); | ||
| 1894 | try writer.writeAll("error{"); | ||
| 1895 | for (names, 0..) |name, i| { | ||
| 1896 | if (i != 0) try writer.writeByte(','); | ||
| 1897 | try writer.writeAll(name); | ||
| 1898 | } | ||
| 1899 | try writer.writeAll("}"); | ||
| 1900 | return; | ||
| 1901 | }, | ||
| 1902 | .error_set_inferred => { | ||
| 1903 | const func = ty.castTag(.error_set_inferred).?.data.func; | ||
| 1904 | return writer.print("({s} func={d})", .{ | ||
| 1905 | @tagName(t), func.owner_decl, | ||
| 1906 | }); | ||
| 1907 | }, | ||
| 1908 | .error_set_merged => { | ||
| 1909 | const names = ty.castTag(.error_set_merged).?.data.keys(); | ||
| 1910 | try writer.writeAll("error{"); | ||
| 1911 | for (names, 0..) |name, i| { | ||
| 1912 | if (i != 0) try writer.writeByte(','); | ||
| 1913 | try writer.writeAll(name); | ||
| 1914 | } | ||
| 1915 | try writer.writeAll("}"); | ||
| 1916 | return; | ||
| 1917 | }, | ||
| 1918 | .error_set_single => { | ||
| 1919 | const name = ty.castTag(.error_set_single).?.data; | ||
| 1920 | return writer.print("error{{{s}}}", .{name}); | ||
| 1921 | }, | ||
| 1922 | .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"), | ||
| 1923 | .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"), | ||
| 1924 | .generic_poison => return writer.writeAll("(generic poison)"), | ||
| 1925 | } | ||
| 1926 | unreachable; | ||
| 1927 | } | ||
| 1928 | } | 182 | } |
| 1929 | 183 | ||
| 1930 | pub const nameAllocArena = nameAlloc; | 184 | pub const nameAllocArena = nameAlloc; |
| ... | @@ -1938,253 +192,16 @@ pub const Type = extern union { | ... | @@ -1938,253 +192,16 @@ pub const Type = extern union { |
| 1938 | 192 | ||
| 1939 | /// Prints a name suitable for `@typeName`. | 193 | /// Prints a name suitable for `@typeName`. |
| 1940 | pub fn print(ty: Type, writer: anytype, mod: *Module) @TypeOf(writer).Error!void { | 194 | pub fn print(ty: Type, writer: anytype, mod: *Module) @TypeOf(writer).Error!void { |
| 1941 | const t = ty.tag(); | 195 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 1942 | switch (t) { | 196 | .int_type => |int_type| { |
| 1943 | .inferred_alloc_const => unreachable, | 197 | const sign_char: u8 = switch (int_type.signedness) { |
| 1944 | .inferred_alloc_mut => unreachable, | 198 | .signed => 'i', |
| 1945 | .generic_poison => unreachable, | 199 | .unsigned => 'u', |
| 1946 | 200 | }; | |
| 1947 | // TODO get rid of these Type.Tag values. | 201 | return writer.print("{c}{d}", .{ sign_char, int_type.bits }); |
| 1948 | .atomic_order => unreachable, | ||
| 1949 | .atomic_rmw_op => unreachable, | ||
| 1950 | .calling_convention => unreachable, | ||
| 1951 | .address_space => unreachable, | ||
| 1952 | .float_mode => unreachable, | ||
| 1953 | .reduce_op => unreachable, | ||
| 1954 | .modifier => unreachable, | ||
| 1955 | .prefetch_options => unreachable, | ||
| 1956 | .export_options => unreachable, | ||
| 1957 | .extern_options => unreachable, | ||
| 1958 | .type_info => unreachable, | ||
| 1959 | |||
| 1960 | .u1, | ||
| 1961 | .u8, | ||
| 1962 | .i8, | ||
| 1963 | .u16, | ||
| 1964 | .i16, | ||
| 1965 | .u29, | ||
| 1966 | .u32, | ||
| 1967 | .i32, | ||
| 1968 | .u64, | ||
| 1969 | .i64, | ||
| 1970 | .u128, | ||
| 1971 | .i128, | ||
| 1972 | .usize, | ||
| 1973 | .isize, | ||
| 1974 | .c_char, | ||
| 1975 | .c_short, | ||
| 1976 | .c_ushort, | ||
| 1977 | .c_int, | ||
| 1978 | .c_uint, | ||
| 1979 | .c_long, | ||
| 1980 | .c_ulong, | ||
| 1981 | .c_longlong, | ||
| 1982 | .c_ulonglong, | ||
| 1983 | .c_longdouble, | ||
| 1984 | .anyopaque, | ||
| 1985 | .f16, | ||
| 1986 | .f32, | ||
| 1987 | .f64, | ||
| 1988 | .f80, | ||
| 1989 | .f128, | ||
| 1990 | .bool, | ||
| 1991 | .void, | ||
| 1992 | .type, | ||
| 1993 | .anyerror, | ||
| 1994 | .@"anyframe", | ||
| 1995 | .comptime_int, | ||
| 1996 | .comptime_float, | ||
| 1997 | .noreturn, | ||
| 1998 | => try writer.writeAll(@tagName(t)), | ||
| 1999 | |||
| 2000 | .enum_literal => try writer.writeAll("@TypeOf(.enum_literal)"), | ||
| 2001 | .null => try writer.writeAll("@TypeOf(null)"), | ||
| 2002 | .undefined => try writer.writeAll("@TypeOf(undefined)"), | ||
| 2003 | .empty_struct_literal => try writer.writeAll("@TypeOf(.{})"), | ||
| 2004 | |||
| 2005 | .empty_struct => { | ||
| 2006 | const namespace = ty.castTag(.empty_struct).?.data; | ||
| 2007 | try namespace.renderFullyQualifiedName(mod, "", writer); | ||
| 2008 | }, | ||
| 2009 | |||
| 2010 | .@"struct" => { | ||
| 2011 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 2012 | const decl = mod.declPtr(struct_obj.owner_decl); | ||
| 2013 | try decl.renderFullyQualifiedName(mod, writer); | ||
| 2014 | }, | ||
| 2015 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 2016 | const union_obj = ty.cast(Payload.Union).?.data; | ||
| 2017 | const decl = mod.declPtr(union_obj.owner_decl); | ||
| 2018 | try decl.renderFullyQualifiedName(mod, writer); | ||
| 2019 | }, | ||
| 2020 | .enum_full, .enum_nonexhaustive => { | ||
| 2021 | const enum_full = ty.cast(Payload.EnumFull).?.data; | ||
| 2022 | const decl = mod.declPtr(enum_full.owner_decl); | ||
| 2023 | try decl.renderFullyQualifiedName(mod, writer); | ||
| 2024 | }, | ||
| 2025 | .enum_simple => { | ||
| 2026 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 2027 | const decl = mod.declPtr(enum_simple.owner_decl); | ||
| 2028 | try decl.renderFullyQualifiedName(mod, writer); | ||
| 2029 | }, | ||
| 2030 | .enum_numbered => { | ||
| 2031 | const enum_numbered = ty.castTag(.enum_numbered).?.data; | ||
| 2032 | const decl = mod.declPtr(enum_numbered.owner_decl); | ||
| 2033 | try decl.renderFullyQualifiedName(mod, writer); | ||
| 2034 | }, | ||
| 2035 | .@"opaque" => { | ||
| 2036 | const opaque_obj = ty.cast(Payload.Opaque).?.data; | ||
| 2037 | const decl = mod.declPtr(opaque_obj.owner_decl); | ||
| 2038 | try decl.renderFullyQualifiedName(mod, writer); | ||
| 2039 | }, | ||
| 2040 | |||
| 2041 | .anyerror_void_error_union => try writer.writeAll("anyerror!void"), | ||
| 2042 | .const_slice_u8 => try writer.writeAll("[]const u8"), | ||
| 2043 | .const_slice_u8_sentinel_0 => try writer.writeAll("[:0]const u8"), | ||
| 2044 | .fn_noreturn_no_args => try writer.writeAll("fn() noreturn"), | ||
| 2045 | .fn_void_no_args => try writer.writeAll("fn() void"), | ||
| 2046 | .fn_naked_noreturn_no_args => try writer.writeAll("fn() callconv(.Naked) noreturn"), | ||
| 2047 | .fn_ccc_void_no_args => try writer.writeAll("fn() callconv(.C) void"), | ||
| 2048 | .single_const_pointer_to_comptime_int => try writer.writeAll("*const comptime_int"), | ||
| 2049 | .manyptr_u8 => try writer.writeAll("[*]u8"), | ||
| 2050 | .manyptr_const_u8 => try writer.writeAll("[*]const u8"), | ||
| 2051 | .manyptr_const_u8_sentinel_0 => try writer.writeAll("[*:0]const u8"), | ||
| 2052 | |||
| 2053 | .error_set_inferred => { | ||
| 2054 | const func = ty.castTag(.error_set_inferred).?.data.func; | ||
| 2055 | |||
| 2056 | try writer.writeAll("@typeInfo(@typeInfo(@TypeOf("); | ||
| 2057 | const owner_decl = mod.declPtr(func.owner_decl); | ||
| 2058 | try owner_decl.renderFullyQualifiedName(mod, writer); | ||
| 2059 | try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set"); | ||
| 2060 | }, | ||
| 2061 | |||
| 2062 | .function => { | ||
| 2063 | const fn_info = ty.fnInfo(); | ||
| 2064 | if (fn_info.is_noinline) { | ||
| 2065 | try writer.writeAll("noinline "); | ||
| 2066 | } | ||
| 2067 | try writer.writeAll("fn("); | ||
| 2068 | for (fn_info.param_types, 0..) |param_ty, i| { | ||
| 2069 | if (i != 0) try writer.writeAll(", "); | ||
| 2070 | if (fn_info.paramIsComptime(i)) { | ||
| 2071 | try writer.writeAll("comptime "); | ||
| 2072 | } | ||
| 2073 | if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) { | ||
| 2074 | try writer.writeAll("noalias "); | ||
| 2075 | }; | ||
| 2076 | if (param_ty.tag() == .generic_poison) { | ||
| 2077 | try writer.writeAll("anytype"); | ||
| 2078 | } else { | ||
| 2079 | try print(param_ty, writer, mod); | ||
| 2080 | } | ||
| 2081 | } | ||
| 2082 | if (fn_info.is_var_args) { | ||
| 2083 | if (fn_info.param_types.len != 0) { | ||
| 2084 | try writer.writeAll(", "); | ||
| 2085 | } | ||
| 2086 | try writer.writeAll("..."); | ||
| 2087 | } | ||
| 2088 | try writer.writeAll(") "); | ||
| 2089 | if (fn_info.alignment != 0) { | ||
| 2090 | try writer.print("align({d}) ", .{fn_info.alignment}); | ||
| 2091 | } | ||
| 2092 | if (fn_info.cc != .Unspecified) { | ||
| 2093 | try writer.writeAll("callconv(."); | ||
| 2094 | try writer.writeAll(@tagName(fn_info.cc)); | ||
| 2095 | try writer.writeAll(") "); | ||
| 2096 | } | ||
| 2097 | if (fn_info.return_type.tag() == .generic_poison) { | ||
| 2098 | try writer.writeAll("anytype"); | ||
| 2099 | } else { | ||
| 2100 | try print(fn_info.return_type, writer, mod); | ||
| 2101 | } | ||
| 2102 | }, | ||
| 2103 | |||
| 2104 | .error_union => { | ||
| 2105 | const error_union = ty.castTag(.error_union).?.data; | ||
| 2106 | try print(error_union.error_set, writer, mod); | ||
| 2107 | try writer.writeAll("!"); | ||
| 2108 | try print(error_union.payload, writer, mod); | ||
| 2109 | }, | ||
| 2110 | |||
| 2111 | .array_u8 => { | ||
| 2112 | const len = ty.castTag(.array_u8).?.data; | ||
| 2113 | try writer.print("[{d}]u8", .{len}); | ||
| 2114 | }, | ||
| 2115 | .array_u8_sentinel_0 => { | ||
| 2116 | const len = ty.castTag(.array_u8_sentinel_0).?.data; | ||
| 2117 | try writer.print("[{d}:0]u8", .{len}); | ||
| 2118 | }, | ||
| 2119 | .vector => { | ||
| 2120 | const payload = ty.castTag(.vector).?.data; | ||
| 2121 | try writer.print("@Vector({d}, ", .{payload.len}); | ||
| 2122 | try print(payload.elem_type, writer, mod); | ||
| 2123 | try writer.writeAll(")"); | ||
| 2124 | }, | ||
| 2125 | .array => { | ||
| 2126 | const payload = ty.castTag(.array).?.data; | ||
| 2127 | try writer.print("[{d}]", .{payload.len}); | ||
| 2128 | try print(payload.elem_type, writer, mod); | ||
| 2129 | }, | ||
| 2130 | .array_sentinel => { | ||
| 2131 | const payload = ty.castTag(.array_sentinel).?.data; | ||
| 2132 | try writer.print("[{d}:{}]", .{ | ||
| 2133 | payload.len, | ||
| 2134 | payload.sentinel.fmtValue(payload.elem_type, mod), | ||
| 2135 | }); | ||
| 2136 | try print(payload.elem_type, writer, mod); | ||
| 2137 | }, | ||
| 2138 | .tuple => { | ||
| 2139 | const tuple = ty.castTag(.tuple).?.data; | ||
| 2140 | |||
| 2141 | try writer.writeAll("tuple{"); | ||
| 2142 | for (tuple.types, 0..) |field_ty, i| { | ||
| 2143 | if (i != 0) try writer.writeAll(", "); | ||
| 2144 | const val = tuple.values[i]; | ||
| 2145 | if (val.tag() != .unreachable_value) { | ||
| 2146 | try writer.writeAll("comptime "); | ||
| 2147 | } | ||
| 2148 | try print(field_ty, writer, mod); | ||
| 2149 | if (val.tag() != .unreachable_value) { | ||
| 2150 | try writer.print(" = {}", .{val.fmtValue(field_ty, mod)}); | ||
| 2151 | } | ||
| 2152 | } | ||
| 2153 | try writer.writeAll("}"); | ||
| 2154 | }, | ||
| 2155 | .anon_struct => { | ||
| 2156 | const anon_struct = ty.castTag(.anon_struct).?.data; | ||
| 2157 | |||
| 2158 | try writer.writeAll("struct{"); | ||
| 2159 | for (anon_struct.types, 0..) |field_ty, i| { | ||
| 2160 | if (i != 0) try writer.writeAll(", "); | ||
| 2161 | const val = anon_struct.values[i]; | ||
| 2162 | if (val.tag() != .unreachable_value) { | ||
| 2163 | try writer.writeAll("comptime "); | ||
| 2164 | } | ||
| 2165 | try writer.writeAll(anon_struct.names[i]); | ||
| 2166 | try writer.writeAll(": "); | ||
| 2167 | |||
| 2168 | try print(field_ty, writer, mod); | ||
| 2169 | |||
| 2170 | if (val.tag() != .unreachable_value) { | ||
| 2171 | try writer.print(" = {}", .{val.fmtValue(field_ty, mod)}); | ||
| 2172 | } | ||
| 2173 | } | ||
| 2174 | try writer.writeAll("}"); | ||
| 2175 | }, | 202 | }, |
| 2176 | 203 | .ptr_type => { | |
| 2177 | .pointer, | 204 | const info = ty.ptrInfo(mod); |
| 2178 | .single_const_pointer, | ||
| 2179 | .single_mut_pointer, | ||
| 2180 | .many_const_pointer, | ||
| 2181 | .many_mut_pointer, | ||
| 2182 | .c_const_pointer, | ||
| 2183 | .c_mut_pointer, | ||
| 2184 | .const_slice, | ||
| 2185 | .mut_slice, | ||
| 2186 | => { | ||
| 2187 | const info = ty.ptrInfo().data; | ||
| 2188 | 205 | ||
| 2189 | if (info.sentinel) |s| switch (info.size) { | 206 | if (info.sentinel) |s| switch (info.size) { |
| 2190 | .One, .C => unreachable, | 207 | .One, .C => unreachable, |
| ... | @@ -2200,7 +217,7 @@ pub const Type = extern union { | ... | @@ -2200,7 +217,7 @@ pub const Type = extern union { |
| 2200 | if (info.@"align" != 0) { | 217 | if (info.@"align" != 0) { |
| 2201 | try writer.print("align({d}", .{info.@"align"}); | 218 | try writer.print("align({d}", .{info.@"align"}); |
| 2202 | } else { | 219 | } else { |
| 2203 | const alignment = info.pointee_type.abiAlignment(mod.getTarget()); | 220 | const alignment = info.pointee_type.abiAlignment(mod); |
| 2204 | try writer.print("align({d}", .{alignment}); | 221 | try writer.print("align({d}", .{alignment}); |
| 2205 | } | 222 | } |
| 2206 | 223 | ||
| ... | @@ -2222,127 +239,228 @@ pub const Type = extern union { | ... | @@ -2222,127 +239,228 @@ pub const Type = extern union { |
| 2222 | if (info.@"allowzero" and info.size != .C) try writer.writeAll("allowzero "); | 239 | if (info.@"allowzero" and info.size != .C) try writer.writeAll("allowzero "); |
| 2223 | 240 | ||
| 2224 | try print(info.pointee_type, writer, mod); | 241 | try print(info.pointee_type, writer, mod); |
| 242 | return; | ||
| 243 | }, | ||
| 244 | .array_type => |array_type| { | ||
| 245 | if (array_type.sentinel == .none) { | ||
| 246 | try writer.print("[{d}]", .{array_type.len}); | ||
| 247 | try print(array_type.child.toType(), writer, mod); | ||
| 248 | } else { | ||
| 249 | try writer.print("[{d}:{}]", .{ | ||
| 250 | array_type.len, | ||
| 251 | array_type.sentinel.toValue().fmtValue(array_type.child.toType(), mod), | ||
| 252 | }); | ||
| 253 | try print(array_type.child.toType(), writer, mod); | ||
| 254 | } | ||
| 255 | return; | ||
| 256 | }, | ||
| 257 | .vector_type => |vector_type| { | ||
| 258 | try writer.print("@Vector({d}, ", .{vector_type.len}); | ||
| 259 | try print(vector_type.child.toType(), writer, mod); | ||
| 260 | try writer.writeAll(")"); | ||
| 261 | return; | ||
| 262 | }, | ||
| 263 | .opt_type => |child| { | ||
| 264 | try writer.writeByte('?'); | ||
| 265 | return print(child.toType(), writer, mod); | ||
| 266 | }, | ||
| 267 | .error_union_type => |error_union_type| { | ||
| 268 | try print(error_union_type.error_set_type.toType(), writer, mod); | ||
| 269 | try writer.writeByte('!'); | ||
| 270 | try print(error_union_type.payload_type.toType(), writer, mod); | ||
| 271 | return; | ||
| 272 | }, | ||
| 273 | .inferred_error_set_type => |index| { | ||
| 274 | const ies = mod.inferredErrorSetPtr(index); | ||
| 275 | const func = ies.func; | ||
| 276 | |||
| 277 | try writer.writeAll("@typeInfo(@typeInfo(@TypeOf("); | ||
| 278 | const owner_decl = mod.declPtr(mod.funcPtr(func).owner_decl); | ||
| 279 | try owner_decl.renderFullyQualifiedName(mod, writer); | ||
| 280 | try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set"); | ||
| 281 | }, | ||
| 282 | .error_set_type => |error_set_type| { | ||
| 283 | const names = error_set_type.names; | ||
| 284 | try writer.writeAll("error{"); | ||
| 285 | for (names, 0..) |name, i| { | ||
| 286 | if (i != 0) try writer.writeByte(','); | ||
| 287 | try writer.print("{}", .{name.fmt(&mod.intern_pool)}); | ||
| 288 | } | ||
| 289 | try writer.writeAll("}"); | ||
| 290 | }, | ||
| 291 | .simple_type => |s| switch (s) { | ||
| 292 | .f16, | ||
| 293 | .f32, | ||
| 294 | .f64, | ||
| 295 | .f80, | ||
| 296 | .f128, | ||
| 297 | .usize, | ||
| 298 | .isize, | ||
| 299 | .c_char, | ||
| 300 | .c_short, | ||
| 301 | .c_ushort, | ||
| 302 | .c_int, | ||
| 303 | .c_uint, | ||
| 304 | .c_long, | ||
| 305 | .c_ulong, | ||
| 306 | .c_longlong, | ||
| 307 | .c_ulonglong, | ||
| 308 | .c_longdouble, | ||
| 309 | .anyopaque, | ||
| 310 | .bool, | ||
| 311 | .void, | ||
| 312 | .type, | ||
| 313 | .anyerror, | ||
| 314 | .comptime_int, | ||
| 315 | .comptime_float, | ||
| 316 | .noreturn, | ||
| 317 | => return writer.writeAll(@tagName(s)), | ||
| 318 | |||
| 319 | .null, | ||
| 320 | .undefined, | ||
| 321 | => try writer.print("@TypeOf({s})", .{@tagName(s)}), | ||
| 322 | |||
| 323 | .enum_literal => try writer.print("@TypeOf(.{s})", .{@tagName(s)}), | ||
| 324 | .atomic_order => try writer.writeAll("std.builtin.AtomicOrder"), | ||
| 325 | .atomic_rmw_op => try writer.writeAll("std.builtin.AtomicRmwOp"), | ||
| 326 | .calling_convention => try writer.writeAll("std.builtin.CallingConvention"), | ||
| 327 | .address_space => try writer.writeAll("std.builtin.AddressSpace"), | ||
| 328 | .float_mode => try writer.writeAll("std.builtin.FloatMode"), | ||
| 329 | .reduce_op => try writer.writeAll("std.builtin.ReduceOp"), | ||
| 330 | .call_modifier => try writer.writeAll("std.builtin.CallModifier"), | ||
| 331 | .prefetch_options => try writer.writeAll("std.builtin.PrefetchOptions"), | ||
| 332 | .export_options => try writer.writeAll("std.builtin.ExportOptions"), | ||
| 333 | .extern_options => try writer.writeAll("std.builtin.ExternOptions"), | ||
| 334 | .type_info => try writer.writeAll("std.builtin.Type"), | ||
| 335 | |||
| 336 | .generic_poison => unreachable, | ||
| 337 | }, | ||
| 338 | .struct_type => |struct_type| { | ||
| 339 | if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { | ||
| 340 | const decl = mod.declPtr(struct_obj.owner_decl); | ||
| 341 | try decl.renderFullyQualifiedName(mod, writer); | ||
| 342 | } else if (struct_type.namespace.unwrap()) |namespace_index| { | ||
| 343 | const namespace = mod.namespacePtr(namespace_index); | ||
| 344 | try namespace.renderFullyQualifiedName(mod, .empty, writer); | ||
| 345 | } else { | ||
| 346 | try writer.writeAll("@TypeOf(.{})"); | ||
| 347 | } | ||
| 348 | }, | ||
| 349 | .anon_struct_type => |anon_struct| { | ||
| 350 | if (anon_struct.types.len == 0) { | ||
| 351 | return writer.writeAll("@TypeOf(.{})"); | ||
| 352 | } | ||
| 353 | try writer.writeAll("struct{"); | ||
| 354 | for (anon_struct.types, anon_struct.values, 0..) |field_ty, val, i| { | ||
| 355 | if (i != 0) try writer.writeAll(", "); | ||
| 356 | if (val != .none) { | ||
| 357 | try writer.writeAll("comptime "); | ||
| 358 | } | ||
| 359 | if (anon_struct.names.len != 0) { | ||
| 360 | try writer.print("{}: ", .{anon_struct.names[i].fmt(&mod.intern_pool)}); | ||
| 361 | } | ||
| 362 | |||
| 363 | try print(field_ty.toType(), writer, mod); | ||
| 364 | |||
| 365 | if (val != .none) { | ||
| 366 | try writer.print(" = {}", .{val.toValue().fmtValue(field_ty.toType(), mod)}); | ||
| 367 | } | ||
| 368 | } | ||
| 369 | try writer.writeAll("}"); | ||
| 2225 | }, | 370 | }, |
| 2226 | 371 | ||
| 2227 | .int_signed => { | 372 | .union_type => |union_type| { |
| 2228 | const bits = ty.castTag(.int_signed).?.data; | 373 | const union_obj = mod.unionPtr(union_type.index); |
| 2229 | return writer.print("i{d}", .{bits}); | 374 | const decl = mod.declPtr(union_obj.owner_decl); |
| 2230 | }, | 375 | try decl.renderFullyQualifiedName(mod, writer); |
| 2231 | .int_unsigned => { | ||
| 2232 | const bits = ty.castTag(.int_unsigned).?.data; | ||
| 2233 | return writer.print("u{d}", .{bits}); | ||
| 2234 | }, | ||
| 2235 | .optional => { | ||
| 2236 | const child_type = ty.castTag(.optional).?.data; | ||
| 2237 | try writer.writeByte('?'); | ||
| 2238 | try print(child_type, writer, mod); | ||
| 2239 | }, | ||
| 2240 | .optional_single_mut_pointer => { | ||
| 2241 | const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data; | ||
| 2242 | try writer.writeAll("?*"); | ||
| 2243 | try print(pointee_type, writer, mod); | ||
| 2244 | }, | 376 | }, |
| 2245 | .optional_single_const_pointer => { | 377 | .opaque_type => |opaque_type| { |
| 2246 | const pointee_type = ty.castTag(.optional_single_const_pointer).?.data; | 378 | const decl = mod.declPtr(opaque_type.decl); |
| 2247 | try writer.writeAll("?*const "); | 379 | try decl.renderFullyQualifiedName(mod, writer); |
| 2248 | try print(pointee_type, writer, mod); | ||
| 2249 | }, | 380 | }, |
| 2250 | .anyframe_T => { | 381 | .enum_type => |enum_type| { |
| 2251 | const return_type = ty.castTag(.anyframe_T).?.data; | 382 | const decl = mod.declPtr(enum_type.decl); |
| 2252 | try writer.print("anyframe->", .{}); | 383 | try decl.renderFullyQualifiedName(mod, writer); |
| 2253 | try print(return_type, writer, mod); | ||
| 2254 | }, | 384 | }, |
| 2255 | .error_set => { | 385 | .func_type => |fn_info| { |
| 2256 | const names = ty.castTag(.error_set).?.data.names.keys(); | 386 | if (fn_info.is_noinline) { |
| 2257 | try writer.writeAll("error{"); | 387 | try writer.writeAll("noinline "); |
| 2258 | for (names, 0..) |name, i| { | ||
| 2259 | if (i != 0) try writer.writeByte(','); | ||
| 2260 | try writer.writeAll(name); | ||
| 2261 | } | 388 | } |
| 2262 | try writer.writeAll("}"); | 389 | try writer.writeAll("fn("); |
| 2263 | }, | 390 | for (fn_info.param_types, 0..) |param_ty, i| { |
| 2264 | .error_set_single => { | 391 | if (i != 0) try writer.writeAll(", "); |
| 2265 | const name = ty.castTag(.error_set_single).?.data; | 392 | if (std.math.cast(u5, i)) |index| { |
| 2266 | return writer.print("error{{{s}}}", .{name}); | 393 | if (fn_info.paramIsComptime(index)) { |
| 2267 | }, | 394 | try writer.writeAll("comptime "); |
| 2268 | .error_set_merged => { | 395 | } |
| 2269 | const names = ty.castTag(.error_set_merged).?.data.keys(); | 396 | if (fn_info.paramIsNoalias(index)) { |
| 2270 | try writer.writeAll("error{"); | 397 | try writer.writeAll("noalias "); |
| 2271 | for (names, 0..) |name, i| { | 398 | } |
| 2272 | if (i != 0) try writer.writeByte(','); | 399 | } |
| 2273 | try writer.writeAll(name); | 400 | if (param_ty == .generic_poison_type) { |
| 401 | try writer.writeAll("anytype"); | ||
| 402 | } else { | ||
| 403 | try print(param_ty.toType(), writer, mod); | ||
| 404 | } | ||
| 2274 | } | 405 | } |
| 2275 | try writer.writeAll("}"); | 406 | if (fn_info.is_var_args) { |
| 407 | if (fn_info.param_types.len != 0) { | ||
| 408 | try writer.writeAll(", "); | ||
| 409 | } | ||
| 410 | try writer.writeAll("..."); | ||
| 411 | } | ||
| 412 | try writer.writeAll(") "); | ||
| 413 | if (fn_info.alignment.toByteUnitsOptional()) |a| { | ||
| 414 | try writer.print("align({d}) ", .{a}); | ||
| 415 | } | ||
| 416 | if (fn_info.cc != .Unspecified) { | ||
| 417 | try writer.writeAll("callconv(."); | ||
| 418 | try writer.writeAll(@tagName(fn_info.cc)); | ||
| 419 | try writer.writeAll(") "); | ||
| 420 | } | ||
| 421 | if (fn_info.return_type == .generic_poison_type) { | ||
| 422 | try writer.writeAll("anytype"); | ||
| 423 | } else { | ||
| 424 | try print(fn_info.return_type.toType(), writer, mod); | ||
| 425 | } | ||
| 426 | }, | ||
| 427 | .anyframe_type => |child| { | ||
| 428 | if (child == .none) return writer.writeAll("anyframe"); | ||
| 429 | try writer.writeAll("anyframe->"); | ||
| 430 | return print(child.toType(), writer, mod); | ||
| 2276 | }, | 431 | }, |
| 432 | |||
| 433 | // values, not types | ||
| 434 | .undef, | ||
| 435 | .runtime_value, | ||
| 436 | .simple_value, | ||
| 437 | .variable, | ||
| 438 | .extern_func, | ||
| 439 | .func, | ||
| 440 | .int, | ||
| 441 | .err, | ||
| 442 | .error_union, | ||
| 443 | .enum_literal, | ||
| 444 | .enum_tag, | ||
| 445 | .empty_enum_value, | ||
| 446 | .float, | ||
| 447 | .ptr, | ||
| 448 | .opt, | ||
| 449 | .aggregate, | ||
| 450 | .un, | ||
| 451 | // memoization, not types | ||
| 452 | .memoized_call, | ||
| 453 | => unreachable, | ||
| 2277 | } | 454 | } |
| 2278 | } | 455 | } |
| 2279 | 456 | ||
| 2280 | pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value { | 457 | pub fn toIntern(ty: Type) InternPool.Index { |
| 2281 | switch (self.tag()) { | 458 | assert(ty.ip_index != .none); |
| 2282 | .u1 => return Value.initTag(.u1_type), | 459 | return ty.ip_index; |
| 2283 | .u8 => return Value.initTag(.u8_type), | 460 | } |
| 2284 | .i8 => return Value.initTag(.i8_type), | 461 | |
| 2285 | .u16 => return Value.initTag(.u16_type), | 462 | pub fn toValue(self: Type) Value { |
| 2286 | .u29 => return Value.initTag(.u29_type), | 463 | return self.toIntern().toValue(); |
| 2287 | .i16 => return Value.initTag(.i16_type), | ||
| 2288 | .u32 => return Value.initTag(.u32_type), | ||
| 2289 | .i32 => return Value.initTag(.i32_type), | ||
| 2290 | .u64 => return Value.initTag(.u64_type), | ||
| 2291 | .i64 => return Value.initTag(.i64_type), | ||
| 2292 | .usize => return Value.initTag(.usize_type), | ||
| 2293 | .isize => return Value.initTag(.isize_type), | ||
| 2294 | .c_char => return Value.initTag(.c_char_type), | ||
| 2295 | .c_short => return Value.initTag(.c_short_type), | ||
| 2296 | .c_ushort => return Value.initTag(.c_ushort_type), | ||
| 2297 | .c_int => return Value.initTag(.c_int_type), | ||
| 2298 | .c_uint => return Value.initTag(.c_uint_type), | ||
| 2299 | .c_long => return Value.initTag(.c_long_type), | ||
| 2300 | .c_ulong => return Value.initTag(.c_ulong_type), | ||
| 2301 | .c_longlong => return Value.initTag(.c_longlong_type), | ||
| 2302 | .c_ulonglong => return Value.initTag(.c_ulonglong_type), | ||
| 2303 | .c_longdouble => return Value.initTag(.c_longdouble_type), | ||
| 2304 | .anyopaque => return Value.initTag(.anyopaque_type), | ||
| 2305 | .f16 => return Value.initTag(.f16_type), | ||
| 2306 | .f32 => return Value.initTag(.f32_type), | ||
| 2307 | .f64 => return Value.initTag(.f64_type), | ||
| 2308 | .f80 => return Value.initTag(.f80_type), | ||
| 2309 | .f128 => return Value.initTag(.f128_type), | ||
| 2310 | .bool => return Value.initTag(.bool_type), | ||
| 2311 | .void => return Value.initTag(.void_type), | ||
| 2312 | .type => return Value.initTag(.type_type), | ||
| 2313 | .anyerror => return Value.initTag(.anyerror_type), | ||
| 2314 | .@"anyframe" => return Value.initTag(.anyframe_type), | ||
| 2315 | .comptime_int => return Value.initTag(.comptime_int_type), | ||
| 2316 | .comptime_float => return Value.initTag(.comptime_float_type), | ||
| 2317 | .noreturn => return Value.initTag(.noreturn_type), | ||
| 2318 | .null => return Value.initTag(.null_type), | ||
| 2319 | .undefined => return Value.initTag(.undefined_type), | ||
| 2320 | .fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type), | ||
| 2321 | .fn_void_no_args => return Value.initTag(.fn_void_no_args_type), | ||
| 2322 | .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type), | ||
| 2323 | .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type), | ||
| 2324 | .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type), | ||
| 2325 | .const_slice_u8 => return Value.initTag(.const_slice_u8_type), | ||
| 2326 | .const_slice_u8_sentinel_0 => return Value.initTag(.const_slice_u8_sentinel_0_type), | ||
| 2327 | .enum_literal => return Value.initTag(.enum_literal_type), | ||
| 2328 | .manyptr_u8 => return Value.initTag(.manyptr_u8_type), | ||
| 2329 | .manyptr_const_u8 => return Value.initTag(.manyptr_const_u8_type), | ||
| 2330 | .manyptr_const_u8_sentinel_0 => return Value.initTag(.manyptr_const_u8_sentinel_0_type), | ||
| 2331 | .atomic_order => return Value.initTag(.atomic_order_type), | ||
| 2332 | .atomic_rmw_op => return Value.initTag(.atomic_rmw_op_type), | ||
| 2333 | .calling_convention => return Value.initTag(.calling_convention_type), | ||
| 2334 | .address_space => return Value.initTag(.address_space_type), | ||
| 2335 | .float_mode => return Value.initTag(.float_mode_type), | ||
| 2336 | .reduce_op => return Value.initTag(.reduce_op_type), | ||
| 2337 | .modifier => return Value.initTag(.modifier_type), | ||
| 2338 | .prefetch_options => return Value.initTag(.prefetch_options_type), | ||
| 2339 | .export_options => return Value.initTag(.export_options_type), | ||
| 2340 | .extern_options => return Value.initTag(.extern_options_type), | ||
| 2341 | .type_info => return Value.initTag(.type_info_type), | ||
| 2342 | .inferred_alloc_const => unreachable, | ||
| 2343 | .inferred_alloc_mut => unreachable, | ||
| 2344 | else => return Value.Tag.ty.create(allocator, self), | ||
| 2345 | } | ||
| 2346 | } | 464 | } |
| 2347 | 465 | ||
| 2348 | const RuntimeBitsError = Module.CompileError || error{NeedLazy}; | 466 | const RuntimeBitsError = Module.CompileError || error{NeedLazy}; |
| ... | @@ -2360,365 +478,319 @@ pub const Type = extern union { | ... | @@ -2360,365 +478,319 @@ pub const Type = extern union { |
| 2360 | /// may return false positives. | 478 | /// may return false positives. |
| 2361 | pub fn hasRuntimeBitsAdvanced( | 479 | pub fn hasRuntimeBitsAdvanced( |
| 2362 | ty: Type, | 480 | ty: Type, |
| 481 | mod: *Module, | ||
| 2363 | ignore_comptime_only: bool, | 482 | ignore_comptime_only: bool, |
| 2364 | strat: AbiAlignmentAdvancedStrat, | 483 | strat: AbiAlignmentAdvancedStrat, |
| 2365 | ) RuntimeBitsError!bool { | 484 | ) RuntimeBitsError!bool { |
| 2366 | switch (ty.tag()) { | 485 | return switch (ty.toIntern()) { |
| 2367 | .u1, | 486 | // False because it is a comptime-only type. |
| 2368 | .u8, | 487 | .empty_struct_type => false, |
| 2369 | .i8, | 488 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 2370 | .u16, | 489 | .int_type => |int_type| int_type.bits != 0, |
| 2371 | .i16, | 490 | .ptr_type => |ptr_type| { |
| 2372 | .u29, | 491 | // Pointers to zero-bit types still have a runtime address; however, pointers |
| 2373 | .u32, | 492 | // to comptime-only types do not, with the exception of function pointers. |
| 2374 | .i32, | 493 | if (ignore_comptime_only) return true; |
| 2375 | .u64, | 494 | const child_ty = ptr_type.child.toType(); |
| 2376 | .i64, | 495 | if (child_ty.zigTypeTag(mod) == .Fn) return !mod.typeToFunc(child_ty).?.is_generic; |
| 2377 | .u128, | 496 | if (strat == .sema) return !(try strat.sema.typeRequiresComptime(ty)); |
| 2378 | .i128, | 497 | return !comptimeOnly(ty, mod); |
| 2379 | .usize, | 498 | }, |
| 2380 | .isize, | 499 | .anyframe_type => true, |
| 2381 | .c_char, | 500 | .array_type => |array_type| { |
| 2382 | .c_short, | 501 | if (array_type.sentinel != .none) { |
| 2383 | .c_ushort, | 502 | return array_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 2384 | .c_int, | 503 | } else { |
| 2385 | .c_uint, | 504 | return array_type.len > 0 and |
| 2386 | .c_long, | 505 | try array_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 2387 | .c_ulong, | 506 | } |
| 2388 | .c_longlong, | 507 | }, |
| 2389 | .c_ulonglong, | 508 | .vector_type => |vector_type| { |
| 2390 | .c_longdouble, | 509 | return vector_type.len > 0 and |
| 2391 | .f16, | 510 | try vector_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 2392 | .f32, | 511 | }, |
| 2393 | .f64, | 512 | .opt_type => |child| { |
| 2394 | .f80, | 513 | const child_ty = child.toType(); |
| 2395 | .f128, | 514 | if (child_ty.isNoReturn(mod)) { |
| 2396 | .bool, | 515 | // Then the optional is comptime-known to be null. |
| 2397 | .anyerror, | 516 | return false; |
| 2398 | .const_slice_u8, | 517 | } |
| 2399 | .const_slice_u8_sentinel_0, | 518 | if (ignore_comptime_only) { |
| 2400 | .array_u8_sentinel_0, | ||
| 2401 | .anyerror_void_error_union, | ||
| 2402 | .error_set_inferred, | ||
| 2403 | .manyptr_u8, | ||
| 2404 | .manyptr_const_u8, | ||
| 2405 | .manyptr_const_u8_sentinel_0, | ||
| 2406 | .atomic_order, | ||
| 2407 | .atomic_rmw_op, | ||
| 2408 | .calling_convention, | ||
| 2409 | .address_space, | ||
| 2410 | .float_mode, | ||
| 2411 | .reduce_op, | ||
| 2412 | .modifier, | ||
| 2413 | .prefetch_options, | ||
| 2414 | .export_options, | ||
| 2415 | .extern_options, | ||
| 2416 | .@"anyframe", | ||
| 2417 | .anyopaque, | ||
| 2418 | .@"opaque", | ||
| 2419 | .type_info, | ||
| 2420 | .error_set_single, | ||
| 2421 | .error_union, | ||
| 2422 | .error_set, | ||
| 2423 | .error_set_merged, | ||
| 2424 | => return true, | ||
| 2425 | |||
| 2426 | // Pointers to zero-bit types still have a runtime address; however, pointers | ||
| 2427 | // to comptime-only types do not, with the exception of function pointers. | ||
| 2428 | .anyframe_T, | ||
| 2429 | .optional_single_mut_pointer, | ||
| 2430 | .optional_single_const_pointer, | ||
| 2431 | .single_const_pointer, | ||
| 2432 | .single_mut_pointer, | ||
| 2433 | .many_const_pointer, | ||
| 2434 | .many_mut_pointer, | ||
| 2435 | .c_const_pointer, | ||
| 2436 | .c_mut_pointer, | ||
| 2437 | .const_slice, | ||
| 2438 | .mut_slice, | ||
| 2439 | .pointer, | ||
| 2440 | => { | ||
| 2441 | if (ignore_comptime_only) { | ||
| 2442 | return true; | ||
| 2443 | } else if (ty.childType().zigTypeTag() == .Fn) { | ||
| 2444 | return !ty.childType().fnInfo().is_generic; | ||
| 2445 | } else if (strat == .sema) { | ||
| 2446 | return !(try strat.sema.typeRequiresComptime(ty)); | ||
| 2447 | } else { | ||
| 2448 | return !comptimeOnly(ty); | ||
| 2449 | } | ||
| 2450 | }, | ||
| 2451 | |||
| 2452 | // These are false because they are comptime-only types. | ||
| 2453 | .single_const_pointer_to_comptime_int, | ||
| 2454 | .void, | ||
| 2455 | .type, | ||
| 2456 | .comptime_int, | ||
| 2457 | .comptime_float, | ||
| 2458 | .noreturn, | ||
| 2459 | .null, | ||
| 2460 | .undefined, | ||
| 2461 | .enum_literal, | ||
| 2462 | .empty_struct, | ||
| 2463 | .empty_struct_literal, | ||
| 2464 | // These are function *bodies*, not pointers. | ||
| 2465 | // Special exceptions have to be made when emitting functions due to | ||
| 2466 | // this returning false. | ||
| 2467 | .function, | ||
| 2468 | .fn_noreturn_no_args, | ||
| 2469 | .fn_void_no_args, | ||
| 2470 | .fn_naked_noreturn_no_args, | ||
| 2471 | .fn_ccc_void_no_args, | ||
| 2472 | => return false, | ||
| 2473 | |||
| 2474 | .optional => { | ||
| 2475 | var buf: Payload.ElemType = undefined; | ||
| 2476 | const child_ty = ty.optionalChild(&buf); | ||
| 2477 | if (child_ty.isNoReturn()) { | ||
| 2478 | // Then the optional is comptime-known to be null. | ||
| 2479 | return false; | ||
| 2480 | } | ||
| 2481 | if (ignore_comptime_only) { | ||
| 2482 | return true; | ||
| 2483 | } else if (strat == .sema) { | ||
| 2484 | return !(try strat.sema.typeRequiresComptime(child_ty)); | ||
| 2485 | } else { | ||
| 2486 | return !comptimeOnly(child_ty); | ||
| 2487 | } | ||
| 2488 | }, | ||
| 2489 | |||
| 2490 | .@"struct" => { | ||
| 2491 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 2492 | if (struct_obj.status == .field_types_wip) { | ||
| 2493 | // In this case, we guess that hasRuntimeBits() for this type is true, | ||
| 2494 | // and then later if our guess was incorrect, we emit a compile error. | ||
| 2495 | struct_obj.assumed_runtime_bits = true; | ||
| 2496 | return true; | ||
| 2497 | } | ||
| 2498 | switch (strat) { | ||
| 2499 | .sema => |sema| _ = try sema.resolveTypeFields(ty), | ||
| 2500 | .eager => assert(struct_obj.haveFieldTypes()), | ||
| 2501 | .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy, | ||
| 2502 | } | ||
| 2503 | for (struct_obj.fields.values()) |field| { | ||
| 2504 | if (field.is_comptime) continue; | ||
| 2505 | if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) | ||
| 2506 | return true; | ||
| 2507 | } else { | ||
| 2508 | return false; | ||
| 2509 | } | ||
| 2510 | }, | ||
| 2511 | |||
| 2512 | .enum_full => { | ||
| 2513 | const enum_full = ty.castTag(.enum_full).?.data; | ||
| 2514 | return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat); | ||
| 2515 | }, | ||
| 2516 | .enum_simple => { | ||
| 2517 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 2518 | return enum_simple.fields.count() >= 2; | ||
| 2519 | }, | ||
| 2520 | .enum_numbered, .enum_nonexhaustive => { | ||
| 2521 | var buffer: Payload.Bits = undefined; | ||
| 2522 | const int_tag_ty = ty.intTagType(&buffer); | ||
| 2523 | return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat); | ||
| 2524 | }, | ||
| 2525 | |||
| 2526 | .@"union" => { | ||
| 2527 | const union_obj = ty.castTag(.@"union").?.data; | ||
| 2528 | if (union_obj.status == .field_types_wip) { | ||
| 2529 | // In this case, we guess that hasRuntimeBits() for this type is true, | ||
| 2530 | // and then later if our guess was incorrect, we emit a compile error. | ||
| 2531 | union_obj.assumed_runtime_bits = true; | ||
| 2532 | return true; | ||
| 2533 | } | ||
| 2534 | switch (strat) { | ||
| 2535 | .sema => |sema| _ = try sema.resolveTypeFields(ty), | ||
| 2536 | .eager => assert(union_obj.haveFieldTypes()), | ||
| 2537 | .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy, | ||
| 2538 | } | ||
| 2539 | for (union_obj.fields.values()) |value| { | ||
| 2540 | if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) | ||
| 2541 | return true; | 519 | return true; |
| 2542 | } else { | 520 | } else if (strat == .sema) { |
| 2543 | return false; | 521 | return !(try strat.sema.typeRequiresComptime(child_ty)); |
| 2544 | } | 522 | } else { |
| 2545 | }, | 523 | return !comptimeOnly(child_ty, mod); |
| 2546 | .union_safety_tagged, .union_tagged => { | 524 | } |
| 2547 | const union_obj = ty.cast(Payload.Union).?.data; | 525 | }, |
| 2548 | if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) { | 526 | .error_union_type, |
| 2549 | return true; | 527 | .error_set_type, |
| 2550 | } | 528 | .inferred_error_set_type, |
| 2551 | 529 | => true, | |
| 2552 | switch (strat) { | 530 | |
| 2553 | .sema => |sema| _ = try sema.resolveTypeFields(ty), | 531 | // These are function *bodies*, not pointers. |
| 2554 | .eager => assert(union_obj.haveFieldTypes()), | 532 | // They return false here because they are comptime-only types. |
| 2555 | .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy, | 533 | // Special exceptions have to be made when emitting functions due to |
| 2556 | } | 534 | // this returning false. |
| 2557 | for (union_obj.fields.values()) |value| { | 535 | .func_type => false, |
| 2558 | if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) | 536 | |
| 537 | .simple_type => |t| switch (t) { | ||
| 538 | .f16, | ||
| 539 | .f32, | ||
| 540 | .f64, | ||
| 541 | .f80, | ||
| 542 | .f128, | ||
| 543 | .usize, | ||
| 544 | .isize, | ||
| 545 | .c_char, | ||
| 546 | .c_short, | ||
| 547 | .c_ushort, | ||
| 548 | .c_int, | ||
| 549 | .c_uint, | ||
| 550 | .c_long, | ||
| 551 | .c_ulong, | ||
| 552 | .c_longlong, | ||
| 553 | .c_ulonglong, | ||
| 554 | .c_longdouble, | ||
| 555 | .bool, | ||
| 556 | .anyerror, | ||
| 557 | .anyopaque, | ||
| 558 | .atomic_order, | ||
| 559 | .atomic_rmw_op, | ||
| 560 | .calling_convention, | ||
| 561 | .address_space, | ||
| 562 | .float_mode, | ||
| 563 | .reduce_op, | ||
| 564 | .call_modifier, | ||
| 565 | .prefetch_options, | ||
| 566 | .export_options, | ||
| 567 | .extern_options, | ||
| 568 | => true, | ||
| 569 | |||
| 570 | // These are false because they are comptime-only types. | ||
| 571 | .void, | ||
| 572 | .type, | ||
| 573 | .comptime_int, | ||
| 574 | .comptime_float, | ||
| 575 | .noreturn, | ||
| 576 | .null, | ||
| 577 | .undefined, | ||
| 578 | .enum_literal, | ||
| 579 | .type_info, | ||
| 580 | => false, | ||
| 581 | |||
| 582 | .generic_poison => unreachable, | ||
| 583 | }, | ||
| 584 | .struct_type => |struct_type| { | ||
| 585 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse { | ||
| 586 | // This struct has no fields. | ||
| 587 | return false; | ||
| 588 | }; | ||
| 589 | if (struct_obj.status == .field_types_wip) { | ||
| 590 | // In this case, we guess that hasRuntimeBits() for this type is true, | ||
| 591 | // and then later if our guess was incorrect, we emit a compile error. | ||
| 592 | struct_obj.assumed_runtime_bits = true; | ||
| 2559 | return true; | 593 | return true; |
| 2560 | } else { | 594 | } |
| 595 | switch (strat) { | ||
| 596 | .sema => |sema| _ = try sema.resolveTypeFields(ty), | ||
| 597 | .eager => assert(struct_obj.haveFieldTypes()), | ||
| 598 | .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy, | ||
| 599 | } | ||
| 600 | for (struct_obj.fields.values()) |field| { | ||
| 601 | if (field.is_comptime) continue; | ||
| 602 | if (try field.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) | ||
| 603 | return true; | ||
| 604 | } else { | ||
| 605 | return false; | ||
| 606 | } | ||
| 607 | }, | ||
| 608 | .anon_struct_type => |tuple| { | ||
| 609 | for (tuple.types, tuple.values) |field_ty, val| { | ||
| 610 | if (val != .none) continue; // comptime field | ||
| 611 | if (try field_ty.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) return true; | ||
| 612 | } | ||
| 2561 | return false; | 613 | return false; |
| 2562 | } | 614 | }, |
| 2563 | }, | ||
| 2564 | |||
| 2565 | .array, .vector => return ty.arrayLen() != 0 and | ||
| 2566 | try ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only, strat), | ||
| 2567 | .array_u8 => return ty.arrayLen() != 0, | ||
| 2568 | .array_sentinel => return ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only, strat), | ||
| 2569 | 615 | ||
| 2570 | .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data != 0, | 616 | .union_type => |union_type| { |
| 617 | const union_obj = mod.unionPtr(union_type.index); | ||
| 618 | switch (union_type.runtime_tag) { | ||
| 619 | .none => { | ||
| 620 | if (union_obj.status == .field_types_wip) { | ||
| 621 | // In this case, we guess that hasRuntimeBits() for this type is true, | ||
| 622 | // and then later if our guess was incorrect, we emit a compile error. | ||
| 623 | union_obj.assumed_runtime_bits = true; | ||
| 624 | return true; | ||
| 625 | } | ||
| 626 | }, | ||
| 627 | .safety, .tagged => { | ||
| 628 | if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) { | ||
| 629 | return true; | ||
| 630 | } | ||
| 631 | }, | ||
| 632 | } | ||
| 633 | switch (strat) { | ||
| 634 | .sema => |sema| _ = try sema.resolveTypeFields(ty), | ||
| 635 | .eager => assert(union_obj.haveFieldTypes()), | ||
| 636 | .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy, | ||
| 637 | } | ||
| 638 | for (union_obj.fields.values()) |value| { | ||
| 639 | if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) | ||
| 640 | return true; | ||
| 641 | } else { | ||
| 642 | return false; | ||
| 643 | } | ||
| 644 | }, | ||
| 2571 | 645 | ||
| 2572 | .tuple, .anon_struct => { | 646 | .opaque_type => true, |
| 2573 | const tuple = ty.tupleFields(); | 647 | .enum_type => |enum_type| enum_type.tag_ty.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat), |
| 2574 | for (tuple.types, 0..) |field_ty, i| { | 648 | |
| 2575 | const val = tuple.values[i]; | 649 | // values, not types |
| 2576 | if (val.tag() != .unreachable_value) continue; // comptime field | 650 | .undef, |
| 2577 | if (try field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, strat)) return true; | 651 | .runtime_value, |
| 2578 | } | 652 | .simple_value, |
| 2579 | return false; | 653 | .variable, |
| 654 | .extern_func, | ||
| 655 | .func, | ||
| 656 | .int, | ||
| 657 | .err, | ||
| 658 | .error_union, | ||
| 659 | .enum_literal, | ||
| 660 | .enum_tag, | ||
| 661 | .empty_enum_value, | ||
| 662 | .float, | ||
| 663 | .ptr, | ||
| 664 | .opt, | ||
| 665 | .aggregate, | ||
| 666 | .un, | ||
| 667 | // memoization, not types | ||
| 668 | .memoized_call, | ||
| 669 | => unreachable, | ||
| 2580 | }, | 670 | }, |
| 2581 | 671 | }; | |
| 2582 | .inferred_alloc_const => unreachable, | ||
| 2583 | .inferred_alloc_mut => unreachable, | ||
| 2584 | .generic_poison => unreachable, | ||
| 2585 | } | ||
| 2586 | } | 672 | } |
| 2587 | 673 | ||
| 2588 | /// true if and only if the type has a well-defined memory layout | 674 | /// true if and only if the type has a well-defined memory layout |
| 2589 | /// readFrom/writeToMemory are supported only for types with a well- | 675 | /// readFrom/writeToMemory are supported only for types with a well- |
| 2590 | /// defined memory layout | 676 | /// defined memory layout |
| 2591 | pub fn hasWellDefinedLayout(ty: Type) bool { | 677 | pub fn hasWellDefinedLayout(ty: Type, mod: *Module) bool { |
| 2592 | return switch (ty.tag()) { | 678 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 2593 | .u1, | 679 | .int_type, |
| 2594 | .u8, | 680 | .vector_type, |
| 2595 | .i8, | ||
| 2596 | .u16, | ||
| 2597 | .i16, | ||
| 2598 | .u29, | ||
| 2599 | .u32, | ||
| 2600 | .i32, | ||
| 2601 | .u64, | ||
| 2602 | .i64, | ||
| 2603 | .u128, | ||
| 2604 | .i128, | ||
| 2605 | .usize, | ||
| 2606 | .isize, | ||
| 2607 | .c_char, | ||
| 2608 | .c_short, | ||
| 2609 | .c_ushort, | ||
| 2610 | .c_int, | ||
| 2611 | .c_uint, | ||
| 2612 | .c_long, | ||
| 2613 | .c_ulong, | ||
| 2614 | .c_longlong, | ||
| 2615 | .c_ulonglong, | ||
| 2616 | .c_longdouble, | ||
| 2617 | .f16, | ||
| 2618 | .f32, | ||
| 2619 | .f64, | ||
| 2620 | .f80, | ||
| 2621 | .f128, | ||
| 2622 | .bool, | ||
| 2623 | .void, | ||
| 2624 | .manyptr_u8, | ||
| 2625 | .manyptr_const_u8, | ||
| 2626 | .manyptr_const_u8_sentinel_0, | ||
| 2627 | .array_u8, | ||
| 2628 | .array_u8_sentinel_0, | ||
| 2629 | .int_signed, | ||
| 2630 | .int_unsigned, | ||
| 2631 | .pointer, | ||
| 2632 | .single_const_pointer, | ||
| 2633 | .single_mut_pointer, | ||
| 2634 | .many_const_pointer, | ||
| 2635 | .many_mut_pointer, | ||
| 2636 | .c_const_pointer, | ||
| 2637 | .c_mut_pointer, | ||
| 2638 | .single_const_pointer_to_comptime_int, | ||
| 2639 | .enum_numbered, | ||
| 2640 | .vector, | ||
| 2641 | .optional_single_mut_pointer, | ||
| 2642 | .optional_single_const_pointer, | ||
| 2643 | => true, | 681 | => true, |
| 2644 | 682 | ||
| 2645 | .anyopaque, | 683 | .error_union_type, |
| 2646 | .anyerror, | 684 | .error_set_type, |
| 2647 | .noreturn, | 685 | .inferred_error_set_type, |
| 2648 | .null, | 686 | .anon_struct_type, |
| 2649 | .@"anyframe", | 687 | .opaque_type, |
| 2650 | .undefined, | 688 | .anyframe_type, |
| 2651 | .atomic_order, | ||
| 2652 | .atomic_rmw_op, | ||
| 2653 | .calling_convention, | ||
| 2654 | .address_space, | ||
| 2655 | .float_mode, | ||
| 2656 | .reduce_op, | ||
| 2657 | .modifier, | ||
| 2658 | .prefetch_options, | ||
| 2659 | .export_options, | ||
| 2660 | .extern_options, | ||
| 2661 | .error_set, | ||
| 2662 | .error_set_single, | ||
| 2663 | .error_set_inferred, | ||
| 2664 | .error_set_merged, | ||
| 2665 | .@"opaque", | ||
| 2666 | .generic_poison, | ||
| 2667 | .type, | ||
| 2668 | .comptime_int, | ||
| 2669 | .comptime_float, | ||
| 2670 | .enum_literal, | ||
| 2671 | .type_info, | ||
| 2672 | // These are function bodies, not function pointers. | 689 | // These are function bodies, not function pointers. |
| 2673 | .fn_noreturn_no_args, | 690 | .func_type, |
| 2674 | .fn_void_no_args, | ||
| 2675 | .fn_naked_noreturn_no_args, | ||
| 2676 | .fn_ccc_void_no_args, | ||
| 2677 | .function, | ||
| 2678 | .const_slice_u8, | ||
| 2679 | .const_slice_u8_sentinel_0, | ||
| 2680 | .const_slice, | ||
| 2681 | .mut_slice, | ||
| 2682 | .enum_simple, | ||
| 2683 | .error_union, | ||
| 2684 | .anyerror_void_error_union, | ||
| 2685 | .anyframe_T, | ||
| 2686 | .tuple, | ||
| 2687 | .anon_struct, | ||
| 2688 | .empty_struct_literal, | ||
| 2689 | .empty_struct, | ||
| 2690 | => false, | 691 | => false, |
| 2691 | 692 | ||
| 2692 | .enum_full, | 693 | .array_type => |array_type| array_type.child.toType().hasWellDefinedLayout(mod), |
| 2693 | .enum_nonexhaustive, | 694 | .opt_type => ty.isPtrLikeOptional(mod), |
| 2694 | => !ty.cast(Payload.EnumFull).?.data.tag_ty_inferred, | 695 | .ptr_type => |ptr_type| ptr_type.flags.size != .Slice, |
| 2695 | |||
| 2696 | .inferred_alloc_mut => unreachable, | ||
| 2697 | .inferred_alloc_const => unreachable, | ||
| 2698 | 696 | ||
| 2699 | .array, | 697 | .simple_type => |t| switch (t) { |
| 2700 | .array_sentinel, | 698 | .f16, |
| 2701 | => ty.childType().hasWellDefinedLayout(), | 699 | .f32, |
| 700 | .f64, | ||
| 701 | .f80, | ||
| 702 | .f128, | ||
| 703 | .usize, | ||
| 704 | .isize, | ||
| 705 | .c_char, | ||
| 706 | .c_short, | ||
| 707 | .c_ushort, | ||
| 708 | .c_int, | ||
| 709 | .c_uint, | ||
| 710 | .c_long, | ||
| 711 | .c_ulong, | ||
| 712 | .c_longlong, | ||
| 713 | .c_ulonglong, | ||
| 714 | .c_longdouble, | ||
| 715 | .bool, | ||
| 716 | .void, | ||
| 717 | => true, | ||
| 2702 | 718 | ||
| 2703 | .optional => ty.isPtrLikeOptional(), | 719 | .anyerror, |
| 2704 | .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto, | 720 | .anyopaque, |
| 2705 | .@"union", .union_safety_tagged => ty.cast(Payload.Union).?.data.layout != .Auto, | 721 | .atomic_order, |
| 2706 | .union_tagged => false, | 722 | .atomic_rmw_op, |
| 723 | .calling_convention, | ||
| 724 | .address_space, | ||
| 725 | .float_mode, | ||
| 726 | .reduce_op, | ||
| 727 | .call_modifier, | ||
| 728 | .prefetch_options, | ||
| 729 | .export_options, | ||
| 730 | .extern_options, | ||
| 731 | .type, | ||
| 732 | .comptime_int, | ||
| 733 | .comptime_float, | ||
| 734 | .noreturn, | ||
| 735 | .null, | ||
| 736 | .undefined, | ||
| 737 | .enum_literal, | ||
| 738 | .type_info, | ||
| 739 | .generic_poison, | ||
| 740 | => false, | ||
| 741 | }, | ||
| 742 | .struct_type => |struct_type| { | ||
| 743 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse { | ||
| 744 | // Struct with no fields has a well-defined layout of no bits. | ||
| 745 | return true; | ||
| 746 | }; | ||
| 747 | return struct_obj.layout != .Auto; | ||
| 748 | }, | ||
| 749 | .union_type => |union_type| switch (union_type.runtime_tag) { | ||
| 750 | .none, .safety => mod.unionPtr(union_type.index).layout != .Auto, | ||
| 751 | .tagged => false, | ||
| 752 | }, | ||
| 753 | .enum_type => |enum_type| switch (enum_type.tag_mode) { | ||
| 754 | .auto => false, | ||
| 755 | .explicit, .nonexhaustive => true, | ||
| 756 | }, | ||
| 757 | |||
| 758 | // values, not types | ||
| 759 | .undef, | ||
| 760 | .runtime_value, | ||
| 761 | .simple_value, | ||
| 762 | .variable, | ||
| 763 | .extern_func, | ||
| 764 | .func, | ||
| 765 | .int, | ||
| 766 | .err, | ||
| 767 | .error_union, | ||
| 768 | .enum_literal, | ||
| 769 | .enum_tag, | ||
| 770 | .empty_enum_value, | ||
| 771 | .float, | ||
| 772 | .ptr, | ||
| 773 | .opt, | ||
| 774 | .aggregate, | ||
| 775 | .un, | ||
| 776 | // memoization, not types | ||
| 777 | .memoized_call, | ||
| 778 | => unreachable, | ||
| 2707 | }; | 779 | }; |
| 2708 | } | 780 | } |
| 2709 | 781 | ||
| 2710 | pub fn hasRuntimeBits(ty: Type) bool { | 782 | pub fn hasRuntimeBits(ty: Type, mod: *Module) bool { |
| 2711 | return hasRuntimeBitsAdvanced(ty, false, .eager) catch unreachable; | 783 | return hasRuntimeBitsAdvanced(ty, mod, false, .eager) catch unreachable; |
| 2712 | } | 784 | } |
| 2713 | 785 | ||
| 2714 | pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool { | 786 | pub fn hasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool { |
| 2715 | return hasRuntimeBitsAdvanced(ty, true, .eager) catch unreachable; | 787 | return hasRuntimeBitsAdvanced(ty, mod, true, .eager) catch unreachable; |
| 2716 | } | 788 | } |
| 2717 | 789 | ||
| 2718 | pub fn isFnOrHasRuntimeBits(ty: Type) bool { | 790 | pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool { |
| 2719 | switch (ty.zigTypeTag()) { | 791 | switch (ty.zigTypeTag(mod)) { |
| 2720 | .Fn => { | 792 | .Fn => { |
| 2721 | const fn_info = ty.fnInfo(); | 793 | const fn_info = mod.typeToFunc(ty).?; |
| 2722 | if (fn_info.is_generic) return false; | 794 | if (fn_info.is_generic) return false; |
| 2723 | if (fn_info.is_var_args) return true; | 795 | if (fn_info.is_var_args) return true; |
| 2724 | switch (fn_info.cc) { | 796 | switch (fn_info.cc) { |
| ... | @@ -2727,131 +799,66 @@ pub const Type = extern union { | ... | @@ -2727,131 +799,66 @@ pub const Type = extern union { |
| 2727 | .Inline => return false, | 799 | .Inline => return false, |
| 2728 | else => {}, | 800 | else => {}, |
| 2729 | } | 801 | } |
| 2730 | if (fn_info.return_type.comptimeOnly()) return false; | 802 | if (fn_info.return_type.toType().comptimeOnly(mod)) return false; |
| 2731 | return true; | 803 | return true; |
| 2732 | }, | 804 | }, |
| 2733 | else => return ty.hasRuntimeBits(), | 805 | else => return ty.hasRuntimeBits(mod), |
| 2734 | } | 806 | } |
| 2735 | } | 807 | } |
| 2736 | 808 | ||
| 2737 | /// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive. | 809 | /// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive. |
| 2738 | pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type) bool { | 810 | pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool { |
| 2739 | return switch (ty.zigTypeTag()) { | 811 | return switch (ty.zigTypeTag(mod)) { |
| 2740 | .Fn => true, | 812 | .Fn => true, |
| 2741 | else => return ty.hasRuntimeBitsIgnoreComptime(), | 813 | else => return ty.hasRuntimeBitsIgnoreComptime(mod), |
| 2742 | }; | 814 | }; |
| 2743 | } | 815 | } |
| 2744 | 816 | ||
| 2745 | /// TODO add enums with no fields here | 817 | pub fn isNoReturn(ty: Type, mod: *Module) bool { |
| 2746 | pub fn isNoReturn(ty: Type) bool { | 818 | return mod.intern_pool.isNoReturn(ty.toIntern()); |
| 2747 | switch (ty.tag()) { | ||
| 2748 | .noreturn => return true, | ||
| 2749 | .error_set => { | ||
| 2750 | const err_set_obj = ty.castTag(.error_set).?.data; | ||
| 2751 | const names = err_set_obj.names.keys(); | ||
| 2752 | return names.len == 0; | ||
| 2753 | }, | ||
| 2754 | .error_set_merged => { | ||
| 2755 | const name_map = ty.castTag(.error_set_merged).?.data; | ||
| 2756 | const names = name_map.keys(); | ||
| 2757 | return names.len == 0; | ||
| 2758 | }, | ||
| 2759 | else => return false, | ||
| 2760 | } | ||
| 2761 | } | 819 | } |
| 2762 | 820 | ||
| 2763 | /// Returns 0 if the pointer is naturally aligned and the element type is 0-bit. | 821 | /// Returns 0 if the pointer is naturally aligned and the element type is 0-bit. |
| 2764 | pub fn ptrAlignment(ty: Type, target: Target) u32 { | 822 | pub fn ptrAlignment(ty: Type, mod: *Module) u32 { |
| 2765 | return ptrAlignmentAdvanced(ty, target, null) catch unreachable; | 823 | return ptrAlignmentAdvanced(ty, mod, null) catch unreachable; |
| 2766 | } | 824 | } |
| 2767 | |||
| 2768 | pub fn ptrAlignmentAdvanced(ty: Type, target: Target, opt_sema: ?*Sema) !u32 { | ||
| 2769 | switch (ty.tag()) { | ||
| 2770 | .single_const_pointer, | ||
| 2771 | .single_mut_pointer, | ||
| 2772 | .many_const_pointer, | ||
| 2773 | .many_mut_pointer, | ||
| 2774 | .c_const_pointer, | ||
| 2775 | .c_mut_pointer, | ||
| 2776 | .const_slice, | ||
| 2777 | .mut_slice, | ||
| 2778 | .optional_single_const_pointer, | ||
| 2779 | .optional_single_mut_pointer, | ||
| 2780 | => { | ||
| 2781 | const child_type = ty.cast(Payload.ElemType).?.data; | ||
| 2782 | if (opt_sema) |sema| { | ||
| 2783 | const res = try child_type.abiAlignmentAdvanced(target, .{ .sema = sema }); | ||
| 2784 | return res.scalar; | ||
| 2785 | } | ||
| 2786 | return (child_type.abiAlignmentAdvanced(target, .eager) catch unreachable).scalar; | ||
| 2787 | }, | ||
| 2788 | 825 | ||
| 2789 | .manyptr_u8, | 826 | pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !u32 { |
| 2790 | .manyptr_const_u8, | 827 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 2791 | .manyptr_const_u8_sentinel_0, | 828 | .ptr_type => |ptr_type| { |
| 2792 | .const_slice_u8, | 829 | if (ptr_type.flags.alignment.toByteUnitsOptional()) |a| { |
| 2793 | .const_slice_u8_sentinel_0, | 830 | return @intCast(u32, a); |
| 2794 | => return 1, | ||
| 2795 | |||
| 2796 | .pointer => { | ||
| 2797 | const ptr_info = ty.castTag(.pointer).?.data; | ||
| 2798 | if (ptr_info.@"align" != 0) { | ||
| 2799 | return ptr_info.@"align"; | ||
| 2800 | } else if (opt_sema) |sema| { | 831 | } else if (opt_sema) |sema| { |
| 2801 | const res = try ptr_info.pointee_type.abiAlignmentAdvanced(target, .{ .sema = sema }); | 832 | const res = try ptr_type.child.toType().abiAlignmentAdvanced(mod, .{ .sema = sema }); |
| 2802 | return res.scalar; | 833 | return res.scalar; |
| 2803 | } else { | 834 | } else { |
| 2804 | return (ptr_info.pointee_type.abiAlignmentAdvanced(target, .eager) catch unreachable).scalar; | 835 | return (ptr_type.child.toType().abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; |
| 2805 | } | 836 | } |
| 2806 | }, | 837 | }, |
| 2807 | .optional => return ty.castTag(.optional).?.data.ptrAlignmentAdvanced(target, opt_sema), | 838 | .opt_type => |child| child.toType().ptrAlignmentAdvanced(mod, opt_sema), |
| 2808 | |||
| 2809 | else => unreachable, | 839 | else => unreachable, |
| 2810 | } | 840 | }; |
| 2811 | } | 841 | } |
| 2812 | 842 | ||
| 2813 | pub fn ptrAddressSpace(self: Type) std.builtin.AddressSpace { | 843 | pub fn ptrAddressSpace(ty: Type, mod: *const Module) std.builtin.AddressSpace { |
| 2814 | return switch (self.tag()) { | 844 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 2815 | .single_const_pointer_to_comptime_int, | 845 | .ptr_type => |ptr_type| ptr_type.flags.address_space, |
| 2816 | .const_slice_u8, | 846 | .opt_type => |child| mod.intern_pool.indexToKey(child).ptr_type.flags.address_space, |
| 2817 | .const_slice_u8_sentinel_0, | ||
| 2818 | .single_const_pointer, | ||
| 2819 | .single_mut_pointer, | ||
| 2820 | .many_const_pointer, | ||
| 2821 | .many_mut_pointer, | ||
| 2822 | .c_const_pointer, | ||
| 2823 | .c_mut_pointer, | ||
| 2824 | .const_slice, | ||
| 2825 | .mut_slice, | ||
| 2826 | .inferred_alloc_const, | ||
| 2827 | .inferred_alloc_mut, | ||
| 2828 | .manyptr_u8, | ||
| 2829 | .manyptr_const_u8, | ||
| 2830 | .manyptr_const_u8_sentinel_0, | ||
| 2831 | => .generic, | ||
| 2832 | |||
| 2833 | .pointer => self.castTag(.pointer).?.data.@"addrspace", | ||
| 2834 | |||
| 2835 | .optional => { | ||
| 2836 | var buf: Payload.ElemType = undefined; | ||
| 2837 | const child_type = self.optionalChild(&buf); | ||
| 2838 | return child_type.ptrAddressSpace(); | ||
| 2839 | }, | ||
| 2840 | |||
| 2841 | else => unreachable, | 847 | else => unreachable, |
| 2842 | }; | 848 | }; |
| 2843 | } | 849 | } |
| 2844 | 850 | ||
| 2845 | /// Returns 0 for 0-bit types. | 851 | /// Returns 0 for 0-bit types. |
| 2846 | pub fn abiAlignment(ty: Type, target: Target) u32 { | 852 | pub fn abiAlignment(ty: Type, mod: *Module) u32 { |
| 2847 | return (ty.abiAlignmentAdvanced(target, .eager) catch unreachable).scalar; | 853 | return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar; |
| 2848 | } | 854 | } |
| 2849 | 855 | ||
| 2850 | /// May capture a reference to `ty`. | 856 | /// May capture a reference to `ty`. |
| 2851 | pub fn lazyAbiAlignment(ty: Type, target: Target, arena: Allocator) !Value { | 857 | /// Returned value has type `comptime_int`. |
| 2852 | switch (try ty.abiAlignmentAdvanced(target, .{ .lazy = arena })) { | 858 | pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value { |
| 859 | switch (try ty.abiAlignmentAdvanced(mod, .lazy)) { | ||
| 2853 | .val => |val| return val, | 860 | .val => |val| return val, |
| 2854 | .scalar => |x| return Value.Tag.int_u64.create(arena, x), | 861 | .scalar => |x| return mod.intValue(Type.comptime_int, x), |
| 2855 | } | 862 | } |
| 2856 | } | 863 | } |
| 2857 | 864 | ||
| ... | @@ -2862,7 +869,7 @@ pub const Type = extern union { | ... | @@ -2862,7 +869,7 @@ pub const Type = extern union { |
| 2862 | 869 | ||
| 2863 | pub const AbiAlignmentAdvancedStrat = union(enum) { | 870 | pub const AbiAlignmentAdvancedStrat = union(enum) { |
| 2864 | eager, | 871 | eager, |
| 2865 | lazy: Allocator, | 872 | lazy, |
| 2866 | sema: *Sema, | 873 | sema: *Sema, |
| 2867 | }; | 874 | }; |
| 2868 | 875 | ||
| ... | @@ -2874,314 +881,322 @@ pub const Type = extern union { | ... | @@ -2874,314 +881,322 @@ pub const Type = extern union { |
| 2874 | /// necessary, possibly returning a CompileError. | 881 | /// necessary, possibly returning a CompileError. |
| 2875 | pub fn abiAlignmentAdvanced( | 882 | pub fn abiAlignmentAdvanced( |
| 2876 | ty: Type, | 883 | ty: Type, |
| 2877 | target: Target, | 884 | mod: *Module, |
| 2878 | strat: AbiAlignmentAdvancedStrat, | 885 | strat: AbiAlignmentAdvancedStrat, |
| 2879 | ) Module.CompileError!AbiAlignmentAdvanced { | 886 | ) Module.CompileError!AbiAlignmentAdvanced { |
| 887 | const target = mod.getTarget(); | ||
| 888 | |||
| 2880 | const opt_sema = switch (strat) { | 889 | const opt_sema = switch (strat) { |
| 2881 | .sema => |sema| sema, | 890 | .sema => |sema| sema, |
| 2882 | else => null, | 891 | else => null, |
| 2883 | }; | 892 | }; |
| 2884 | switch (ty.tag()) { | ||
| 2885 | .u1, | ||
| 2886 | .u8, | ||
| 2887 | .i8, | ||
| 2888 | .bool, | ||
| 2889 | .array_u8_sentinel_0, | ||
| 2890 | .array_u8, | ||
| 2891 | .atomic_order, | ||
| 2892 | .atomic_rmw_op, | ||
| 2893 | .calling_convention, | ||
| 2894 | .address_space, | ||
| 2895 | .float_mode, | ||
| 2896 | .reduce_op, | ||
| 2897 | .modifier, | ||
| 2898 | .prefetch_options, | ||
| 2899 | .export_options, | ||
| 2900 | .extern_options, | ||
| 2901 | .@"opaque", | ||
| 2902 | .anyopaque, | ||
| 2903 | => return AbiAlignmentAdvanced{ .scalar = 1 }, | ||
| 2904 | |||
| 2905 | .fn_noreturn_no_args, // represents machine code; not a pointer | ||
| 2906 | .fn_void_no_args, // represents machine code; not a pointer | ||
| 2907 | .fn_naked_noreturn_no_args, // represents machine code; not a pointer | ||
| 2908 | .fn_ccc_void_no_args, // represents machine code; not a pointer | ||
| 2909 | => return AbiAlignmentAdvanced{ .scalar = target_util.defaultFunctionAlignment(target) }, | ||
| 2910 | |||
| 2911 | // represents machine code; not a pointer | ||
| 2912 | .function => { | ||
| 2913 | const alignment = ty.castTag(.function).?.data.alignment; | ||
| 2914 | if (alignment != 0) return AbiAlignmentAdvanced{ .scalar = alignment }; | ||
| 2915 | return AbiAlignmentAdvanced{ .scalar = target_util.defaultFunctionAlignment(target) }; | ||
| 2916 | }, | ||
| 2917 | 893 | ||
| 2918 | .isize, | 894 | switch (ty.toIntern()) { |
| 2919 | .usize, | 895 | .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 }, |
| 2920 | .single_const_pointer_to_comptime_int, | 896 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 2921 | .const_slice_u8, | 897 | .int_type => |int_type| { |
| 2922 | .const_slice_u8_sentinel_0, | 898 | if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 }; |
| 2923 | .single_const_pointer, | 899 | return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(int_type.bits, target) }; |
| 2924 | .single_mut_pointer, | 900 | }, |
| 2925 | .many_const_pointer, | 901 | .ptr_type, .anyframe_type => { |
| 2926 | .many_mut_pointer, | 902 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; |
| 2927 | .c_const_pointer, | 903 | }, |
| 2928 | .c_mut_pointer, | 904 | .array_type => |array_type| { |
| 2929 | .const_slice, | 905 | return array_type.child.toType().abiAlignmentAdvanced(mod, strat); |
| 2930 | .mut_slice, | 906 | }, |
| 2931 | .optional_single_const_pointer, | 907 | .vector_type => |vector_type| { |
| 2932 | .optional_single_mut_pointer, | 908 | const bits_u64 = try bitSizeAdvanced(vector_type.child.toType(), mod, opt_sema); |
| 2933 | .pointer, | 909 | const bits = @intCast(u32, bits_u64); |
| 2934 | .manyptr_u8, | 910 | const bytes = ((bits * vector_type.len) + 7) / 8; |
| 2935 | .manyptr_const_u8, | 911 | const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes); |
| 2936 | .manyptr_const_u8_sentinel_0, | 912 | return AbiAlignmentAdvanced{ .scalar = alignment }; |
| 2937 | .@"anyframe", | ||
| 2938 | .anyframe_T, | ||
| 2939 | => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | ||
| 2940 | |||
| 2941 | .c_char => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.char) }, | ||
| 2942 | .c_short => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.short) }, | ||
| 2943 | .c_ushort => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ushort) }, | ||
| 2944 | .c_int => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.int) }, | ||
| 2945 | .c_uint => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.uint) }, | ||
| 2946 | .c_long => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.long) }, | ||
| 2947 | .c_ulong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulong) }, | ||
| 2948 | .c_longlong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longlong) }, | ||
| 2949 | .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulonglong) }, | ||
| 2950 | .c_longdouble => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | ||
| 2951 | |||
| 2952 | .f16 => return AbiAlignmentAdvanced{ .scalar = 2 }, | ||
| 2953 | .f32 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.float) }, | ||
| 2954 | .f64 => switch (target.c_type_bit_size(.double)) { | ||
| 2955 | 64 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.double) }, | ||
| 2956 | else => return AbiAlignmentAdvanced{ .scalar = 8 }, | ||
| 2957 | }, | ||
| 2958 | .f80 => switch (target.c_type_bit_size(.longdouble)) { | ||
| 2959 | 80 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | ||
| 2960 | else => { | ||
| 2961 | var payload: Payload.Bits = .{ | ||
| 2962 | .base = .{ .tag = .int_unsigned }, | ||
| 2963 | .data = 80, | ||
| 2964 | }; | ||
| 2965 | const u80_ty = initPayload(&payload.base); | ||
| 2966 | return AbiAlignmentAdvanced{ .scalar = abiAlignment(u80_ty, target) }; | ||
| 2967 | }, | 913 | }, |
| 2968 | }, | ||
| 2969 | .f128 => switch (target.c_type_bit_size(.longdouble)) { | ||
| 2970 | 128 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | ||
| 2971 | else => return AbiAlignmentAdvanced{ .scalar = 16 }, | ||
| 2972 | }, | ||
| 2973 | |||
| 2974 | // TODO revisit this when we have the concept of the error tag type | ||
| 2975 | .anyerror_void_error_union, | ||
| 2976 | .anyerror, | ||
| 2977 | .error_set_inferred, | ||
| 2978 | .error_set_single, | ||
| 2979 | .error_set, | ||
| 2980 | .error_set_merged, | ||
| 2981 | => return AbiAlignmentAdvanced{ .scalar = 2 }, | ||
| 2982 | |||
| 2983 | .array, .array_sentinel => return ty.elemType().abiAlignmentAdvanced(target, strat), | ||
| 2984 | |||
| 2985 | .vector => { | ||
| 2986 | const len = ty.arrayLen(); | ||
| 2987 | const bits = try bitSizeAdvanced(ty.elemType(), target, opt_sema); | ||
| 2988 | const bytes = ((bits * len) + 7) / 8; | ||
| 2989 | const alignment = std.math.ceilPowerOfTwoAssert(u64, bytes); | ||
| 2990 | return AbiAlignmentAdvanced{ .scalar = @intCast(u32, alignment) }; | ||
| 2991 | }, | ||
| 2992 | |||
| 2993 | .i16, .u16 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(16, target) }, | ||
| 2994 | .u29 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(29, target) }, | ||
| 2995 | .i32, .u32 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(32, target) }, | ||
| 2996 | .i64, .u64 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(64, target) }, | ||
| 2997 | .u128, .i128 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(128, target) }, | ||
| 2998 | 914 | ||
| 2999 | .int_signed, .int_unsigned => { | 915 | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 3000 | const bits: u16 = ty.cast(Payload.Bits).?.data; | 916 | .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, info.payload_type.toType()), |
| 3001 | if (bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 }; | ||
| 3002 | return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(bits, target) }; | ||
| 3003 | }, | ||
| 3004 | 917 | ||
| 3005 | .optional => { | 918 | // TODO revisit this when we have the concept of the error tag type |
| 3006 | var buf: Payload.ElemType = undefined; | 919 | .error_set_type, .inferred_error_set_type => return AbiAlignmentAdvanced{ .scalar = 2 }, |
| 3007 | const child_type = ty.optionalChild(&buf); | ||
| 3008 | 920 | ||
| 3009 | switch (child_type.zigTypeTag()) { | 921 | // represents machine code; not a pointer |
| 3010 | .Pointer => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | 922 | .func_type => |func_type| return AbiAlignmentAdvanced{ |
| 3011 | .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, target, strat), | 923 | .scalar = if (func_type.alignment.toByteUnitsOptional()) |a| |
| 3012 | .NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 }, | 924 | @intCast(u32, a) |
| 3013 | else => {}, | 925 | else |
| 3014 | } | 926 | target_util.defaultFunctionAlignment(target), |
| 927 | }, | ||
| 3015 | 928 | ||
| 3016 | switch (strat) { | 929 | .simple_type => |t| switch (t) { |
| 3017 | .eager, .sema => { | 930 | .bool, |
| 3018 | if (!(child_type.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | 931 | .atomic_order, |
| 3019 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | 932 | .atomic_rmw_op, |
| 3020 | else => |e| return e, | 933 | .calling_convention, |
| 3021 | })) { | 934 | .address_space, |
| 3022 | return AbiAlignmentAdvanced{ .scalar = 1 }; | 935 | .float_mode, |
| 3023 | } | 936 | .reduce_op, |
| 3024 | return child_type.abiAlignmentAdvanced(target, strat); | 937 | .call_modifier, |
| 938 | .prefetch_options, | ||
| 939 | .anyopaque, | ||
| 940 | => return AbiAlignmentAdvanced{ .scalar = 1 }, | ||
| 941 | |||
| 942 | .usize, | ||
| 943 | .isize, | ||
| 944 | .export_options, | ||
| 945 | .extern_options, | ||
| 946 | => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | ||
| 947 | |||
| 948 | .c_char => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.char) }, | ||
| 949 | .c_short => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.short) }, | ||
| 950 | .c_ushort => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ushort) }, | ||
| 951 | .c_int => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.int) }, | ||
| 952 | .c_uint => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.uint) }, | ||
| 953 | .c_long => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.long) }, | ||
| 954 | .c_ulong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulong) }, | ||
| 955 | .c_longlong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longlong) }, | ||
| 956 | .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulonglong) }, | ||
| 957 | .c_longdouble => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | ||
| 958 | |||
| 959 | .f16 => return AbiAlignmentAdvanced{ .scalar = 2 }, | ||
| 960 | .f32 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.float) }, | ||
| 961 | .f64 => switch (target.c_type_bit_size(.double)) { | ||
| 962 | 64 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.double) }, | ||
| 963 | else => return AbiAlignmentAdvanced{ .scalar = 8 }, | ||
| 3025 | }, | 964 | }, |
| 3026 | .lazy => |arena| switch (try child_type.abiAlignmentAdvanced(target, strat)) { | 965 | .f80 => switch (target.c_type_bit_size(.longdouble)) { |
| 3027 | .scalar => |x| return AbiAlignmentAdvanced{ .scalar = @max(x, 1) }, | 966 | 80 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, |
| 3028 | .val => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | 967 | else => { |
| 968 | const u80_ty: Type = .{ .ip_index = .u80_type }; | ||
| 969 | return AbiAlignmentAdvanced{ .scalar = abiAlignment(u80_ty, mod) }; | ||
| 970 | }, | ||
| 971 | }, | ||
| 972 | .f128 => switch (target.c_type_bit_size(.longdouble)) { | ||
| 973 | 128 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, | ||
| 974 | else => return AbiAlignmentAdvanced{ .scalar = 16 }, | ||
| 3029 | }, | 975 | }, |
| 3030 | } | ||
| 3031 | }, | ||
| 3032 | 976 | ||
| 3033 | .error_union => { | 977 | // TODO revisit this when we have the concept of the error tag type |
| 3034 | // This code needs to be kept in sync with the equivalent switch prong | 978 | .anyerror => return AbiAlignmentAdvanced{ .scalar = 2 }, |
| 3035 | // in abiSizeAdvanced. | 979 | |
| 3036 | const data = ty.castTag(.error_union).?.data; | 980 | .void, |
| 3037 | const code_align = abiAlignment(Type.anyerror, target); | 981 | .type, |
| 3038 | switch (strat) { | 982 | .comptime_int, |
| 3039 | .eager, .sema => { | 983 | .comptime_float, |
| 3040 | if (!(data.payload.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | 984 | .null, |
| 3041 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | 985 | .undefined, |
| 3042 | else => |e| return e, | 986 | .enum_literal, |
| 3043 | })) { | 987 | .type_info, |
| 3044 | return AbiAlignmentAdvanced{ .scalar = code_align }; | 988 | => return AbiAlignmentAdvanced{ .scalar = 0 }, |
| 989 | |||
| 990 | .noreturn => unreachable, | ||
| 991 | .generic_poison => unreachable, | ||
| 992 | }, | ||
| 993 | .struct_type => |struct_type| { | ||
| 994 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | ||
| 995 | return AbiAlignmentAdvanced{ .scalar = 0 }; | ||
| 996 | |||
| 997 | if (opt_sema) |sema| { | ||
| 998 | if (struct_obj.status == .field_types_wip) { | ||
| 999 | // We'll guess "pointer-aligned", if the struct has an | ||
| 1000 | // underaligned pointer field then some allocations | ||
| 1001 | // might require explicit alignment. | ||
| 1002 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; | ||
| 3045 | } | 1003 | } |
| 3046 | return AbiAlignmentAdvanced{ .scalar = @max( | 1004 | _ = try sema.resolveTypeFields(ty); |
| 3047 | code_align, | 1005 | } |
| 3048 | (try data.payload.abiAlignmentAdvanced(target, strat)).scalar, | 1006 | if (!struct_obj.haveFieldTypes()) switch (strat) { |
| 3049 | ) }; | 1007 | .eager => unreachable, // struct layout not resolved |
| 3050 | }, | 1008 | .sema => unreachable, // handled above |
| 3051 | .lazy => |arena| { | 1009 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ |
| 3052 | switch (try data.payload.abiAlignmentAdvanced(target, strat)) { | 1010 | .ty = .comptime_int_type, |
| 3053 | .scalar => |payload_align| { | 1011 | .storage = .{ .lazy_align = ty.toIntern() }, |
| 3054 | return AbiAlignmentAdvanced{ | 1012 | } })).toValue() }, |
| 3055 | .scalar = @max(code_align, payload_align), | 1013 | }; |
| 3056 | }; | 1014 | if (struct_obj.layout == .Packed) { |
| 3057 | }, | 1015 | switch (strat) { |
| 3058 | .val => {}, | 1016 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 1017 | .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1018 | .ty = .comptime_int_type, | ||
| 1019 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1020 | } })).toValue() }, | ||
| 1021 | .eager => {}, | ||
| 3059 | } | 1022 | } |
| 3060 | return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }; | 1023 | assert(struct_obj.haveLayout()); |
| 3061 | }, | 1024 | return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(mod) }; |
| 3062 | } | ||
| 3063 | }, | ||
| 3064 | |||
| 3065 | .@"struct" => { | ||
| 3066 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 3067 | if (opt_sema) |sema| { | ||
| 3068 | if (struct_obj.status == .field_types_wip) { | ||
| 3069 | // We'll guess "pointer-aligned", if the struct has an | ||
| 3070 | // underaligned pointer field then some allocations | ||
| 3071 | // might require explicit alignment. | ||
| 3072 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; | ||
| 3073 | } | 1025 | } |
| 3074 | _ = try sema.resolveTypeFields(ty); | 1026 | |
| 3075 | } | 1027 | const fields = ty.structFields(mod); |
| 3076 | if (!struct_obj.haveFieldTypes()) switch (strat) { | 1028 | var big_align: u32 = 0; |
| 3077 | .eager => unreachable, // struct layout not resolved | 1029 | for (fields.values()) |field| { |
| 3078 | .sema => unreachable, // handled above | 1030 | if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 3079 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | 1031 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ |
| 3080 | }; | 1032 | .ty = .comptime_int_type, |
| 3081 | if (struct_obj.layout == .Packed) { | 1033 | .storage = .{ .lazy_align = ty.toIntern() }, |
| 3082 | switch (strat) { | 1034 | } })).toValue() }, |
| 3083 | .sema => |sema| try sema.resolveTypeLayout(ty), | 1035 | else => |e| return e, |
| 3084 | .lazy => |arena| { | 1036 | })) continue; |
| 3085 | if (!struct_obj.haveLayout()) { | 1037 | |
| 3086 | return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }; | 1038 | const field_align = if (field.abi_align != 0) |
| 1039 | field.abi_align | ||
| 1040 | else switch (try field.ty.abiAlignmentAdvanced(mod, strat)) { | ||
| 1041 | .scalar => |a| a, | ||
| 1042 | .val => switch (strat) { | ||
| 1043 | .eager => unreachable, // struct layout not resolved | ||
| 1044 | .sema => unreachable, // handled above | ||
| 1045 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1046 | .ty = .comptime_int_type, | ||
| 1047 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1048 | } })).toValue() }, | ||
| 1049 | }, | ||
| 1050 | }; | ||
| 1051 | big_align = @max(big_align, field_align); | ||
| 1052 | |||
| 1053 | // This logic is duplicated in Module.Struct.Field.alignment. | ||
| 1054 | if (struct_obj.layout == .Extern or target.ofmt == .c) { | ||
| 1055 | if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { | ||
| 1056 | // The C ABI requires 128 bit integer fields of structs | ||
| 1057 | // to be 16-bytes aligned. | ||
| 1058 | big_align = @max(big_align, 16); | ||
| 3087 | } | 1059 | } |
| 3088 | }, | 1060 | } |
| 3089 | .eager => {}, | ||
| 3090 | } | 1061 | } |
| 3091 | assert(struct_obj.haveLayout()); | 1062 | return AbiAlignmentAdvanced{ .scalar = big_align }; |
| 3092 | return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(target) }; | 1063 | }, |
| 3093 | } | 1064 | .anon_struct_type => |tuple| { |
| 3094 | 1065 | var big_align: u32 = 0; | |
| 3095 | const fields = ty.structFields(); | 1066 | for (tuple.types, tuple.values) |field_ty, val| { |
| 3096 | var big_align: u32 = 0; | 1067 | if (val != .none) continue; // comptime field |
| 3097 | for (fields.values()) |field| { | 1068 | if (!(field_ty.toType().hasRuntimeBits(mod))) continue; |
| 3098 | if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | 1069 | |
| 3099 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | 1070 | switch (try field_ty.toType().abiAlignmentAdvanced(mod, strat)) { |
| 3100 | else => |e| return e, | 1071 | .scalar => |field_align| big_align = @max(big_align, field_align), |
| 3101 | })) continue; | 1072 | .val => switch (strat) { |
| 3102 | 1073 | .eager => unreachable, // field type alignment not resolved | |
| 3103 | const field_align = if (field.abi_align != 0) | 1074 | .sema => unreachable, // passed to abiAlignmentAdvanced above |
| 3104 | field.abi_align | 1075 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ |
| 3105 | else switch (try field.ty.abiAlignmentAdvanced(target, strat)) { | 1076 | .ty = .comptime_int_type, |
| 3106 | .scalar => |a| a, | 1077 | .storage = .{ .lazy_align = ty.toIntern() }, |
| 3107 | .val => switch (strat) { | 1078 | } })).toValue() }, |
| 3108 | .eager => unreachable, // struct layout not resolved | 1079 | }, |
| 3109 | .sema => unreachable, // handled above | ||
| 3110 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | ||
| 3111 | }, | ||
| 3112 | }; | ||
| 3113 | big_align = @max(big_align, field_align); | ||
| 3114 | |||
| 3115 | // This logic is duplicated in Module.Struct.Field.alignment. | ||
| 3116 | if (struct_obj.layout == .Extern or target.ofmt == .c) { | ||
| 3117 | if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) { | ||
| 3118 | // The C ABI requires 128 bit integer fields of structs | ||
| 3119 | // to be 16-bytes aligned. | ||
| 3120 | big_align = @max(big_align, 16); | ||
| 3121 | } | 1080 | } |
| 3122 | } | 1081 | } |
| 3123 | } | 1082 | return AbiAlignmentAdvanced{ .scalar = big_align }; |
| 3124 | return AbiAlignmentAdvanced{ .scalar = big_align }; | 1083 | }, |
| 3125 | }, | ||
| 3126 | |||
| 3127 | .tuple, .anon_struct => { | ||
| 3128 | const tuple = ty.tupleFields(); | ||
| 3129 | var big_align: u32 = 0; | ||
| 3130 | for (tuple.types, 0..) |field_ty, i| { | ||
| 3131 | const val = tuple.values[i]; | ||
| 3132 | if (val.tag() != .unreachable_value) continue; // comptime field | ||
| 3133 | if (!(field_ty.hasRuntimeBits())) continue; | ||
| 3134 | 1084 | ||
| 3135 | switch (try field_ty.abiAlignmentAdvanced(target, strat)) { | 1085 | .union_type => |union_type| { |
| 3136 | .scalar => |field_align| big_align = @max(big_align, field_align), | 1086 | const union_obj = mod.unionPtr(union_type.index); |
| 3137 | .val => switch (strat) { | 1087 | return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag()); |
| 3138 | .eager => unreachable, // field type alignment not resolved | 1088 | }, |
| 3139 | .sema => unreachable, // passed to abiAlignmentAdvanced above | 1089 | .opaque_type => return AbiAlignmentAdvanced{ .scalar = 1 }, |
| 3140 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | 1090 | .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) }, |
| 3141 | }, | 1091 | |
| 3142 | } | 1092 | // values, not types |
| 3143 | } | 1093 | .undef, |
| 3144 | return AbiAlignmentAdvanced{ .scalar = big_align }; | 1094 | .runtime_value, |
| 1095 | .simple_value, | ||
| 1096 | .variable, | ||
| 1097 | .extern_func, | ||
| 1098 | .func, | ||
| 1099 | .int, | ||
| 1100 | .err, | ||
| 1101 | .error_union, | ||
| 1102 | .enum_literal, | ||
| 1103 | .enum_tag, | ||
| 1104 | .empty_enum_value, | ||
| 1105 | .float, | ||
| 1106 | .ptr, | ||
| 1107 | .opt, | ||
| 1108 | .aggregate, | ||
| 1109 | .un, | ||
| 1110 | // memoization, not types | ||
| 1111 | .memoized_call, | ||
| 1112 | => unreachable, | ||
| 3145 | }, | 1113 | }, |
| 1114 | } | ||
| 1115 | } | ||
| 3146 | 1116 | ||
| 3147 | .enum_full, .enum_nonexhaustive, .enum_simple, .enum_numbered => { | 1117 | fn abiAlignmentAdvancedErrorUnion( |
| 3148 | var buffer: Payload.Bits = undefined; | 1118 | ty: Type, |
| 3149 | const int_tag_ty = ty.intTagType(&buffer); | 1119 | mod: *Module, |
| 3150 | return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(target) }; | 1120 | strat: AbiAlignmentAdvancedStrat, |
| 3151 | }, | 1121 | payload_ty: Type, |
| 3152 | .@"union" => { | 1122 | ) Module.CompileError!AbiAlignmentAdvanced { |
| 3153 | const union_obj = ty.castTag(.@"union").?.data; | 1123 | // This code needs to be kept in sync with the equivalent switch prong |
| 3154 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, false); | 1124 | // in abiSizeAdvanced. |
| 3155 | }, | 1125 | const code_align = abiAlignment(Type.anyerror, mod); |
| 3156 | .union_safety_tagged, .union_tagged => { | 1126 | switch (strat) { |
| 3157 | const union_obj = ty.cast(Payload.Union).?.data; | 1127 | .eager, .sema => { |
| 3158 | return abiAlignmentAdvancedUnion(ty, target, strat, union_obj, true); | 1128 | if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 1129 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1130 | .ty = .comptime_int_type, | ||
| 1131 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1132 | } })).toValue() }, | ||
| 1133 | else => |e| return e, | ||
| 1134 | })) { | ||
| 1135 | return AbiAlignmentAdvanced{ .scalar = code_align }; | ||
| 1136 | } | ||
| 1137 | return AbiAlignmentAdvanced{ .scalar = @max( | ||
| 1138 | code_align, | ||
| 1139 | (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar, | ||
| 1140 | ) }; | ||
| 1141 | }, | ||
| 1142 | .lazy => { | ||
| 1143 | switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) { | ||
| 1144 | .scalar => |payload_align| { | ||
| 1145 | return AbiAlignmentAdvanced{ | ||
| 1146 | .scalar = @max(code_align, payload_align), | ||
| 1147 | }; | ||
| 1148 | }, | ||
| 1149 | .val => {}, | ||
| 1150 | } | ||
| 1151 | return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1152 | .ty = .comptime_int_type, | ||
| 1153 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1154 | } })).toValue() }; | ||
| 3159 | }, | 1155 | }, |
| 1156 | } | ||
| 1157 | } | ||
| 3160 | 1158 | ||
| 3161 | .empty_struct, | 1159 | fn abiAlignmentAdvancedOptional( |
| 3162 | .void, | 1160 | ty: Type, |
| 3163 | .empty_struct_literal, | 1161 | mod: *Module, |
| 3164 | .type, | 1162 | strat: AbiAlignmentAdvancedStrat, |
| 3165 | .comptime_int, | 1163 | ) Module.CompileError!AbiAlignmentAdvanced { |
| 3166 | .comptime_float, | 1164 | const target = mod.getTarget(); |
| 3167 | .null, | 1165 | const child_type = ty.optionalChild(mod); |
| 3168 | .undefined, | ||
| 3169 | .enum_literal, | ||
| 3170 | .type_info, | ||
| 3171 | => return AbiAlignmentAdvanced{ .scalar = 0 }, | ||
| 3172 | 1166 | ||
| 3173 | .noreturn, | 1167 | switch (child_type.zigTypeTag(mod)) { |
| 3174 | .inferred_alloc_const, | 1168 | .Pointer => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 3175 | .inferred_alloc_mut, | 1169 | .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat), |
| 3176 | => unreachable, | 1170 | .NoReturn => return AbiAlignmentAdvanced{ .scalar = 0 }, |
| 1171 | else => {}, | ||
| 1172 | } | ||
| 3177 | 1173 | ||
| 3178 | .generic_poison => unreachable, | 1174 | switch (strat) { |
| 1175 | .eager, .sema => { | ||
| 1176 | if (!(child_type.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { | ||
| 1177 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1178 | .ty = .comptime_int_type, | ||
| 1179 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1180 | } })).toValue() }, | ||
| 1181 | else => |e| return e, | ||
| 1182 | })) { | ||
| 1183 | return AbiAlignmentAdvanced{ .scalar = 1 }; | ||
| 1184 | } | ||
| 1185 | return child_type.abiAlignmentAdvanced(mod, strat); | ||
| 1186 | }, | ||
| 1187 | .lazy => switch (try child_type.abiAlignmentAdvanced(mod, strat)) { | ||
| 1188 | .scalar => |x| return AbiAlignmentAdvanced{ .scalar = @max(x, 1) }, | ||
| 1189 | .val => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1190 | .ty = .comptime_int_type, | ||
| 1191 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1192 | } })).toValue() }, | ||
| 1193 | }, | ||
| 3179 | } | 1194 | } |
| 3180 | } | 1195 | } |
| 3181 | 1196 | ||
| 3182 | pub fn abiAlignmentAdvancedUnion( | 1197 | pub fn abiAlignmentAdvancedUnion( |
| 3183 | ty: Type, | 1198 | ty: Type, |
| 3184 | target: Target, | 1199 | mod: *Module, |
| 3185 | strat: AbiAlignmentAdvancedStrat, | 1200 | strat: AbiAlignmentAdvancedStrat, |
| 3186 | union_obj: *Module.Union, | 1201 | union_obj: *Module.Union, |
| 3187 | have_tag: bool, | 1202 | have_tag: bool, |
| ... | @@ -3195,6 +1210,7 @@ pub const Type = extern union { | ... | @@ -3195,6 +1210,7 @@ pub const Type = extern union { |
| 3195 | // We'll guess "pointer-aligned", if the union has an | 1210 | // We'll guess "pointer-aligned", if the union has an |
| 3196 | // underaligned pointer field then some allocations | 1211 | // underaligned pointer field then some allocations |
| 3197 | // might require explicit alignment. | 1212 | // might require explicit alignment. |
| 1213 | const target = mod.getTarget(); | ||
| 3198 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; | 1214 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; |
| 3199 | } | 1215 | } |
| 3200 | _ = try sema.resolveTypeFields(ty); | 1216 | _ = try sema.resolveTypeFields(ty); |
| ... | @@ -3202,32 +1218,41 @@ pub const Type = extern union { | ... | @@ -3202,32 +1218,41 @@ pub const Type = extern union { |
| 3202 | if (!union_obj.haveFieldTypes()) switch (strat) { | 1218 | if (!union_obj.haveFieldTypes()) switch (strat) { |
| 3203 | .eager => unreachable, // union layout not resolved | 1219 | .eager => unreachable, // union layout not resolved |
| 3204 | .sema => unreachable, // handled above | 1220 | .sema => unreachable, // handled above |
| 3205 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | 1221 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ |
| 1222 | .ty = .comptime_int_type, | ||
| 1223 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1224 | } })).toValue() }, | ||
| 3206 | }; | 1225 | }; |
| 3207 | if (union_obj.fields.count() == 0) { | 1226 | if (union_obj.fields.count() == 0) { |
| 3208 | if (have_tag) { | 1227 | if (have_tag) { |
| 3209 | return abiAlignmentAdvanced(union_obj.tag_ty, target, strat); | 1228 | return abiAlignmentAdvanced(union_obj.tag_ty, mod, strat); |
| 3210 | } else { | 1229 | } else { |
| 3211 | return AbiAlignmentAdvanced{ .scalar = @boolToInt(union_obj.layout == .Extern) }; | 1230 | return AbiAlignmentAdvanced{ .scalar = @boolToInt(union_obj.layout == .Extern) }; |
| 3212 | } | 1231 | } |
| 3213 | } | 1232 | } |
| 3214 | 1233 | ||
| 3215 | var max_align: u32 = 0; | 1234 | var max_align: u32 = 0; |
| 3216 | if (have_tag) max_align = union_obj.tag_ty.abiAlignment(target); | 1235 | if (have_tag) max_align = union_obj.tag_ty.abiAlignment(mod); |
| 3217 | for (union_obj.fields.values()) |field| { | 1236 | for (union_obj.fields.values()) |field| { |
| 3218 | if (!(field.ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | 1237 | if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 3219 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | 1238 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ |
| 1239 | .ty = .comptime_int_type, | ||
| 1240 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1241 | } })).toValue() }, | ||
| 3220 | else => |e| return e, | 1242 | else => |e| return e, |
| 3221 | })) continue; | 1243 | })) continue; |
| 3222 | 1244 | ||
| 3223 | const field_align = if (field.abi_align != 0) | 1245 | const field_align = if (field.abi_align != 0) |
| 3224 | field.abi_align | 1246 | field.abi_align |
| 3225 | else switch (try field.ty.abiAlignmentAdvanced(target, strat)) { | 1247 | else switch (try field.ty.abiAlignmentAdvanced(mod, strat)) { |
| 3226 | .scalar => |a| a, | 1248 | .scalar => |a| a, |
| 3227 | .val => switch (strat) { | 1249 | .val => switch (strat) { |
| 3228 | .eager => unreachable, // struct layout not resolved | 1250 | .eager => unreachable, // struct layout not resolved |
| 3229 | .sema => unreachable, // handled above | 1251 | .sema => unreachable, // handled above |
| 3230 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | 1252 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ |
| 1253 | .ty = .comptime_int_type, | ||
| 1254 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1255 | } })).toValue() }, | ||
| 3231 | }, | 1256 | }, |
| 3232 | }; | 1257 | }; |
| 3233 | max_align = @max(max_align, field_align); | 1258 | max_align = @max(max_align, field_align); |
| ... | @@ -3236,17 +1261,17 @@ pub const Type = extern union { | ... | @@ -3236,17 +1261,17 @@ pub const Type = extern union { |
| 3236 | } | 1261 | } |
| 3237 | 1262 | ||
| 3238 | /// May capture a reference to `ty`. | 1263 | /// May capture a reference to `ty`. |
| 3239 | pub fn lazyAbiSize(ty: Type, target: Target, arena: Allocator) !Value { | 1264 | pub fn lazyAbiSize(ty: Type, mod: *Module) !Value { |
| 3240 | switch (try ty.abiSizeAdvanced(target, .{ .lazy = arena })) { | 1265 | switch (try ty.abiSizeAdvanced(mod, .lazy)) { |
| 3241 | .val => |val| return val, | 1266 | .val => |val| return val, |
| 3242 | .scalar => |x| return Value.Tag.int_u64.create(arena, x), | 1267 | .scalar => |x| return mod.intValue(Type.comptime_int, x), |
| 3243 | } | 1268 | } |
| 3244 | } | 1269 | } |
| 3245 | 1270 | ||
| 3246 | /// Asserts the type has the ABI size already resolved. | 1271 | /// Asserts the type has the ABI size already resolved. |
| 3247 | /// Types that return false for hasRuntimeBits() return 0. | 1272 | /// Types that return false for hasRuntimeBits() return 0. |
| 3248 | pub fn abiSize(ty: Type, target: Target) u64 { | 1273 | pub fn abiSize(ty: Type, mod: *Module) u64 { |
| 3249 | return (abiSizeAdvanced(ty, target, .eager) catch unreachable).scalar; | 1274 | return (abiSizeAdvanced(ty, mod, .eager) catch unreachable).scalar; |
| 3250 | } | 1275 | } |
| 3251 | 1276 | ||
| 3252 | const AbiSizeAdvanced = union(enum) { | 1277 | const AbiSizeAdvanced = union(enum) { |
| ... | @@ -3262,315 +1287,310 @@ pub const Type = extern union { | ... | @@ -3262,315 +1287,310 @@ pub const Type = extern union { |
| 3262 | /// necessary, possibly returning a CompileError. | 1287 | /// necessary, possibly returning a CompileError. |
| 3263 | pub fn abiSizeAdvanced( | 1288 | pub fn abiSizeAdvanced( |
| 3264 | ty: Type, | 1289 | ty: Type, |
| 3265 | target: Target, | 1290 | mod: *Module, |
| 3266 | strat: AbiAlignmentAdvancedStrat, | 1291 | strat: AbiAlignmentAdvancedStrat, |
| 3267 | ) Module.CompileError!AbiSizeAdvanced { | 1292 | ) Module.CompileError!AbiSizeAdvanced { |
| 3268 | switch (ty.tag()) { | 1293 | const target = mod.getTarget(); |
| 3269 | .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer | 1294 | |
| 3270 | .fn_void_no_args => unreachable, // represents machine code; not a pointer | 1295 | switch (ty.toIntern()) { |
| 3271 | .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer | 1296 | .empty_struct_type => return AbiSizeAdvanced{ .scalar = 0 }, |
| 3272 | .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer | 1297 | |
| 3273 | .function => unreachable, // represents machine code; not a pointer | 1298 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3274 | .@"opaque" => unreachable, // no size available | 1299 | .int_type => |int_type| { |
| 3275 | .noreturn => unreachable, | 1300 | if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; |
| 3276 | .inferred_alloc_const => unreachable, | 1301 | return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) }; |
| 3277 | .inferred_alloc_mut => unreachable, | ||
| 3278 | .generic_poison => unreachable, | ||
| 3279 | .modifier => unreachable, // missing call to resolveTypeFields | ||
| 3280 | .prefetch_options => unreachable, // missing call to resolveTypeFields | ||
| 3281 | .export_options => unreachable, // missing call to resolveTypeFields | ||
| 3282 | .extern_options => unreachable, // missing call to resolveTypeFields | ||
| 3283 | .type_info => unreachable, // missing call to resolveTypeFields | ||
| 3284 | |||
| 3285 | .anyopaque, | ||
| 3286 | .type, | ||
| 3287 | .comptime_int, | ||
| 3288 | .comptime_float, | ||
| 3289 | .null, | ||
| 3290 | .undefined, | ||
| 3291 | .enum_literal, | ||
| 3292 | .single_const_pointer_to_comptime_int, | ||
| 3293 | .empty_struct_literal, | ||
| 3294 | .empty_struct, | ||
| 3295 | .void, | ||
| 3296 | => return AbiSizeAdvanced{ .scalar = 0 }, | ||
| 3297 | |||
| 3298 | .@"struct", .tuple, .anon_struct => switch (ty.containerLayout()) { | ||
| 3299 | .Packed => { | ||
| 3300 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 3301 | switch (strat) { | ||
| 3302 | .sema => |sema| try sema.resolveTypeLayout(ty), | ||
| 3303 | .lazy => |arena| { | ||
| 3304 | if (!struct_obj.haveLayout()) { | ||
| 3305 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; | ||
| 3306 | } | ||
| 3307 | }, | ||
| 3308 | .eager => {}, | ||
| 3309 | } | ||
| 3310 | assert(struct_obj.haveLayout()); | ||
| 3311 | return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(target) }; | ||
| 3312 | }, | 1302 | }, |
| 3313 | else => { | 1303 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 3314 | switch (strat) { | 1304 | .Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 }, |
| 3315 | .sema => |sema| try sema.resolveTypeLayout(ty), | 1305 | else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 3316 | .lazy => |arena| { | 1306 | }, |
| 3317 | if (ty.castTag(.@"struct")) |payload| { | 1307 | .anyframe_type => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 3318 | const struct_obj = payload.data; | 1308 | |
| 3319 | if (!struct_obj.haveLayout()) { | 1309 | .array_type => |array_type| { |
| 3320 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; | 1310 | const len = array_type.len + @boolToInt(array_type.sentinel != .none); |
| 3321 | } | 1311 | switch (try array_type.child.toType().abiSizeAdvanced(mod, strat)) { |
| 3322 | } | 1312 | .scalar => |elem_size| return .{ .scalar = len * elem_size }, |
| 1313 | .val => switch (strat) { | ||
| 1314 | .sema, .eager => unreachable, | ||
| 1315 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1316 | .ty = .comptime_int_type, | ||
| 1317 | .storage = .{ .lazy_size = ty.toIntern() }, | ||
| 1318 | } })).toValue() }, | ||
| 3323 | }, | 1319 | }, |
| 3324 | .eager => {}, | ||
| 3325 | } | ||
| 3326 | const field_count = ty.structFieldCount(); | ||
| 3327 | if (field_count == 0) { | ||
| 3328 | return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 3329 | } | 1320 | } |
| 3330 | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, target) }; | ||
| 3331 | }, | 1321 | }, |
| 3332 | }, | 1322 | .vector_type => |vector_type| { |
| 3333 | 1323 | const opt_sema = switch (strat) { | |
| 3334 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { | 1324 | .sema => |sema| sema, |
| 3335 | var buffer: Payload.Bits = undefined; | 1325 | .eager => null, |
| 3336 | const int_tag_ty = ty.intTagType(&buffer); | 1326 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ |
| 3337 | return AbiSizeAdvanced{ .scalar = int_tag_ty.abiSize(target) }; | 1327 | .ty = .comptime_int_type, |
| 3338 | }, | 1328 | .storage = .{ .lazy_size = ty.toIntern() }, |
| 3339 | .@"union" => { | 1329 | } })).toValue() }, |
| 3340 | const union_obj = ty.castTag(.@"union").?.data; | 1330 | }; |
| 3341 | return abiSizeAdvancedUnion(ty, target, strat, union_obj, false); | 1331 | const elem_bits_u64 = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema); |
| 3342 | }, | 1332 | const elem_bits = @intCast(u32, elem_bits_u64); |
| 3343 | .union_safety_tagged, .union_tagged => { | 1333 | const total_bits = elem_bits * vector_type.len; |
| 3344 | const union_obj = ty.cast(Payload.Union).?.data; | 1334 | const total_bytes = (total_bits + 7) / 8; |
| 3345 | return abiSizeAdvancedUnion(ty, target, strat, union_obj, true); | 1335 | const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) { |
| 3346 | }, | 1336 | .scalar => |x| x, |
| 3347 | 1337 | .val => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 3348 | .u1, | 1338 | .ty = .comptime_int_type, |
| 3349 | .u8, | 1339 | .storage = .{ .lazy_size = ty.toIntern() }, |
| 3350 | .i8, | 1340 | } })).toValue() }, |
| 3351 | .bool, | ||
| 3352 | .atomic_order, | ||
| 3353 | .atomic_rmw_op, | ||
| 3354 | .calling_convention, | ||
| 3355 | .address_space, | ||
| 3356 | .float_mode, | ||
| 3357 | .reduce_op, | ||
| 3358 | => return AbiSizeAdvanced{ .scalar = 1 }, | ||
| 3359 | |||
| 3360 | .array_u8 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8).?.data }, | ||
| 3361 | .array_u8_sentinel_0 => return AbiSizeAdvanced{ .scalar = ty.castTag(.array_u8_sentinel_0).?.data + 1 }, | ||
| 3362 | .array => { | ||
| 3363 | const payload = ty.castTag(.array).?.data; | ||
| 3364 | switch (try payload.elem_type.abiSizeAdvanced(target, strat)) { | ||
| 3365 | .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = payload.len * elem_size }, | ||
| 3366 | .val => switch (strat) { | ||
| 3367 | .sema => unreachable, | ||
| 3368 | .eager => unreachable, | ||
| 3369 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, | ||
| 3370 | }, | ||
| 3371 | } | ||
| 3372 | }, | ||
| 3373 | .array_sentinel => { | ||
| 3374 | const payload = ty.castTag(.array_sentinel).?.data; | ||
| 3375 | switch (try payload.elem_type.abiSizeAdvanced(target, strat)) { | ||
| 3376 | .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = (payload.len + 1) * elem_size }, | ||
| 3377 | .val => switch (strat) { | ||
| 3378 | .sema => unreachable, | ||
| 3379 | .eager => unreachable, | ||
| 3380 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, | ||
| 3381 | }, | ||
| 3382 | } | ||
| 3383 | }, | ||
| 3384 | |||
| 3385 | .vector => { | ||
| 3386 | const payload = ty.castTag(.vector).?.data; | ||
| 3387 | const opt_sema = switch (strat) { | ||
| 3388 | .sema => |sema| sema, | ||
| 3389 | .eager => null, | ||
| 3390 | .lazy => |arena| return AbiSizeAdvanced{ | ||
| 3391 | .val = try Value.Tag.lazy_size.create(arena, ty), | ||
| 3392 | }, | ||
| 3393 | }; | ||
| 3394 | const elem_bits = try payload.elem_type.bitSizeAdvanced(target, opt_sema); | ||
| 3395 | const total_bits = elem_bits * payload.len; | ||
| 3396 | const total_bytes = (total_bits + 7) / 8; | ||
| 3397 | const alignment = switch (try ty.abiAlignmentAdvanced(target, strat)) { | ||
| 3398 | .scalar => |x| x, | ||
| 3399 | .val => return AbiSizeAdvanced{ | ||
| 3400 | .val = try Value.Tag.lazy_size.create(strat.lazy, ty), | ||
| 3401 | }, | ||
| 3402 | }; | ||
| 3403 | const result = std.mem.alignForwardGeneric(u64, total_bytes, alignment); | ||
| 3404 | return AbiSizeAdvanced{ .scalar = result }; | ||
| 3405 | }, | ||
| 3406 | |||
| 3407 | .isize, | ||
| 3408 | .usize, | ||
| 3409 | .@"anyframe", | ||
| 3410 | .anyframe_T, | ||
| 3411 | .optional_single_const_pointer, | ||
| 3412 | .optional_single_mut_pointer, | ||
| 3413 | .single_const_pointer, | ||
| 3414 | .single_mut_pointer, | ||
| 3415 | .many_const_pointer, | ||
| 3416 | .many_mut_pointer, | ||
| 3417 | .c_const_pointer, | ||
| 3418 | .c_mut_pointer, | ||
| 3419 | .manyptr_u8, | ||
| 3420 | .manyptr_const_u8, | ||
| 3421 | .manyptr_const_u8_sentinel_0, | ||
| 3422 | => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | ||
| 3423 | |||
| 3424 | .const_slice, | ||
| 3425 | .mut_slice, | ||
| 3426 | .const_slice_u8, | ||
| 3427 | .const_slice_u8_sentinel_0, | ||
| 3428 | => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 }, | ||
| 3429 | |||
| 3430 | .pointer => switch (ty.castTag(.pointer).?.data.size) { | ||
| 3431 | .Slice => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 }, | ||
| 3432 | else => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | ||
| 3433 | }, | ||
| 3434 | |||
| 3435 | .c_char => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.char) }, | ||
| 3436 | .c_short => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.short) }, | ||
| 3437 | .c_ushort => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ushort) }, | ||
| 3438 | .c_int => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.int) }, | ||
| 3439 | .c_uint => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.uint) }, | ||
| 3440 | .c_long => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.long) }, | ||
| 3441 | .c_ulong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulong) }, | ||
| 3442 | .c_longlong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longlong) }, | ||
| 3443 | .c_ulonglong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulonglong) }, | ||
| 3444 | .c_longdouble => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, | ||
| 3445 | |||
| 3446 | .f16 => return AbiSizeAdvanced{ .scalar = 2 }, | ||
| 3447 | .f32 => return AbiSizeAdvanced{ .scalar = 4 }, | ||
| 3448 | .f64 => return AbiSizeAdvanced{ .scalar = 8 }, | ||
| 3449 | .f128 => return AbiSizeAdvanced{ .scalar = 16 }, | ||
| 3450 | .f80 => switch (target.c_type_bit_size(.longdouble)) { | ||
| 3451 | 80 => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, | ||
| 3452 | else => { | ||
| 3453 | var payload: Payload.Bits = .{ | ||
| 3454 | .base = .{ .tag = .int_unsigned }, | ||
| 3455 | .data = 80, | ||
| 3456 | }; | 1341 | }; |
| 3457 | const u80_ty = initPayload(&payload.base); | 1342 | const result = std.mem.alignForwardGeneric(u32, total_bytes, alignment); |
| 3458 | return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, target) }; | 1343 | return AbiSizeAdvanced{ .scalar = result }; |
| 3459 | }, | 1344 | }, |
| 3460 | }, | ||
| 3461 | |||
| 3462 | // TODO revisit this when we have the concept of the error tag type | ||
| 3463 | .anyerror_void_error_union, | ||
| 3464 | .anyerror, | ||
| 3465 | .error_set_inferred, | ||
| 3466 | .error_set, | ||
| 3467 | .error_set_merged, | ||
| 3468 | .error_set_single, | ||
| 3469 | => return AbiSizeAdvanced{ .scalar = 2 }, | ||
| 3470 | |||
| 3471 | .i16, .u16 => return AbiSizeAdvanced{ .scalar = intAbiSize(16, target) }, | ||
| 3472 | .u29 => return AbiSizeAdvanced{ .scalar = intAbiSize(29, target) }, | ||
| 3473 | .i32, .u32 => return AbiSizeAdvanced{ .scalar = intAbiSize(32, target) }, | ||
| 3474 | .i64, .u64 => return AbiSizeAdvanced{ .scalar = intAbiSize(64, target) }, | ||
| 3475 | .u128, .i128 => return AbiSizeAdvanced{ .scalar = intAbiSize(128, target) }, | ||
| 3476 | .int_signed, .int_unsigned => { | ||
| 3477 | const bits: u16 = ty.cast(Payload.Bits).?.data; | ||
| 3478 | if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 3479 | return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) }; | ||
| 3480 | }, | ||
| 3481 | 1345 | ||
| 3482 | .optional => { | 1346 | .opt_type => return ty.abiSizeAdvancedOptional(mod, strat), |
| 3483 | var buf: Payload.ElemType = undefined; | 1347 | |
| 3484 | const child_type = ty.optionalChild(&buf); | 1348 | // TODO revisit this when we have the concept of the error tag type |
| 3485 | 1349 | .error_set_type, .inferred_error_set_type => return AbiSizeAdvanced{ .scalar = 2 }, | |
| 3486 | if (child_type.isNoReturn()) { | 1350 | |
| 3487 | return AbiSizeAdvanced{ .scalar = 0 }; | 1351 | .error_union_type => |error_union_type| { |
| 3488 | } | 1352 | const payload_ty = error_union_type.payload_type.toType(); |
| 3489 | 1353 | // This code needs to be kept in sync with the equivalent switch prong | |
| 3490 | if (!(child_type.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | 1354 | // in abiAlignmentAdvanced. |
| 3491 | error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, | 1355 | const code_size = abiSize(Type.anyerror, mod); |
| 3492 | else => |e| return e, | 1356 | if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 3493 | })) return AbiSizeAdvanced{ .scalar = 1 }; | 1357 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ |
| 3494 | 1358 | .ty = .comptime_int_type, | |
| 3495 | if (ty.optionalReprIsPayload()) { | 1359 | .storage = .{ .lazy_size = ty.toIntern() }, |
| 3496 | return abiSizeAdvanced(child_type, target, strat); | 1360 | } })).toValue() }, |
| 3497 | } | 1361 | else => |e| return e, |
| 1362 | })) { | ||
| 1363 | // Same as anyerror. | ||
| 1364 | return AbiSizeAdvanced{ .scalar = code_size }; | ||
| 1365 | } | ||
| 1366 | const code_align = abiAlignment(Type.anyerror, mod); | ||
| 1367 | const payload_align = abiAlignment(payload_ty, mod); | ||
| 1368 | const payload_size = switch (try payload_ty.abiSizeAdvanced(mod, strat)) { | ||
| 1369 | .scalar => |elem_size| elem_size, | ||
| 1370 | .val => switch (strat) { | ||
| 1371 | .sema => unreachable, | ||
| 1372 | .eager => unreachable, | ||
| 1373 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1374 | .ty = .comptime_int_type, | ||
| 1375 | .storage = .{ .lazy_size = ty.toIntern() }, | ||
| 1376 | } })).toValue() }, | ||
| 1377 | }, | ||
| 1378 | }; | ||
| 3498 | 1379 | ||
| 3499 | const payload_size = switch (try child_type.abiSizeAdvanced(target, strat)) { | 1380 | var size: u64 = 0; |
| 3500 | .scalar => |elem_size| elem_size, | 1381 | if (code_align > payload_align) { |
| 3501 | .val => switch (strat) { | 1382 | size += code_size; |
| 3502 | .sema => unreachable, | 1383 | size = std.mem.alignForwardGeneric(u64, size, payload_align); |
| 3503 | .eager => unreachable, | 1384 | size += payload_size; |
| 3504 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, | 1385 | size = std.mem.alignForwardGeneric(u64, size, code_align); |
| 1386 | } else { | ||
| 1387 | size += payload_size; | ||
| 1388 | size = std.mem.alignForwardGeneric(u64, size, code_align); | ||
| 1389 | size += code_size; | ||
| 1390 | size = std.mem.alignForwardGeneric(u64, size, payload_align); | ||
| 1391 | } | ||
| 1392 | return AbiSizeAdvanced{ .scalar = size }; | ||
| 1393 | }, | ||
| 1394 | .func_type => unreachable, // represents machine code; not a pointer | ||
| 1395 | .simple_type => |t| switch (t) { | ||
| 1396 | .bool, | ||
| 1397 | .atomic_order, | ||
| 1398 | .atomic_rmw_op, | ||
| 1399 | .calling_convention, | ||
| 1400 | .address_space, | ||
| 1401 | .float_mode, | ||
| 1402 | .reduce_op, | ||
| 1403 | .call_modifier, | ||
| 1404 | => return AbiSizeAdvanced{ .scalar = 1 }, | ||
| 1405 | |||
| 1406 | .f16 => return AbiSizeAdvanced{ .scalar = 2 }, | ||
| 1407 | .f32 => return AbiSizeAdvanced{ .scalar = 4 }, | ||
| 1408 | .f64 => return AbiSizeAdvanced{ .scalar = 8 }, | ||
| 1409 | .f128 => return AbiSizeAdvanced{ .scalar = 16 }, | ||
| 1410 | .f80 => switch (target.c_type_bit_size(.longdouble)) { | ||
| 1411 | 80 => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, | ||
| 1412 | else => { | ||
| 1413 | const u80_ty: Type = .{ .ip_index = .u80_type }; | ||
| 1414 | return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, mod) }; | ||
| 1415 | }, | ||
| 3505 | }, | 1416 | }, |
| 3506 | }; | ||
| 3507 | 1417 | ||
| 3508 | // Optional types are represented as a struct with the child type as the first | 1418 | .usize, |
| 3509 | // field and a boolean as the second. Since the child type's abi alignment is | 1419 | .isize, |
| 3510 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal | 1420 | => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 3511 | // to the child type's ABI alignment. | 1421 | |
| 3512 | return AbiSizeAdvanced{ | 1422 | .c_char => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.char) }, |
| 3513 | .scalar = child_type.abiAlignment(target) + payload_size, | 1423 | .c_short => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.short) }, |
| 3514 | }; | 1424 | .c_ushort => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ushort) }, |
| 3515 | }, | 1425 | .c_int => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.int) }, |
| 3516 | 1426 | .c_uint => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.uint) }, | |
| 3517 | .error_union => { | 1427 | .c_long => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.long) }, |
| 3518 | // This code needs to be kept in sync with the equivalent switch prong | 1428 | .c_ulong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulong) }, |
| 3519 | // in abiAlignmentAdvanced. | 1429 | .c_longlong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longlong) }, |
| 3520 | const data = ty.castTag(.error_union).?.data; | 1430 | .c_ulonglong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulonglong) }, |
| 3521 | const code_size = abiSize(Type.anyerror, target); | 1431 | .c_longdouble => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, |
| 3522 | if (!(data.payload.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | 1432 | |
| 3523 | error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, | 1433 | .anyopaque, |
| 3524 | else => |e| return e, | 1434 | .void, |
| 3525 | })) { | 1435 | .type, |
| 3526 | // Same as anyerror. | 1436 | .comptime_int, |
| 3527 | return AbiSizeAdvanced{ .scalar = code_size }; | 1437 | .comptime_float, |
| 3528 | } | 1438 | .null, |
| 3529 | const code_align = abiAlignment(Type.anyerror, target); | 1439 | .undefined, |
| 3530 | const payload_align = abiAlignment(data.payload, target); | 1440 | .enum_literal, |
| 3531 | const payload_size = switch (try data.payload.abiSizeAdvanced(target, strat)) { | 1441 | => return AbiSizeAdvanced{ .scalar = 0 }, |
| 3532 | .scalar => |elem_size| elem_size, | 1442 | |
| 3533 | .val => switch (strat) { | 1443 | // TODO revisit this when we have the concept of the error tag type |
| 3534 | .sema => unreachable, | 1444 | .anyerror => return AbiSizeAdvanced{ .scalar = 2 }, |
| 3535 | .eager => unreachable, | 1445 | |
| 3536 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, | 1446 | .prefetch_options => unreachable, // missing call to resolveTypeFields |
| 1447 | .export_options => unreachable, // missing call to resolveTypeFields | ||
| 1448 | .extern_options => unreachable, // missing call to resolveTypeFields | ||
| 1449 | |||
| 1450 | .type_info => unreachable, | ||
| 1451 | .noreturn => unreachable, | ||
| 1452 | .generic_poison => unreachable, | ||
| 1453 | }, | ||
| 1454 | .struct_type => |struct_type| switch (ty.containerLayout(mod)) { | ||
| 1455 | .Packed => { | ||
| 1456 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | ||
| 1457 | return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 1458 | |||
| 1459 | switch (strat) { | ||
| 1460 | .sema => |sema| try sema.resolveTypeLayout(ty), | ||
| 1461 | .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1462 | .ty = .comptime_int_type, | ||
| 1463 | .storage = .{ .lazy_size = ty.toIntern() }, | ||
| 1464 | } })).toValue() }, | ||
| 1465 | .eager => {}, | ||
| 1466 | } | ||
| 1467 | assert(struct_obj.haveLayout()); | ||
| 1468 | return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(mod) }; | ||
| 3537 | }, | 1469 | }, |
| 3538 | }; | 1470 | else => { |
| 1471 | switch (strat) { | ||
| 1472 | .sema => |sema| try sema.resolveTypeLayout(ty), | ||
| 1473 | .lazy => { | ||
| 1474 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | ||
| 1475 | return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 1476 | if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1477 | .ty = .comptime_int_type, | ||
| 1478 | .storage = .{ .lazy_size = ty.toIntern() }, | ||
| 1479 | } })).toValue() }; | ||
| 1480 | }, | ||
| 1481 | .eager => {}, | ||
| 1482 | } | ||
| 1483 | const field_count = ty.structFieldCount(mod); | ||
| 1484 | if (field_count == 0) { | ||
| 1485 | return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 1486 | } | ||
| 1487 | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) }; | ||
| 1488 | }, | ||
| 1489 | }, | ||
| 1490 | .anon_struct_type => |tuple| { | ||
| 1491 | switch (strat) { | ||
| 1492 | .sema => |sema| try sema.resolveTypeLayout(ty), | ||
| 1493 | .lazy, .eager => {}, | ||
| 1494 | } | ||
| 1495 | const field_count = tuple.types.len; | ||
| 1496 | if (field_count == 0) { | ||
| 1497 | return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 1498 | } | ||
| 1499 | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) }; | ||
| 1500 | }, | ||
| 3539 | 1501 | ||
| 3540 | var size: u64 = 0; | 1502 | .union_type => |union_type| { |
| 3541 | if (code_align > payload_align) { | 1503 | const union_obj = mod.unionPtr(union_type.index); |
| 3542 | size += code_size; | 1504 | return abiSizeAdvancedUnion(ty, mod, strat, union_obj, union_type.hasTag()); |
| 3543 | size = std.mem.alignForwardGeneric(u64, size, payload_align); | 1505 | }, |
| 3544 | size += payload_size; | 1506 | .opaque_type => unreachable, // no size available |
| 3545 | size = std.mem.alignForwardGeneric(u64, size, code_align); | 1507 | .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) }, |
| 3546 | } else { | 1508 | |
| 3547 | size += payload_size; | 1509 | // values, not types |
| 3548 | size = std.mem.alignForwardGeneric(u64, size, code_align); | 1510 | .undef, |
| 3549 | size += code_size; | 1511 | .runtime_value, |
| 3550 | size = std.mem.alignForwardGeneric(u64, size, payload_align); | 1512 | .simple_value, |
| 3551 | } | 1513 | .variable, |
| 3552 | return AbiSizeAdvanced{ .scalar = size }; | 1514 | .extern_func, |
| 1515 | .func, | ||
| 1516 | .int, | ||
| 1517 | .err, | ||
| 1518 | .error_union, | ||
| 1519 | .enum_literal, | ||
| 1520 | .enum_tag, | ||
| 1521 | .empty_enum_value, | ||
| 1522 | .float, | ||
| 1523 | .ptr, | ||
| 1524 | .opt, | ||
| 1525 | .aggregate, | ||
| 1526 | .un, | ||
| 1527 | // memoization, not types | ||
| 1528 | .memoized_call, | ||
| 1529 | => unreachable, | ||
| 3553 | }, | 1530 | }, |
| 3554 | } | 1531 | } |
| 3555 | } | 1532 | } |
| 3556 | 1533 | ||
| 3557 | pub fn abiSizeAdvancedUnion( | 1534 | pub fn abiSizeAdvancedUnion( |
| 3558 | ty: Type, | 1535 | ty: Type, |
| 3559 | target: Target, | 1536 | mod: *Module, |
| 3560 | strat: AbiAlignmentAdvancedStrat, | 1537 | strat: AbiAlignmentAdvancedStrat, |
| 3561 | union_obj: *Module.Union, | 1538 | union_obj: *Module.Union, |
| 3562 | have_tag: bool, | 1539 | have_tag: bool, |
| 3563 | ) Module.CompileError!AbiSizeAdvanced { | 1540 | ) Module.CompileError!AbiSizeAdvanced { |
| 3564 | switch (strat) { | 1541 | switch (strat) { |
| 3565 | .sema => |sema| try sema.resolveTypeLayout(ty), | 1542 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 3566 | .lazy => |arena| { | 1543 | .lazy => if (!union_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ |
| 3567 | if (!union_obj.haveLayout()) { | 1544 | .ty = .comptime_int_type, |
| 3568 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; | 1545 | .storage = .{ .lazy_size = ty.toIntern() }, |
| 3569 | } | 1546 | } })).toValue() }, |
| 3570 | }, | ||
| 3571 | .eager => {}, | 1547 | .eager => {}, |
| 3572 | } | 1548 | } |
| 3573 | return AbiSizeAdvanced{ .scalar = union_obj.abiSize(target, have_tag) }; | 1549 | return AbiSizeAdvanced{ .scalar = union_obj.abiSize(mod, have_tag) }; |
| 1550 | } | ||
| 1551 | |||
| 1552 | fn abiSizeAdvancedOptional( | ||
| 1553 | ty: Type, | ||
| 1554 | mod: *Module, | ||
| 1555 | strat: AbiAlignmentAdvancedStrat, | ||
| 1556 | ) Module.CompileError!AbiSizeAdvanced { | ||
| 1557 | const child_ty = ty.optionalChild(mod); | ||
| 1558 | |||
| 1559 | if (child_ty.isNoReturn(mod)) { | ||
| 1560 | return AbiSizeAdvanced{ .scalar = 0 }; | ||
| 1561 | } | ||
| 1562 | |||
| 1563 | if (!(child_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { | ||
| 1564 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1565 | .ty = .comptime_int_type, | ||
| 1566 | .storage = .{ .lazy_size = ty.toIntern() }, | ||
| 1567 | } })).toValue() }, | ||
| 1568 | else => |e| return e, | ||
| 1569 | })) return AbiSizeAdvanced{ .scalar = 1 }; | ||
| 1570 | |||
| 1571 | if (ty.optionalReprIsPayload(mod)) { | ||
| 1572 | return abiSizeAdvanced(child_ty, mod, strat); | ||
| 1573 | } | ||
| 1574 | |||
| 1575 | const payload_size = switch (try child_ty.abiSizeAdvanced(mod, strat)) { | ||
| 1576 | .scalar => |elem_size| elem_size, | ||
| 1577 | .val => switch (strat) { | ||
| 1578 | .sema => unreachable, | ||
| 1579 | .eager => unreachable, | ||
| 1580 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1581 | .ty = .comptime_int_type, | ||
| 1582 | .storage = .{ .lazy_size = ty.toIntern() }, | ||
| 1583 | } })).toValue() }, | ||
| 1584 | }, | ||
| 1585 | }; | ||
| 1586 | |||
| 1587 | // Optional types are represented as a struct with the child type as the first | ||
| 1588 | // field and a boolean as the second. Since the child type's abi alignment is | ||
| 1589 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal | ||
| 1590 | // to the child type's ABI alignment. | ||
| 1591 | return AbiSizeAdvanced{ | ||
| 1592 | .scalar = child_ty.abiAlignment(mod) + payload_size, | ||
| 1593 | }; | ||
| 3574 | } | 1594 | } |
| 3575 | 1595 | ||
| 3576 | fn intAbiSize(bits: u16, target: Target) u64 { | 1596 | fn intAbiSize(bits: u16, target: Target) u64 { |
| ... | @@ -3585,8 +1605,8 @@ pub const Type = extern union { | ... | @@ -3585,8 +1605,8 @@ pub const Type = extern union { |
| 3585 | ); | 1605 | ); |
| 3586 | } | 1606 | } |
| 3587 | 1607 | ||
| 3588 | pub fn bitSize(ty: Type, target: Target) u64 { | 1608 | pub fn bitSize(ty: Type, mod: *Module) u64 { |
| 3589 | return bitSizeAdvanced(ty, target, null) catch unreachable; | 1609 | return bitSizeAdvanced(ty, mod, null) catch unreachable; |
| 3590 | } | 1610 | } |
| 3591 | 1611 | ||
| 3592 | /// If you pass `opt_sema`, any recursive type resolutions will happen if | 1612 | /// If you pass `opt_sema`, any recursive type resolutions will happen if |
| ... | @@ -3594,568 +1614,318 @@ pub const Type = extern union { | ... | @@ -3594,568 +1614,318 @@ pub const Type = extern union { |
| 3594 | /// the type is fully resolved, and there will be no error, guaranteed. | 1614 | /// the type is fully resolved, and there will be no error, guaranteed. |
| 3595 | pub fn bitSizeAdvanced( | 1615 | pub fn bitSizeAdvanced( |
| 3596 | ty: Type, | 1616 | ty: Type, |
| 3597 | target: Target, | 1617 | mod: *Module, |
| 3598 | opt_sema: ?*Sema, | 1618 | opt_sema: ?*Sema, |
| 3599 | ) Module.CompileError!u64 { | 1619 | ) Module.CompileError!u64 { |
| 1620 | const target = mod.getTarget(); | ||
| 1621 | |||
| 3600 | const strat: AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; | 1622 | const strat: AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; |
| 3601 | switch (ty.tag()) { | 1623 | |
| 3602 | .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer | 1624 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3603 | .fn_void_no_args => unreachable, // represents machine code; not a pointer | 1625 | .int_type => |int_type| return int_type.bits, |
| 3604 | .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer | 1626 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 3605 | .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer | 1627 | .Slice => return target.ptrBitWidth() * 2, |
| 3606 | .function => unreachable, // represents machine code; not a pointer | 1628 | else => return target.ptrBitWidth(), |
| 3607 | .anyopaque => unreachable, | 1629 | }, |
| 3608 | .type => unreachable, | 1630 | .anyframe_type => return target.ptrBitWidth(), |
| 3609 | .comptime_int => unreachable, | 1631 | |
| 3610 | .comptime_float => unreachable, | 1632 | .array_type => |array_type| { |
| 3611 | .noreturn => unreachable, | 1633 | const len = array_type.len + @boolToInt(array_type.sentinel != .none); |
| 3612 | .null => unreachable, | 1634 | if (len == 0) return 0; |
| 3613 | .undefined => unreachable, | 1635 | const elem_ty = array_type.child.toType(); |
| 3614 | .enum_literal => unreachable, | 1636 | const elem_size = std.math.max(elem_ty.abiAlignment(mod), elem_ty.abiSize(mod)); |
| 3615 | .single_const_pointer_to_comptime_int => unreachable, | 1637 | if (elem_size == 0) return 0; |
| 3616 | .empty_struct => unreachable, | 1638 | const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema); |
| 3617 | .empty_struct_literal => unreachable, | 1639 | return (len - 1) * 8 * elem_size + elem_bit_size; |
| 3618 | .inferred_alloc_const => unreachable, | 1640 | }, |
| 3619 | .inferred_alloc_mut => unreachable, | 1641 | .vector_type => |vector_type| { |
| 3620 | .@"opaque" => unreachable, | 1642 | const child_ty = vector_type.child.toType(); |
| 3621 | .generic_poison => unreachable, | 1643 | const elem_bit_size = try bitSizeAdvanced(child_ty, mod, opt_sema); |
| 3622 | 1644 | return elem_bit_size * vector_type.len; | |
| 3623 | .void => return 0, | 1645 | }, |
| 3624 | .bool, .u1 => return 1, | 1646 | .opt_type => { |
| 3625 | .u8, .i8 => return 8, | 1647 | // Optionals and error unions are not packed so their bitsize |
| 3626 | .i16, .u16, .f16 => return 16, | 1648 | // includes padding bits. |
| 3627 | .u29 => return 29, | 1649 | return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; |
| 3628 | .i32, .u32, .f32 => return 32, | 1650 | }, |
| 3629 | .i64, .u64, .f64 => return 64, | 1651 | |
| 3630 | .f80 => return 80, | 1652 | // TODO revisit this when we have the concept of the error tag type |
| 3631 | .u128, .i128, .f128 => return 128, | 1653 | .error_set_type, .inferred_error_set_type => return 16, |
| 3632 | 1654 | ||
| 3633 | .@"struct" => { | 1655 | .error_union_type => { |
| 3634 | const struct_obj = ty.castTag(.@"struct").?.data; | 1656 | // Optionals and error unions are not packed so their bitsize |
| 1657 | // includes padding bits. | ||
| 1658 | return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8; | ||
| 1659 | }, | ||
| 1660 | .func_type => unreachable, // represents machine code; not a pointer | ||
| 1661 | .simple_type => |t| switch (t) { | ||
| 1662 | .f16 => return 16, | ||
| 1663 | .f32 => return 32, | ||
| 1664 | .f64 => return 64, | ||
| 1665 | .f80 => return 80, | ||
| 1666 | .f128 => return 128, | ||
| 1667 | |||
| 1668 | .usize, | ||
| 1669 | .isize, | ||
| 1670 | => return target.ptrBitWidth(), | ||
| 1671 | |||
| 1672 | .c_char => return target.c_type_bit_size(.char), | ||
| 1673 | .c_short => return target.c_type_bit_size(.short), | ||
| 1674 | .c_ushort => return target.c_type_bit_size(.ushort), | ||
| 1675 | .c_int => return target.c_type_bit_size(.int), | ||
| 1676 | .c_uint => return target.c_type_bit_size(.uint), | ||
| 1677 | .c_long => return target.c_type_bit_size(.long), | ||
| 1678 | .c_ulong => return target.c_type_bit_size(.ulong), | ||
| 1679 | .c_longlong => return target.c_type_bit_size(.longlong), | ||
| 1680 | .c_ulonglong => return target.c_type_bit_size(.ulonglong), | ||
| 1681 | .c_longdouble => return target.c_type_bit_size(.longdouble), | ||
| 1682 | |||
| 1683 | .bool => return 1, | ||
| 1684 | .void => return 0, | ||
| 1685 | |||
| 1686 | // TODO revisit this when we have the concept of the error tag type | ||
| 1687 | .anyerror => return 16, | ||
| 1688 | |||
| 1689 | .anyopaque => unreachable, | ||
| 1690 | .type => unreachable, | ||
| 1691 | .comptime_int => unreachable, | ||
| 1692 | .comptime_float => unreachable, | ||
| 1693 | .noreturn => unreachable, | ||
| 1694 | .null => unreachable, | ||
| 1695 | .undefined => unreachable, | ||
| 1696 | .enum_literal => unreachable, | ||
| 1697 | .generic_poison => unreachable, | ||
| 1698 | |||
| 1699 | .atomic_order => unreachable, // missing call to resolveTypeFields | ||
| 1700 | .atomic_rmw_op => unreachable, // missing call to resolveTypeFields | ||
| 1701 | .calling_convention => unreachable, // missing call to resolveTypeFields | ||
| 1702 | .address_space => unreachable, // missing call to resolveTypeFields | ||
| 1703 | .float_mode => unreachable, // missing call to resolveTypeFields | ||
| 1704 | .reduce_op => unreachable, // missing call to resolveTypeFields | ||
| 1705 | .call_modifier => unreachable, // missing call to resolveTypeFields | ||
| 1706 | .prefetch_options => unreachable, // missing call to resolveTypeFields | ||
| 1707 | .export_options => unreachable, // missing call to resolveTypeFields | ||
| 1708 | .extern_options => unreachable, // missing call to resolveTypeFields | ||
| 1709 | .type_info => unreachable, // missing call to resolveTypeFields | ||
| 1710 | }, | ||
| 1711 | .struct_type => |struct_type| { | ||
| 1712 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; | ||
| 3635 | if (struct_obj.layout != .Packed) { | 1713 | if (struct_obj.layout != .Packed) { |
| 3636 | return (try ty.abiSizeAdvanced(target, strat)).scalar * 8; | 1714 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; |
| 3637 | } | 1715 | } |
| 3638 | if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty); | 1716 | if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty); |
| 3639 | assert(struct_obj.haveLayout()); | 1717 | assert(struct_obj.haveLayout()); |
| 3640 | return try struct_obj.backing_int_ty.bitSizeAdvanced(target, opt_sema); | 1718 | return try struct_obj.backing_int_ty.bitSizeAdvanced(mod, opt_sema); |
| 3641 | }, | 1719 | }, |
| 3642 | 1720 | ||
| 3643 | .tuple, .anon_struct => { | 1721 | .anon_struct_type => { |
| 3644 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); | 1722 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); |
| 3645 | if (ty.containerLayout() != .Packed) { | 1723 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; |
| 3646 | return (try ty.abiSizeAdvanced(target, strat)).scalar * 8; | ||
| 3647 | } | ||
| 3648 | var total: u64 = 0; | ||
| 3649 | for (ty.tupleFields().types) |field_ty| { | ||
| 3650 | total += try bitSizeAdvanced(field_ty, target, opt_sema); | ||
| 3651 | } | ||
| 3652 | return total; | ||
| 3653 | }, | ||
| 3654 | |||
| 3655 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { | ||
| 3656 | var buffer: Payload.Bits = undefined; | ||
| 3657 | const int_tag_ty = ty.intTagType(&buffer); | ||
| 3658 | return try bitSizeAdvanced(int_tag_ty, target, opt_sema); | ||
| 3659 | }, | 1724 | }, |
| 3660 | 1725 | ||
| 3661 | .@"union", .union_safety_tagged, .union_tagged => { | 1726 | .union_type => |union_type| { |
| 3662 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); | 1727 | if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty); |
| 3663 | if (ty.containerLayout() != .Packed) { | 1728 | if (ty.containerLayout(mod) != .Packed) { |
| 3664 | return (try ty.abiSizeAdvanced(target, strat)).scalar * 8; | 1729 | return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8; |
| 3665 | } | 1730 | } |
| 3666 | const union_obj = ty.cast(Payload.Union).?.data; | 1731 | const union_obj = mod.unionPtr(union_type.index); |
| 3667 | assert(union_obj.haveFieldTypes()); | 1732 | assert(union_obj.haveFieldTypes()); |
| 3668 | 1733 | ||
| 3669 | var size: u64 = 0; | 1734 | var size: u64 = 0; |
| 3670 | for (union_obj.fields.values()) |field| { | 1735 | for (union_obj.fields.values()) |field| { |
| 3671 | size = @max(size, try bitSizeAdvanced(field.ty, target, opt_sema)); | 1736 | size = @max(size, try bitSizeAdvanced(field.ty, mod, opt_sema)); |
| 3672 | } | 1737 | } |
| 3673 | return size; | 1738 | return size; |
| 3674 | }, | 1739 | }, |
| 3675 | 1740 | .opaque_type => unreachable, | |
| 3676 | .vector => { | 1741 | .enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema), |
| 3677 | const payload = ty.castTag(.vector).?.data; | 1742 | |
| 3678 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, opt_sema); | 1743 | // values, not types |
| 3679 | return elem_bit_size * payload.len; | 1744 | .undef, |
| 3680 | }, | 1745 | .runtime_value, |
| 3681 | .array_u8 => return 8 * ty.castTag(.array_u8).?.data, | 1746 | .simple_value, |
| 3682 | .array_u8_sentinel_0 => return 8 * (ty.castTag(.array_u8_sentinel_0).?.data + 1), | 1747 | .variable, |
| 3683 | .array => { | 1748 | .extern_func, |
| 3684 | const payload = ty.castTag(.array).?.data; | 1749 | .func, |
| 3685 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); | 1750 | .int, |
| 3686 | if (elem_size == 0 or payload.len == 0) | 1751 | .err, |
| 3687 | return @as(u64, 0); | 1752 | .error_union, |
| 3688 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, opt_sema); | 1753 | .enum_literal, |
| 3689 | return (payload.len - 1) * 8 * elem_size + elem_bit_size; | 1754 | .enum_tag, |
| 3690 | }, | 1755 | .empty_enum_value, |
| 3691 | .array_sentinel => { | 1756 | .float, |
| 3692 | const payload = ty.castTag(.array_sentinel).?.data; | 1757 | .ptr, |
| 3693 | const elem_size = std.math.max( | 1758 | .opt, |
| 3694 | payload.elem_type.abiAlignment(target), | 1759 | .aggregate, |
| 3695 | payload.elem_type.abiSize(target), | 1760 | .un, |
| 3696 | ); | 1761 | // memoization, not types |
| 3697 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, opt_sema); | 1762 | .memoized_call, |
| 3698 | return payload.len * 8 * elem_size + elem_bit_size; | 1763 | => unreachable, |
| 3699 | }, | ||
| 3700 | |||
| 3701 | .isize, | ||
| 3702 | .usize, | ||
| 3703 | .@"anyframe", | ||
| 3704 | .anyframe_T, | ||
| 3705 | => return target.ptrBitWidth(), | ||
| 3706 | |||
| 3707 | .const_slice, | ||
| 3708 | .mut_slice, | ||
| 3709 | => return target.ptrBitWidth() * 2, | ||
| 3710 | |||
| 3711 | .const_slice_u8, | ||
| 3712 | .const_slice_u8_sentinel_0, | ||
| 3713 | => return target.ptrBitWidth() * 2, | ||
| 3714 | |||
| 3715 | .optional_single_const_pointer, | ||
| 3716 | .optional_single_mut_pointer, | ||
| 3717 | => { | ||
| 3718 | return target.ptrBitWidth(); | ||
| 3719 | }, | ||
| 3720 | |||
| 3721 | .single_const_pointer, | ||
| 3722 | .single_mut_pointer, | ||
| 3723 | .many_const_pointer, | ||
| 3724 | .many_mut_pointer, | ||
| 3725 | .c_const_pointer, | ||
| 3726 | .c_mut_pointer, | ||
| 3727 | => { | ||
| 3728 | return target.ptrBitWidth(); | ||
| 3729 | }, | ||
| 3730 | |||
| 3731 | .pointer => switch (ty.castTag(.pointer).?.data.size) { | ||
| 3732 | .Slice => return target.ptrBitWidth() * 2, | ||
| 3733 | else => return target.ptrBitWidth(), | ||
| 3734 | }, | ||
| 3735 | |||
| 3736 | .manyptr_u8, | ||
| 3737 | .manyptr_const_u8, | ||
| 3738 | .manyptr_const_u8_sentinel_0, | ||
| 3739 | => return target.ptrBitWidth(), | ||
| 3740 | |||
| 3741 | .c_char => return target.c_type_bit_size(.char), | ||
| 3742 | .c_short => return target.c_type_bit_size(.short), | ||
| 3743 | .c_ushort => return target.c_type_bit_size(.ushort), | ||
| 3744 | .c_int => return target.c_type_bit_size(.int), | ||
| 3745 | .c_uint => return target.c_type_bit_size(.uint), | ||
| 3746 | .c_long => return target.c_type_bit_size(.long), | ||
| 3747 | .c_ulong => return target.c_type_bit_size(.ulong), | ||
| 3748 | .c_longlong => return target.c_type_bit_size(.longlong), | ||
| 3749 | .c_ulonglong => return target.c_type_bit_size(.ulonglong), | ||
| 3750 | .c_longdouble => return target.c_type_bit_size(.longdouble), | ||
| 3751 | |||
| 3752 | .error_set, | ||
| 3753 | .error_set_single, | ||
| 3754 | .anyerror_void_error_union, | ||
| 3755 | .anyerror, | ||
| 3756 | .error_set_inferred, | ||
| 3757 | .error_set_merged, | ||
| 3758 | => return 16, // TODO revisit this when we have the concept of the error tag type | ||
| 3759 | |||
| 3760 | .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data, | ||
| 3761 | |||
| 3762 | .optional, .error_union => { | ||
| 3763 | // Optionals and error unions are not packed so their bitsize | ||
| 3764 | // includes padding bits. | ||
| 3765 | return (try abiSizeAdvanced(ty, target, strat)).scalar * 8; | ||
| 3766 | }, | ||
| 3767 | |||
| 3768 | .atomic_order, | ||
| 3769 | .atomic_rmw_op, | ||
| 3770 | .calling_convention, | ||
| 3771 | .address_space, | ||
| 3772 | .float_mode, | ||
| 3773 | .reduce_op, | ||
| 3774 | .modifier, | ||
| 3775 | .prefetch_options, | ||
| 3776 | .export_options, | ||
| 3777 | .extern_options, | ||
| 3778 | .type_info, | ||
| 3779 | => @panic("TODO at some point we gotta resolve builtin types"), | ||
| 3780 | } | 1764 | } |
| 3781 | } | 1765 | } |
| 3782 | 1766 | ||
| 3783 | /// Returns true if the type's layout is already resolved and it is safe | 1767 | /// Returns true if the type's layout is already resolved and it is safe |
| 3784 | /// to use `abiSize`, `abiAlignment` and `bitSize` on it. | 1768 | /// to use `abiSize`, `abiAlignment` and `bitSize` on it. |
| 3785 | pub fn layoutIsResolved(ty: Type) bool { | 1769 | pub fn layoutIsResolved(ty: Type, mod: *Module) bool { |
| 3786 | switch (ty.zigTypeTag()) { | 1770 | switch (ty.zigTypeTag(mod)) { |
| 3787 | .Struct => { | 1771 | .Struct => { |
| 3788 | if (ty.castTag(.@"struct")) |struct_ty| { | 1772 | if (mod.typeToStruct(ty)) |struct_obj| { |
| 3789 | return struct_ty.data.haveLayout(); | 1773 | return struct_obj.haveLayout(); |
| 3790 | } | 1774 | } |
| 3791 | return true; | 1775 | return true; |
| 3792 | }, | 1776 | }, |
| 3793 | .Union => { | 1777 | .Union => { |
| 3794 | if (ty.cast(Payload.Union)) |union_ty| { | 1778 | if (mod.typeToUnion(ty)) |union_obj| { |
| 3795 | return union_ty.data.haveLayout(); | 1779 | return union_obj.haveLayout(); |
| 3796 | } | 1780 | } |
| 3797 | return true; | 1781 | return true; |
| 3798 | }, | 1782 | }, |
| 3799 | .Array => { | 1783 | .Array => { |
| 3800 | if (ty.arrayLenIncludingSentinel() == 0) return true; | 1784 | if (ty.arrayLenIncludingSentinel(mod) == 0) return true; |
| 3801 | return ty.childType().layoutIsResolved(); | 1785 | return ty.childType(mod).layoutIsResolved(mod); |
| 3802 | }, | 1786 | }, |
| 3803 | .Optional => { | 1787 | .Optional => { |
| 3804 | var buf: Type.Payload.ElemType = undefined; | 1788 | const payload_ty = ty.optionalChild(mod); |
| 3805 | const payload_ty = ty.optionalChild(&buf); | 1789 | return payload_ty.layoutIsResolved(mod); |
| 3806 | return payload_ty.layoutIsResolved(); | ||
| 3807 | }, | 1790 | }, |
| 3808 | .ErrorUnion => { | 1791 | .ErrorUnion => { |
| 3809 | const payload_ty = ty.errorUnionPayload(); | 1792 | const payload_ty = ty.errorUnionPayload(mod); |
| 3810 | return payload_ty.layoutIsResolved(); | 1793 | return payload_ty.layoutIsResolved(mod); |
| 3811 | }, | 1794 | }, |
| 3812 | else => return true, | 1795 | else => return true, |
| 3813 | } | 1796 | } |
| 3814 | } | 1797 | } |
| 3815 | 1798 | ||
| 3816 | pub fn isSinglePointer(self: Type) bool { | 1799 | pub fn isSinglePointer(ty: Type, mod: *const Module) bool { |
| 3817 | return switch (self.tag()) { | 1800 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3818 | .single_const_pointer, | 1801 | .ptr_type => |ptr_info| ptr_info.flags.size == .One, |
| 3819 | .single_mut_pointer, | ||
| 3820 | .single_const_pointer_to_comptime_int, | ||
| 3821 | .inferred_alloc_const, | ||
| 3822 | .inferred_alloc_mut, | ||
| 3823 | => true, | ||
| 3824 | |||
| 3825 | .pointer => self.castTag(.pointer).?.data.size == .One, | ||
| 3826 | |||
| 3827 | else => false, | 1802 | else => false, |
| 3828 | }; | 1803 | }; |
| 3829 | } | 1804 | } |
| 3830 | 1805 | ||
| 3831 | /// Asserts `ty` is a pointer. | 1806 | /// Asserts `ty` is a pointer. |
| 3832 | pub fn ptrSize(ty: Type) std.builtin.Type.Pointer.Size { | 1807 | pub fn ptrSize(ty: Type, mod: *const Module) std.builtin.Type.Pointer.Size { |
| 3833 | return ptrSizeOrNull(ty).?; | 1808 | return ptrSizeOrNull(ty, mod).?; |
| 3834 | } | 1809 | } |
| 3835 | 1810 | ||
| 3836 | /// Returns `null` if `ty` is not a pointer. | 1811 | /// Returns `null` if `ty` is not a pointer. |
| 3837 | pub fn ptrSizeOrNull(ty: Type) ?std.builtin.Type.Pointer.Size { | 1812 | pub fn ptrSizeOrNull(ty: Type, mod: *const Module) ?std.builtin.Type.Pointer.Size { |
| 3838 | return switch (ty.tag()) { | 1813 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3839 | .const_slice, | 1814 | .ptr_type => |ptr_info| ptr_info.flags.size, |
| 3840 | .mut_slice, | ||
| 3841 | .const_slice_u8, | ||
| 3842 | .const_slice_u8_sentinel_0, | ||
| 3843 | => .Slice, | ||
| 3844 | |||
| 3845 | .many_const_pointer, | ||
| 3846 | .many_mut_pointer, | ||
| 3847 | .manyptr_u8, | ||
| 3848 | .manyptr_const_u8, | ||
| 3849 | .manyptr_const_u8_sentinel_0, | ||
| 3850 | => .Many, | ||
| 3851 | |||
| 3852 | .c_const_pointer, | ||
| 3853 | .c_mut_pointer, | ||
| 3854 | => .C, | ||
| 3855 | |||
| 3856 | .single_const_pointer, | ||
| 3857 | .single_mut_pointer, | ||
| 3858 | .single_const_pointer_to_comptime_int, | ||
| 3859 | .inferred_alloc_const, | ||
| 3860 | .inferred_alloc_mut, | ||
| 3861 | => .One, | ||
| 3862 | |||
| 3863 | .pointer => ty.castTag(.pointer).?.data.size, | ||
| 3864 | |||
| 3865 | else => null, | 1815 | else => null, |
| 3866 | }; | 1816 | }; |
| 3867 | } | 1817 | } |
| 3868 | 1818 | ||
| 3869 | pub fn isSlice(self: Type) bool { | 1819 | pub fn isSlice(ty: Type, mod: *const Module) bool { |
| 3870 | return switch (self.tag()) { | 1820 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3871 | .const_slice, | 1821 | .ptr_type => |ptr_type| ptr_type.flags.size == .Slice, |
| 3872 | .mut_slice, | ||
| 3873 | .const_slice_u8, | ||
| 3874 | .const_slice_u8_sentinel_0, | ||
| 3875 | => true, | ||
| 3876 | |||
| 3877 | .pointer => self.castTag(.pointer).?.data.size == .Slice, | ||
| 3878 | |||
| 3879 | else => false, | 1822 | else => false, |
| 3880 | }; | 1823 | }; |
| 3881 | } | 1824 | } |
| 3882 | 1825 | ||
| 3883 | pub const SlicePtrFieldTypeBuffer = union { | 1826 | pub fn slicePtrFieldType(ty: Type, mod: *const Module) Type { |
| 3884 | elem_type: Payload.ElemType, | 1827 | return mod.intern_pool.slicePtrType(ty.toIntern()).toType(); |
| 3885 | pointer: Payload.Pointer, | ||
| 3886 | }; | ||
| 3887 | |||
| 3888 | pub fn slicePtrFieldType(self: Type, buffer: *SlicePtrFieldTypeBuffer) Type { | ||
| 3889 | switch (self.tag()) { | ||
| 3890 | .const_slice_u8 => return Type.initTag(.manyptr_const_u8), | ||
| 3891 | .const_slice_u8_sentinel_0 => return Type.initTag(.manyptr_const_u8_sentinel_0), | ||
| 3892 | |||
| 3893 | .const_slice => { | ||
| 3894 | const elem_type = self.castTag(.const_slice).?.data; | ||
| 3895 | buffer.* = .{ | ||
| 3896 | .elem_type = .{ | ||
| 3897 | .base = .{ .tag = .many_const_pointer }, | ||
| 3898 | .data = elem_type, | ||
| 3899 | }, | ||
| 3900 | }; | ||
| 3901 | return Type.initPayload(&buffer.elem_type.base); | ||
| 3902 | }, | ||
| 3903 | .mut_slice => { | ||
| 3904 | const elem_type = self.castTag(.mut_slice).?.data; | ||
| 3905 | buffer.* = .{ | ||
| 3906 | .elem_type = .{ | ||
| 3907 | .base = .{ .tag = .many_mut_pointer }, | ||
| 3908 | .data = elem_type, | ||
| 3909 | }, | ||
| 3910 | }; | ||
| 3911 | return Type.initPayload(&buffer.elem_type.base); | ||
| 3912 | }, | ||
| 3913 | |||
| 3914 | .pointer => { | ||
| 3915 | const payload = self.castTag(.pointer).?.data; | ||
| 3916 | assert(payload.size == .Slice); | ||
| 3917 | |||
| 3918 | if (payload.sentinel != null or | ||
| 3919 | payload.@"align" != 0 or | ||
| 3920 | payload.@"addrspace" != .generic or | ||
| 3921 | payload.bit_offset != 0 or | ||
| 3922 | payload.host_size != 0 or | ||
| 3923 | payload.vector_index != .none or | ||
| 3924 | payload.@"allowzero" or | ||
| 3925 | payload.@"volatile") | ||
| 3926 | { | ||
| 3927 | buffer.* = .{ | ||
| 3928 | .pointer = .{ | ||
| 3929 | .data = .{ | ||
| 3930 | .pointee_type = payload.pointee_type, | ||
| 3931 | .sentinel = payload.sentinel, | ||
| 3932 | .@"align" = payload.@"align", | ||
| 3933 | .@"addrspace" = payload.@"addrspace", | ||
| 3934 | .bit_offset = payload.bit_offset, | ||
| 3935 | .host_size = payload.host_size, | ||
| 3936 | .vector_index = payload.vector_index, | ||
| 3937 | .@"allowzero" = payload.@"allowzero", | ||
| 3938 | .mutable = payload.mutable, | ||
| 3939 | .@"volatile" = payload.@"volatile", | ||
| 3940 | .size = .Many, | ||
| 3941 | }, | ||
| 3942 | }, | ||
| 3943 | }; | ||
| 3944 | return Type.initPayload(&buffer.pointer.base); | ||
| 3945 | } else if (payload.mutable) { | ||
| 3946 | buffer.* = .{ | ||
| 3947 | .elem_type = .{ | ||
| 3948 | .base = .{ .tag = .many_mut_pointer }, | ||
| 3949 | .data = payload.pointee_type, | ||
| 3950 | }, | ||
| 3951 | }; | ||
| 3952 | return Type.initPayload(&buffer.elem_type.base); | ||
| 3953 | } else { | ||
| 3954 | buffer.* = .{ | ||
| 3955 | .elem_type = .{ | ||
| 3956 | .base = .{ .tag = .many_const_pointer }, | ||
| 3957 | .data = payload.pointee_type, | ||
| 3958 | }, | ||
| 3959 | }; | ||
| 3960 | return Type.initPayload(&buffer.elem_type.base); | ||
| 3961 | } | ||
| 3962 | }, | ||
| 3963 | |||
| 3964 | else => unreachable, | ||
| 3965 | } | ||
| 3966 | } | 1828 | } |
| 3967 | 1829 | ||
| 3968 | pub fn isConstPtr(self: Type) bool { | 1830 | pub fn isConstPtr(ty: Type, mod: *const Module) bool { |
| 3969 | return switch (self.tag()) { | 1831 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3970 | .single_const_pointer, | 1832 | .ptr_type => |ptr_type| ptr_type.flags.is_const, |
| 3971 | .many_const_pointer, | ||
| 3972 | .c_const_pointer, | ||
| 3973 | .single_const_pointer_to_comptime_int, | ||
| 3974 | .const_slice_u8, | ||
| 3975 | .const_slice_u8_sentinel_0, | ||
| 3976 | .const_slice, | ||
| 3977 | .manyptr_const_u8, | ||
| 3978 | .manyptr_const_u8_sentinel_0, | ||
| 3979 | => true, | ||
| 3980 | |||
| 3981 | .pointer => !self.castTag(.pointer).?.data.mutable, | ||
| 3982 | |||
| 3983 | else => false, | 1833 | else => false, |
| 3984 | }; | 1834 | }; |
| 3985 | } | 1835 | } |
| 3986 | 1836 | ||
| 3987 | pub fn isVolatilePtr(self: Type) bool { | 1837 | pub fn isVolatilePtr(ty: Type, mod: *const Module) bool { |
| 3988 | return switch (self.tag()) { | 1838 | return isVolatilePtrIp(ty, &mod.intern_pool); |
| 3989 | .pointer => { | 1839 | } |
| 3990 | const payload = self.castTag(.pointer).?.data; | 1840 | |
| 3991 | return payload.@"volatile"; | 1841 | pub fn isVolatilePtrIp(ty: Type, ip: *const InternPool) bool { |
| 3992 | }, | 1842 | return switch (ip.indexToKey(ty.toIntern())) { |
| 1843 | .ptr_type => |ptr_type| ptr_type.flags.is_volatile, | ||
| 3993 | else => false, | 1844 | else => false, |
| 3994 | }; | 1845 | }; |
| 3995 | } | 1846 | } |
| 3996 | 1847 | ||
| 3997 | pub fn isAllowzeroPtr(self: Type) bool { | 1848 | pub fn isAllowzeroPtr(ty: Type, mod: *const Module) bool { |
| 3998 | return switch (self.tag()) { | 1849 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 3999 | .pointer => { | 1850 | .ptr_type => |ptr_type| ptr_type.flags.is_allowzero, |
| 4000 | const payload = self.castTag(.pointer).?.data; | 1851 | .opt_type => true, |
| 4001 | return payload.@"allowzero"; | 1852 | else => false, |
| 4002 | }, | ||
| 4003 | else => return self.zigTypeTag() == .Optional, | ||
| 4004 | }; | 1853 | }; |
| 4005 | } | 1854 | } |
| 4006 | 1855 | ||
| 4007 | pub fn isCPtr(self: Type) bool { | 1856 | pub fn isCPtr(ty: Type, mod: *const Module) bool { |
| 4008 | return switch (self.tag()) { | 1857 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4009 | .c_const_pointer, | 1858 | .ptr_type => |ptr_type| ptr_type.flags.size == .C, |
| 4010 | .c_mut_pointer, | 1859 | else => false, |
| 4011 | => return true, | ||
| 4012 | |||
| 4013 | .pointer => self.castTag(.pointer).?.data.size == .C, | ||
| 4014 | |||
| 4015 | else => return false, | ||
| 4016 | }; | 1860 | }; |
| 4017 | } | 1861 | } |
| 4018 | 1862 | ||
| 4019 | pub fn isPtrAtRuntime(self: Type) bool { | 1863 | pub fn isPtrAtRuntime(ty: Type, mod: *const Module) bool { |
| 4020 | switch (self.tag()) { | 1864 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4021 | .c_const_pointer, | 1865 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 4022 | .c_mut_pointer, | 1866 | .Slice => false, |
| 4023 | .many_const_pointer, | 1867 | .One, .Many, .C => true, |
| 4024 | .many_mut_pointer, | ||
| 4025 | .manyptr_const_u8, | ||
| 4026 | .manyptr_const_u8_sentinel_0, | ||
| 4027 | .manyptr_u8, | ||
| 4028 | .optional_single_const_pointer, | ||
| 4029 | .optional_single_mut_pointer, | ||
| 4030 | .single_const_pointer, | ||
| 4031 | .single_const_pointer_to_comptime_int, | ||
| 4032 | .single_mut_pointer, | ||
| 4033 | => return true, | ||
| 4034 | |||
| 4035 | .pointer => switch (self.castTag(.pointer).?.data.size) { | ||
| 4036 | .Slice => return false, | ||
| 4037 | .One, .Many, .C => return true, | ||
| 4038 | }, | 1868 | }, |
| 4039 | 1869 | .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) { | |
| 4040 | .optional => { | 1870 | .ptr_type => |p| switch (p.flags.size) { |
| 4041 | var buf: Payload.ElemType = undefined; | 1871 | .Slice, .C => false, |
| 4042 | const child_type = self.optionalChild(&buf); | 1872 | .Many, .One => !p.flags.is_allowzero, |
| 4043 | if (child_type.zigTypeTag() != .Pointer) return false; | 1873 | }, |
| 4044 | const info = child_type.ptrInfo().data; | 1874 | else => false, |
| 4045 | switch (info.size) { | ||
| 4046 | .Slice, .C => return false, | ||
| 4047 | .Many, .One => return !info.@"allowzero", | ||
| 4048 | } | ||
| 4049 | }, | 1875 | }, |
| 4050 | 1876 | else => false, | |
| 4051 | else => return false, | 1877 | }; |
| 4052 | } | ||
| 4053 | } | 1878 | } |
| 4054 | 1879 | ||
| 4055 | /// For pointer-like optionals, returns true, otherwise returns the allowzero property | 1880 | /// For pointer-like optionals, returns true, otherwise returns the allowzero property |
| 4056 | /// of pointers. | 1881 | /// of pointers. |
| 4057 | pub fn ptrAllowsZero(ty: Type) bool { | 1882 | pub fn ptrAllowsZero(ty: Type, mod: *const Module) bool { |
| 4058 | if (ty.isPtrLikeOptional()) { | 1883 | if (ty.isPtrLikeOptional(mod)) { |
| 4059 | return true; | 1884 | return true; |
| 4060 | } | 1885 | } |
| 4061 | return ty.ptrInfo().data.@"allowzero"; | 1886 | return ty.ptrInfo(mod).@"allowzero"; |
| 4062 | } | 1887 | } |
| 4063 | 1888 | ||
| 4064 | /// See also `isPtrLikeOptional`. | 1889 | /// See also `isPtrLikeOptional`. |
| 4065 | pub fn optionalReprIsPayload(ty: Type) bool { | 1890 | pub fn optionalReprIsPayload(ty: Type, mod: *const Module) bool { |
| 4066 | switch (ty.tag()) { | 1891 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4067 | .optional_single_const_pointer, | 1892 | .opt_type => |child_type| child_type == .anyerror_type or switch (mod.intern_pool.indexToKey(child_type)) { |
| 4068 | .optional_single_mut_pointer, | 1893 | .ptr_type => |ptr_type| ptr_type.flags.size != .C and !ptr_type.flags.is_allowzero, |
| 4069 | .c_const_pointer, | 1894 | .error_set_type => true, |
| 4070 | .c_mut_pointer, | 1895 | else => false, |
| 4071 | => return true, | 1896 | }, |
| 4072 | 1897 | .ptr_type => |ptr_type| ptr_type.flags.size == .C, | |
| 4073 | .optional => { | 1898 | else => false, |
| 4074 | const child_ty = ty.castTag(.optional).?.data; | 1899 | }; |
| 4075 | switch (child_ty.zigTypeTag()) { | ||
| 4076 | .Pointer => { | ||
| 4077 | const info = child_ty.ptrInfo().data; | ||
| 4078 | switch (info.size) { | ||
| 4079 | .C => return false, | ||
| 4080 | .Slice, .Many, .One => return !info.@"allowzero", | ||
| 4081 | } | ||
| 4082 | }, | ||
| 4083 | .ErrorSet => return true, | ||
| 4084 | else => return false, | ||
| 4085 | } | ||
| 4086 | }, | ||
| 4087 | |||
| 4088 | .pointer => return ty.castTag(.pointer).?.data.size == .C, | ||
| 4089 | |||
| 4090 | else => return false, | ||
| 4091 | } | ||
| 4092 | } | 1900 | } |
| 4093 | 1901 | ||
| 4094 | /// Returns true if the type is optional and would be lowered to a single pointer | 1902 | /// Returns true if the type is optional and would be lowered to a single pointer |
| 4095 | /// address value, using 0 for null. Note that this returns true for C pointers. | 1903 | /// address value, using 0 for null. Note that this returns true for C pointers. |
| 4096 | pub fn isPtrLikeOptional(self: Type) bool { | 1904 | /// This function must be kept in sync with `Sema.typePtrOrOptionalPtrTy`. |
| 4097 | switch (self.tag()) { | 1905 | pub fn isPtrLikeOptional(ty: Type, mod: *const Module) bool { |
| 4098 | .optional_single_const_pointer, | 1906 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4099 | .optional_single_mut_pointer, | 1907 | .ptr_type => |ptr_type| ptr_type.flags.size == .C, |
| 4100 | .c_const_pointer, | 1908 | .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) { |
| 4101 | .c_mut_pointer, | 1909 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 4102 | => return true, | 1910 | .Slice, .C => false, |
| 4103 | 1911 | .Many, .One => !ptr_type.flags.is_allowzero, | |
| 4104 | .optional => { | 1912 | }, |
| 4105 | const child_ty = self.castTag(.optional).?.data; | 1913 | else => false, |
| 4106 | if (child_ty.zigTypeTag() != .Pointer) return false; | ||
| 4107 | const info = child_ty.ptrInfo().data; | ||
| 4108 | switch (info.size) { | ||
| 4109 | .Slice, .C => return false, | ||
| 4110 | .Many, .One => return !info.@"allowzero", | ||
| 4111 | } | ||
| 4112 | }, | 1914 | }, |
| 4113 | 1915 | else => false, | |
| 4114 | .pointer => return self.castTag(.pointer).?.data.size == .C, | 1916 | }; |
| 4115 | |||
| 4116 | else => return false, | ||
| 4117 | } | ||
| 4118 | } | 1917 | } |
| 4119 | 1918 | ||
| 4120 | /// For *[N]T, returns [N]T. | 1919 | /// For *[N]T, returns [N]T. |
| 4121 | /// For *T, returns T. | 1920 | /// For *T, returns T. |
| 4122 | /// For [*]T, returns T. | 1921 | /// For [*]T, returns T. |
| 4123 | pub fn childType(ty: Type) Type { | 1922 | pub fn childType(ty: Type, mod: *const Module) Type { |
| 4124 | return switch (ty.tag()) { | 1923 | return childTypeIp(ty, &mod.intern_pool); |
| 4125 | .vector => ty.castTag(.vector).?.data.elem_type, | ||
| 4126 | .array => ty.castTag(.array).?.data.elem_type, | ||
| 4127 | .array_sentinel => ty.castTag(.array_sentinel).?.data.elem_type, | ||
| 4128 | .optional_single_mut_pointer, | ||
| 4129 | .optional_single_const_pointer, | ||
| 4130 | .single_const_pointer, | ||
| 4131 | .single_mut_pointer, | ||
| 4132 | .many_const_pointer, | ||
| 4133 | .many_mut_pointer, | ||
| 4134 | .c_const_pointer, | ||
| 4135 | .c_mut_pointer, | ||
| 4136 | .const_slice, | ||
| 4137 | .mut_slice, | ||
| 4138 | => ty.castPointer().?.data, | ||
| 4139 | |||
| 4140 | .array_u8, | ||
| 4141 | .array_u8_sentinel_0, | ||
| 4142 | .const_slice_u8, | ||
| 4143 | .const_slice_u8_sentinel_0, | ||
| 4144 | .manyptr_u8, | ||
| 4145 | .manyptr_const_u8, | ||
| 4146 | .manyptr_const_u8_sentinel_0, | ||
| 4147 | => Type.u8, | ||
| 4148 | |||
| 4149 | .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), | ||
| 4150 | .pointer => ty.castTag(.pointer).?.data.pointee_type, | ||
| 4151 | |||
| 4152 | else => unreachable, | ||
| 4153 | }; | ||
| 4154 | } | 1924 | } |
| 4155 | 1925 | ||
| 4156 | /// Asserts the type is a pointer or array type. | 1926 | pub fn childTypeIp(ty: Type, ip: *const InternPool) Type { |
| 4157 | /// TODO this is deprecated in favor of `childType`. | 1927 | return ip.childType(ty.toIntern()).toType(); |
| 4158 | pub const elemType = childType; | 1928 | } |
| 4159 | 1929 | ||
| 4160 | /// For *[N]T, returns T. | 1930 | /// For *[N]T, returns T. |
| 4161 | /// For ?*T, returns T. | 1931 | /// For ?*T, returns T. |
| ... | @@ -4166,283 +1936,178 @@ pub const Type = extern union { | ... | @@ -4166,283 +1936,178 @@ pub const Type = extern union { |
| 4166 | /// For [N]T, returns T. | 1936 | /// For [N]T, returns T. |
| 4167 | /// For []T, returns T. | 1937 | /// For []T, returns T. |
| 4168 | /// For anyframe->T, returns T. | 1938 | /// For anyframe->T, returns T. |
| 4169 | pub fn elemType2(ty: Type) Type { | 1939 | pub fn elemType2(ty: Type, mod: *const Module) Type { |
| 4170 | return switch (ty.tag()) { | 1940 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4171 | .vector => ty.castTag(.vector).?.data.elem_type, | 1941 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 4172 | .array => ty.castTag(.array).?.data.elem_type, | 1942 | .One => ptr_type.child.toType().shallowElemType(mod), |
| 4173 | .array_sentinel => ty.castTag(.array_sentinel).?.data.elem_type, | 1943 | .Many, .C, .Slice => ptr_type.child.toType(), |
| 4174 | .many_const_pointer, | 1944 | }, |
| 4175 | .many_mut_pointer, | 1945 | .anyframe_type => |child| { |
| 4176 | .c_const_pointer, | 1946 | assert(child != .none); |
| 4177 | .c_mut_pointer, | 1947 | return child.toType(); |
| 4178 | .const_slice, | 1948 | }, |
| 4179 | .mut_slice, | 1949 | .vector_type => |vector_type| vector_type.child.toType(), |
| 4180 | => ty.castPointer().?.data, | 1950 | .array_type => |array_type| array_type.child.toType(), |
| 4181 | 1951 | .opt_type => |child| mod.intern_pool.childType(child).toType(), | |
| 4182 | .single_const_pointer, | ||
| 4183 | .single_mut_pointer, | ||
| 4184 | => ty.castPointer().?.data.shallowElemType(), | ||
| 4185 | |||
| 4186 | .array_u8, | ||
| 4187 | .array_u8_sentinel_0, | ||
| 4188 | .const_slice_u8, | ||
| 4189 | .const_slice_u8_sentinel_0, | ||
| 4190 | .manyptr_u8, | ||
| 4191 | .manyptr_const_u8, | ||
| 4192 | .manyptr_const_u8_sentinel_0, | ||
| 4193 | => Type.u8, | ||
| 4194 | |||
| 4195 | .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), | ||
| 4196 | .pointer => { | ||
| 4197 | const info = ty.castTag(.pointer).?.data; | ||
| 4198 | const child_ty = info.pointee_type; | ||
| 4199 | if (info.size == .One) { | ||
| 4200 | return child_ty.shallowElemType(); | ||
| 4201 | } else { | ||
| 4202 | return child_ty; | ||
| 4203 | } | ||
| 4204 | }, | ||
| 4205 | .optional => ty.castTag(.optional).?.data.childType(), | ||
| 4206 | .optional_single_mut_pointer => ty.castPointer().?.data, | ||
| 4207 | .optional_single_const_pointer => ty.castPointer().?.data, | ||
| 4208 | |||
| 4209 | .anyframe_T => ty.castTag(.anyframe_T).?.data, | ||
| 4210 | .@"anyframe" => Type.void, | ||
| 4211 | |||
| 4212 | else => unreachable, | 1952 | else => unreachable, |
| 4213 | }; | 1953 | }; |
| 4214 | } | 1954 | } |
| 4215 | 1955 | ||
| 4216 | fn shallowElemType(child_ty: Type) Type { | 1956 | fn shallowElemType(child_ty: Type, mod: *const Module) Type { |
| 4217 | return switch (child_ty.zigTypeTag()) { | 1957 | return switch (child_ty.zigTypeTag(mod)) { |
| 4218 | .Array, .Vector => child_ty.childType(), | 1958 | .Array, .Vector => child_ty.childType(mod), |
| 4219 | else => child_ty, | 1959 | else => child_ty, |
| 4220 | }; | 1960 | }; |
| 4221 | } | 1961 | } |
| 4222 | 1962 | ||
| 4223 | /// For vectors, returns the element type. Otherwise returns self. | 1963 | /// For vectors, returns the element type. Otherwise returns self. |
| 4224 | pub fn scalarType(ty: Type) Type { | 1964 | pub fn scalarType(ty: Type, mod: *Module) Type { |
| 4225 | return switch (ty.zigTypeTag()) { | 1965 | return switch (ty.zigTypeTag(mod)) { |
| 4226 | .Vector => ty.childType(), | 1966 | .Vector => ty.childType(mod), |
| 4227 | else => ty, | 1967 | else => ty, |
| 4228 | }; | 1968 | }; |
| 4229 | } | 1969 | } |
| 4230 | 1970 | ||
| 4231 | /// Asserts that the type is an optional. | 1971 | /// Asserts that the type is an optional. |
| 4232 | /// Resulting `Type` will have inner memory referencing `buf`. | ||
| 4233 | /// Note that for C pointers this returns the type unmodified. | 1972 | /// Note that for C pointers this returns the type unmodified. |
| 4234 | pub fn optionalChild(ty: Type, buf: *Payload.ElemType) Type { | 1973 | pub fn optionalChild(ty: Type, mod: *const Module) Type { |
| 4235 | return switch (ty.tag()) { | 1974 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4236 | .optional => ty.castTag(.optional).?.data, | 1975 | .opt_type => |child| child.toType(), |
| 4237 | .optional_single_mut_pointer => { | 1976 | .ptr_type => |ptr_type| b: { |
| 4238 | buf.* = .{ | 1977 | assert(ptr_type.flags.size == .C); |
| 4239 | .base = .{ .tag = .single_mut_pointer }, | 1978 | break :b ty; |
| 4240 | .data = ty.castPointer().?.data, | ||
| 4241 | }; | ||
| 4242 | return Type.initPayload(&buf.base); | ||
| 4243 | }, | ||
| 4244 | .optional_single_const_pointer => { | ||
| 4245 | buf.* = .{ | ||
| 4246 | .base = .{ .tag = .single_const_pointer }, | ||
| 4247 | .data = ty.castPointer().?.data, | ||
| 4248 | }; | ||
| 4249 | return Type.initPayload(&buf.base); | ||
| 4250 | }, | 1979 | }, |
| 4251 | |||
| 4252 | .pointer, // here we assume it is a C pointer | ||
| 4253 | .c_const_pointer, | ||
| 4254 | .c_mut_pointer, | ||
| 4255 | => return ty, | ||
| 4256 | |||
| 4257 | else => unreachable, | 1980 | else => unreachable, |
| 4258 | }; | 1981 | }; |
| 4259 | } | 1982 | } |
| 4260 | 1983 | ||
| 4261 | /// Asserts that the type is an optional. | ||
| 4262 | /// Same as `optionalChild` but allocates the buffer if needed. | ||
| 4263 | pub fn optionalChildAlloc(ty: Type, allocator: Allocator) !Type { | ||
| 4264 | switch (ty.tag()) { | ||
| 4265 | .optional => return ty.castTag(.optional).?.data, | ||
| 4266 | .optional_single_mut_pointer => { | ||
| 4267 | return Tag.single_mut_pointer.create(allocator, ty.castPointer().?.data); | ||
| 4268 | }, | ||
| 4269 | .optional_single_const_pointer => { | ||
| 4270 | return Tag.single_const_pointer.create(allocator, ty.castPointer().?.data); | ||
| 4271 | }, | ||
| 4272 | .pointer, // here we assume it is a C pointer | ||
| 4273 | .c_const_pointer, | ||
| 4274 | .c_mut_pointer, | ||
| 4275 | => return ty, | ||
| 4276 | |||
| 4277 | else => unreachable, | ||
| 4278 | } | ||
| 4279 | } | ||
| 4280 | |||
| 4281 | /// Returns the tag type of a union, if the type is a union and it has a tag type. | 1984 | /// Returns the tag type of a union, if the type is a union and it has a tag type. |
| 4282 | /// Otherwise, returns `null`. | 1985 | /// Otherwise, returns `null`. |
| 4283 | pub fn unionTagType(ty: Type) ?Type { | 1986 | pub fn unionTagType(ty: Type, mod: *Module) ?Type { |
| 4284 | return switch (ty.tag()) { | 1987 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4285 | .union_tagged => { | 1988 | .union_type => |union_type| switch (union_type.runtime_tag) { |
| 4286 | const union_obj = ty.castTag(.union_tagged).?.data; | 1989 | .tagged => { |
| 4287 | assert(union_obj.haveFieldTypes()); | 1990 | const union_obj = mod.unionPtr(union_type.index); |
| 4288 | return union_obj.tag_ty; | 1991 | assert(union_obj.haveFieldTypes()); |
| 1992 | return union_obj.tag_ty; | ||
| 1993 | }, | ||
| 1994 | else => null, | ||
| 4289 | }, | 1995 | }, |
| 4290 | |||
| 4291 | .atomic_order, | ||
| 4292 | .atomic_rmw_op, | ||
| 4293 | .calling_convention, | ||
| 4294 | .address_space, | ||
| 4295 | .float_mode, | ||
| 4296 | .reduce_op, | ||
| 4297 | .modifier, | ||
| 4298 | .prefetch_options, | ||
| 4299 | .export_options, | ||
| 4300 | .extern_options, | ||
| 4301 | .type_info, | ||
| 4302 | => unreachable, // needed to call resolveTypeFields first | ||
| 4303 | |||
| 4304 | else => null, | 1996 | else => null, |
| 4305 | }; | 1997 | }; |
| 4306 | } | 1998 | } |
| 4307 | 1999 | ||
| 4308 | /// Same as `unionTagType` but includes safety tag. | 2000 | /// Same as `unionTagType` but includes safety tag. |
| 4309 | /// Codegen should use this version. | 2001 | /// Codegen should use this version. |
| 4310 | pub fn unionTagTypeSafety(ty: Type) ?Type { | 2002 | pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type { |
| 4311 | return switch (ty.tag()) { | 2003 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4312 | .union_safety_tagged, .union_tagged => { | 2004 | .union_type => |union_type| { |
| 4313 | const union_obj = ty.cast(Payload.Union).?.data; | 2005 | if (!union_type.hasTag()) return null; |
| 2006 | const union_obj = mod.unionPtr(union_type.index); | ||
| 4314 | assert(union_obj.haveFieldTypes()); | 2007 | assert(union_obj.haveFieldTypes()); |
| 4315 | return union_obj.tag_ty; | 2008 | return union_obj.tag_ty; |
| 4316 | }, | 2009 | }, |
| 4317 | |||
| 4318 | .atomic_order, | ||
| 4319 | .atomic_rmw_op, | ||
| 4320 | .calling_convention, | ||
| 4321 | .address_space, | ||
| 4322 | .float_mode, | ||
| 4323 | .reduce_op, | ||
| 4324 | .modifier, | ||
| 4325 | .prefetch_options, | ||
| 4326 | .export_options, | ||
| 4327 | .extern_options, | ||
| 4328 | .type_info, | ||
| 4329 | => unreachable, // needed to call resolveTypeFields first | ||
| 4330 | |||
| 4331 | else => null, | 2010 | else => null, |
| 4332 | }; | 2011 | }; |
| 4333 | } | 2012 | } |
| 4334 | 2013 | ||
| 4335 | /// Asserts the type is a union; returns the tag type, even if the tag will | 2014 | /// Asserts the type is a union; returns the tag type, even if the tag will |
| 4336 | /// not be stored at runtime. | 2015 | /// not be stored at runtime. |
| 4337 | pub fn unionTagTypeHypothetical(ty: Type) Type { | 2016 | pub fn unionTagTypeHypothetical(ty: Type, mod: *Module) Type { |
| 4338 | const union_obj = ty.cast(Payload.Union).?.data; | 2017 | const union_obj = mod.typeToUnion(ty).?; |
| 4339 | assert(union_obj.haveFieldTypes()); | 2018 | assert(union_obj.haveFieldTypes()); |
| 4340 | return union_obj.tag_ty; | 2019 | return union_obj.tag_ty; |
| 4341 | } | 2020 | } |
| 4342 | 2021 | ||
| 4343 | pub fn unionFields(ty: Type) Module.Union.Fields { | 2022 | pub fn unionFields(ty: Type, mod: *Module) Module.Union.Fields { |
| 4344 | const union_obj = ty.cast(Payload.Union).?.data; | 2023 | const union_obj = mod.typeToUnion(ty).?; |
| 4345 | assert(union_obj.haveFieldTypes()); | 2024 | assert(union_obj.haveFieldTypes()); |
| 4346 | return union_obj.fields; | 2025 | return union_obj.fields; |
| 4347 | } | 2026 | } |
| 4348 | 2027 | ||
| 4349 | pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type { | 2028 | pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) Type { |
| 4350 | const union_obj = ty.cast(Payload.Union).?.data; | 2029 | const union_obj = mod.typeToUnion(ty).?; |
| 4351 | const index = ty.unionTagFieldIndex(enum_tag, mod).?; | 2030 | const index = ty.unionTagFieldIndex(enum_tag, mod).?; |
| 4352 | assert(union_obj.haveFieldTypes()); | 2031 | assert(union_obj.haveFieldTypes()); |
| 4353 | return union_obj.fields.values()[index].ty; | 2032 | return union_obj.fields.values()[index].ty; |
| 4354 | } | 2033 | } |
| 4355 | 2034 | ||
| 4356 | pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize { | 2035 | pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize { |
| 4357 | const union_obj = ty.cast(Payload.Union).?.data; | 2036 | const union_obj = mod.typeToUnion(ty).?; |
| 4358 | const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null; | 2037 | const index = union_obj.tag_ty.enumTagFieldIndex(enum_tag, mod) orelse return null; |
| 4359 | const name = union_obj.tag_ty.enumFieldName(index); | 2038 | const name = union_obj.tag_ty.enumFieldName(index, mod); |
| 4360 | return union_obj.fields.getIndex(name); | 2039 | return union_obj.fields.getIndex(name); |
| 4361 | } | 2040 | } |
| 4362 | 2041 | ||
| 4363 | pub fn unionHasAllZeroBitFieldTypes(ty: Type) bool { | 2042 | pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool { |
| 4364 | return ty.cast(Payload.Union).?.data.hasAllZeroBitFieldTypes(); | 2043 | const union_obj = mod.typeToUnion(ty).?; |
| 2044 | return union_obj.hasAllZeroBitFieldTypes(mod); | ||
| 4365 | } | 2045 | } |
| 4366 | 2046 | ||
| 4367 | pub fn unionGetLayout(ty: Type, target: Target) Module.Union.Layout { | 2047 | pub fn unionGetLayout(ty: Type, mod: *Module) Module.Union.Layout { |
| 4368 | switch (ty.tag()) { | 2048 | const union_type = mod.intern_pool.indexToKey(ty.toIntern()).union_type; |
| 4369 | .@"union" => { | 2049 | const union_obj = mod.unionPtr(union_type.index); |
| 4370 | const union_obj = ty.castTag(.@"union").?.data; | 2050 | return union_obj.getLayout(mod, union_type.hasTag()); |
| 4371 | return union_obj.getLayout(target, false); | ||
| 4372 | }, | ||
| 4373 | .union_safety_tagged, .union_tagged => { | ||
| 4374 | const union_obj = ty.cast(Payload.Union).?.data; | ||
| 4375 | return union_obj.getLayout(target, true); | ||
| 4376 | }, | ||
| 4377 | else => unreachable, | ||
| 4378 | } | ||
| 4379 | } | 2051 | } |
| 4380 | 2052 | ||
| 4381 | pub fn containerLayout(ty: Type) std.builtin.Type.ContainerLayout { | 2053 | pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout { |
| 4382 | return switch (ty.tag()) { | 2054 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4383 | .tuple, .empty_struct_literal, .anon_struct => .Auto, | 2055 | .struct_type => |struct_type| { |
| 4384 | .@"struct" => ty.castTag(.@"struct").?.data.layout, | 2056 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .Auto; |
| 4385 | .@"union" => ty.castTag(.@"union").?.data.layout, | 2057 | return struct_obj.layout; |
| 4386 | .union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.layout, | 2058 | }, |
| 4387 | .union_tagged => ty.castTag(.union_tagged).?.data.layout, | 2059 | .anon_struct_type => .Auto, |
| 2060 | .union_type => |union_type| { | ||
| 2061 | const union_obj = mod.unionPtr(union_type.index); | ||
| 2062 | return union_obj.layout; | ||
| 2063 | }, | ||
| 4388 | else => unreachable, | 2064 | else => unreachable, |
| 4389 | }; | 2065 | }; |
| 4390 | } | 2066 | } |
| 4391 | 2067 | ||
| 4392 | /// Asserts that the type is an error union. | 2068 | /// Asserts that the type is an error union. |
| 4393 | pub fn errorUnionPayload(self: Type) Type { | 2069 | pub fn errorUnionPayload(ty: Type, mod: *Module) Type { |
| 4394 | return switch (self.tag()) { | 2070 | return mod.intern_pool.indexToKey(ty.toIntern()).error_union_type.payload_type.toType(); |
| 4395 | .anyerror_void_error_union => Type.initTag(.void), | ||
| 4396 | .error_union => self.castTag(.error_union).?.data.payload, | ||
| 4397 | else => unreachable, | ||
| 4398 | }; | ||
| 4399 | } | 2071 | } |
| 4400 | 2072 | ||
| 4401 | pub fn errorUnionSet(self: Type) Type { | 2073 | /// Asserts that the type is an error union. |
| 4402 | return switch (self.tag()) { | 2074 | pub fn errorUnionSet(ty: Type, mod: *Module) Type { |
| 4403 | .anyerror_void_error_union => Type.initTag(.anyerror), | 2075 | return mod.intern_pool.indexToKey(ty.toIntern()).error_union_type.error_set_type.toType(); |
| 4404 | .error_union => self.castTag(.error_union).?.data.error_set, | ||
| 4405 | else => unreachable, | ||
| 4406 | }; | ||
| 4407 | } | 2076 | } |
| 4408 | 2077 | ||
| 4409 | /// Returns false for unresolved inferred error sets. | 2078 | /// Returns false for unresolved inferred error sets. |
| 4410 | pub fn errorSetIsEmpty(ty: Type) bool { | 2079 | pub fn errorSetIsEmpty(ty: Type, mod: *Module) bool { |
| 4411 | switch (ty.tag()) { | 2080 | return switch (ty.toIntern()) { |
| 4412 | .anyerror => return false, | 2081 | .anyerror_type => false, |
| 4413 | .error_set_inferred => { | 2082 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4414 | const inferred_error_set = ty.castTag(.error_set_inferred).?.data; | 2083 | .error_set_type => |error_set_type| error_set_type.names.len == 0, |
| 4415 | // Can't know for sure. | 2084 | .inferred_error_set_type => |index| { |
| 4416 | if (!inferred_error_set.is_resolved) return false; | 2085 | const inferred_error_set = mod.inferredErrorSetPtr(index); |
| 4417 | if (inferred_error_set.is_anyerror) return false; | 2086 | // Can't know for sure. |
| 4418 | return inferred_error_set.errors.count() == 0; | 2087 | if (!inferred_error_set.is_resolved) return false; |
| 4419 | }, | 2088 | if (inferred_error_set.is_anyerror) return false; |
| 4420 | .error_set_single => return false, | 2089 | return inferred_error_set.errors.count() == 0; |
| 4421 | .error_set => { | 2090 | }, |
| 4422 | const err_set_obj = ty.castTag(.error_set).?.data; | 2091 | else => unreachable, |
| 4423 | return err_set_obj.names.count() == 0; | ||
| 4424 | }, | ||
| 4425 | .error_set_merged => { | ||
| 4426 | const name_map = ty.castTag(.error_set_merged).?.data; | ||
| 4427 | return name_map.count() == 0; | ||
| 4428 | }, | 2092 | }, |
| 4429 | else => unreachable, | 2093 | }; |
| 4430 | } | ||
| 4431 | } | 2094 | } |
| 4432 | 2095 | ||
| 4433 | /// Returns true if it is an error set that includes anyerror, false otherwise. | 2096 | /// Returns true if it is an error set that includes anyerror, false otherwise. |
| 4434 | /// Note that the result may be a false negative if the type did not get error set | 2097 | /// Note that the result may be a false negative if the type did not get error set |
| 4435 | /// resolution prior to this call. | 2098 | /// resolution prior to this call. |
| 4436 | pub fn isAnyError(ty: Type) bool { | 2099 | pub fn isAnyError(ty: Type, mod: *Module) bool { |
| 4437 | return switch (ty.tag()) { | 2100 | return switch (ty.toIntern()) { |
| 4438 | .anyerror => true, | 2101 | .anyerror_type => true, |
| 4439 | .error_set_inferred => ty.castTag(.error_set_inferred).?.data.is_anyerror, | 2102 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4440 | else => false, | 2103 | .inferred_error_set_type => |i| mod.inferredErrorSetPtr(i).is_anyerror, |
| 2104 | else => false, | ||
| 2105 | }, | ||
| 4441 | }; | 2106 | }; |
| 4442 | } | 2107 | } |
| 4443 | 2108 | ||
| 4444 | pub fn isError(ty: Type) bool { | 2109 | pub fn isError(ty: Type, mod: *const Module) bool { |
| 4445 | return switch (ty.zigTypeTag()) { | 2110 | return switch (ty.zigTypeTag(mod)) { |
| 4446 | .ErrorUnion, .ErrorSet => true, | 2111 | .ErrorUnion, .ErrorSet => true, |
| 4447 | else => false, | 2112 | else => false, |
| 4448 | }; | 2113 | }; |
| ... | @@ -4451,230 +2116,221 @@ pub const Type = extern union { | ... | @@ -4451,230 +2116,221 @@ pub const Type = extern union { |
| 4451 | /// Returns whether ty, which must be an error set, includes an error `name`. | 2116 | /// Returns whether ty, which must be an error set, includes an error `name`. |
| 4452 | /// Might return a false negative if `ty` is an inferred error set and not fully | 2117 | /// Might return a false negative if `ty` is an inferred error set and not fully |
| 4453 | /// resolved yet. | 2118 | /// resolved yet. |
| 4454 | pub fn errorSetHasField(ty: Type, name: []const u8) bool { | 2119 | pub fn errorSetHasFieldIp( |
| 4455 | if (ty.isAnyError()) { | 2120 | ip: *const InternPool, |
| 4456 | return true; | 2121 | ty: InternPool.Index, |
| 4457 | } | 2122 | name: InternPool.NullTerminatedString, |
| 4458 | 2123 | ) bool { | |
| 4459 | switch (ty.tag()) { | 2124 | return switch (ty) { |
| 4460 | .error_set_single => { | 2125 | .anyerror_type => true, |
| 4461 | const data = ty.castTag(.error_set_single).?.data; | 2126 | else => switch (ip.indexToKey(ty)) { |
| 4462 | return std.mem.eql(u8, data, name); | 2127 | .error_set_type => |error_set_type| { |
| 4463 | }, | 2128 | return error_set_type.nameIndex(ip, name) != null; |
| 4464 | .error_set_inferred => { | 2129 | }, |
| 4465 | const data = ty.castTag(.error_set_inferred).?.data; | 2130 | .inferred_error_set_type => |index| { |
| 4466 | return data.errors.contains(name); | 2131 | const ies = ip.inferredErrorSetPtrConst(index); |
| 4467 | }, | 2132 | if (ies.is_anyerror) return true; |
| 4468 | .error_set_merged => { | 2133 | return ies.errors.contains(name); |
| 4469 | const data = ty.castTag(.error_set_merged).?.data; | 2134 | }, |
| 4470 | return data.contains(name); | 2135 | else => unreachable, |
| 4471 | }, | 2136 | }, |
| 4472 | .error_set => { | 2137 | }; |
| 4473 | const data = ty.castTag(.error_set).?.data; | 2138 | } |
| 4474 | return data.names.contains(name); | 2139 | |
| 2140 | /// Returns whether ty, which must be an error set, includes an error `name`. | ||
| 2141 | /// Might return a false negative if `ty` is an inferred error set and not fully | ||
| 2142 | /// resolved yet. | ||
| 2143 | pub fn errorSetHasField(ty: Type, name: []const u8, mod: *Module) bool { | ||
| 2144 | const ip = &mod.intern_pool; | ||
| 2145 | return switch (ty.toIntern()) { | ||
| 2146 | .anyerror_type => true, | ||
| 2147 | else => switch (ip.indexToKey(ty.toIntern())) { | ||
| 2148 | .error_set_type => |error_set_type| { | ||
| 2149 | // If the string is not interned, then the field certainly is not present. | ||
| 2150 | const field_name_interned = ip.getString(name).unwrap() orelse return false; | ||
| 2151 | return error_set_type.nameIndex(ip, field_name_interned) != null; | ||
| 2152 | }, | ||
| 2153 | .inferred_error_set_type => |index| { | ||
| 2154 | const ies = ip.inferredErrorSetPtr(index); | ||
| 2155 | if (ies.is_anyerror) return true; | ||
| 2156 | // If the string is not interned, then the field certainly is not present. | ||
| 2157 | const field_name_interned = ip.getString(name).unwrap() orelse return false; | ||
| 2158 | return ies.errors.contains(field_name_interned); | ||
| 2159 | }, | ||
| 2160 | else => unreachable, | ||
| 4475 | }, | 2161 | }, |
| 4476 | else => unreachable, | 2162 | }; |
| 4477 | } | ||
| 4478 | } | 2163 | } |
| 4479 | 2164 | ||
| 4480 | /// Asserts the type is an array or vector or struct. | 2165 | /// Asserts the type is an array or vector or struct. |
| 4481 | pub fn arrayLen(ty: Type) u64 { | 2166 | pub fn arrayLen(ty: Type, mod: *const Module) u64 { |
| 4482 | return switch (ty.tag()) { | 2167 | return arrayLenIp(ty, &mod.intern_pool); |
| 4483 | .vector => ty.castTag(.vector).?.data.len, | 2168 | } |
| 4484 | .array => ty.castTag(.array).?.data.len, | 2169 | |
| 4485 | .array_sentinel => ty.castTag(.array_sentinel).?.data.len, | 2170 | pub fn arrayLenIp(ty: Type, ip: *const InternPool) u64 { |
| 4486 | .array_u8 => ty.castTag(.array_u8).?.data, | 2171 | return switch (ip.indexToKey(ty.toIntern())) { |
| 4487 | .array_u8_sentinel_0 => ty.castTag(.array_u8_sentinel_0).?.data, | 2172 | .vector_type => |vector_type| vector_type.len, |
| 4488 | .tuple => ty.castTag(.tuple).?.data.types.len, | 2173 | .array_type => |array_type| array_type.len, |
| 4489 | .anon_struct => ty.castTag(.anon_struct).?.data.types.len, | 2174 | .struct_type => |struct_type| { |
| 4490 | .@"struct" => ty.castTag(.@"struct").?.data.fields.count(), | 2175 | const struct_obj = ip.structPtrUnwrapConst(struct_type.index) orelse return 0; |
| 4491 | .empty_struct, .empty_struct_literal => 0, | 2176 | return struct_obj.fields.count(); |
| 2177 | }, | ||
| 2178 | .anon_struct_type => |tuple| tuple.types.len, | ||
| 4492 | 2179 | ||
| 4493 | else => unreachable, | 2180 | else => unreachable, |
| 4494 | }; | 2181 | }; |
| 4495 | } | 2182 | } |
| 4496 | 2183 | ||
| 4497 | pub fn arrayLenIncludingSentinel(ty: Type) u64 { | 2184 | pub fn arrayLenIncludingSentinel(ty: Type, mod: *const Module) u64 { |
| 4498 | return ty.arrayLen() + @boolToInt(ty.sentinel() != null); | 2185 | return ty.arrayLen(mod) + @boolToInt(ty.sentinel(mod) != null); |
| 4499 | } | 2186 | } |
| 4500 | 2187 | ||
| 4501 | pub fn vectorLen(ty: Type) u32 { | 2188 | pub fn vectorLen(ty: Type, mod: *const Module) u32 { |
| 4502 | return switch (ty.tag()) { | 2189 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4503 | .vector => @intCast(u32, ty.castTag(.vector).?.data.len), | 2190 | .vector_type => |vector_type| vector_type.len, |
| 4504 | .tuple => @intCast(u32, ty.castTag(.tuple).?.data.types.len), | 2191 | .anon_struct_type => |tuple| @intCast(u32, tuple.types.len), |
| 4505 | .anon_struct => @intCast(u32, ty.castTag(.anon_struct).?.data.types.len), | ||
| 4506 | else => unreachable, | 2192 | else => unreachable, |
| 4507 | }; | 2193 | }; |
| 4508 | } | 2194 | } |
| 4509 | 2195 | ||
| 4510 | /// Asserts the type is an array, pointer or vector. | 2196 | /// Asserts the type is an array, pointer or vector. |
| 4511 | pub fn sentinel(self: Type) ?Value { | 2197 | pub fn sentinel(ty: Type, mod: *const Module) ?Value { |
| 4512 | return switch (self.tag()) { | 2198 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4513 | .single_const_pointer, | 2199 | .vector_type, |
| 4514 | .single_mut_pointer, | 2200 | .struct_type, |
| 4515 | .many_const_pointer, | 2201 | .anon_struct_type, |
| 4516 | .many_mut_pointer, | 2202 | => null, |
| 4517 | .c_const_pointer, | 2203 | |
| 4518 | .c_mut_pointer, | 2204 | .array_type => |t| if (t.sentinel != .none) t.sentinel.toValue() else null, |
| 4519 | .single_const_pointer_to_comptime_int, | 2205 | .ptr_type => |t| if (t.sentinel != .none) t.sentinel.toValue() else null, |
| 4520 | .vector, | ||
| 4521 | .array, | ||
| 4522 | .array_u8, | ||
| 4523 | .manyptr_u8, | ||
| 4524 | .manyptr_const_u8, | ||
| 4525 | .const_slice_u8, | ||
| 4526 | .const_slice, | ||
| 4527 | .mut_slice, | ||
| 4528 | .tuple, | ||
| 4529 | .empty_struct_literal, | ||
| 4530 | .@"struct", | ||
| 4531 | => return null, | ||
| 4532 | |||
| 4533 | .pointer => return self.castTag(.pointer).?.data.sentinel, | ||
| 4534 | .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel, | ||
| 4535 | |||
| 4536 | .array_u8_sentinel_0, | ||
| 4537 | .const_slice_u8_sentinel_0, | ||
| 4538 | .manyptr_const_u8_sentinel_0, | ||
| 4539 | => return Value.zero, | ||
| 4540 | 2206 | ||
| 4541 | else => unreachable, | 2207 | else => unreachable, |
| 4542 | }; | 2208 | }; |
| 4543 | } | 2209 | } |
| 4544 | 2210 | ||
| 4545 | /// Returns true if and only if the type is a fixed-width integer. | 2211 | /// Returns true if and only if the type is a fixed-width integer. |
| 4546 | pub fn isInt(self: Type) bool { | 2212 | pub fn isInt(self: Type, mod: *const Module) bool { |
| 4547 | return self.isSignedInt() or self.isUnsignedInt(); | 2213 | return self.isSignedInt(mod) or self.isUnsignedInt(mod); |
| 4548 | } | 2214 | } |
| 4549 | 2215 | ||
| 4550 | /// Returns true if and only if the type is a fixed-width, signed integer. | 2216 | /// Returns true if and only if the type is a fixed-width, signed integer. |
| 4551 | pub fn isSignedInt(self: Type) bool { | 2217 | pub fn isSignedInt(ty: Type, mod: *const Module) bool { |
| 4552 | return switch (self.tag()) { | 2218 | return switch (ty.toIntern()) { |
| 4553 | .int_signed, | 2219 | .c_char_type, .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true, |
| 4554 | .i8, | 2220 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4555 | .isize, | 2221 | .int_type => |int_type| int_type.signedness == .signed, |
| 4556 | .c_char, | 2222 | else => false, |
| 4557 | .c_short, | 2223 | }, |
| 4558 | .c_int, | ||
| 4559 | .c_long, | ||
| 4560 | .c_longlong, | ||
| 4561 | .i16, | ||
| 4562 | .i32, | ||
| 4563 | .i64, | ||
| 4564 | .i128, | ||
| 4565 | => true, | ||
| 4566 | |||
| 4567 | else => false, | ||
| 4568 | }; | 2224 | }; |
| 4569 | } | 2225 | } |
| 4570 | 2226 | ||
| 4571 | /// Returns true if and only if the type is a fixed-width, unsigned integer. | 2227 | /// Returns true if and only if the type is a fixed-width, unsigned integer. |
| 4572 | pub fn isUnsignedInt(self: Type) bool { | 2228 | pub fn isUnsignedInt(ty: Type, mod: *const Module) bool { |
| 4573 | return switch (self.tag()) { | 2229 | return switch (ty.toIntern()) { |
| 4574 | .int_unsigned, | 2230 | .usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true, |
| 4575 | .usize, | 2231 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 4576 | .c_ushort, | 2232 | .int_type => |int_type| int_type.signedness == .unsigned, |
| 4577 | .c_uint, | 2233 | else => false, |
| 4578 | .c_ulong, | 2234 | }, |
| 4579 | .c_ulonglong, | ||
| 4580 | .u1, | ||
| 4581 | .u8, | ||
| 4582 | .u16, | ||
| 4583 | .u29, | ||
| 4584 | .u32, | ||
| 4585 | .u64, | ||
| 4586 | .u128, | ||
| 4587 | => true, | ||
| 4588 | |||
| 4589 | else => false, | ||
| 4590 | }; | 2235 | }; |
| 4591 | } | 2236 | } |
| 4592 | 2237 | ||
| 4593 | /// Returns true for integers, enums, error sets, and packed structs. | 2238 | /// Returns true for integers, enums, error sets, and packed structs. |
| 4594 | /// If this function returns true, then intInfo() can be called on the type. | 2239 | /// If this function returns true, then intInfo() can be called on the type. |
| 4595 | pub fn isAbiInt(ty: Type) bool { | 2240 | pub fn isAbiInt(ty: Type, mod: *Module) bool { |
| 4596 | return switch (ty.zigTypeTag()) { | 2241 | return switch (ty.zigTypeTag(mod)) { |
| 4597 | .Int, .Enum, .ErrorSet => true, | 2242 | .Int, .Enum, .ErrorSet => true, |
| 4598 | .Struct => ty.containerLayout() == .Packed, | 2243 | .Struct => ty.containerLayout(mod) == .Packed, |
| 4599 | else => false, | 2244 | else => false, |
| 4600 | }; | 2245 | }; |
| 4601 | } | 2246 | } |
| 4602 | 2247 | ||
| 4603 | /// Asserts the type is an integer, enum, error set, or vector of one of them. | 2248 | /// Asserts the type is an integer, enum, error set, or vector of one of them. |
| 4604 | pub fn intInfo(self: Type, target: Target) std.builtin.Type.Int { | 2249 | pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType { |
| 4605 | var ty = self; | 2250 | const target = mod.getTarget(); |
| 4606 | while (true) switch (ty.tag()) { | 2251 | var ty = starting_ty; |
| 4607 | .int_unsigned => return .{ | ||
| 4608 | .signedness = .unsigned, | ||
| 4609 | .bits = ty.castTag(.int_unsigned).?.data, | ||
| 4610 | }, | ||
| 4611 | .int_signed => return .{ | ||
| 4612 | .signedness = .signed, | ||
| 4613 | .bits = ty.castTag(.int_signed).?.data, | ||
| 4614 | }, | ||
| 4615 | .u1 => return .{ .signedness = .unsigned, .bits = 1 }, | ||
| 4616 | .u8 => return .{ .signedness = .unsigned, .bits = 8 }, | ||
| 4617 | .i8 => return .{ .signedness = .signed, .bits = 8 }, | ||
| 4618 | .u16 => return .{ .signedness = .unsigned, .bits = 16 }, | ||
| 4619 | .i16 => return .{ .signedness = .signed, .bits = 16 }, | ||
| 4620 | .u29 => return .{ .signedness = .unsigned, .bits = 29 }, | ||
| 4621 | .u32 => return .{ .signedness = .unsigned, .bits = 32 }, | ||
| 4622 | .i32 => return .{ .signedness = .signed, .bits = 32 }, | ||
| 4623 | .u64 => return .{ .signedness = .unsigned, .bits = 64 }, | ||
| 4624 | .i64 => return .{ .signedness = .signed, .bits = 64 }, | ||
| 4625 | .u128 => return .{ .signedness = .unsigned, .bits = 128 }, | ||
| 4626 | .i128 => return .{ .signedness = .signed, .bits = 128 }, | ||
| 4627 | .usize => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() }, | ||
| 4628 | .isize => return .{ .signedness = .signed, .bits = target.ptrBitWidth() }, | ||
| 4629 | .c_char => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.char) }, | ||
| 4630 | .c_short => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.short) }, | ||
| 4631 | .c_ushort => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ushort) }, | ||
| 4632 | .c_int => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.int) }, | ||
| 4633 | .c_uint => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.uint) }, | ||
| 4634 | .c_long => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.long) }, | ||
| 4635 | .c_ulong => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) }, | ||
| 4636 | .c_longlong => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) }, | ||
| 4637 | .c_ulonglong => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) }, | ||
| 4638 | |||
| 4639 | .enum_full, .enum_nonexhaustive => ty = ty.cast(Payload.EnumFull).?.data.tag_ty, | ||
| 4640 | .enum_numbered => ty = ty.castTag(.enum_numbered).?.data.tag_ty, | ||
| 4641 | .enum_simple => { | ||
| 4642 | const enum_obj = ty.castTag(.enum_simple).?.data; | ||
| 4643 | const field_count = enum_obj.fields.count(); | ||
| 4644 | if (field_count == 0) return .{ .signedness = .unsigned, .bits = 0 }; | ||
| 4645 | return .{ .signedness = .unsigned, .bits = smallestUnsignedBits(field_count - 1) }; | ||
| 4646 | }, | ||
| 4647 | 2252 | ||
| 4648 | .error_set, .error_set_single, .anyerror, .error_set_inferred, .error_set_merged => { | 2253 | while (true) switch (ty.toIntern()) { |
| 2254 | .anyerror_type => { | ||
| 4649 | // TODO revisit this when error sets support custom int types | 2255 | // TODO revisit this when error sets support custom int types |
| 4650 | return .{ .signedness = .unsigned, .bits = 16 }; | 2256 | return .{ .signedness = .unsigned, .bits = 16 }; |
| 4651 | }, | 2257 | }, |
| 2258 | .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() }, | ||
| 2259 | .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() }, | ||
| 2260 | .c_char_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.char) }, | ||
| 2261 | .c_short_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.short) }, | ||
| 2262 | .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ushort) }, | ||
| 2263 | .c_int_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.int) }, | ||
| 2264 | .c_uint_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.uint) }, | ||
| 2265 | .c_long_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.long) }, | ||
| 2266 | .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) }, | ||
| 2267 | .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) }, | ||
| 2268 | .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) }, | ||
| 2269 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { | ||
| 2270 | .int_type => |int_type| return int_type, | ||
| 2271 | .struct_type => |struct_type| { | ||
| 2272 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 2273 | assert(struct_obj.layout == .Packed); | ||
| 2274 | ty = struct_obj.backing_int_ty; | ||
| 2275 | }, | ||
| 2276 | .enum_type => |enum_type| ty = enum_type.tag_ty.toType(), | ||
| 2277 | .vector_type => |vector_type| ty = vector_type.child.toType(), | ||
| 4652 | 2278 | ||
| 4653 | .vector => ty = ty.castTag(.vector).?.data.elem_type, | 2279 | // TODO revisit this when error sets support custom int types |
| 4654 | 2280 | .error_set_type, .inferred_error_set_type => return .{ .signedness = .unsigned, .bits = 16 }, | |
| 4655 | .@"struct" => { | 2281 | |
| 4656 | const struct_obj = ty.castTag(.@"struct").?.data; | 2282 | .anon_struct_type => unreachable, |
| 4657 | assert(struct_obj.layout == .Packed); | 2283 | |
| 4658 | ty = struct_obj.backing_int_ty; | 2284 | .ptr_type => unreachable, |
| 4659 | }, | 2285 | .anyframe_type => unreachable, |
| 4660 | 2286 | .array_type => unreachable, | |
| 4661 | else => unreachable, | 2287 | |
| 4662 | }; | 2288 | .opt_type => unreachable, |
| 4663 | } | 2289 | .error_union_type => unreachable, |
| 4664 | 2290 | .func_type => unreachable, | |
| 4665 | pub fn isNamedInt(self: Type) bool { | 2291 | .simple_type => unreachable, // handled via Index enum tag above |
| 4666 | return switch (self.tag()) { | 2292 | |
| 4667 | .usize, | 2293 | .union_type => unreachable, |
| 4668 | .isize, | 2294 | .opaque_type => unreachable, |
| 4669 | .c_char, | 2295 | |
| 4670 | .c_short, | 2296 | // values, not types |
| 4671 | .c_ushort, | 2297 | .undef, |
| 4672 | .c_int, | 2298 | .runtime_value, |
| 4673 | .c_uint, | 2299 | .simple_value, |
| 4674 | .c_long, | 2300 | .variable, |
| 4675 | .c_ulong, | 2301 | .extern_func, |
| 4676 | .c_longlong, | 2302 | .func, |
| 4677 | .c_ulonglong, | 2303 | .int, |
| 2304 | .err, | ||
| 2305 | .error_union, | ||
| 2306 | .enum_literal, | ||
| 2307 | .enum_tag, | ||
| 2308 | .empty_enum_value, | ||
| 2309 | .float, | ||
| 2310 | .ptr, | ||
| 2311 | .opt, | ||
| 2312 | .aggregate, | ||
| 2313 | .un, | ||
| 2314 | // memoization, not types | ||
| 2315 | .memoized_call, | ||
| 2316 | => unreachable, | ||
| 2317 | }, | ||
| 2318 | }; | ||
| 2319 | } | ||
| 2320 | |||
| 2321 | pub fn isNamedInt(ty: Type) bool { | ||
| 2322 | return switch (ty.toIntern()) { | ||
| 2323 | .usize_type, | ||
| 2324 | .isize_type, | ||
| 2325 | .c_char_type, | ||
| 2326 | .c_short_type, | ||
| 2327 | .c_ushort_type, | ||
| 2328 | .c_int_type, | ||
| 2329 | .c_uint_type, | ||
| 2330 | .c_long_type, | ||
| 2331 | .c_ulong_type, | ||
| 2332 | .c_longlong_type, | ||
| 2333 | .c_ulonglong_type, | ||
| 4678 | => true, | 2334 | => true, |
| 4679 | 2335 | ||
| 4680 | else => false, | 2336 | else => false, |
| ... | @@ -4682,14 +2338,14 @@ pub const Type = extern union { | ... | @@ -4682,14 +2338,14 @@ pub const Type = extern union { |
| 4682 | } | 2338 | } |
| 4683 | 2339 | ||
| 4684 | /// Returns `false` for `comptime_float`. | 2340 | /// Returns `false` for `comptime_float`. |
| 4685 | pub fn isRuntimeFloat(self: Type) bool { | 2341 | pub fn isRuntimeFloat(ty: Type) bool { |
| 4686 | return switch (self.tag()) { | 2342 | return switch (ty.toIntern()) { |
| 4687 | .f16, | 2343 | .f16_type, |
| 4688 | .f32, | 2344 | .f32_type, |
| 4689 | .f64, | 2345 | .f64_type, |
| 4690 | .f80, | 2346 | .f80_type, |
| 4691 | .f128, | 2347 | .f128_type, |
| 4692 | .c_longdouble, | 2348 | .c_longdouble_type, |
| 4693 | => true, | 2349 | => true, |
| 4694 | 2350 | ||
| 4695 | else => false, | 2351 | else => false, |
| ... | @@ -4697,15 +2353,15 @@ pub const Type = extern union { | ... | @@ -4697,15 +2353,15 @@ pub const Type = extern union { |
| 4697 | } | 2353 | } |
| 4698 | 2354 | ||
| 4699 | /// Returns `true` for `comptime_float`. | 2355 | /// Returns `true` for `comptime_float`. |
| 4700 | pub fn isAnyFloat(self: Type) bool { | 2356 | pub fn isAnyFloat(ty: Type) bool { |
| 4701 | return switch (self.tag()) { | 2357 | return switch (ty.toIntern()) { |
| 4702 | .f16, | 2358 | .f16_type, |
| 4703 | .f32, | 2359 | .f32_type, |
| 4704 | .f64, | 2360 | .f64_type, |
| 4705 | .f80, | 2361 | .f80_type, |
| 4706 | .f128, | 2362 | .f128_type, |
| 4707 | .c_longdouble, | 2363 | .c_longdouble_type, |
| 4708 | .comptime_float, | 2364 | .comptime_float_type, |
| 4709 | => true, | 2365 | => true, |
| 4710 | 2366 | ||
| 4711 | else => false, | 2367 | else => false, |
| ... | @@ -4714,431 +2370,304 @@ pub const Type = extern union { | ... | @@ -4714,431 +2370,304 @@ pub const Type = extern union { |
| 4714 | 2370 | ||
| 4715 | /// Asserts the type is a fixed-size float or comptime_float. | 2371 | /// Asserts the type is a fixed-size float or comptime_float. |
| 4716 | /// Returns 128 for comptime_float types. | 2372 | /// Returns 128 for comptime_float types. |
| 4717 | pub fn floatBits(self: Type, target: Target) u16 { | 2373 | pub fn floatBits(ty: Type, target: Target) u16 { |
| 4718 | return switch (self.tag()) { | 2374 | return switch (ty.toIntern()) { |
| 4719 | .f16 => 16, | 2375 | .f16_type => 16, |
| 4720 | .f32 => 32, | 2376 | .f32_type => 32, |
| 4721 | .f64 => 64, | 2377 | .f64_type => 64, |
| 4722 | .f80 => 80, | 2378 | .f80_type => 80, |
| 4723 | .f128, .comptime_float => 128, | 2379 | .f128_type, .comptime_float_type => 128, |
| 4724 | .c_longdouble => target.c_type_bit_size(.longdouble), | 2380 | .c_longdouble_type => target.c_type_bit_size(.longdouble), |
| 4725 | |||
| 4726 | else => unreachable, | ||
| 4727 | }; | ||
| 4728 | } | ||
| 4729 | |||
| 4730 | /// Asserts the type is a function. | ||
| 4731 | pub fn fnParamLen(self: Type) usize { | ||
| 4732 | return switch (self.tag()) { | ||
| 4733 | .fn_noreturn_no_args => 0, | ||
| 4734 | .fn_void_no_args => 0, | ||
| 4735 | .fn_naked_noreturn_no_args => 0, | ||
| 4736 | .fn_ccc_void_no_args => 0, | ||
| 4737 | .function => self.castTag(.function).?.data.param_types.len, | ||
| 4738 | 2381 | ||
| 4739 | else => unreachable, | 2382 | else => unreachable, |
| 4740 | }; | 2383 | }; |
| 4741 | } | 2384 | } |
| 4742 | 2385 | ||
| 4743 | /// Asserts the type is a function. The length of the slice must be at least the length | 2386 | /// Asserts the type is a function or a function pointer. |
| 4744 | /// given by `fnParamLen`. | 2387 | pub fn fnReturnType(ty: Type, mod: *Module) Type { |
| 4745 | pub fn fnParamTypes(self: Type, types: []Type) void { | 2388 | return fnReturnTypeIp(ty, &mod.intern_pool); |
| 4746 | switch (self.tag()) { | ||
| 4747 | .fn_noreturn_no_args => return, | ||
| 4748 | .fn_void_no_args => return, | ||
| 4749 | .fn_naked_noreturn_no_args => return, | ||
| 4750 | .fn_ccc_void_no_args => return, | ||
| 4751 | .function => { | ||
| 4752 | const payload = self.castTag(.function).?.data; | ||
| 4753 | @memcpy(types[0..payload.param_types.len], payload.param_types); | ||
| 4754 | }, | ||
| 4755 | |||
| 4756 | else => unreachable, | ||
| 4757 | } | ||
| 4758 | } | ||
| 4759 | |||
| 4760 | /// Asserts the type is a function. | ||
| 4761 | pub fn fnParamType(self: Type, index: usize) Type { | ||
| 4762 | switch (self.tag()) { | ||
| 4763 | .function => { | ||
| 4764 | const payload = self.castTag(.function).?.data; | ||
| 4765 | return payload.param_types[index]; | ||
| 4766 | }, | ||
| 4767 | |||
| 4768 | else => unreachable, | ||
| 4769 | } | ||
| 4770 | } | ||
| 4771 | |||
| 4772 | /// Asserts the type is a function. | ||
| 4773 | pub fn fnReturnType(self: Type) Type { | ||
| 4774 | return switch (self.tag()) { | ||
| 4775 | .fn_noreturn_no_args => Type.initTag(.noreturn), | ||
| 4776 | .fn_naked_noreturn_no_args => Type.initTag(.noreturn), | ||
| 4777 | |||
| 4778 | .fn_void_no_args, | ||
| 4779 | .fn_ccc_void_no_args, | ||
| 4780 | => Type.initTag(.void), | ||
| 4781 | |||
| 4782 | .function => self.castTag(.function).?.data.return_type, | ||
| 4783 | |||
| 4784 | else => unreachable, | ||
| 4785 | }; | ||
| 4786 | } | 2389 | } |
| 4787 | 2390 | ||
| 4788 | /// Asserts the type is a function. | 2391 | pub fn fnReturnTypeIp(ty: Type, ip: *const InternPool) Type { |
| 4789 | pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention { | 2392 | return switch (ip.indexToKey(ty.toIntern())) { |
| 4790 | return switch (self.tag()) { | 2393 | .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type.return_type, |
| 4791 | .fn_noreturn_no_args => .Unspecified, | 2394 | .func_type => |func_type| func_type.return_type, |
| 4792 | .fn_void_no_args => .Unspecified, | ||
| 4793 | .fn_naked_noreturn_no_args => .Naked, | ||
| 4794 | .fn_ccc_void_no_args => .C, | ||
| 4795 | .function => self.castTag(.function).?.data.cc, | ||
| 4796 | |||
| 4797 | else => unreachable, | 2395 | else => unreachable, |
| 4798 | }; | 2396 | }.toType(); |
| 4799 | } | 2397 | } |
| 4800 | 2398 | ||
| 4801 | /// Asserts the type is a function. | 2399 | /// Asserts the type is a function. |
| 4802 | pub fn fnCallingConventionAllowsZigTypes(target: Target, cc: std.builtin.CallingConvention) bool { | 2400 | pub fn fnCallingConvention(ty: Type, mod: *Module) std.builtin.CallingConvention { |
| 4803 | return switch (cc) { | 2401 | return mod.intern_pool.indexToKey(ty.toIntern()).func_type.cc; |
| 4804 | .Unspecified, .Async, .Inline => true, | ||
| 4805 | // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. | ||
| 4806 | // The goal is to experiment with more integrated CPU/GPU code. | ||
| 4807 | .Kernel => target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64, | ||
| 4808 | else => false, | ||
| 4809 | }; | ||
| 4810 | } | 2402 | } |
| 4811 | 2403 | ||
| 4812 | pub fn isValidParamType(self: Type) bool { | 2404 | pub fn isValidParamType(self: Type, mod: *const Module) bool { |
| 4813 | return switch (self.zigTypeTagOrPoison() catch return true) { | 2405 | return switch (self.zigTypeTagOrPoison(mod) catch return true) { |
| 4814 | .Undefined, .Null, .Opaque, .NoReturn => false, | 2406 | .Undefined, .Null, .Opaque, .NoReturn => false, |
| 4815 | else => true, | 2407 | else => true, |
| 4816 | }; | 2408 | }; |
| 4817 | } | 2409 | } |
| 4818 | 2410 | ||
| 4819 | pub fn isValidReturnType(self: Type) bool { | 2411 | pub fn isValidReturnType(self: Type, mod: *const Module) bool { |
| 4820 | return switch (self.zigTypeTagOrPoison() catch return true) { | 2412 | return switch (self.zigTypeTagOrPoison(mod) catch return true) { |
| 4821 | .Undefined, .Null, .Opaque => false, | 2413 | .Undefined, .Null, .Opaque => false, |
| 4822 | else => true, | 2414 | else => true, |
| 4823 | }; | 2415 | }; |
| 4824 | } | 2416 | } |
| 4825 | 2417 | ||
| 4826 | /// Asserts the type is a function. | 2418 | /// Asserts the type is a function. |
| 4827 | pub fn fnIsVarArgs(self: Type) bool { | 2419 | pub fn fnIsVarArgs(ty: Type, mod: *Module) bool { |
| 4828 | return switch (self.tag()) { | 2420 | return mod.intern_pool.indexToKey(ty.toIntern()).func_type.is_var_args; |
| 4829 | .fn_noreturn_no_args => false, | 2421 | } |
| 4830 | .fn_void_no_args => false, | 2422 | |
| 4831 | .fn_naked_noreturn_no_args => false, | 2423 | pub fn isNumeric(ty: Type, mod: *const Module) bool { |
| 4832 | .fn_ccc_void_no_args => false, | 2424 | return switch (ty.toIntern()) { |
| 4833 | .function => self.castTag(.function).?.data.is_var_args, | 2425 | .f16_type, |
| 4834 | 2426 | .f32_type, | |
| 4835 | else => unreachable, | 2427 | .f64_type, |
| 4836 | }; | 2428 | .f80_type, |
| 4837 | } | 2429 | .f128_type, |
| 4838 | 2430 | .c_longdouble_type, | |
| 4839 | pub fn fnInfo(ty: Type) Payload.Function.Data { | 2431 | .comptime_int_type, |
| 4840 | return switch (ty.tag()) { | 2432 | .comptime_float_type, |
| 4841 | .fn_noreturn_no_args => .{ | 2433 | .usize_type, |
| 4842 | .param_types = &.{}, | 2434 | .isize_type, |
| 4843 | .comptime_params = undefined, | 2435 | .c_char_type, |
| 4844 | .return_type = initTag(.noreturn), | 2436 | .c_short_type, |
| 4845 | .cc = .Unspecified, | 2437 | .c_ushort_type, |
| 4846 | .alignment = 0, | 2438 | .c_int_type, |
| 4847 | .is_var_args = false, | 2439 | .c_uint_type, |
| 4848 | .is_generic = false, | 2440 | .c_long_type, |
| 4849 | .is_noinline = false, | 2441 | .c_ulong_type, |
| 4850 | .align_is_generic = false, | 2442 | .c_longlong_type, |
| 4851 | .cc_is_generic = false, | 2443 | .c_ulonglong_type, |
| 4852 | .section_is_generic = false, | ||
| 4853 | .addrspace_is_generic = false, | ||
| 4854 | .noalias_bits = 0, | ||
| 4855 | }, | ||
| 4856 | .fn_void_no_args => .{ | ||
| 4857 | .param_types = &.{}, | ||
| 4858 | .comptime_params = undefined, | ||
| 4859 | .return_type = initTag(.void), | ||
| 4860 | .cc = .Unspecified, | ||
| 4861 | .alignment = 0, | ||
| 4862 | .is_var_args = false, | ||
| 4863 | .is_generic = false, | ||
| 4864 | .is_noinline = false, | ||
| 4865 | .align_is_generic = false, | ||
| 4866 | .cc_is_generic = false, | ||
| 4867 | .section_is_generic = false, | ||
| 4868 | .addrspace_is_generic = false, | ||
| 4869 | .noalias_bits = 0, | ||
| 4870 | }, | ||
| 4871 | .fn_naked_noreturn_no_args => .{ | ||
| 4872 | .param_types = &.{}, | ||
| 4873 | .comptime_params = undefined, | ||
| 4874 | .return_type = initTag(.noreturn), | ||
| 4875 | .cc = .Naked, | ||
| 4876 | .alignment = 0, | ||
| 4877 | .is_var_args = false, | ||
| 4878 | .is_generic = false, | ||
| 4879 | .is_noinline = false, | ||
| 4880 | .align_is_generic = false, | ||
| 4881 | .cc_is_generic = false, | ||
| 4882 | .section_is_generic = false, | ||
| 4883 | .addrspace_is_generic = false, | ||
| 4884 | .noalias_bits = 0, | ||
| 4885 | }, | ||
| 4886 | .fn_ccc_void_no_args => .{ | ||
| 4887 | .param_types = &.{}, | ||
| 4888 | .comptime_params = undefined, | ||
| 4889 | .return_type = initTag(.void), | ||
| 4890 | .cc = .C, | ||
| 4891 | .alignment = 0, | ||
| 4892 | .is_var_args = false, | ||
| 4893 | .is_generic = false, | ||
| 4894 | .is_noinline = false, | ||
| 4895 | .align_is_generic = false, | ||
| 4896 | .cc_is_generic = false, | ||
| 4897 | .section_is_generic = false, | ||
| 4898 | .addrspace_is_generic = false, | ||
| 4899 | .noalias_bits = 0, | ||
| 4900 | }, | ||
| 4901 | .function => ty.castTag(.function).?.data, | ||
| 4902 | |||
| 4903 | else => unreachable, | ||
| 4904 | }; | ||
| 4905 | } | ||
| 4906 | |||
| 4907 | pub fn isNumeric(self: Type) bool { | ||
| 4908 | return switch (self.tag()) { | ||
| 4909 | .f16, | ||
| 4910 | .f32, | ||
| 4911 | .f64, | ||
| 4912 | .f80, | ||
| 4913 | .f128, | ||
| 4914 | .c_longdouble, | ||
| 4915 | .comptime_int, | ||
| 4916 | .comptime_float, | ||
| 4917 | .u1, | ||
| 4918 | .u8, | ||
| 4919 | .i8, | ||
| 4920 | .u16, | ||
| 4921 | .i16, | ||
| 4922 | .u29, | ||
| 4923 | .u32, | ||
| 4924 | .i32, | ||
| 4925 | .u64, | ||
| 4926 | .i64, | ||
| 4927 | .u128, | ||
| 4928 | .i128, | ||
| 4929 | .usize, | ||
| 4930 | .isize, | ||
| 4931 | .c_char, | ||
| 4932 | .c_short, | ||
| 4933 | .c_ushort, | ||
| 4934 | .c_int, | ||
| 4935 | .c_uint, | ||
| 4936 | .c_long, | ||
| 4937 | .c_ulong, | ||
| 4938 | .c_longlong, | ||
| 4939 | .c_ulonglong, | ||
| 4940 | .int_unsigned, | ||
| 4941 | .int_signed, | ||
| 4942 | => true, | 2444 | => true, |
| 4943 | 2445 | ||
| 4944 | else => false, | 2446 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 2447 | .int_type => true, | ||
| 2448 | else => false, | ||
| 2449 | }, | ||
| 4945 | }; | 2450 | }; |
| 4946 | } | 2451 | } |
| 4947 | 2452 | ||
| 4948 | /// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which | 2453 | /// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which |
| 4949 | /// resolves field types rather than asserting they are already resolved. | 2454 | /// resolves field types rather than asserting they are already resolved. |
| 4950 | pub fn onePossibleValue(starting_type: Type) ?Value { | 2455 | pub fn onePossibleValue(starting_type: Type, mod: *Module) !?Value { |
| 4951 | var ty = starting_type; | 2456 | var ty = starting_type; |
| 4952 | while (true) switch (ty.tag()) { | ||
| 4953 | .f16, | ||
| 4954 | .f32, | ||
| 4955 | .f64, | ||
| 4956 | .f80, | ||
| 4957 | .f128, | ||
| 4958 | .c_longdouble, | ||
| 4959 | .comptime_int, | ||
| 4960 | .comptime_float, | ||
| 4961 | .u1, | ||
| 4962 | .u8, | ||
| 4963 | .i8, | ||
| 4964 | .u16, | ||
| 4965 | .i16, | ||
| 4966 | .u29, | ||
| 4967 | .u32, | ||
| 4968 | .i32, | ||
| 4969 | .u64, | ||
| 4970 | .i64, | ||
| 4971 | .u128, | ||
| 4972 | .i128, | ||
| 4973 | .usize, | ||
| 4974 | .isize, | ||
| 4975 | .c_char, | ||
| 4976 | .c_short, | ||
| 4977 | .c_ushort, | ||
| 4978 | .c_int, | ||
| 4979 | .c_uint, | ||
| 4980 | .c_long, | ||
| 4981 | .c_ulong, | ||
| 4982 | .c_longlong, | ||
| 4983 | .c_ulonglong, | ||
| 4984 | .bool, | ||
| 4985 | .type, | ||
| 4986 | .anyerror, | ||
| 4987 | .error_union, | ||
| 4988 | .error_set_single, | ||
| 4989 | .error_set, | ||
| 4990 | .error_set_merged, | ||
| 4991 | .fn_noreturn_no_args, | ||
| 4992 | .fn_void_no_args, | ||
| 4993 | .fn_naked_noreturn_no_args, | ||
| 4994 | .fn_ccc_void_no_args, | ||
| 4995 | .function, | ||
| 4996 | .single_const_pointer_to_comptime_int, | ||
| 4997 | .array_sentinel, | ||
| 4998 | .array_u8_sentinel_0, | ||
| 4999 | .const_slice_u8, | ||
| 5000 | .const_slice_u8_sentinel_0, | ||
| 5001 | .const_slice, | ||
| 5002 | .mut_slice, | ||
| 5003 | .anyopaque, | ||
| 5004 | .optional_single_mut_pointer, | ||
| 5005 | .optional_single_const_pointer, | ||
| 5006 | .enum_literal, | ||
| 5007 | .anyerror_void_error_union, | ||
| 5008 | .error_set_inferred, | ||
| 5009 | .@"opaque", | ||
| 5010 | .manyptr_u8, | ||
| 5011 | .manyptr_const_u8, | ||
| 5012 | .manyptr_const_u8_sentinel_0, | ||
| 5013 | .atomic_order, | ||
| 5014 | .atomic_rmw_op, | ||
| 5015 | .calling_convention, | ||
| 5016 | .address_space, | ||
| 5017 | .float_mode, | ||
| 5018 | .reduce_op, | ||
| 5019 | .modifier, | ||
| 5020 | .prefetch_options, | ||
| 5021 | .export_options, | ||
| 5022 | .extern_options, | ||
| 5023 | .type_info, | ||
| 5024 | .@"anyframe", | ||
| 5025 | .anyframe_T, | ||
| 5026 | .many_const_pointer, | ||
| 5027 | .many_mut_pointer, | ||
| 5028 | .c_const_pointer, | ||
| 5029 | .c_mut_pointer, | ||
| 5030 | .single_const_pointer, | ||
| 5031 | .single_mut_pointer, | ||
| 5032 | .pointer, | ||
| 5033 | => return null, | ||
| 5034 | |||
| 5035 | .optional => { | ||
| 5036 | var buf: Payload.ElemType = undefined; | ||
| 5037 | const child_ty = ty.optionalChild(&buf); | ||
| 5038 | if (child_ty.isNoReturn()) { | ||
| 5039 | return Value.null; | ||
| 5040 | } else { | ||
| 5041 | return null; | ||
| 5042 | } | ||
| 5043 | }, | ||
| 5044 | 2457 | ||
| 5045 | .@"struct" => { | 2458 | while (true) switch (ty.toIntern()) { |
| 5046 | const s = ty.castTag(.@"struct").?.data; | 2459 | .empty_struct_type => return Value.empty_struct, |
| 5047 | assert(s.haveFieldTypes()); | ||
| 5048 | for (s.fields.values()) |field| { | ||
| 5049 | if (field.is_comptime) continue; | ||
| 5050 | if (field.ty.onePossibleValue() != null) continue; | ||
| 5051 | return null; | ||
| 5052 | } | ||
| 5053 | return Value.initTag(.empty_struct_value); | ||
| 5054 | }, | ||
| 5055 | 2460 | ||
| 5056 | .tuple, .anon_struct => { | 2461 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5057 | const tuple = ty.tupleFields(); | 2462 | .int_type => |int_type| { |
| 5058 | for (tuple.values, 0..) |val, i| { | 2463 | if (int_type.bits == 0) { |
| 5059 | const is_comptime = val.tag() != .unreachable_value; | 2464 | return try mod.intValue(ty, 0); |
| 5060 | if (is_comptime) continue; | 2465 | } else { |
| 5061 | if (tuple.types[i].onePossibleValue() != null) continue; | 2466 | return null; |
| 5062 | return null; | 2467 | } |
| 5063 | } | 2468 | }, |
| 5064 | return Value.initTag(.empty_struct_value); | ||
| 5065 | }, | ||
| 5066 | 2469 | ||
| 5067 | .enum_numbered => { | 2470 | .ptr_type, |
| 5068 | const enum_numbered = ty.castTag(.enum_numbered).?.data; | 2471 | .error_union_type, |
| 5069 | // An explicit tag type is always provided for enum_numbered. | 2472 | .func_type, |
| 5070 | if (enum_numbered.tag_ty.hasRuntimeBits()) { | 2473 | .anyframe_type, |
| 5071 | return null; | 2474 | .error_set_type, |
| 5072 | } | 2475 | .inferred_error_set_type, |
| 5073 | assert(enum_numbered.fields.count() == 1); | 2476 | => return null, |
| 5074 | return enum_numbered.values.keys()[0]; | 2477 | |
| 5075 | }, | 2478 | inline .array_type, .vector_type => |seq_type, seq_tag| { |
| 5076 | .enum_full => { | 2479 | const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none; |
| 5077 | const enum_full = ty.castTag(.enum_full).?.data; | 2480 | if (seq_type.len + @boolToInt(has_sentinel) == 0) return (try mod.intern(.{ .aggregate = .{ |
| 5078 | if (enum_full.tag_ty.hasRuntimeBits()) { | 2481 | .ty = ty.toIntern(), |
| 2482 | .storage = .{ .elems = &.{} }, | ||
| 2483 | } })).toValue(); | ||
| 2484 | if (try seq_type.child.toType().onePossibleValue(mod)) |opv| { | ||
| 2485 | return (try mod.intern(.{ .aggregate = .{ | ||
| 2486 | .ty = ty.toIntern(), | ||
| 2487 | .storage = .{ .repeated_elem = opv.toIntern() }, | ||
| 2488 | } })).toValue(); | ||
| 2489 | } | ||
| 5079 | return null; | 2490 | return null; |
| 5080 | } | 2491 | }, |
| 5081 | switch (enum_full.fields.count()) { | 2492 | .opt_type => |child| { |
| 5082 | 0 => return Value.initTag(.unreachable_value), | 2493 | if (child == .noreturn_type) { |
| 5083 | 1 => if (enum_full.values.count() == 0) { | 2494 | return try mod.nullValue(ty); |
| 5084 | return Value.zero; // auto-numbered | ||
| 5085 | } else { | 2495 | } else { |
| 5086 | return enum_full.values.keys()[0]; | 2496 | return null; |
| 2497 | } | ||
| 2498 | }, | ||
| 2499 | |||
| 2500 | .simple_type => |t| switch (t) { | ||
| 2501 | .f16, | ||
| 2502 | .f32, | ||
| 2503 | .f64, | ||
| 2504 | .f80, | ||
| 2505 | .f128, | ||
| 2506 | .usize, | ||
| 2507 | .isize, | ||
| 2508 | .c_char, | ||
| 2509 | .c_short, | ||
| 2510 | .c_ushort, | ||
| 2511 | .c_int, | ||
| 2512 | .c_uint, | ||
| 2513 | .c_long, | ||
| 2514 | .c_ulong, | ||
| 2515 | .c_longlong, | ||
| 2516 | .c_ulonglong, | ||
| 2517 | .c_longdouble, | ||
| 2518 | .anyopaque, | ||
| 2519 | .bool, | ||
| 2520 | .type, | ||
| 2521 | .anyerror, | ||
| 2522 | .comptime_int, | ||
| 2523 | .comptime_float, | ||
| 2524 | .enum_literal, | ||
| 2525 | .atomic_order, | ||
| 2526 | .atomic_rmw_op, | ||
| 2527 | .calling_convention, | ||
| 2528 | .address_space, | ||
| 2529 | .float_mode, | ||
| 2530 | .reduce_op, | ||
| 2531 | .call_modifier, | ||
| 2532 | .prefetch_options, | ||
| 2533 | .export_options, | ||
| 2534 | .extern_options, | ||
| 2535 | .type_info, | ||
| 2536 | => return null, | ||
| 2537 | |||
| 2538 | .void => return Value.void, | ||
| 2539 | .noreturn => return Value.@"unreachable", | ||
| 2540 | .null => return Value.null, | ||
| 2541 | .undefined => return Value.undef, | ||
| 2542 | |||
| 2543 | .generic_poison => unreachable, | ||
| 2544 | }, | ||
| 2545 | .struct_type => |struct_type| { | ||
| 2546 | if (mod.structPtrUnwrap(struct_type.index)) |s| { | ||
| 2547 | assert(s.haveFieldTypes()); | ||
| 2548 | const field_vals = try mod.gpa.alloc(InternPool.Index, s.fields.count()); | ||
| 2549 | defer mod.gpa.free(field_vals); | ||
| 2550 | for (field_vals, s.fields.values()) |*field_val, field| { | ||
| 2551 | if (field.is_comptime) { | ||
| 2552 | field_val.* = field.default_val; | ||
| 2553 | continue; | ||
| 2554 | } | ||
| 2555 | if (try field.ty.onePossibleValue(mod)) |field_opv| { | ||
| 2556 | field_val.* = try field_opv.intern(field.ty, mod); | ||
| 2557 | } else return null; | ||
| 2558 | } | ||
| 2559 | |||
| 2560 | // In this case the struct has no runtime-known fields and | ||
| 2561 | // therefore has one possible value. | ||
| 2562 | return (try mod.intern(.{ .aggregate = .{ | ||
| 2563 | .ty = ty.toIntern(), | ||
| 2564 | .storage = .{ .elems = field_vals }, | ||
| 2565 | } })).toValue(); | ||
| 2566 | } | ||
| 2567 | |||
| 2568 | // In this case the struct has no fields at all and | ||
| 2569 | // therefore has one possible value. | ||
| 2570 | return (try mod.intern(.{ .aggregate = .{ | ||
| 2571 | .ty = ty.toIntern(), | ||
| 2572 | .storage = .{ .elems = &.{} }, | ||
| 2573 | } })).toValue(); | ||
| 2574 | }, | ||
| 2575 | |||
| 2576 | .anon_struct_type => |tuple| { | ||
| 2577 | for (tuple.values) |val| { | ||
| 2578 | if (val == .none) return null; | ||
| 2579 | } | ||
| 2580 | // In this case the struct has all comptime-known fields and | ||
| 2581 | // therefore has one possible value. | ||
| 2582 | // TODO: write something like getCoercedInts to avoid needing to dupe | ||
| 2583 | const duped_values = try mod.gpa.dupe(InternPool.Index, tuple.values); | ||
| 2584 | defer mod.gpa.free(duped_values); | ||
| 2585 | return (try mod.intern(.{ .aggregate = .{ | ||
| 2586 | .ty = ty.toIntern(), | ||
| 2587 | .storage = .{ .elems = duped_values }, | ||
| 2588 | } })).toValue(); | ||
| 2589 | }, | ||
| 2590 | |||
| 2591 | .union_type => |union_type| { | ||
| 2592 | const union_obj = mod.unionPtr(union_type.index); | ||
| 2593 | const tag_val = (try union_obj.tag_ty.onePossibleValue(mod)) orelse return null; | ||
| 2594 | if (union_obj.fields.count() == 0) { | ||
| 2595 | const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); | ||
| 2596 | return only.toValue(); | ||
| 2597 | } | ||
| 2598 | const only_field = union_obj.fields.values()[0]; | ||
| 2599 | const val_val = (try only_field.ty.onePossibleValue(mod)) orelse return null; | ||
| 2600 | const only = try mod.intern(.{ .un = .{ | ||
| 2601 | .ty = ty.toIntern(), | ||
| 2602 | .tag = tag_val.toIntern(), | ||
| 2603 | .val = val_val.toIntern(), | ||
| 2604 | } }); | ||
| 2605 | return only.toValue(); | ||
| 2606 | }, | ||
| 2607 | .opaque_type => return null, | ||
| 2608 | .enum_type => |enum_type| switch (enum_type.tag_mode) { | ||
| 2609 | .nonexhaustive => { | ||
| 2610 | if (enum_type.tag_ty == .comptime_int_type) return null; | ||
| 2611 | |||
| 2612 | if (try enum_type.tag_ty.toType().onePossibleValue(mod)) |int_opv| { | ||
| 2613 | const only = try mod.intern(.{ .enum_tag = .{ | ||
| 2614 | .ty = ty.toIntern(), | ||
| 2615 | .int = int_opv.toIntern(), | ||
| 2616 | } }); | ||
| 2617 | return only.toValue(); | ||
| 2618 | } | ||
| 2619 | |||
| 2620 | return null; | ||
| 5087 | }, | 2621 | }, |
| 5088 | else => return null, | 2622 | .auto, .explicit => { |
| 5089 | } | 2623 | if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null; |
| 5090 | }, | ||
| 5091 | .enum_simple => { | ||
| 5092 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 5093 | switch (enum_simple.fields.count()) { | ||
| 5094 | 0 => return Value.initTag(.unreachable_value), | ||
| 5095 | 1 => return Value.zero, | ||
| 5096 | else => return null, | ||
| 5097 | } | ||
| 5098 | }, | ||
| 5099 | .enum_nonexhaustive => { | ||
| 5100 | const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty; | ||
| 5101 | if (!tag_ty.hasRuntimeBits()) { | ||
| 5102 | return Value.zero; | ||
| 5103 | } else { | ||
| 5104 | return null; | ||
| 5105 | } | ||
| 5106 | }, | ||
| 5107 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 5108 | const union_obj = ty.cast(Payload.Union).?.data; | ||
| 5109 | const tag_val = union_obj.tag_ty.onePossibleValue() orelse return null; | ||
| 5110 | if (union_obj.fields.count() == 0) return Value.initTag(.unreachable_value); | ||
| 5111 | const only_field = union_obj.fields.values()[0]; | ||
| 5112 | const val_val = only_field.ty.onePossibleValue() orelse return null; | ||
| 5113 | _ = tag_val; | ||
| 5114 | _ = val_val; | ||
| 5115 | return Value.initTag(.empty_struct_value); | ||
| 5116 | }, | ||
| 5117 | 2624 | ||
| 5118 | .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), | 2625 | switch (enum_type.names.len) { |
| 5119 | .void => return Value.initTag(.void_value), | 2626 | 0 => { |
| 5120 | .noreturn => return Value.initTag(.unreachable_value), | 2627 | const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() }); |
| 5121 | .null => return Value.initTag(.null_value), | 2628 | return only.toValue(); |
| 5122 | .undefined => return Value.initTag(.undef), | 2629 | }, |
| 2630 | 1 => { | ||
| 2631 | if (enum_type.values.len == 0) { | ||
| 2632 | const only = try mod.intern(.{ .enum_tag = .{ | ||
| 2633 | .ty = ty.toIntern(), | ||
| 2634 | .int = try mod.intern(.{ .int = .{ | ||
| 2635 | .ty = enum_type.tag_ty, | ||
| 2636 | .storage = .{ .u64 = 0 }, | ||
| 2637 | } }), | ||
| 2638 | } }); | ||
| 2639 | return only.toValue(); | ||
| 2640 | } else { | ||
| 2641 | return enum_type.values[0].toValue(); | ||
| 2642 | } | ||
| 2643 | }, | ||
| 2644 | else => return null, | ||
| 2645 | } | ||
| 2646 | }, | ||
| 2647 | }, | ||
| 5123 | 2648 | ||
| 5124 | .int_unsigned, .int_signed => { | 2649 | // values, not types |
| 5125 | if (ty.cast(Payload.Bits).?.data == 0) { | 2650 | .undef, |
| 5126 | return Value.zero; | 2651 | .runtime_value, |
| 5127 | } else { | 2652 | .simple_value, |
| 5128 | return null; | 2653 | .variable, |
| 5129 | } | 2654 | .extern_func, |
| 5130 | }, | 2655 | .func, |
| 5131 | .vector, .array, .array_u8 => { | 2656 | .int, |
| 5132 | if (ty.arrayLen() == 0) | 2657 | .err, |
| 5133 | return Value.initTag(.empty_array); | 2658 | .error_union, |
| 5134 | if (ty.elemType().onePossibleValue() != null) | 2659 | .enum_literal, |
| 5135 | return Value.initTag(.the_only_possible_value); | 2660 | .enum_tag, |
| 5136 | return null; | 2661 | .empty_enum_value, |
| 2662 | .float, | ||
| 2663 | .ptr, | ||
| 2664 | .opt, | ||
| 2665 | .aggregate, | ||
| 2666 | .un, | ||
| 2667 | // memoization, not types | ||
| 2668 | .memoized_call, | ||
| 2669 | => unreachable, | ||
| 5137 | }, | 2670 | }, |
| 5138 | |||
| 5139 | .inferred_alloc_const => unreachable, | ||
| 5140 | .inferred_alloc_mut => unreachable, | ||
| 5141 | .generic_poison => unreachable, | ||
| 5142 | }; | 2671 | }; |
| 5143 | } | 2672 | } |
| 5144 | 2673 | ||
| ... | @@ -5146,350 +2675,298 @@ pub const Type = extern union { | ... | @@ -5146,350 +2675,298 @@ pub const Type = extern union { |
| 5146 | /// resolves field types rather than asserting they are already resolved. | 2675 | /// resolves field types rather than asserting they are already resolved. |
| 5147 | /// TODO merge these implementations together with the "advanced" pattern seen | 2676 | /// TODO merge these implementations together with the "advanced" pattern seen |
| 5148 | /// elsewhere in this file. | 2677 | /// elsewhere in this file. |
| 5149 | pub fn comptimeOnly(ty: Type) bool { | 2678 | pub fn comptimeOnly(ty: Type, mod: *Module) bool { |
| 5150 | return switch (ty.tag()) { | 2679 | return switch (ty.toIntern()) { |
| 5151 | .u1, | 2680 | .empty_struct_type => false, |
| 5152 | .u8, | 2681 | |
| 5153 | .i8, | 2682 | else => switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5154 | .u16, | 2683 | .int_type => false, |
| 5155 | .i16, | 2684 | .ptr_type => |ptr_type| { |
| 5156 | .u29, | 2685 | const child_ty = ptr_type.child.toType(); |
| 5157 | .u32, | 2686 | if (child_ty.zigTypeTag(mod) == .Fn) { |
| 5158 | .i32, | 2687 | return false; |
| 5159 | .u64, | 2688 | } else { |
| 5160 | .i64, | 2689 | return child_ty.comptimeOnly(mod); |
| 5161 | .u128, | 2690 | } |
| 5162 | .i128, | 2691 | }, |
| 5163 | .usize, | 2692 | .anyframe_type => |child| { |
| 5164 | .isize, | 2693 | if (child == .none) return false; |
| 5165 | .c_char, | 2694 | return child.toType().comptimeOnly(mod); |
| 5166 | .c_short, | 2695 | }, |
| 5167 | .c_ushort, | 2696 | .array_type => |array_type| array_type.child.toType().comptimeOnly(mod), |
| 5168 | .c_int, | 2697 | .vector_type => |vector_type| vector_type.child.toType().comptimeOnly(mod), |
| 5169 | .c_uint, | 2698 | .opt_type => |child| child.toType().comptimeOnly(mod), |
| 5170 | .c_long, | 2699 | .error_union_type => |error_union_type| error_union_type.payload_type.toType().comptimeOnly(mod), |
| 5171 | .c_ulong, | 2700 | |
| 5172 | .c_longlong, | 2701 | .error_set_type, |
| 5173 | .c_ulonglong, | 2702 | .inferred_error_set_type, |
| 5174 | .c_longdouble, | 2703 | => false, |
| 5175 | .f16, | 2704 | |
| 5176 | .f32, | 2705 | // These are function bodies, not function pointers. |
| 5177 | .f64, | 2706 | .func_type => true, |
| 5178 | .f80, | 2707 | |
| 5179 | .f128, | 2708 | .simple_type => |t| switch (t) { |
| 5180 | .anyopaque, | 2709 | .f16, |
| 5181 | .bool, | 2710 | .f32, |
| 5182 | .void, | 2711 | .f64, |
| 5183 | .anyerror, | 2712 | .f80, |
| 5184 | .noreturn, | 2713 | .f128, |
| 5185 | .@"anyframe", | 2714 | .usize, |
| 5186 | .null, | 2715 | .isize, |
| 5187 | .undefined, | 2716 | .c_char, |
| 5188 | .atomic_order, | 2717 | .c_short, |
| 5189 | .atomic_rmw_op, | 2718 | .c_ushort, |
| 5190 | .calling_convention, | 2719 | .c_int, |
| 5191 | .address_space, | 2720 | .c_uint, |
| 5192 | .float_mode, | 2721 | .c_long, |
| 5193 | .reduce_op, | 2722 | .c_ulong, |
| 5194 | .modifier, | 2723 | .c_longlong, |
| 5195 | .prefetch_options, | 2724 | .c_ulonglong, |
| 5196 | .export_options, | 2725 | .c_longdouble, |
| 5197 | .extern_options, | 2726 | .anyopaque, |
| 5198 | .manyptr_u8, | 2727 | .bool, |
| 5199 | .manyptr_const_u8, | 2728 | .void, |
| 5200 | .manyptr_const_u8_sentinel_0, | 2729 | .anyerror, |
| 5201 | .const_slice_u8, | 2730 | .noreturn, |
| 5202 | .const_slice_u8_sentinel_0, | 2731 | .generic_poison, |
| 5203 | .anyerror_void_error_union, | 2732 | .atomic_order, |
| 5204 | .empty_struct_literal, | 2733 | .atomic_rmw_op, |
| 5205 | .empty_struct, | 2734 | .calling_convention, |
| 5206 | .error_set, | 2735 | .address_space, |
| 5207 | .error_set_single, | 2736 | .float_mode, |
| 5208 | .error_set_inferred, | 2737 | .reduce_op, |
| 5209 | .error_set_merged, | 2738 | .call_modifier, |
| 5210 | .@"opaque", | 2739 | .prefetch_options, |
| 5211 | .generic_poison, | 2740 | .export_options, |
| 5212 | .array_u8, | 2741 | .extern_options, |
| 5213 | .array_u8_sentinel_0, | 2742 | => false, |
| 5214 | .int_signed, | 2743 | |
| 5215 | .int_unsigned, | 2744 | .type, |
| 5216 | .enum_simple, | 2745 | .comptime_int, |
| 5217 | => false, | 2746 | .comptime_float, |
| 5218 | 2747 | .null, | |
| 5219 | .single_const_pointer_to_comptime_int, | 2748 | .undefined, |
| 5220 | .type, | 2749 | .enum_literal, |
| 5221 | .comptime_int, | 2750 | .type_info, |
| 5222 | .comptime_float, | 2751 | => true, |
| 5223 | .enum_literal, | 2752 | }, |
| 5224 | .type_info, | 2753 | .struct_type => |struct_type| { |
| 5225 | // These are function bodies, not function pointers. | 2754 | // A struct with no fields is not comptime-only. |
| 5226 | .fn_noreturn_no_args, | 2755 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; |
| 5227 | .fn_void_no_args, | 2756 | switch (struct_obj.requires_comptime) { |
| 5228 | .fn_naked_noreturn_no_args, | 2757 | .wip, .unknown => { |
| 5229 | .fn_ccc_void_no_args, | 2758 | // Return false to avoid incorrect dependency loops. |
| 5230 | .function, | 2759 | // This will be handled correctly once merged with |
| 5231 | => true, | 2760 | // `Sema.typeRequiresComptime`. |
| 2761 | return false; | ||
| 2762 | }, | ||
| 2763 | .no => return false, | ||
| 2764 | .yes => return true, | ||
| 2765 | } | ||
| 2766 | }, | ||
| 5232 | 2767 | ||
| 5233 | .inferred_alloc_mut => unreachable, | 2768 | .anon_struct_type => |tuple| { |
| 5234 | .inferred_alloc_const => unreachable, | 2769 | for (tuple.types, tuple.values) |field_ty, val| { |
| 5235 | 2770 | const have_comptime_val = val != .none; | |
| 5236 | .array, | 2771 | if (!have_comptime_val and field_ty.toType().comptimeOnly(mod)) return true; |
| 5237 | .array_sentinel, | 2772 | } |
| 5238 | .vector, | ||
| 5239 | => return ty.childType().comptimeOnly(), | ||
| 5240 | |||
| 5241 | .pointer, | ||
| 5242 | .single_const_pointer, | ||
| 5243 | .single_mut_pointer, | ||
| 5244 | .many_const_pointer, | ||
| 5245 | .many_mut_pointer, | ||
| 5246 | .c_const_pointer, | ||
| 5247 | .c_mut_pointer, | ||
| 5248 | .const_slice, | ||
| 5249 | .mut_slice, | ||
| 5250 | => { | ||
| 5251 | const child_ty = ty.childType(); | ||
| 5252 | if (child_ty.zigTypeTag() == .Fn) { | ||
| 5253 | return false; | 2773 | return false; |
| 5254 | } else { | 2774 | }, |
| 5255 | return child_ty.comptimeOnly(); | ||
| 5256 | } | ||
| 5257 | }, | ||
| 5258 | |||
| 5259 | .optional, | ||
| 5260 | .optional_single_mut_pointer, | ||
| 5261 | .optional_single_const_pointer, | ||
| 5262 | => { | ||
| 5263 | var buf: Type.Payload.ElemType = undefined; | ||
| 5264 | return ty.optionalChild(&buf).comptimeOnly(); | ||
| 5265 | }, | ||
| 5266 | 2775 | ||
| 5267 | .tuple, .anon_struct => { | 2776 | .union_type => |union_type| { |
| 5268 | const tuple = ty.tupleFields(); | 2777 | const union_obj = mod.unionPtr(union_type.index); |
| 5269 | for (tuple.types, 0..) |field_ty, i| { | 2778 | switch (union_obj.requires_comptime) { |
| 5270 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; | 2779 | .wip, .unknown => { |
| 5271 | if (!have_comptime_val and field_ty.comptimeOnly()) return true; | 2780 | // Return false to avoid incorrect dependency loops. |
| 5272 | } | 2781 | // This will be handled correctly once merged with |
| 5273 | return false; | 2782 | // `Sema.typeRequiresComptime`. |
| 5274 | }, | 2783 | return false; |
| 2784 | }, | ||
| 2785 | .no => return false, | ||
| 2786 | .yes => return true, | ||
| 2787 | } | ||
| 2788 | }, | ||
| 5275 | 2789 | ||
| 5276 | .@"struct" => { | 2790 | .opaque_type => false, |
| 5277 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 5278 | switch (struct_obj.requires_comptime) { | ||
| 5279 | .wip, .unknown => { | ||
| 5280 | // Return false to avoid incorrect dependency loops. | ||
| 5281 | // This will be handled correctly once merged with | ||
| 5282 | // `Sema.typeRequiresComptime`. | ||
| 5283 | return false; | ||
| 5284 | }, | ||
| 5285 | .no => return false, | ||
| 5286 | .yes => return true, | ||
| 5287 | } | ||
| 5288 | }, | ||
| 5289 | 2791 | ||
| 5290 | .@"union", .union_safety_tagged, .union_tagged => { | 2792 | .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod), |
| 5291 | const union_obj = ty.cast(Type.Payload.Union).?.data; | ||
| 5292 | switch (union_obj.requires_comptime) { | ||
| 5293 | .wip, .unknown => { | ||
| 5294 | // Return false to avoid incorrect dependency loops. | ||
| 5295 | // This will be handled correctly once merged with | ||
| 5296 | // `Sema.typeRequiresComptime`. | ||
| 5297 | return false; | ||
| 5298 | }, | ||
| 5299 | .no => return false, | ||
| 5300 | .yes => return true, | ||
| 5301 | } | ||
| 5302 | }, | ||
| 5303 | 2793 | ||
| 5304 | .error_union => return ty.errorUnionPayload().comptimeOnly(), | 2794 | // values, not types |
| 5305 | .anyframe_T => { | 2795 | .undef, |
| 5306 | const child_ty = ty.castTag(.anyframe_T).?.data; | 2796 | .runtime_value, |
| 5307 | return child_ty.comptimeOnly(); | 2797 | .simple_value, |
| 5308 | }, | 2798 | .variable, |
| 5309 | .enum_numbered => { | 2799 | .extern_func, |
| 5310 | const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; | 2800 | .func, |
| 5311 | return tag_ty.comptimeOnly(); | 2801 | .int, |
| 5312 | }, | 2802 | .err, |
| 5313 | .enum_full, .enum_nonexhaustive => { | 2803 | .error_union, |
| 5314 | const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; | 2804 | .enum_literal, |
| 5315 | return tag_ty.comptimeOnly(); | 2805 | .enum_tag, |
| 2806 | .empty_enum_value, | ||
| 2807 | .float, | ||
| 2808 | .ptr, | ||
| 2809 | .opt, | ||
| 2810 | .aggregate, | ||
| 2811 | .un, | ||
| 2812 | // memoization, not types | ||
| 2813 | .memoized_call, | ||
| 2814 | => unreachable, | ||
| 5316 | }, | 2815 | }, |
| 5317 | }; | 2816 | }; |
| 5318 | } | 2817 | } |
| 5319 | 2818 | ||
| 5320 | pub fn isArrayOrVector(ty: Type) bool { | 2819 | pub fn isVector(ty: Type, mod: *const Module) bool { |
| 5321 | return switch (ty.zigTypeTag()) { | 2820 | return ty.zigTypeTag(mod) == .Vector; |
| 2821 | } | ||
| 2822 | |||
| 2823 | pub fn isArrayOrVector(ty: Type, mod: *const Module) bool { | ||
| 2824 | return switch (ty.zigTypeTag(mod)) { | ||
| 5322 | .Array, .Vector => true, | 2825 | .Array, .Vector => true, |
| 5323 | else => false, | 2826 | else => false, |
| 5324 | }; | 2827 | }; |
| 5325 | } | 2828 | } |
| 5326 | 2829 | ||
| 5327 | pub fn isIndexable(ty: Type) bool { | 2830 | pub fn isIndexable(ty: Type, mod: *Module) bool { |
| 5328 | return switch (ty.zigTypeTag()) { | 2831 | return switch (ty.zigTypeTag(mod)) { |
| 5329 | .Array, .Vector => true, | 2832 | .Array, .Vector => true, |
| 5330 | .Pointer => switch (ty.ptrSize()) { | 2833 | .Pointer => switch (ty.ptrSize(mod)) { |
| 5331 | .Slice, .Many, .C => true, | 2834 | .Slice, .Many, .C => true, |
| 5332 | .One => ty.elemType().zigTypeTag() == .Array, | 2835 | .One => ty.childType(mod).zigTypeTag(mod) == .Array, |
| 5333 | }, | 2836 | }, |
| 5334 | .Struct => ty.isTuple(), | 2837 | .Struct => ty.isTuple(mod), |
| 5335 | else => false, | 2838 | else => false, |
| 5336 | }; | 2839 | }; |
| 5337 | } | 2840 | } |
| 5338 | 2841 | ||
| 5339 | pub fn indexableHasLen(ty: Type) bool { | 2842 | pub fn indexableHasLen(ty: Type, mod: *Module) bool { |
| 5340 | return switch (ty.zigTypeTag()) { | 2843 | return switch (ty.zigTypeTag(mod)) { |
| 5341 | .Array, .Vector => true, | 2844 | .Array, .Vector => true, |
| 5342 | .Pointer => switch (ty.ptrSize()) { | 2845 | .Pointer => switch (ty.ptrSize(mod)) { |
| 5343 | .Many, .C => false, | 2846 | .Many, .C => false, |
| 5344 | .Slice => true, | 2847 | .Slice => true, |
| 5345 | .One => ty.elemType().zigTypeTag() == .Array, | 2848 | .One => ty.childType(mod).zigTypeTag(mod) == .Array, |
| 5346 | }, | 2849 | }, |
| 5347 | .Struct => ty.isTuple(), | 2850 | .Struct => ty.isTuple(mod), |
| 5348 | else => false, | 2851 | else => false, |
| 5349 | }; | 2852 | }; |
| 5350 | } | 2853 | } |
| 5351 | 2854 | ||
| 5352 | /// Returns null if the type has no namespace. | 2855 | /// Returns null if the type has no namespace. |
| 5353 | pub fn getNamespace(self: Type) ?*Module.Namespace { | 2856 | pub fn getNamespaceIndex(ty: Type, mod: *Module) Module.Namespace.OptionalIndex { |
| 5354 | return switch (self.tag()) { | 2857 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5355 | .@"struct" => &self.castTag(.@"struct").?.data.namespace, | 2858 | .opaque_type => |opaque_type| opaque_type.namespace.toOptional(), |
| 5356 | .enum_full => &self.castTag(.enum_full).?.data.namespace, | 2859 | .struct_type => |struct_type| struct_type.namespace, |
| 5357 | .enum_nonexhaustive => &self.castTag(.enum_nonexhaustive).?.data.namespace, | 2860 | .union_type => |union_type| mod.unionPtr(union_type.index).namespace.toOptional(), |
| 5358 | .empty_struct => self.castTag(.empty_struct).?.data, | 2861 | .enum_type => |enum_type| enum_type.namespace, |
| 5359 | .@"opaque" => &self.castTag(.@"opaque").?.data.namespace, | ||
| 5360 | .@"union" => &self.castTag(.@"union").?.data.namespace, | ||
| 5361 | .union_safety_tagged => &self.castTag(.union_safety_tagged).?.data.namespace, | ||
| 5362 | .union_tagged => &self.castTag(.union_tagged).?.data.namespace, | ||
| 5363 | 2862 | ||
| 5364 | else => null, | 2863 | else => .none, |
| 5365 | }; | 2864 | }; |
| 5366 | } | 2865 | } |
| 5367 | 2866 | ||
| 5368 | // Works for vectors and vectors of integers. | 2867 | /// Returns null if the type has no namespace. |
| 5369 | pub fn minInt(ty: Type, arena: Allocator, target: Target) !Value { | 2868 | pub fn getNamespace(ty: Type, mod: *Module) ?*Module.Namespace { |
| 5370 | const scalar = try minIntScalar(ty.scalarType(), arena, target); | 2869 | return if (getNamespaceIndex(ty, mod).unwrap()) |i| mod.namespacePtr(i) else null; |
| 5371 | if (ty.zigTypeTag() == .Vector and scalar.tag() != .the_only_possible_value) { | ||
| 5372 | return Value.Tag.repeated.create(arena, scalar); | ||
| 5373 | } else { | ||
| 5374 | return scalar; | ||
| 5375 | } | ||
| 5376 | } | 2870 | } |
| 5377 | 2871 | ||
| 5378 | /// Asserts that self.zigTypeTag() == .Int. | 2872 | // Works for vectors and vectors of integers. |
| 5379 | pub fn minIntScalar(ty: Type, arena: Allocator, target: Target) !Value { | 2873 | pub fn minInt(ty: Type, mod: *Module, dest_ty: Type) !Value { |
| 5380 | assert(ty.zigTypeTag() == .Int); | 2874 | const scalar = try minIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod)); |
| 5381 | const info = ty.intInfo(target); | 2875 | return if (ty.zigTypeTag(mod) == .Vector) (try mod.intern(.{ .aggregate = .{ |
| 5382 | 2876 | .ty = dest_ty.toIntern(), | |
| 5383 | if (info.bits == 0) { | 2877 | .storage = .{ .repeated_elem = scalar.toIntern() }, |
| 5384 | return Value.initTag(.the_only_possible_value); | 2878 | } })).toValue() else scalar; |
| 5385 | } | 2879 | } |
| 5386 | 2880 | ||
| 5387 | if (info.signedness == .unsigned) { | 2881 | /// Asserts that the type is an integer. |
| 5388 | return Value.zero; | 2882 | pub fn minIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value { |
| 5389 | } | 2883 | const info = ty.intInfo(mod); |
| 2884 | if (info.signedness == .unsigned) return mod.intValue(dest_ty, 0); | ||
| 2885 | if (info.bits == 0) return mod.intValue(dest_ty, -1); | ||
| 5390 | 2886 | ||
| 5391 | if (std.math.cast(u6, info.bits - 1)) |shift| { | 2887 | if (std.math.cast(u6, info.bits - 1)) |shift| { |
| 5392 | const n = @as(i64, std.math.minInt(i64)) >> (63 - shift); | 2888 | const n = @as(i64, std.math.minInt(i64)) >> (63 - shift); |
| 5393 | return Value.Tag.int_i64.create(arena, n); | 2889 | return mod.intValue(dest_ty, n); |
| 5394 | } | 2890 | } |
| 5395 | 2891 | ||
| 5396 | var res = try std.math.big.int.Managed.init(arena); | 2892 | var res = try std.math.big.int.Managed.init(mod.gpa); |
| 2893 | defer res.deinit(); | ||
| 2894 | |||
| 5397 | try res.setTwosCompIntLimit(.min, info.signedness, info.bits); | 2895 | try res.setTwosCompIntLimit(.min, info.signedness, info.bits); |
| 5398 | 2896 | ||
| 5399 | const res_const = res.toConst(); | 2897 | return mod.intValue_big(dest_ty, res.toConst()); |
| 5400 | if (res_const.positive) { | ||
| 5401 | return Value.Tag.int_big_positive.create(arena, res_const.limbs); | ||
| 5402 | } else { | ||
| 5403 | return Value.Tag.int_big_negative.create(arena, res_const.limbs); | ||
| 5404 | } | ||
| 5405 | } | 2898 | } |
| 5406 | 2899 | ||
| 5407 | // Works for vectors and vectors of integers. | 2900 | // Works for vectors and vectors of integers. |
| 5408 | pub fn maxInt(ty: Type, arena: Allocator, target: Target) !Value { | 2901 | /// The returned Value will have type dest_ty. |
| 5409 | const scalar = try maxIntScalar(ty.scalarType(), arena, target); | 2902 | pub fn maxInt(ty: Type, mod: *Module, dest_ty: Type) !Value { |
| 5410 | if (ty.zigTypeTag() == .Vector and scalar.tag() != .the_only_possible_value) { | 2903 | const scalar = try maxIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod)); |
| 5411 | return Value.Tag.repeated.create(arena, scalar); | 2904 | return if (ty.zigTypeTag(mod) == .Vector) (try mod.intern(.{ .aggregate = .{ |
| 5412 | } else { | 2905 | .ty = dest_ty.toIntern(), |
| 5413 | return scalar; | 2906 | .storage = .{ .repeated_elem = scalar.toIntern() }, |
| 5414 | } | 2907 | } })).toValue() else scalar; |
| 5415 | } | 2908 | } |
| 5416 | 2909 | ||
| 5417 | /// Asserts that self.zigTypeTag() == .Int. | 2910 | /// The returned Value will have type dest_ty. |
| 5418 | pub fn maxIntScalar(self: Type, arena: Allocator, target: Target) !Value { | 2911 | pub fn maxIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value { |
| 5419 | assert(self.zigTypeTag() == .Int); | 2912 | const info = ty.intInfo(mod); |
| 5420 | const info = self.intInfo(target); | ||
| 5421 | |||
| 5422 | if (info.bits == 0) { | ||
| 5423 | return Value.initTag(.the_only_possible_value); | ||
| 5424 | } | ||
| 5425 | 2913 | ||
| 5426 | switch (info.bits - @boolToInt(info.signedness == .signed)) { | 2914 | switch (info.bits) { |
| 5427 | 0 => return Value.zero, | 2915 | 0 => return switch (info.signedness) { |
| 5428 | 1 => return Value.one, | 2916 | .signed => try mod.intValue(dest_ty, -1), |
| 2917 | .unsigned => try mod.intValue(dest_ty, 0), | ||
| 2918 | }, | ||
| 2919 | 1 => return switch (info.signedness) { | ||
| 2920 | .signed => try mod.intValue(dest_ty, 0), | ||
| 2921 | .unsigned => try mod.intValue(dest_ty, 1), | ||
| 2922 | }, | ||
| 5429 | else => {}, | 2923 | else => {}, |
| 5430 | } | 2924 | } |
| 5431 | 2925 | ||
| 5432 | if (std.math.cast(u6, info.bits - 1)) |shift| switch (info.signedness) { | 2926 | if (std.math.cast(u6, info.bits - 1)) |shift| switch (info.signedness) { |
| 5433 | .signed => { | 2927 | .signed => { |
| 5434 | const n = @as(i64, std.math.maxInt(i64)) >> (63 - shift); | 2928 | const n = @as(i64, std.math.maxInt(i64)) >> (63 - shift); |
| 5435 | return Value.Tag.int_i64.create(arena, n); | 2929 | return mod.intValue(dest_ty, n); |
| 5436 | }, | 2930 | }, |
| 5437 | .unsigned => { | 2931 | .unsigned => { |
| 5438 | const n = @as(u64, std.math.maxInt(u64)) >> (63 - shift); | 2932 | const n = @as(u64, std.math.maxInt(u64)) >> (63 - shift); |
| 5439 | return Value.Tag.int_u64.create(arena, n); | 2933 | return mod.intValue(dest_ty, n); |
| 5440 | }, | 2934 | }, |
| 5441 | }; | 2935 | }; |
| 5442 | 2936 | ||
| 5443 | var res = try std.math.big.int.Managed.init(arena); | 2937 | var res = try std.math.big.int.Managed.init(mod.gpa); |
| 2938 | defer res.deinit(); | ||
| 2939 | |||
| 5444 | try res.setTwosCompIntLimit(.max, info.signedness, info.bits); | 2940 | try res.setTwosCompIntLimit(.max, info.signedness, info.bits); |
| 5445 | 2941 | ||
| 5446 | const res_const = res.toConst(); | 2942 | return mod.intValue_big(dest_ty, res.toConst()); |
| 5447 | if (res_const.positive) { | ||
| 5448 | return Value.Tag.int_big_positive.create(arena, res_const.limbs); | ||
| 5449 | } else { | ||
| 5450 | return Value.Tag.int_big_negative.create(arena, res_const.limbs); | ||
| 5451 | } | ||
| 5452 | } | 2943 | } |
| 5453 | 2944 | ||
| 5454 | /// Asserts the type is an enum or a union. | 2945 | /// Asserts the type is an enum or a union. |
| 5455 | pub fn intTagType(ty: Type, buffer: *Payload.Bits) Type { | 2946 | pub fn intTagType(ty: Type, mod: *Module) Type { |
| 5456 | switch (ty.tag()) { | 2947 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5457 | .enum_full, .enum_nonexhaustive => return ty.cast(Payload.EnumFull).?.data.tag_ty, | 2948 | .union_type => |union_type| mod.unionPtr(union_type.index).tag_ty.intTagType(mod), |
| 5458 | .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty, | 2949 | .enum_type => |enum_type| enum_type.tag_ty.toType(), |
| 5459 | .enum_simple => { | ||
| 5460 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 5461 | const field_count = enum_simple.fields.count(); | ||
| 5462 | const bits: u16 = if (field_count == 0) 0 else std.math.log2_int_ceil(usize, field_count); | ||
| 5463 | buffer.* = .{ | ||
| 5464 | .base = .{ .tag = .int_unsigned }, | ||
| 5465 | .data = bits, | ||
| 5466 | }; | ||
| 5467 | return Type.initPayload(&buffer.base); | ||
| 5468 | }, | ||
| 5469 | .union_tagged => return ty.castTag(.union_tagged).?.data.tag_ty.intTagType(buffer), | ||
| 5470 | else => unreachable, | 2950 | else => unreachable, |
| 5471 | } | 2951 | }; |
| 5472 | } | 2952 | } |
| 5473 | 2953 | ||
| 5474 | pub fn isNonexhaustiveEnum(ty: Type) bool { | 2954 | pub fn isNonexhaustiveEnum(ty: Type, mod: *Module) bool { |
| 5475 | return switch (ty.tag()) { | 2955 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5476 | .enum_nonexhaustive => true, | 2956 | .enum_type => |enum_type| switch (enum_type.tag_mode) { |
| 2957 | .nonexhaustive => true, | ||
| 2958 | .auto, .explicit => false, | ||
| 2959 | }, | ||
| 5477 | else => false, | 2960 | else => false, |
| 5478 | }; | 2961 | }; |
| 5479 | } | 2962 | } |
| 5480 | 2963 | ||
| 5481 | // Asserts that `ty` is an error set and not `anyerror`. | 2964 | // Asserts that `ty` is an error set and not `anyerror`. |
| 5482 | pub fn errorSetNames(ty: Type) []const []const u8 { | 2965 | pub fn errorSetNames(ty: Type, mod: *Module) []const InternPool.NullTerminatedString { |
| 5483 | return switch (ty.tag()) { | 2966 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5484 | .error_set_single => blk: { | 2967 | .error_set_type => |x| x.names, |
| 5485 | // Work around coercion problems | 2968 | .inferred_error_set_type => |index| { |
| 5486 | const tmp: *const [1][]const u8 = &ty.castTag(.error_set_single).?.data; | 2969 | const inferred_error_set = mod.inferredErrorSetPtr(index); |
| 5487 | break :blk tmp; | ||
| 5488 | }, | ||
| 5489 | .error_set_merged => ty.castTag(.error_set_merged).?.data.keys(), | ||
| 5490 | .error_set => ty.castTag(.error_set).?.data.names.keys(), | ||
| 5491 | .error_set_inferred => { | ||
| 5492 | const inferred_error_set = ty.castTag(.error_set_inferred).?.data; | ||
| 5493 | assert(inferred_error_set.is_resolved); | 2970 | assert(inferred_error_set.is_resolved); |
| 5494 | assert(!inferred_error_set.is_anyerror); | 2971 | assert(!inferred_error_set.is_anyerror); |
| 5495 | return inferred_error_set.errors.keys(); | 2972 | return inferred_error_set.errors.keys(); |
| ... | @@ -5498,133 +2975,43 @@ pub const Type = extern union { | ... | @@ -5498,133 +2975,43 @@ pub const Type = extern union { |
| 5498 | }; | 2975 | }; |
| 5499 | } | 2976 | } |
| 5500 | 2977 | ||
| 5501 | /// Merge lhs with rhs. | 2978 | pub fn enumFields(ty: Type, mod: *Module) []const InternPool.NullTerminatedString { |
| 5502 | /// Asserts that lhs and rhs are both error sets and are resolved. | 2979 | return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names; |
| 5503 | pub fn errorSetMerge(lhs: Type, arena: Allocator, rhs: Type) !Type { | ||
| 5504 | const lhs_names = lhs.errorSetNames(); | ||
| 5505 | const rhs_names = rhs.errorSetNames(); | ||
| 5506 | var names: Module.ErrorSet.NameMap = .{}; | ||
| 5507 | try names.ensureUnusedCapacity(arena, lhs_names.len); | ||
| 5508 | for (lhs_names) |name| { | ||
| 5509 | names.putAssumeCapacityNoClobber(name, {}); | ||
| 5510 | } | ||
| 5511 | for (rhs_names) |name| { | ||
| 5512 | try names.put(arena, name, {}); | ||
| 5513 | } | ||
| 5514 | |||
| 5515 | // names must be sorted | ||
| 5516 | Module.ErrorSet.sortNames(&names); | ||
| 5517 | |||
| 5518 | return try Tag.error_set_merged.create(arena, names); | ||
| 5519 | } | ||
| 5520 | |||
| 5521 | pub fn enumFields(ty: Type) Module.EnumFull.NameMap { | ||
| 5522 | return switch (ty.tag()) { | ||
| 5523 | .enum_full, .enum_nonexhaustive => ty.cast(Payload.EnumFull).?.data.fields, | ||
| 5524 | .enum_simple => ty.castTag(.enum_simple).?.data.fields, | ||
| 5525 | .enum_numbered => ty.castTag(.enum_numbered).?.data.fields, | ||
| 5526 | .atomic_order, | ||
| 5527 | .atomic_rmw_op, | ||
| 5528 | .calling_convention, | ||
| 5529 | .address_space, | ||
| 5530 | .float_mode, | ||
| 5531 | .reduce_op, | ||
| 5532 | .modifier, | ||
| 5533 | .prefetch_options, | ||
| 5534 | .export_options, | ||
| 5535 | .extern_options, | ||
| 5536 | => @panic("TODO resolve std.builtin types"), | ||
| 5537 | else => unreachable, | ||
| 5538 | }; | ||
| 5539 | } | 2980 | } |
| 5540 | 2981 | ||
| 5541 | pub fn enumFieldCount(ty: Type) usize { | 2982 | pub fn enumFieldCount(ty: Type, mod: *Module) usize { |
| 5542 | return ty.enumFields().count(); | 2983 | return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names.len; |
| 5543 | } | 2984 | } |
| 5544 | 2985 | ||
| 5545 | pub fn enumFieldName(ty: Type, field_index: usize) []const u8 { | 2986 | pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString { |
| 5546 | return ty.enumFields().keys()[field_index]; | 2987 | return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names[field_index]; |
| 5547 | } | 2988 | } |
| 5548 | 2989 | ||
| 5549 | pub fn enumFieldIndex(ty: Type, field_name: []const u8) ?usize { | 2990 | pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, mod: *Module) ?u32 { |
| 5550 | return ty.enumFields().getIndex(field_name); | 2991 | const ip = &mod.intern_pool; |
| 2992 | const enum_type = ip.indexToKey(ty.toIntern()).enum_type; | ||
| 2993 | return enum_type.nameIndex(ip, field_name); | ||
| 5551 | } | 2994 | } |
| 5552 | 2995 | ||
| 5553 | /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or | 2996 | /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or |
| 5554 | /// an integer which represents the enum value. Returns the field index in | 2997 | /// an integer which represents the enum value. Returns the field index in |
| 5555 | /// declaration order, or `null` if `enum_tag` does not match any field. | 2998 | /// declaration order, or `null` if `enum_tag` does not match any field. |
| 5556 | pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?usize { | 2999 | pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 { |
| 5557 | if (enum_tag.castTag(.enum_field_index)) |payload| { | 3000 | const ip = &mod.intern_pool; |
| 5558 | return @as(usize, payload.data); | 3001 | const enum_type = ip.indexToKey(ty.toIntern()).enum_type; |
| 5559 | } | 3002 | const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) { |
| 5560 | const S = struct { | 3003 | .int => enum_tag.toIntern(), |
| 5561 | fn fieldWithRange(int_ty: Type, int_val: Value, end: usize, m: *Module) ?usize { | 3004 | .enum_tag => |info| info.int, |
| 5562 | if (int_val.compareAllWithZero(.lt, m)) return null; | ||
| 5563 | var end_payload: Value.Payload.U64 = .{ | ||
| 5564 | .base = .{ .tag = .int_u64 }, | ||
| 5565 | .data = end, | ||
| 5566 | }; | ||
| 5567 | const end_val = Value.initPayload(&end_payload.base); | ||
| 5568 | if (int_val.compareAll(.gte, end_val, int_ty, m)) return null; | ||
| 5569 | return @intCast(usize, int_val.toUnsignedInt(m.getTarget())); | ||
| 5570 | } | ||
| 5571 | }; | ||
| 5572 | switch (ty.tag()) { | ||
| 5573 | .enum_full, .enum_nonexhaustive => { | ||
| 5574 | const enum_full = ty.cast(Payload.EnumFull).?.data; | ||
| 5575 | const tag_ty = enum_full.tag_ty; | ||
| 5576 | if (enum_full.values.count() == 0) { | ||
| 5577 | return S.fieldWithRange(tag_ty, enum_tag, enum_full.fields.count(), mod); | ||
| 5578 | } else { | ||
| 5579 | return enum_full.values.getIndexContext(enum_tag, .{ | ||
| 5580 | .ty = tag_ty, | ||
| 5581 | .mod = mod, | ||
| 5582 | }); | ||
| 5583 | } | ||
| 5584 | }, | ||
| 5585 | .enum_numbered => { | ||
| 5586 | const enum_obj = ty.castTag(.enum_numbered).?.data; | ||
| 5587 | const tag_ty = enum_obj.tag_ty; | ||
| 5588 | if (enum_obj.values.count() == 0) { | ||
| 5589 | return S.fieldWithRange(tag_ty, enum_tag, enum_obj.fields.count(), mod); | ||
| 5590 | } else { | ||
| 5591 | return enum_obj.values.getIndexContext(enum_tag, .{ | ||
| 5592 | .ty = tag_ty, | ||
| 5593 | .mod = mod, | ||
| 5594 | }); | ||
| 5595 | } | ||
| 5596 | }, | ||
| 5597 | .enum_simple => { | ||
| 5598 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 5599 | const fields_len = enum_simple.fields.count(); | ||
| 5600 | const bits = std.math.log2_int_ceil(usize, fields_len); | ||
| 5601 | var buffer: Payload.Bits = .{ | ||
| 5602 | .base = .{ .tag = .int_unsigned }, | ||
| 5603 | .data = bits, | ||
| 5604 | }; | ||
| 5605 | const tag_ty = Type.initPayload(&buffer.base); | ||
| 5606 | return S.fieldWithRange(tag_ty, enum_tag, fields_len, mod); | ||
| 5607 | }, | ||
| 5608 | .atomic_order, | ||
| 5609 | .atomic_rmw_op, | ||
| 5610 | .calling_convention, | ||
| 5611 | .address_space, | ||
| 5612 | .float_mode, | ||
| 5613 | .reduce_op, | ||
| 5614 | .modifier, | ||
| 5615 | .prefetch_options, | ||
| 5616 | .export_options, | ||
| 5617 | .extern_options, | ||
| 5618 | => @panic("TODO resolve std.builtin types"), | ||
| 5619 | else => unreachable, | 3005 | else => unreachable, |
| 5620 | } | 3006 | }; |
| 3007 | assert(ip.typeOf(int_tag) == enum_type.tag_ty); | ||
| 3008 | return enum_type.tagValueIndex(ip, int_tag); | ||
| 5621 | } | 3009 | } |
| 5622 | 3010 | ||
| 5623 | pub fn structFields(ty: Type) Module.Struct.Fields { | 3011 | pub fn structFields(ty: Type, mod: *Module) Module.Struct.Fields { |
| 5624 | switch (ty.tag()) { | 3012 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5625 | .empty_struct, .empty_struct_literal => return .{}, | 3013 | .struct_type => |struct_type| { |
| 5626 | .@"struct" => { | 3014 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return .{}; |
| 5627 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 5628 | assert(struct_obj.haveFieldTypes()); | 3015 | assert(struct_obj.haveFieldTypes()); |
| 5629 | return struct_obj.fields; | 3016 | return struct_obj.fields; |
| 5630 | }, | 3017 | }, |
| ... | @@ -5632,141 +3019,122 @@ pub const Type = extern union { | ... | @@ -5632,141 +3019,122 @@ pub const Type = extern union { |
| 5632 | } | 3019 | } |
| 5633 | } | 3020 | } |
| 5634 | 3021 | ||
| 5635 | pub fn structFieldName(ty: Type, field_index: usize) []const u8 { | 3022 | pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString { |
| 5636 | switch (ty.tag()) { | 3023 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5637 | .@"struct" => { | 3024 | .struct_type => |struct_type| { |
| 5638 | const struct_obj = ty.castTag(.@"struct").?.data; | 3025 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 5639 | assert(struct_obj.haveFieldTypes()); | 3026 | assert(struct_obj.haveFieldTypes()); |
| 5640 | return struct_obj.fields.keys()[field_index]; | 3027 | return struct_obj.fields.keys()[field_index]; |
| 5641 | }, | 3028 | }, |
| 5642 | .anon_struct => return ty.castTag(.anon_struct).?.data.names[field_index], | 3029 | .anon_struct_type => |anon_struct| anon_struct.names[field_index], |
| 5643 | else => unreachable, | 3030 | else => unreachable, |
| 5644 | } | 3031 | }; |
| 5645 | } | 3032 | } |
| 5646 | 3033 | ||
| 5647 | pub fn structFieldCount(ty: Type) usize { | 3034 | pub fn structFieldCount(ty: Type, mod: *Module) usize { |
| 5648 | switch (ty.tag()) { | 3035 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5649 | .@"struct" => { | 3036 | .struct_type => |struct_type| { |
| 5650 | const struct_obj = ty.castTag(.@"struct").?.data; | 3037 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return 0; |
| 5651 | assert(struct_obj.haveFieldTypes()); | 3038 | assert(struct_obj.haveFieldTypes()); |
| 5652 | return struct_obj.fields.count(); | 3039 | return struct_obj.fields.count(); |
| 5653 | }, | 3040 | }, |
| 5654 | .empty_struct, .empty_struct_literal => return 0, | 3041 | .anon_struct_type => |anon_struct| anon_struct.types.len, |
| 5655 | .tuple => return ty.castTag(.tuple).?.data.types.len, | ||
| 5656 | .anon_struct => return ty.castTag(.anon_struct).?.data.types.len, | ||
| 5657 | else => unreachable, | 3042 | else => unreachable, |
| 5658 | } | 3043 | }; |
| 5659 | } | 3044 | } |
| 5660 | 3045 | ||
| 5661 | /// Supports structs and unions. | 3046 | /// Supports structs and unions. |
| 5662 | pub fn structFieldType(ty: Type, index: usize) Type { | 3047 | pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type { |
| 5663 | switch (ty.tag()) { | 3048 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5664 | .@"struct" => { | 3049 | .struct_type => |struct_type| { |
| 5665 | const struct_obj = ty.castTag(.@"struct").?.data; | 3050 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 5666 | return struct_obj.fields.values()[index].ty; | 3051 | return struct_obj.fields.values()[index].ty; |
| 5667 | }, | 3052 | }, |
| 5668 | .@"union", .union_safety_tagged, .union_tagged => { | 3053 | .union_type => |union_type| { |
| 5669 | const union_obj = ty.cast(Payload.Union).?.data; | 3054 | const union_obj = mod.unionPtr(union_type.index); |
| 5670 | return union_obj.fields.values()[index].ty; | 3055 | return union_obj.fields.values()[index].ty; |
| 5671 | }, | 3056 | }, |
| 5672 | .tuple => return ty.castTag(.tuple).?.data.types[index], | 3057 | .anon_struct_type => |anon_struct| anon_struct.types[index].toType(), |
| 5673 | .anon_struct => return ty.castTag(.anon_struct).?.data.types[index], | ||
| 5674 | else => unreachable, | 3058 | else => unreachable, |
| 5675 | } | 3059 | }; |
| 5676 | } | 3060 | } |
| 5677 | 3061 | ||
| 5678 | pub fn structFieldAlign(ty: Type, index: usize, target: Target) u32 { | 3062 | pub fn structFieldAlign(ty: Type, index: usize, mod: *Module) u32 { |
| 5679 | switch (ty.tag()) { | 3063 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5680 | .@"struct" => { | 3064 | .struct_type => |struct_type| { |
| 5681 | const struct_obj = ty.castTag(.@"struct").?.data; | 3065 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 5682 | assert(struct_obj.layout != .Packed); | 3066 | assert(struct_obj.layout != .Packed); |
| 5683 | return struct_obj.fields.values()[index].alignment(target, struct_obj.layout); | 3067 | return struct_obj.fields.values()[index].alignment(mod, struct_obj.layout); |
| 3068 | }, | ||
| 3069 | .anon_struct_type => |anon_struct| { | ||
| 3070 | return anon_struct.types[index].toType().abiAlignment(mod); | ||
| 5684 | }, | 3071 | }, |
| 5685 | .@"union", .union_safety_tagged, .union_tagged => { | 3072 | .union_type => |union_type| { |
| 5686 | const union_obj = ty.cast(Payload.Union).?.data; | 3073 | const union_obj = mod.unionPtr(union_type.index); |
| 5687 | return union_obj.fields.values()[index].normalAlignment(target); | 3074 | return union_obj.fields.values()[index].normalAlignment(mod); |
| 5688 | }, | 3075 | }, |
| 5689 | .tuple => return ty.castTag(.tuple).?.data.types[index].abiAlignment(target), | ||
| 5690 | .anon_struct => return ty.castTag(.anon_struct).?.data.types[index].abiAlignment(target), | ||
| 5691 | else => unreachable, | 3076 | else => unreachable, |
| 5692 | } | 3077 | } |
| 5693 | } | 3078 | } |
| 5694 | 3079 | ||
| 5695 | pub fn structFieldDefaultValue(ty: Type, index: usize) Value { | 3080 | pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value { |
| 5696 | switch (ty.tag()) { | 3081 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5697 | .@"struct" => { | 3082 | .struct_type => |struct_type| { |
| 5698 | const struct_obj = ty.castTag(.@"struct").?.data; | 3083 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 5699 | return struct_obj.fields.values()[index].default_val; | 3084 | const val = struct_obj.fields.values()[index].default_val; |
| 3085 | // TODO: avoid using `unreachable` to indicate this. | ||
| 3086 | if (val == .none) return Value.@"unreachable"; | ||
| 3087 | return val.toValue(); | ||
| 5700 | }, | 3088 | }, |
| 5701 | .tuple => { | 3089 | .anon_struct_type => |anon_struct| { |
| 5702 | const tuple = ty.castTag(.tuple).?.data; | 3090 | const val = anon_struct.values[index]; |
| 5703 | return tuple.values[index]; | 3091 | // TODO: avoid using `unreachable` to indicate this. |
| 5704 | }, | 3092 | if (val == .none) return Value.@"unreachable"; |
| 5705 | .anon_struct => { | 3093 | return val.toValue(); |
| 5706 | const struct_obj = ty.castTag(.anon_struct).?.data; | ||
| 5707 | return struct_obj.values[index]; | ||
| 5708 | }, | 3094 | }, |
| 5709 | else => unreachable, | 3095 | else => unreachable, |
| 5710 | } | 3096 | } |
| 5711 | } | 3097 | } |
| 5712 | 3098 | ||
| 5713 | pub fn structFieldValueComptime(ty: Type, index: usize) ?Value { | 3099 | pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value { |
| 5714 | switch (ty.tag()) { | 3100 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5715 | .@"struct" => { | 3101 | .struct_type => |struct_type| { |
| 5716 | const struct_obj = ty.castTag(.@"struct").?.data; | 3102 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 5717 | const field = struct_obj.fields.values()[index]; | 3103 | const field = struct_obj.fields.values()[index]; |
| 5718 | if (field.is_comptime) { | 3104 | if (field.is_comptime) { |
| 5719 | return field.default_val; | 3105 | return field.default_val.toValue(); |
| 5720 | } else { | 3106 | } else { |
| 5721 | return field.ty.onePossibleValue(); | 3107 | return field.ty.onePossibleValue(mod); |
| 5722 | } | 3108 | } |
| 5723 | }, | 3109 | }, |
| 5724 | .tuple => { | 3110 | .anon_struct_type => |tuple| { |
| 5725 | const tuple = ty.castTag(.tuple).?.data; | ||
| 5726 | const val = tuple.values[index]; | 3111 | const val = tuple.values[index]; |
| 5727 | if (val.tag() == .unreachable_value) { | 3112 | if (val == .none) { |
| 5728 | return tuple.types[index].onePossibleValue(); | 3113 | return tuple.types[index].toType().onePossibleValue(mod); |
| 5729 | } else { | ||
| 5730 | return val; | ||
| 5731 | } | ||
| 5732 | }, | ||
| 5733 | .anon_struct => { | ||
| 5734 | const anon_struct = ty.castTag(.anon_struct).?.data; | ||
| 5735 | const val = anon_struct.values[index]; | ||
| 5736 | if (val.tag() == .unreachable_value) { | ||
| 5737 | return anon_struct.types[index].onePossibleValue(); | ||
| 5738 | } else { | 3114 | } else { |
| 5739 | return val; | 3115 | return val.toValue(); |
| 5740 | } | 3116 | } |
| 5741 | }, | 3117 | }, |
| 5742 | else => unreachable, | 3118 | else => unreachable, |
| 5743 | } | 3119 | } |
| 5744 | } | 3120 | } |
| 5745 | 3121 | ||
| 5746 | pub fn structFieldIsComptime(ty: Type, index: usize) bool { | 3122 | pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool { |
| 5747 | switch (ty.tag()) { | 3123 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5748 | .@"struct" => { | 3124 | .struct_type => |struct_type| { |
| 5749 | const struct_obj = ty.castTag(.@"struct").?.data; | 3125 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 5750 | if (struct_obj.layout == .Packed) return false; | 3126 | if (struct_obj.layout == .Packed) return false; |
| 5751 | const field = struct_obj.fields.values()[index]; | 3127 | const field = struct_obj.fields.values()[index]; |
| 5752 | return field.is_comptime; | 3128 | return field.is_comptime; |
| 5753 | }, | 3129 | }, |
| 5754 | .tuple => { | 3130 | .anon_struct_type => |anon_struct| anon_struct.values[index] != .none, |
| 5755 | const tuple = ty.castTag(.tuple).?.data; | ||
| 5756 | const val = tuple.values[index]; | ||
| 5757 | return val.tag() != .unreachable_value; | ||
| 5758 | }, | ||
| 5759 | .anon_struct => { | ||
| 5760 | const anon_struct = ty.castTag(.anon_struct).?.data; | ||
| 5761 | const val = anon_struct.values[index]; | ||
| 5762 | return val.tag() != .unreachable_value; | ||
| 5763 | }, | ||
| 5764 | else => unreachable, | 3131 | else => unreachable, |
| 5765 | } | 3132 | }; |
| 5766 | } | 3133 | } |
| 5767 | 3134 | ||
| 5768 | pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, target: Target) u32 { | 3135 | pub fn packedStructFieldByteOffset(ty: Type, field_index: usize, mod: *Module) u32 { |
| 5769 | const struct_obj = ty.castTag(.@"struct").?.data; | 3136 | const struct_type = mod.intern_pool.indexToKey(ty.toIntern()).struct_type; |
| 3137 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 5770 | assert(struct_obj.layout == .Packed); | 3138 | assert(struct_obj.layout == .Packed); |
| 5771 | comptime assert(Type.packed_struct_layout_version == 2); | 3139 | comptime assert(Type.packed_struct_layout_version == 2); |
| 5772 | 3140 | ||
| ... | @@ -5774,9 +3142,9 @@ pub const Type = extern union { | ... | @@ -5774,9 +3142,9 @@ pub const Type = extern union { |
| 5774 | var elem_size_bits: u16 = undefined; | 3142 | var elem_size_bits: u16 = undefined; |
| 5775 | var running_bits: u16 = 0; | 3143 | var running_bits: u16 = 0; |
| 5776 | for (struct_obj.fields.values(), 0..) |f, i| { | 3144 | for (struct_obj.fields.values(), 0..) |f, i| { |
| 5777 | if (!f.ty.hasRuntimeBits()) continue; | 3145 | if (!f.ty.hasRuntimeBits(mod)) continue; |
| 5778 | 3146 | ||
| 5779 | const field_bits = @intCast(u16, f.ty.bitSize(target)); | 3147 | const field_bits = @intCast(u16, f.ty.bitSize(mod)); |
| 5780 | if (i == field_index) { | 3148 | if (i == field_index) { |
| 5781 | bit_offset = running_bits; | 3149 | bit_offset = running_bits; |
| 5782 | elem_size_bits = field_bits; | 3150 | elem_size_bits = field_bits; |
| ... | @@ -5797,9 +3165,10 @@ pub const Type = extern union { | ... | @@ -5797,9 +3165,10 @@ pub const Type = extern union { |
| 5797 | offset: u64 = 0, | 3165 | offset: u64 = 0, |
| 5798 | big_align: u32 = 0, | 3166 | big_align: u32 = 0, |
| 5799 | struct_obj: *Module.Struct, | 3167 | struct_obj: *Module.Struct, |
| 5800 | target: Target, | 3168 | module: *Module, |
| 5801 | 3169 | ||
| 5802 | pub fn next(it: *StructOffsetIterator) ?FieldOffset { | 3170 | pub fn next(it: *StructOffsetIterator) ?FieldOffset { |
| 3171 | const mod = it.module; | ||
| 5803 | var i = it.field; | 3172 | var i = it.field; |
| 5804 | if (it.struct_obj.fields.count() <= i) | 3173 | if (it.struct_obj.fields.count() <= i) |
| 5805 | return null; | 3174 | return null; |
| ... | @@ -5811,35 +3180,36 @@ pub const Type = extern union { | ... | @@ -5811,35 +3180,36 @@ pub const Type = extern union { |
| 5811 | const field = it.struct_obj.fields.values()[i]; | 3180 | const field = it.struct_obj.fields.values()[i]; |
| 5812 | it.field += 1; | 3181 | it.field += 1; |
| 5813 | 3182 | ||
| 5814 | if (field.is_comptime or !field.ty.hasRuntimeBits()) { | 3183 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) { |
| 5815 | return FieldOffset{ .field = i, .offset = it.offset }; | 3184 | return FieldOffset{ .field = i, .offset = it.offset }; |
| 5816 | } | 3185 | } |
| 5817 | 3186 | ||
| 5818 | const field_align = field.alignment(it.target, it.struct_obj.layout); | 3187 | const field_align = field.alignment(mod, it.struct_obj.layout); |
| 5819 | it.big_align = @max(it.big_align, field_align); | 3188 | it.big_align = @max(it.big_align, field_align); |
| 5820 | const field_offset = std.mem.alignForwardGeneric(u64, it.offset, field_align); | 3189 | const field_offset = std.mem.alignForwardGeneric(u64, it.offset, field_align); |
| 5821 | it.offset = field_offset + field.ty.abiSize(it.target); | 3190 | it.offset = field_offset + field.ty.abiSize(mod); |
| 5822 | return FieldOffset{ .field = i, .offset = field_offset }; | 3191 | return FieldOffset{ .field = i, .offset = field_offset }; |
| 5823 | } | 3192 | } |
| 5824 | }; | 3193 | }; |
| 5825 | 3194 | ||
| 5826 | /// Get an iterator that iterates over all the struct field, returning the field and | 3195 | /// Get an iterator that iterates over all the struct field, returning the field and |
| 5827 | /// offset of that field. Asserts that the type is a non-packed struct. | 3196 | /// offset of that field. Asserts that the type is a non-packed struct. |
| 5828 | pub fn iterateStructOffsets(ty: Type, target: Target) StructOffsetIterator { | 3197 | pub fn iterateStructOffsets(ty: Type, mod: *Module) StructOffsetIterator { |
| 5829 | const struct_obj = ty.castTag(.@"struct").?.data; | 3198 | const struct_type = mod.intern_pool.indexToKey(ty.toIntern()).struct_type; |
| 3199 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | ||
| 5830 | assert(struct_obj.haveLayout()); | 3200 | assert(struct_obj.haveLayout()); |
| 5831 | assert(struct_obj.layout != .Packed); | 3201 | assert(struct_obj.layout != .Packed); |
| 5832 | return .{ .struct_obj = struct_obj, .target = target }; | 3202 | return .{ .struct_obj = struct_obj, .module = mod }; |
| 5833 | } | 3203 | } |
| 5834 | 3204 | ||
| 5835 | /// Supports structs and unions. | 3205 | /// Supports structs and unions. |
| 5836 | pub fn structFieldOffset(ty: Type, index: usize, target: Target) u64 { | 3206 | pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 { |
| 5837 | switch (ty.tag()) { | 3207 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5838 | .@"struct" => { | 3208 | .struct_type => |struct_type| { |
| 5839 | const struct_obj = ty.castTag(.@"struct").?.data; | 3209 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 5840 | assert(struct_obj.haveLayout()); | 3210 | assert(struct_obj.haveLayout()); |
| 5841 | assert(struct_obj.layout != .Packed); | 3211 | assert(struct_obj.layout != .Packed); |
| 5842 | var it = ty.iterateStructOffsets(target); | 3212 | var it = ty.iterateStructOffsets(mod); |
| 5843 | while (it.next()) |field_offset| { | 3213 | while (it.next()) |field_offset| { |
| 5844 | if (index == field_offset.field) | 3214 | if (index == field_offset.field) |
| 5845 | return field_offset.offset; | 3215 | return field_offset.offset; |
| ... | @@ -5848,34 +3218,32 @@ pub const Type = extern union { | ... | @@ -5848,34 +3218,32 @@ pub const Type = extern union { |
| 5848 | return std.mem.alignForwardGeneric(u64, it.offset, @max(it.big_align, 1)); | 3218 | return std.mem.alignForwardGeneric(u64, it.offset, @max(it.big_align, 1)); |
| 5849 | }, | 3219 | }, |
| 5850 | 3220 | ||
| 5851 | .tuple, .anon_struct => { | 3221 | .anon_struct_type => |tuple| { |
| 5852 | const tuple = ty.tupleFields(); | ||
| 5853 | |||
| 5854 | var offset: u64 = 0; | 3222 | var offset: u64 = 0; |
| 5855 | var big_align: u32 = 0; | 3223 | var big_align: u32 = 0; |
| 5856 | 3224 | ||
| 5857 | for (tuple.types, 0..) |field_ty, i| { | 3225 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { |
| 5858 | const field_val = tuple.values[i]; | 3226 | if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) { |
| 5859 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) { | ||
| 5860 | // comptime field | 3227 | // comptime field |
| 5861 | if (i == index) return offset; | 3228 | if (i == index) return offset; |
| 5862 | continue; | 3229 | continue; |
| 5863 | } | 3230 | } |
| 5864 | 3231 | ||
| 5865 | const field_align = field_ty.abiAlignment(target); | 3232 | const field_align = field_ty.toType().abiAlignment(mod); |
| 5866 | big_align = @max(big_align, field_align); | 3233 | big_align = @max(big_align, field_align); |
| 5867 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 3234 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 5868 | if (i == index) return offset; | 3235 | if (i == index) return offset; |
| 5869 | offset += field_ty.abiSize(target); | 3236 | offset += field_ty.toType().abiSize(mod); |
| 5870 | } | 3237 | } |
| 5871 | offset = std.mem.alignForwardGeneric(u64, offset, @max(big_align, 1)); | 3238 | offset = std.mem.alignForwardGeneric(u64, offset, @max(big_align, 1)); |
| 5872 | return offset; | 3239 | return offset; |
| 5873 | }, | 3240 | }, |
| 5874 | 3241 | ||
| 5875 | .@"union" => return 0, | 3242 | .union_type => |union_type| { |
| 5876 | .union_safety_tagged, .union_tagged => { | 3243 | if (!union_type.hasTag()) |
| 5877 | const union_obj = ty.cast(Payload.Union).?.data; | 3244 | return 0; |
| 5878 | const layout = union_obj.getLayout(target, true); | 3245 | const union_obj = mod.unionPtr(union_type.index); |
| 3246 | const layout = union_obj.getLayout(mod, true); | ||
| 5879 | if (layout.tag_align >= layout.payload_align) { | 3247 | if (layout.tag_align >= layout.payload_align) { |
| 5880 | // {Tag, Payload} | 3248 | // {Tag, Payload} |
| 5881 | return std.mem.alignForwardGeneric(u64, layout.tag_size, layout.payload_align); | 3249 | return std.mem.alignForwardGeneric(u64, layout.tag_size, layout.payload_align); |
| ... | @@ -5884,6 +3252,7 @@ pub const Type = extern union { | ... | @@ -5884,6 +3252,7 @@ pub const Type = extern union { |
| 5884 | return 0; | 3252 | return 0; |
| 5885 | } | 3253 | } |
| 5886 | }, | 3254 | }, |
| 3255 | |||
| 5887 | else => unreachable, | 3256 | else => unreachable, |
| 5888 | } | 3257 | } |
| 5889 | } | 3258 | } |
| ... | @@ -5893,507 +3262,92 @@ pub const Type = extern union { | ... | @@ -5893,507 +3262,92 @@ pub const Type = extern union { |
| 5893 | } | 3262 | } |
| 5894 | 3263 | ||
| 5895 | pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc { | 3264 | pub fn declSrcLocOrNull(ty: Type, mod: *Module) ?Module.SrcLoc { |
| 5896 | switch (ty.tag()) { | 3265 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5897 | .enum_full, .enum_nonexhaustive => { | 3266 | .struct_type => |struct_type| { |
| 5898 | const enum_full = ty.cast(Payload.EnumFull).?.data; | 3267 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; |
| 5899 | return enum_full.srcLoc(mod); | ||
| 5900 | }, | ||
| 5901 | .enum_numbered => { | ||
| 5902 | const enum_numbered = ty.castTag(.enum_numbered).?.data; | ||
| 5903 | return enum_numbered.srcLoc(mod); | ||
| 5904 | }, | ||
| 5905 | .enum_simple => { | ||
| 5906 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 5907 | return enum_simple.srcLoc(mod); | ||
| 5908 | }, | ||
| 5909 | .@"struct" => { | ||
| 5910 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 5911 | return struct_obj.srcLoc(mod); | 3268 | return struct_obj.srcLoc(mod); |
| 5912 | }, | 3269 | }, |
| 5913 | .error_set => { | 3270 | .union_type => |union_type| { |
| 5914 | const error_set = ty.castTag(.error_set).?.data; | 3271 | const union_obj = mod.unionPtr(union_type.index); |
| 5915 | return error_set.srcLoc(mod); | ||
| 5916 | }, | ||
| 5917 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 5918 | const union_obj = ty.cast(Payload.Union).?.data; | ||
| 5919 | return union_obj.srcLoc(mod); | 3272 | return union_obj.srcLoc(mod); |
| 5920 | }, | 3273 | }, |
| 5921 | .@"opaque" => { | 3274 | .opaque_type => |opaque_type| mod.opaqueSrcLoc(opaque_type), |
| 5922 | const opaque_obj = ty.cast(Payload.Opaque).?.data; | 3275 | .enum_type => |enum_type| mod.declPtr(enum_type.decl).srcLoc(mod), |
| 5923 | return opaque_obj.srcLoc(mod); | 3276 | else => null, |
| 5924 | }, | 3277 | }; |
| 5925 | .atomic_order, | ||
| 5926 | .atomic_rmw_op, | ||
| 5927 | .calling_convention, | ||
| 5928 | .address_space, | ||
| 5929 | .float_mode, | ||
| 5930 | .reduce_op, | ||
| 5931 | .modifier, | ||
| 5932 | .prefetch_options, | ||
| 5933 | .export_options, | ||
| 5934 | .extern_options, | ||
| 5935 | .type_info, | ||
| 5936 | => unreachable, // needed to call resolveTypeFields first | ||
| 5937 | |||
| 5938 | else => return null, | ||
| 5939 | } | ||
| 5940 | } | 3278 | } |
| 5941 | 3279 | ||
| 5942 | pub fn getOwnerDecl(ty: Type) Module.Decl.Index { | 3280 | pub fn getOwnerDecl(ty: Type, mod: *Module) Module.Decl.Index { |
| 5943 | return ty.getOwnerDeclOrNull() orelse unreachable; | 3281 | return ty.getOwnerDeclOrNull(mod) orelse unreachable; |
| 5944 | } | 3282 | } |
| 5945 | 3283 | ||
| 5946 | pub fn getOwnerDeclOrNull(ty: Type) ?Module.Decl.Index { | 3284 | pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?Module.Decl.Index { |
| 5947 | switch (ty.tag()) { | 3285 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 5948 | .enum_full, .enum_nonexhaustive => { | 3286 | .struct_type => |struct_type| { |
| 5949 | const enum_full = ty.cast(Payload.EnumFull).?.data; | 3287 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return null; |
| 5950 | return enum_full.owner_decl; | ||
| 5951 | }, | ||
| 5952 | .enum_numbered => return ty.castTag(.enum_numbered).?.data.owner_decl, | ||
| 5953 | .enum_simple => { | ||
| 5954 | const enum_simple = ty.castTag(.enum_simple).?.data; | ||
| 5955 | return enum_simple.owner_decl; | ||
| 5956 | }, | ||
| 5957 | .@"struct" => { | ||
| 5958 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 5959 | return struct_obj.owner_decl; | 3288 | return struct_obj.owner_decl; |
| 5960 | }, | 3289 | }, |
| 5961 | .error_set => { | 3290 | .union_type => |union_type| { |
| 5962 | const error_set = ty.castTag(.error_set).?.data; | 3291 | const union_obj = mod.unionPtr(union_type.index); |
| 5963 | return error_set.owner_decl; | ||
| 5964 | }, | ||
| 5965 | .@"union", .union_safety_tagged, .union_tagged => { | ||
| 5966 | const union_obj = ty.cast(Payload.Union).?.data; | ||
| 5967 | return union_obj.owner_decl; | 3292 | return union_obj.owner_decl; |
| 5968 | }, | 3293 | }, |
| 5969 | .@"opaque" => { | 3294 | .opaque_type => |opaque_type| opaque_type.decl, |
| 5970 | const opaque_obj = ty.cast(Payload.Opaque).?.data; | 3295 | .enum_type => |enum_type| enum_type.decl, |
| 5971 | return opaque_obj.owner_decl; | 3296 | else => null, |
| 5972 | }, | 3297 | }; |
| 5973 | .atomic_order, | ||
| 5974 | .atomic_rmw_op, | ||
| 5975 | .calling_convention, | ||
| 5976 | .address_space, | ||
| 5977 | .float_mode, | ||
| 5978 | .reduce_op, | ||
| 5979 | .modifier, | ||
| 5980 | .prefetch_options, | ||
| 5981 | .export_options, | ||
| 5982 | .extern_options, | ||
| 5983 | .type_info, | ||
| 5984 | => unreachable, // These need to be resolved earlier. | ||
| 5985 | |||
| 5986 | else => return null, | ||
| 5987 | } | ||
| 5988 | } | 3298 | } |
| 5989 | 3299 | ||
| 5990 | /// This enum does not directly correspond to `std.builtin.TypeId` because | 3300 | pub fn isGenericPoison(ty: Type) bool { |
| 5991 | /// it has extra enum tags in it, as a way of using less memory. For example, | 3301 | return ty.toIntern() == .generic_poison_type; |
| 5992 | /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types | ||
| 5993 | /// but with different alignment values, in this data structure they are represented | ||
| 5994 | /// with different enum tags, because the the former requires more payload data than the latter. | ||
| 5995 | /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`. | ||
| 5996 | pub const Tag = enum(usize) { | ||
| 5997 | // The first section of this enum are tags that require no payload. | ||
| 5998 | u1, | ||
| 5999 | u8, | ||
| 6000 | i8, | ||
| 6001 | u16, | ||
| 6002 | i16, | ||
| 6003 | u29, | ||
| 6004 | u32, | ||
| 6005 | i32, | ||
| 6006 | u64, | ||
| 6007 | i64, | ||
| 6008 | u128, | ||
| 6009 | i128, | ||
| 6010 | usize, | ||
| 6011 | isize, | ||
| 6012 | c_char, | ||
| 6013 | c_short, | ||
| 6014 | c_ushort, | ||
| 6015 | c_int, | ||
| 6016 | c_uint, | ||
| 6017 | c_long, | ||
| 6018 | c_ulong, | ||
| 6019 | c_longlong, | ||
| 6020 | c_ulonglong, | ||
| 6021 | c_longdouble, | ||
| 6022 | f16, | ||
| 6023 | f32, | ||
| 6024 | f64, | ||
| 6025 | f80, | ||
| 6026 | f128, | ||
| 6027 | anyopaque, | ||
| 6028 | bool, | ||
| 6029 | void, | ||
| 6030 | type, | ||
| 6031 | anyerror, | ||
| 6032 | comptime_int, | ||
| 6033 | comptime_float, | ||
| 6034 | noreturn, | ||
| 6035 | @"anyframe", | ||
| 6036 | null, | ||
| 6037 | undefined, | ||
| 6038 | enum_literal, | ||
| 6039 | atomic_order, | ||
| 6040 | atomic_rmw_op, | ||
| 6041 | calling_convention, | ||
| 6042 | address_space, | ||
| 6043 | float_mode, | ||
| 6044 | reduce_op, | ||
| 6045 | modifier, | ||
| 6046 | prefetch_options, | ||
| 6047 | export_options, | ||
| 6048 | extern_options, | ||
| 6049 | type_info, | ||
| 6050 | manyptr_u8, | ||
| 6051 | manyptr_const_u8, | ||
| 6052 | manyptr_const_u8_sentinel_0, | ||
| 6053 | fn_noreturn_no_args, | ||
| 6054 | fn_void_no_args, | ||
| 6055 | fn_naked_noreturn_no_args, | ||
| 6056 | fn_ccc_void_no_args, | ||
| 6057 | single_const_pointer_to_comptime_int, | ||
| 6058 | const_slice_u8, | ||
| 6059 | const_slice_u8_sentinel_0, | ||
| 6060 | anyerror_void_error_union, | ||
| 6061 | generic_poison, | ||
| 6062 | /// Same as `empty_struct` except it has an empty namespace. | ||
| 6063 | empty_struct_literal, | ||
| 6064 | /// This is a special value that tracks a set of types that have been stored | ||
| 6065 | /// to an inferred allocation. It does not support most of the normal type queries. | ||
| 6066 | /// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc. | ||
| 6067 | inferred_alloc_mut, | ||
| 6068 | /// Same as `inferred_alloc_mut` but the local is `var` not `const`. | ||
| 6069 | inferred_alloc_const, // See last_no_payload_tag below. | ||
| 6070 | // After this, the tag requires a payload. | ||
| 6071 | |||
| 6072 | array_u8, | ||
| 6073 | array_u8_sentinel_0, | ||
| 6074 | array, | ||
| 6075 | array_sentinel, | ||
| 6076 | vector, | ||
| 6077 | /// Possible Value tags for this: @"struct" | ||
| 6078 | tuple, | ||
| 6079 | /// Possible Value tags for this: @"struct" | ||
| 6080 | anon_struct, | ||
| 6081 | pointer, | ||
| 6082 | single_const_pointer, | ||
| 6083 | single_mut_pointer, | ||
| 6084 | many_const_pointer, | ||
| 6085 | many_mut_pointer, | ||
| 6086 | c_const_pointer, | ||
| 6087 | c_mut_pointer, | ||
| 6088 | const_slice, | ||
| 6089 | mut_slice, | ||
| 6090 | int_signed, | ||
| 6091 | int_unsigned, | ||
| 6092 | function, | ||
| 6093 | optional, | ||
| 6094 | optional_single_mut_pointer, | ||
| 6095 | optional_single_const_pointer, | ||
| 6096 | error_union, | ||
| 6097 | anyframe_T, | ||
| 6098 | error_set, | ||
| 6099 | error_set_single, | ||
| 6100 | /// The type is the inferred error set of a specific function. | ||
| 6101 | error_set_inferred, | ||
| 6102 | error_set_merged, | ||
| 6103 | empty_struct, | ||
| 6104 | @"opaque", | ||
| 6105 | @"struct", | ||
| 6106 | @"union", | ||
| 6107 | union_safety_tagged, | ||
| 6108 | union_tagged, | ||
| 6109 | enum_simple, | ||
| 6110 | enum_numbered, | ||
| 6111 | enum_full, | ||
| 6112 | enum_nonexhaustive, | ||
| 6113 | |||
| 6114 | pub const last_no_payload_tag = Tag.inferred_alloc_const; | ||
| 6115 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; | ||
| 6116 | |||
| 6117 | pub fn Type(comptime t: Tag) type { | ||
| 6118 | // Keep in sync with tools/stage2_pretty_printers_common.py | ||
| 6119 | return switch (t) { | ||
| 6120 | .u1, | ||
| 6121 | .u8, | ||
| 6122 | .i8, | ||
| 6123 | .u16, | ||
| 6124 | .i16, | ||
| 6125 | .u29, | ||
| 6126 | .u32, | ||
| 6127 | .i32, | ||
| 6128 | .u64, | ||
| 6129 | .i64, | ||
| 6130 | .u128, | ||
| 6131 | .i128, | ||
| 6132 | .usize, | ||
| 6133 | .isize, | ||
| 6134 | .c_char, | ||
| 6135 | .c_short, | ||
| 6136 | .c_ushort, | ||
| 6137 | .c_int, | ||
| 6138 | .c_uint, | ||
| 6139 | .c_long, | ||
| 6140 | .c_ulong, | ||
| 6141 | .c_longlong, | ||
| 6142 | .c_ulonglong, | ||
| 6143 | .c_longdouble, | ||
| 6144 | .f16, | ||
| 6145 | .f32, | ||
| 6146 | .f64, | ||
| 6147 | .f80, | ||
| 6148 | .f128, | ||
| 6149 | .anyopaque, | ||
| 6150 | .bool, | ||
| 6151 | .void, | ||
| 6152 | .type, | ||
| 6153 | .anyerror, | ||
| 6154 | .comptime_int, | ||
| 6155 | .comptime_float, | ||
| 6156 | .noreturn, | ||
| 6157 | .enum_literal, | ||
| 6158 | .null, | ||
| 6159 | .undefined, | ||
| 6160 | .fn_noreturn_no_args, | ||
| 6161 | .fn_void_no_args, | ||
| 6162 | .fn_naked_noreturn_no_args, | ||
| 6163 | .fn_ccc_void_no_args, | ||
| 6164 | .single_const_pointer_to_comptime_int, | ||
| 6165 | .anyerror_void_error_union, | ||
| 6166 | .const_slice_u8, | ||
| 6167 | .const_slice_u8_sentinel_0, | ||
| 6168 | .generic_poison, | ||
| 6169 | .inferred_alloc_const, | ||
| 6170 | .inferred_alloc_mut, | ||
| 6171 | .empty_struct_literal, | ||
| 6172 | .manyptr_u8, | ||
| 6173 | .manyptr_const_u8, | ||
| 6174 | .manyptr_const_u8_sentinel_0, | ||
| 6175 | .atomic_order, | ||
| 6176 | .atomic_rmw_op, | ||
| 6177 | .calling_convention, | ||
| 6178 | .address_space, | ||
| 6179 | .float_mode, | ||
| 6180 | .reduce_op, | ||
| 6181 | .modifier, | ||
| 6182 | .prefetch_options, | ||
| 6183 | .export_options, | ||
| 6184 | .extern_options, | ||
| 6185 | .type_info, | ||
| 6186 | .@"anyframe", | ||
| 6187 | => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), | ||
| 6188 | |||
| 6189 | .array_u8, | ||
| 6190 | .array_u8_sentinel_0, | ||
| 6191 | => Payload.Len, | ||
| 6192 | |||
| 6193 | .single_const_pointer, | ||
| 6194 | .single_mut_pointer, | ||
| 6195 | .many_const_pointer, | ||
| 6196 | .many_mut_pointer, | ||
| 6197 | .c_const_pointer, | ||
| 6198 | .c_mut_pointer, | ||
| 6199 | .const_slice, | ||
| 6200 | .mut_slice, | ||
| 6201 | .optional, | ||
| 6202 | .optional_single_mut_pointer, | ||
| 6203 | .optional_single_const_pointer, | ||
| 6204 | .anyframe_T, | ||
| 6205 | => Payload.ElemType, | ||
| 6206 | |||
| 6207 | .int_signed, | ||
| 6208 | .int_unsigned, | ||
| 6209 | => Payload.Bits, | ||
| 6210 | |||
| 6211 | .error_set => Payload.ErrorSet, | ||
| 6212 | .error_set_inferred => Payload.ErrorSetInferred, | ||
| 6213 | .error_set_merged => Payload.ErrorSetMerged, | ||
| 6214 | |||
| 6215 | .array, .vector => Payload.Array, | ||
| 6216 | .array_sentinel => Payload.ArraySentinel, | ||
| 6217 | .pointer => Payload.Pointer, | ||
| 6218 | .function => Payload.Function, | ||
| 6219 | .error_union => Payload.ErrorUnion, | ||
| 6220 | .error_set_single => Payload.Name, | ||
| 6221 | .@"opaque" => Payload.Opaque, | ||
| 6222 | .@"struct" => Payload.Struct, | ||
| 6223 | .@"union", .union_safety_tagged, .union_tagged => Payload.Union, | ||
| 6224 | .enum_full, .enum_nonexhaustive => Payload.EnumFull, | ||
| 6225 | .enum_simple => Payload.EnumSimple, | ||
| 6226 | .enum_numbered => Payload.EnumNumbered, | ||
| 6227 | .empty_struct => Payload.ContainerScope, | ||
| 6228 | .tuple => Payload.Tuple, | ||
| 6229 | .anon_struct => Payload.AnonStruct, | ||
| 6230 | }; | ||
| 6231 | } | ||
| 6232 | |||
| 6233 | pub fn init(comptime t: Tag) file_struct.Type { | ||
| 6234 | comptime std.debug.assert(@enumToInt(t) < Tag.no_payload_count); | ||
| 6235 | return .{ .tag_if_small_enough = t }; | ||
| 6236 | } | ||
| 6237 | |||
| 6238 | pub fn create(comptime t: Tag, ally: Allocator, data: Data(t)) error{OutOfMemory}!file_struct.Type { | ||
| 6239 | const p = try ally.create(t.Type()); | ||
| 6240 | p.* = .{ | ||
| 6241 | .base = .{ .tag = t }, | ||
| 6242 | .data = data, | ||
| 6243 | }; | ||
| 6244 | return file_struct.Type{ .ptr_otherwise = &p.base }; | ||
| 6245 | } | ||
| 6246 | |||
| 6247 | pub fn Data(comptime t: Tag) type { | ||
| 6248 | return std.meta.fieldInfo(t.Type(), .data).type; | ||
| 6249 | } | ||
| 6250 | }; | ||
| 6251 | |||
| 6252 | pub fn isTuple(ty: Type) bool { | ||
| 6253 | return switch (ty.tag()) { | ||
| 6254 | .tuple, .empty_struct_literal => true, | ||
| 6255 | .@"struct" => ty.castTag(.@"struct").?.data.is_tuple, | ||
| 6256 | else => false, | ||
| 6257 | }; | ||
| 6258 | } | 3302 | } |
| 6259 | 3303 | ||
| 6260 | pub fn isAnonStruct(ty: Type) bool { | 3304 | pub fn isTuple(ty: Type, mod: *Module) bool { |
| 6261 | return switch (ty.tag()) { | 3305 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 6262 | .anon_struct, .empty_struct_literal => true, | 3306 | .struct_type => |struct_type| { |
| 3307 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | ||
| 3308 | return struct_obj.is_tuple; | ||
| 3309 | }, | ||
| 3310 | .anon_struct_type => |anon_struct| anon_struct.names.len == 0, | ||
| 6263 | else => false, | 3311 | else => false, |
| 6264 | }; | 3312 | }; |
| 6265 | } | 3313 | } |
| 6266 | 3314 | ||
| 6267 | pub fn isTupleOrAnonStruct(ty: Type) bool { | 3315 | pub fn isAnonStruct(ty: Type, mod: *Module) bool { |
| 6268 | return switch (ty.tag()) { | 3316 | if (ty.toIntern() == .empty_struct_type) return true; |
| 6269 | .tuple, .empty_struct_literal, .anon_struct => true, | 3317 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 6270 | .@"struct" => ty.castTag(.@"struct").?.data.is_tuple, | 3318 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len > 0, |
| 6271 | else => false, | 3319 | else => false, |
| 6272 | }; | 3320 | }; |
| 6273 | } | 3321 | } |
| 6274 | 3322 | ||
| 6275 | pub fn isSimpleTuple(ty: Type) bool { | 3323 | pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool { |
| 6276 | return switch (ty.tag()) { | 3324 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 6277 | .tuple, .empty_struct_literal => true, | 3325 | .struct_type => |struct_type| { |
| 3326 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false; | ||
| 3327 | return struct_obj.is_tuple; | ||
| 3328 | }, | ||
| 3329 | .anon_struct_type => true, | ||
| 6278 | else => false, | 3330 | else => false, |
| 6279 | }; | 3331 | }; |
| 6280 | } | 3332 | } |
| 6281 | 3333 | ||
| 6282 | pub fn isSimpleTupleOrAnonStruct(ty: Type) bool { | 3334 | pub fn isSimpleTuple(ty: Type, mod: *Module) bool { |
| 6283 | return switch (ty.tag()) { | 3335 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 6284 | .tuple, .empty_struct_literal, .anon_struct => true, | 3336 | .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0, |
| 6285 | else => false, | 3337 | else => false, |
| 6286 | }; | 3338 | }; |
| 6287 | } | 3339 | } |
| 6288 | 3340 | ||
| 6289 | // Only allowed for simple tuple types | 3341 | pub fn isSimpleTupleOrAnonStruct(ty: Type, mod: *Module) bool { |
| 6290 | pub fn tupleFields(ty: Type) Payload.Tuple.Data { | 3342 | return switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 6291 | return switch (ty.tag()) { | 3343 | .anon_struct_type => true, |
| 6292 | .tuple => ty.castTag(.tuple).?.data, | 3344 | else => false, |
| 6293 | .anon_struct => .{ | ||
| 6294 | .types = ty.castTag(.anon_struct).?.data.types, | ||
| 6295 | .values = ty.castTag(.anon_struct).?.data.values, | ||
| 6296 | }, | ||
| 6297 | .empty_struct_literal => .{ .types = &.{}, .values = &.{} }, | ||
| 6298 | else => unreachable, | ||
| 6299 | }; | 3345 | }; |
| 6300 | } | 3346 | } |
| 6301 | 3347 | ||
| 6302 | /// The sub-types are named after what fields they contain. | ||
| 6303 | pub const Payload = struct { | 3348 | pub const Payload = struct { |
| 6304 | tag: Tag, | 3349 | /// TODO: remove this data structure since we have `InternPool.Key.PtrType`. |
| 6305 | |||
| 6306 | pub const Len = struct { | ||
| 6307 | base: Payload, | ||
| 6308 | data: u64, | ||
| 6309 | }; | ||
| 6310 | |||
| 6311 | pub const Array = struct { | ||
| 6312 | base: Payload, | ||
| 6313 | data: struct { | ||
| 6314 | len: u64, | ||
| 6315 | elem_type: Type, | ||
| 6316 | }, | ||
| 6317 | }; | ||
| 6318 | |||
| 6319 | pub const ArraySentinel = struct { | ||
| 6320 | pub const base_tag = Tag.array_sentinel; | ||
| 6321 | |||
| 6322 | base: Payload = Payload{ .tag = base_tag }, | ||
| 6323 | data: struct { | ||
| 6324 | len: u64, | ||
| 6325 | sentinel: Value, | ||
| 6326 | elem_type: Type, | ||
| 6327 | }, | ||
| 6328 | }; | ||
| 6329 | |||
| 6330 | pub const ElemType = struct { | ||
| 6331 | base: Payload, | ||
| 6332 | data: Type, | ||
| 6333 | }; | ||
| 6334 | |||
| 6335 | pub const Bits = struct { | ||
| 6336 | base: Payload, | ||
| 6337 | data: u16, | ||
| 6338 | }; | ||
| 6339 | |||
| 6340 | pub const Function = struct { | ||
| 6341 | pub const base_tag = Tag.function; | ||
| 6342 | |||
| 6343 | base: Payload = Payload{ .tag = base_tag }, | ||
| 6344 | data: Data, | ||
| 6345 | |||
| 6346 | // TODO look into optimizing this memory to take fewer bytes | ||
| 6347 | pub const Data = struct { | ||
| 6348 | param_types: []Type, | ||
| 6349 | comptime_params: [*]bool, | ||
| 6350 | return_type: Type, | ||
| 6351 | /// If zero use default target function code alignment. | ||
| 6352 | alignment: u32, | ||
| 6353 | noalias_bits: u32, | ||
| 6354 | cc: std.builtin.CallingConvention, | ||
| 6355 | is_var_args: bool, | ||
| 6356 | is_generic: bool, | ||
| 6357 | is_noinline: bool, | ||
| 6358 | align_is_generic: bool, | ||
| 6359 | cc_is_generic: bool, | ||
| 6360 | section_is_generic: bool, | ||
| 6361 | addrspace_is_generic: bool, | ||
| 6362 | |||
| 6363 | pub fn paramIsComptime(self: @This(), i: usize) bool { | ||
| 6364 | assert(i < self.param_types.len); | ||
| 6365 | return self.comptime_params[i]; | ||
| 6366 | } | ||
| 6367 | }; | ||
| 6368 | }; | ||
| 6369 | |||
| 6370 | pub const ErrorSet = struct { | ||
| 6371 | pub const base_tag = Tag.error_set; | ||
| 6372 | |||
| 6373 | base: Payload = Payload{ .tag = base_tag }, | ||
| 6374 | data: *Module.ErrorSet, | ||
| 6375 | }; | ||
| 6376 | |||
| 6377 | pub const ErrorSetMerged = struct { | ||
| 6378 | pub const base_tag = Tag.error_set_merged; | ||
| 6379 | |||
| 6380 | base: Payload = Payload{ .tag = base_tag }, | ||
| 6381 | data: Module.ErrorSet.NameMap, | ||
| 6382 | }; | ||
| 6383 | |||
| 6384 | pub const ErrorSetInferred = struct { | ||
| 6385 | pub const base_tag = Tag.error_set_inferred; | ||
| 6386 | |||
| 6387 | base: Payload = Payload{ .tag = base_tag }, | ||
| 6388 | data: *Module.Fn.InferredErrorSet, | ||
| 6389 | }; | ||
| 6390 | |||
| 6391 | pub const Pointer = struct { | 3350 | pub const Pointer = struct { |
| 6392 | pub const base_tag = Tag.pointer; | ||
| 6393 | |||
| 6394 | base: Payload = Payload{ .tag = base_tag }, | ||
| 6395 | data: Data, | ||
| 6396 | |||
| 6397 | pub const Data = struct { | 3351 | pub const Data = struct { |
| 6398 | pointee_type: Type, | 3352 | pointee_type: Type, |
| 6399 | sentinel: ?Value = null, | 3353 | sentinel: ?Value = null, |
| ... | @@ -6417,145 +3371,103 @@ pub const Type = extern union { | ... | @@ -6417,145 +3371,103 @@ pub const Type = extern union { |
| 6417 | @"volatile": bool = false, | 3371 | @"volatile": bool = false, |
| 6418 | size: std.builtin.Type.Pointer.Size = .One, | 3372 | size: std.builtin.Type.Pointer.Size = .One, |
| 6419 | 3373 | ||
| 6420 | pub const VectorIndex = enum(u32) { | 3374 | pub const VectorIndex = InternPool.Key.PtrType.VectorIndex; |
| 6421 | none = std.math.maxInt(u32), | ||
| 6422 | runtime = std.math.maxInt(u32) - 1, | ||
| 6423 | _, | ||
| 6424 | }; | ||
| 6425 | 3375 | ||
| 6426 | pub fn alignment(data: Data, target: Target) u32 { | 3376 | pub fn alignment(data: Data, mod: *Module) u32 { |
| 6427 | if (data.@"align" != 0) return data.@"align"; | 3377 | if (data.@"align" != 0) return data.@"align"; |
| 6428 | return abiAlignment(data.pointee_type, target); | 3378 | return abiAlignment(data.pointee_type, mod); |
| 3379 | } | ||
| 3380 | |||
| 3381 | pub fn fromKey(p: InternPool.Key.PtrType) Data { | ||
| 3382 | return .{ | ||
| 3383 | .pointee_type = p.child.toType(), | ||
| 3384 | .sentinel = if (p.sentinel != .none) p.sentinel.toValue() else null, | ||
| 3385 | .@"align" = @intCast(u32, p.flags.alignment.toByteUnits(0)), | ||
| 3386 | .@"addrspace" = p.flags.address_space, | ||
| 3387 | .bit_offset = p.packed_offset.bit_offset, | ||
| 3388 | .host_size = p.packed_offset.host_size, | ||
| 3389 | .vector_index = p.flags.vector_index, | ||
| 3390 | .@"allowzero" = p.flags.is_allowzero, | ||
| 3391 | .mutable = !p.flags.is_const, | ||
| 3392 | .@"volatile" = p.flags.is_volatile, | ||
| 3393 | .size = p.flags.size, | ||
| 3394 | }; | ||
| 6429 | } | 3395 | } |
| 6430 | }; | 3396 | }; |
| 6431 | }; | 3397 | }; |
| 3398 | }; | ||
| 6432 | 3399 | ||
| 6433 | pub const ErrorUnion = struct { | 3400 | pub const @"u1": Type = .{ .ip_index = .u1_type }; |
| 6434 | pub const base_tag = Tag.error_union; | 3401 | pub const @"u8": Type = .{ .ip_index = .u8_type }; |
| 6435 | 3402 | pub const @"u16": Type = .{ .ip_index = .u16_type }; | |
| 6436 | base: Payload = Payload{ .tag = base_tag }, | 3403 | pub const @"u29": Type = .{ .ip_index = .u29_type }; |
| 6437 | data: struct { | 3404 | pub const @"u32": Type = .{ .ip_index = .u32_type }; |
| 6438 | error_set: Type, | 3405 | pub const @"u64": Type = .{ .ip_index = .u64_type }; |
| 6439 | payload: Type, | 3406 | pub const @"u128": Type = .{ .ip_index = .u128_type }; |
| 6440 | }, | 3407 | |
| 6441 | }; | 3408 | pub const @"i8": Type = .{ .ip_index = .i8_type }; |
| 6442 | 3409 | pub const @"i16": Type = .{ .ip_index = .i16_type }; | |
| 6443 | pub const Decl = struct { | 3410 | pub const @"i32": Type = .{ .ip_index = .i32_type }; |
| 6444 | base: Payload, | 3411 | pub const @"i64": Type = .{ .ip_index = .i64_type }; |
| 6445 | data: *Module.Decl, | 3412 | pub const @"i128": Type = .{ .ip_index = .i128_type }; |
| 6446 | }; | 3413 | |
| 6447 | 3414 | pub const @"f16": Type = .{ .ip_index = .f16_type }; | |
| 6448 | pub const Name = struct { | 3415 | pub const @"f32": Type = .{ .ip_index = .f32_type }; |
| 6449 | base: Payload, | 3416 | pub const @"f64": Type = .{ .ip_index = .f64_type }; |
| 6450 | /// memory is owned by `Module` | 3417 | pub const @"f80": Type = .{ .ip_index = .f80_type }; |
| 6451 | data: []const u8, | 3418 | pub const @"f128": Type = .{ .ip_index = .f128_type }; |
| 6452 | }; | 3419 | |
| 6453 | 3420 | pub const @"bool": Type = .{ .ip_index = .bool_type }; | |
| 6454 | /// Mostly used for namespace like structs with zero fields. | 3421 | pub const @"usize": Type = .{ .ip_index = .usize_type }; |
| 6455 | /// Most commonly used for files. | 3422 | pub const @"isize": Type = .{ .ip_index = .isize_type }; |
| 6456 | pub const ContainerScope = struct { | 3423 | pub const @"comptime_int": Type = .{ .ip_index = .comptime_int_type }; |
| 6457 | base: Payload, | 3424 | pub const @"comptime_float": Type = .{ .ip_index = .comptime_float_type }; |
| 6458 | data: *Module.Namespace, | 3425 | pub const @"void": Type = .{ .ip_index = .void_type }; |
| 6459 | }; | 3426 | pub const @"type": Type = .{ .ip_index = .type_type }; |
| 6460 | 3427 | pub const @"anyerror": Type = .{ .ip_index = .anyerror_type }; | |
| 6461 | pub const Opaque = struct { | 3428 | pub const @"anyopaque": Type = .{ .ip_index = .anyopaque_type }; |
| 6462 | base: Payload = .{ .tag = .@"opaque" }, | 3429 | pub const @"anyframe": Type = .{ .ip_index = .anyframe_type }; |
| 6463 | data: *Module.Opaque, | 3430 | pub const @"null": Type = .{ .ip_index = .null_type }; |
| 6464 | }; | 3431 | pub const @"undefined": Type = .{ .ip_index = .undefined_type }; |
| 6465 | 3432 | pub const @"noreturn": Type = .{ .ip_index = .noreturn_type }; | |
| 6466 | pub const Struct = struct { | 3433 | |
| 6467 | base: Payload = .{ .tag = .@"struct" }, | 3434 | pub const @"c_char": Type = .{ .ip_index = .c_char_type }; |
| 6468 | data: *Module.Struct, | 3435 | pub const @"c_short": Type = .{ .ip_index = .c_short_type }; |
| 6469 | }; | 3436 | pub const @"c_ushort": Type = .{ .ip_index = .c_ushort_type }; |
| 6470 | 3437 | pub const @"c_int": Type = .{ .ip_index = .c_int_type }; | |
| 6471 | pub const Tuple = struct { | 3438 | pub const @"c_uint": Type = .{ .ip_index = .c_uint_type }; |
| 6472 | base: Payload = .{ .tag = .tuple }, | 3439 | pub const @"c_long": Type = .{ .ip_index = .c_long_type }; |
| 6473 | data: Data, | 3440 | pub const @"c_ulong": Type = .{ .ip_index = .c_ulong_type }; |
| 6474 | 3441 | pub const @"c_longlong": Type = .{ .ip_index = .c_longlong_type }; | |
| 6475 | pub const Data = struct { | 3442 | pub const @"c_ulonglong": Type = .{ .ip_index = .c_ulonglong_type }; |
| 6476 | types: []Type, | 3443 | pub const @"c_longdouble": Type = .{ .ip_index = .c_longdouble_type }; |
| 6477 | /// unreachable_value elements are used to indicate runtime-known. | 3444 | |
| 6478 | values: []Value, | 3445 | pub const slice_const_u8: Type = .{ .ip_index = .slice_const_u8_type }; |
| 6479 | }; | 3446 | pub const manyptr_u8: Type = .{ .ip_index = .manyptr_u8_type }; |
| 6480 | }; | 3447 | pub const single_const_pointer_to_comptime_int: Type = .{ |
| 6481 | 3448 | .ip_index = .single_const_pointer_to_comptime_int_type, | |
| 6482 | pub const AnonStruct = struct { | ||
| 6483 | base: Payload = .{ .tag = .anon_struct }, | ||
| 6484 | data: Data, | ||
| 6485 | |||
| 6486 | pub const Data = struct { | ||
| 6487 | names: []const []const u8, | ||
| 6488 | types: []Type, | ||
| 6489 | /// unreachable_value elements are used to indicate runtime-known. | ||
| 6490 | values: []Value, | ||
| 6491 | }; | ||
| 6492 | }; | ||
| 6493 | |||
| 6494 | pub const Union = struct { | ||
| 6495 | base: Payload, | ||
| 6496 | data: *Module.Union, | ||
| 6497 | }; | ||
| 6498 | |||
| 6499 | pub const EnumFull = struct { | ||
| 6500 | base: Payload, | ||
| 6501 | data: *Module.EnumFull, | ||
| 6502 | }; | ||
| 6503 | |||
| 6504 | pub const EnumSimple = struct { | ||
| 6505 | base: Payload = .{ .tag = .enum_simple }, | ||
| 6506 | data: *Module.EnumSimple, | ||
| 6507 | }; | ||
| 6508 | |||
| 6509 | pub const EnumNumbered = struct { | ||
| 6510 | base: Payload = .{ .tag = .enum_numbered }, | ||
| 6511 | data: *Module.EnumNumbered, | ||
| 6512 | }; | ||
| 6513 | }; | 3449 | }; |
| 3450 | pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type }; | ||
| 3451 | pub const empty_struct_literal: Type = .{ .ip_index = .empty_struct_type }; | ||
| 6514 | 3452 | ||
| 6515 | pub const @"u1" = initTag(.u1); | 3453 | pub const generic_poison: Type = .{ .ip_index = .generic_poison_type }; |
| 6516 | pub const @"u8" = initTag(.u8); | ||
| 6517 | pub const @"u16" = initTag(.u16); | ||
| 6518 | pub const @"u29" = initTag(.u29); | ||
| 6519 | pub const @"u32" = initTag(.u32); | ||
| 6520 | pub const @"u64" = initTag(.u64); | ||
| 6521 | |||
| 6522 | pub const @"i32" = initTag(.i32); | ||
| 6523 | pub const @"i64" = initTag(.i64); | ||
| 6524 | |||
| 6525 | pub const @"f16" = initTag(.f16); | ||
| 6526 | pub const @"f32" = initTag(.f32); | ||
| 6527 | pub const @"f64" = initTag(.f64); | ||
| 6528 | pub const @"f80" = initTag(.f80); | ||
| 6529 | pub const @"f128" = initTag(.f128); | ||
| 6530 | |||
| 6531 | pub const @"bool" = initTag(.bool); | ||
| 6532 | pub const @"usize" = initTag(.usize); | ||
| 6533 | pub const @"isize" = initTag(.isize); | ||
| 6534 | pub const @"comptime_int" = initTag(.comptime_int); | ||
| 6535 | pub const @"void" = initTag(.void); | ||
| 6536 | pub const @"type" = initTag(.type); | ||
| 6537 | pub const @"anyerror" = initTag(.anyerror); | ||
| 6538 | pub const @"anyopaque" = initTag(.anyopaque); | ||
| 6539 | pub const @"null" = initTag(.null); | ||
| 6540 | 3454 | ||
| 6541 | pub const err_int = Type.u16; | 3455 | pub const err_int = Type.u16; |
| 6542 | 3456 | ||
| 6543 | pub fn ptr(arena: Allocator, mod: *Module, data: Payload.Pointer.Data) !Type { | 3457 | pub fn ptr(arena: Allocator, mod: *Module, data: Payload.Pointer.Data) !Type { |
| 6544 | const target = mod.getTarget(); | 3458 | // TODO: update callsites of this function to directly call mod.ptrType |
| 3459 | // and then delete this function. | ||
| 3460 | _ = arena; | ||
| 6545 | 3461 | ||
| 6546 | var d = data; | 3462 | var d = data; |
| 6547 | 3463 | ||
| 6548 | if (d.size == .C) { | ||
| 6549 | d.@"allowzero" = true; | ||
| 6550 | } | ||
| 6551 | |||
| 6552 | // Canonicalize non-zero alignment. If it matches the ABI alignment of the pointee | 3464 | // Canonicalize non-zero alignment. If it matches the ABI alignment of the pointee |
| 6553 | // type, we change it to 0 here. If this causes an assertion trip because the | 3465 | // type, we change it to 0 here. If this causes an assertion trip because the |
| 6554 | // pointee type needs to be resolved more, that needs to be done before calling | 3466 | // pointee type needs to be resolved more, that needs to be done before calling |
| 6555 | // this ptr() function. | 3467 | // this ptr() function. |
| 6556 | if (d.@"align" != 0) canonicalize: { | 3468 | if (d.@"align" != 0) canonicalize: { |
| 6557 | if (!d.pointee_type.layoutIsResolved()) break :canonicalize; | 3469 | if (!d.pointee_type.layoutIsResolved(mod)) break :canonicalize; |
| 6558 | if (d.@"align" == d.pointee_type.abiAlignment(target)) { | 3470 | if (d.@"align" == d.pointee_type.abiAlignment(mod)) { |
| 6559 | d.@"align" = 0; | 3471 | d.@"align" = 0; |
| 6560 | } | 3472 | } |
| 6561 | } | 3473 | } |
| ... | @@ -6565,57 +3477,29 @@ pub const Type = extern union { | ... | @@ -6565,57 +3477,29 @@ pub const Type = extern union { |
| 6565 | // needs to be resolved before calling this ptr() function. | 3477 | // needs to be resolved before calling this ptr() function. |
| 6566 | if (d.host_size != 0) { | 3478 | if (d.host_size != 0) { |
| 6567 | assert(d.bit_offset < d.host_size * 8); | 3479 | assert(d.bit_offset < d.host_size * 8); |
| 6568 | if (d.host_size * 8 == d.pointee_type.bitSize(target)) { | 3480 | if (d.host_size * 8 == d.pointee_type.bitSize(mod)) { |
| 6569 | assert(d.bit_offset == 0); | 3481 | assert(d.bit_offset == 0); |
| 6570 | d.host_size = 0; | 3482 | d.host_size = 0; |
| 6571 | } | 3483 | } |
| 6572 | } | 3484 | } |
| 6573 | 3485 | ||
| 6574 | if (d.@"align" == 0 and d.@"addrspace" == .generic and | 3486 | return mod.ptrType(.{ |
| 6575 | d.bit_offset == 0 and d.host_size == 0 and d.vector_index == .none and | 3487 | .child = d.pointee_type.ip_index, |
| 6576 | !d.@"allowzero" and !d.@"volatile") | 3488 | .sentinel = if (d.sentinel) |s| s.ip_index else .none, |
| 6577 | { | 3489 | .flags = .{ |
| 6578 | if (d.sentinel) |sent| { | 3490 | .alignment = InternPool.Alignment.fromByteUnits(d.@"align"), |
| 6579 | if (!d.mutable and d.pointee_type.eql(Type.u8, mod)) { | 3491 | .vector_index = d.vector_index, |
| 6580 | switch (d.size) { | 3492 | .size = d.size, |
| 6581 | .Slice => { | 3493 | .is_const = !d.mutable, |
| 6582 | if (sent.compareAllWithZero(.eq, mod)) { | 3494 | .is_volatile = d.@"volatile", |
| 6583 | return Type.initTag(.const_slice_u8_sentinel_0); | 3495 | .is_allowzero = d.@"allowzero", |
| 6584 | } | 3496 | .address_space = d.@"addrspace", |
| 6585 | }, | 3497 | }, |
| 6586 | .Many => { | 3498 | .packed_offset = .{ |
| 6587 | if (sent.compareAllWithZero(.eq, mod)) { | 3499 | .host_size = d.host_size, |
| 6588 | return Type.initTag(.manyptr_const_u8_sentinel_0); | 3500 | .bit_offset = d.bit_offset, |
| 6589 | } | 3501 | }, |
| 6590 | }, | 3502 | }); |
| 6591 | else => {}, | ||
| 6592 | } | ||
| 6593 | } | ||
| 6594 | } else if (!d.mutable and d.pointee_type.eql(Type.u8, mod)) { | ||
| 6595 | switch (d.size) { | ||
| 6596 | .Slice => return Type.initTag(.const_slice_u8), | ||
| 6597 | .Many => return Type.initTag(.manyptr_const_u8), | ||
| 6598 | else => {}, | ||
| 6599 | } | ||
| 6600 | } else { | ||
| 6601 | const T = Type.Tag; | ||
| 6602 | const type_payload = try arena.create(Type.Payload.ElemType); | ||
| 6603 | type_payload.* = .{ | ||
| 6604 | .base = .{ | ||
| 6605 | .tag = switch (d.size) { | ||
| 6606 | .One => if (d.mutable) T.single_mut_pointer else T.single_const_pointer, | ||
| 6607 | .Many => if (d.mutable) T.many_mut_pointer else T.many_const_pointer, | ||
| 6608 | .C => if (d.mutable) T.c_mut_pointer else T.c_const_pointer, | ||
| 6609 | .Slice => if (d.mutable) T.mut_slice else T.const_slice, | ||
| 6610 | }, | ||
| 6611 | }, | ||
| 6612 | .data = d.pointee_type, | ||
| 6613 | }; | ||
| 6614 | return Type.initPayload(&type_payload.base); | ||
| 6615 | } | ||
| 6616 | } | ||
| 6617 | |||
| 6618 | return Type.Tag.pointer.create(arena, d); | ||
| 6619 | } | 3503 | } |
| 6620 | 3504 | ||
| 6621 | pub fn array( | 3505 | pub fn array( |
| ... | @@ -6625,68 +3509,23 @@ pub const Type = extern union { | ... | @@ -6625,68 +3509,23 @@ pub const Type = extern union { |
| 6625 | elem_type: Type, | 3509 | elem_type: Type, |
| 6626 | mod: *Module, | 3510 | mod: *Module, |
| 6627 | ) Allocator.Error!Type { | 3511 | ) Allocator.Error!Type { |
| 6628 | if (elem_type.eql(Type.u8, mod)) { | 3512 | // TODO: update callsites of this function to directly call mod.arrayType |
| 6629 | if (sent) |some| { | 3513 | // and then delete this function. |
| 6630 | if (some.eql(Value.zero, elem_type, mod)) { | 3514 | _ = arena; |
| 6631 | return Tag.array_u8_sentinel_0.create(arena, len); | ||
| 6632 | } | ||
| 6633 | } else { | ||
| 6634 | return Tag.array_u8.create(arena, len); | ||
| 6635 | } | ||
| 6636 | } | ||
| 6637 | |||
| 6638 | if (sent) |some| { | ||
| 6639 | return Tag.array_sentinel.create(arena, .{ | ||
| 6640 | .len = len, | ||
| 6641 | .sentinel = some, | ||
| 6642 | .elem_type = elem_type, | ||
| 6643 | }); | ||
| 6644 | } | ||
| 6645 | |||
| 6646 | return Tag.array.create(arena, .{ | ||
| 6647 | .len = len, | ||
| 6648 | .elem_type = elem_type, | ||
| 6649 | }); | ||
| 6650 | } | ||
| 6651 | 3515 | ||
| 6652 | pub fn vector(arena: Allocator, len: u64, elem_type: Type) Allocator.Error!Type { | 3516 | return mod.arrayType(.{ |
| 6653 | return Tag.vector.create(arena, .{ | ||
| 6654 | .len = len, | 3517 | .len = len, |
| 6655 | .elem_type = elem_type, | 3518 | .child = elem_type.ip_index, |
| 3519 | .sentinel = if (sent) |s| s.ip_index else .none, | ||
| 6656 | }); | 3520 | }); |
| 6657 | } | 3521 | } |
| 6658 | 3522 | ||
| 6659 | pub fn optional(arena: Allocator, child_type: Type) Allocator.Error!Type { | 3523 | pub fn optional(arena: Allocator, child_type: Type, mod: *Module) Allocator.Error!Type { |
| 6660 | switch (child_type.tag()) { | 3524 | // TODO: update callsites of this function to directly call |
| 6661 | .single_const_pointer => return Type.Tag.optional_single_const_pointer.create( | 3525 | // mod.optionalType and then delete this function. |
| 6662 | arena, | 3526 | _ = arena; |
| 6663 | child_type.elemType(), | ||
| 6664 | ), | ||
| 6665 | .single_mut_pointer => return Type.Tag.optional_single_mut_pointer.create( | ||
| 6666 | arena, | ||
| 6667 | child_type.elemType(), | ||
| 6668 | ), | ||
| 6669 | else => return Type.Tag.optional.create(arena, child_type), | ||
| 6670 | } | ||
| 6671 | } | ||
| 6672 | |||
| 6673 | pub fn errorUnion( | ||
| 6674 | arena: Allocator, | ||
| 6675 | error_set: Type, | ||
| 6676 | payload: Type, | ||
| 6677 | mod: *Module, | ||
| 6678 | ) Allocator.Error!Type { | ||
| 6679 | assert(error_set.zigTypeTag() == .ErrorSet); | ||
| 6680 | if (error_set.eql(Type.anyerror, mod) and | ||
| 6681 | payload.eql(Type.void, mod)) | ||
| 6682 | { | ||
| 6683 | return Type.initTag(.anyerror_void_error_union); | ||
| 6684 | } | ||
| 6685 | 3527 | ||
| 6686 | return Type.Tag.error_union.create(arena, .{ | 3528 | return mod.optionalType(child_type.ip_index); |
| 6687 | .error_set = error_set, | ||
| 6688 | .payload = payload, | ||
| 6689 | }); | ||
| 6690 | } | 3529 | } |
| 6691 | 3530 | ||
| 6692 | pub fn smallestUnsignedBits(max: u64) u16 { | 3531 | pub fn smallestUnsignedBits(max: u64) u16 { |
| ... | @@ -6696,113 +3535,7 @@ pub const Type = extern union { | ... | @@ -6696,113 +3535,7 @@ pub const Type = extern union { |
| 6696 | return @intCast(u16, base + @boolToInt(upper < max)); | 3535 | return @intCast(u16, base + @boolToInt(upper < max)); |
| 6697 | } | 3536 | } |
| 6698 | 3537 | ||
| 6699 | pub fn smallestUnsignedInt(arena: Allocator, max: u64) !Type { | ||
| 6700 | const bits = smallestUnsignedBits(max); | ||
| 6701 | return intWithBits(arena, false, bits); | ||
| 6702 | } | ||
| 6703 | |||
| 6704 | pub fn intWithBits(arena: Allocator, sign: bool, bits: u16) !Type { | ||
| 6705 | return if (sign) switch (bits) { | ||
| 6706 | 8 => initTag(.i8), | ||
| 6707 | 16 => initTag(.i16), | ||
| 6708 | 32 => initTag(.i32), | ||
| 6709 | 64 => initTag(.i64), | ||
| 6710 | else => return Tag.int_signed.create(arena, bits), | ||
| 6711 | } else switch (bits) { | ||
| 6712 | 1 => initTag(.u1), | ||
| 6713 | 8 => initTag(.u8), | ||
| 6714 | 16 => initTag(.u16), | ||
| 6715 | 32 => initTag(.u32), | ||
| 6716 | 64 => initTag(.u64), | ||
| 6717 | else => return Tag.int_unsigned.create(arena, bits), | ||
| 6718 | }; | ||
| 6719 | } | ||
| 6720 | |||
| 6721 | /// Given a value representing an integer, returns the number of bits necessary to represent | ||
| 6722 | /// this value in an integer. If `sign` is true, returns the number of bits necessary in a | ||
| 6723 | /// twos-complement integer; otherwise in an unsigned integer. | ||
| 6724 | /// Asserts that `val` is not undef. If `val` is negative, asserts that `sign` is true. | ||
| 6725 | pub fn intBitsForValue(target: Target, val: Value, sign: bool) u16 { | ||
| 6726 | assert(!val.isUndef()); | ||
| 6727 | switch (val.tag()) { | ||
| 6728 | .int_big_positive => { | ||
| 6729 | const limbs = val.castTag(.int_big_positive).?.data; | ||
| 6730 | const big: std.math.big.int.Const = .{ .limbs = limbs, .positive = true }; | ||
| 6731 | return @intCast(u16, big.bitCountAbs() + @boolToInt(sign)); | ||
| 6732 | }, | ||
| 6733 | .int_big_negative => { | ||
| 6734 | const limbs = val.castTag(.int_big_negative).?.data; | ||
| 6735 | // Zero is still a possibility, in which case unsigned is fine | ||
| 6736 | for (limbs) |limb| { | ||
| 6737 | if (limb != 0) break; | ||
| 6738 | } else return 0; // val == 0 | ||
| 6739 | assert(sign); | ||
| 6740 | const big: std.math.big.int.Const = .{ .limbs = limbs, .positive = false }; | ||
| 6741 | return @intCast(u16, big.bitCountTwosComp()); | ||
| 6742 | }, | ||
| 6743 | .int_i64 => { | ||
| 6744 | const x = val.castTag(.int_i64).?.data; | ||
| 6745 | if (x >= 0) return smallestUnsignedBits(@intCast(u64, x)); | ||
| 6746 | assert(sign); | ||
| 6747 | return smallestUnsignedBits(@intCast(u64, -x - 1)) + 1; | ||
| 6748 | }, | ||
| 6749 | else => { | ||
| 6750 | const x = val.toUnsignedInt(target); | ||
| 6751 | return smallestUnsignedBits(x) + @boolToInt(sign); | ||
| 6752 | }, | ||
| 6753 | } | ||
| 6754 | } | ||
| 6755 | |||
| 6756 | /// Returns the smallest possible integer type containing both `min` and `max`. Asserts that neither | ||
| 6757 | /// value is undef. | ||
| 6758 | /// TODO: if #3806 is implemented, this becomes trivial | ||
| 6759 | pub fn intFittingRange(target: Target, arena: Allocator, min: Value, max: Value) !Type { | ||
| 6760 | assert(!min.isUndef()); | ||
| 6761 | assert(!max.isUndef()); | ||
| 6762 | |||
| 6763 | if (std.debug.runtime_safety) { | ||
| 6764 | assert(Value.order(min, max, target).compare(.lte)); | ||
| 6765 | } | ||
| 6766 | |||
| 6767 | const sign = min.orderAgainstZero() == .lt; | ||
| 6768 | |||
| 6769 | const min_val_bits = intBitsForValue(target, min, sign); | ||
| 6770 | const max_val_bits = intBitsForValue(target, max, sign); | ||
| 6771 | const bits = @max(min_val_bits, max_val_bits); | ||
| 6772 | |||
| 6773 | return intWithBits(arena, sign, bits); | ||
| 6774 | } | ||
| 6775 | |||
| 6776 | /// This is only used for comptime asserts. Bump this number when you make a change | 3538 | /// This is only used for comptime asserts. Bump this number when you make a change |
| 6777 | /// to packed struct layout to find out all the places in the codebase you need to edit! | 3539 | /// to packed struct layout to find out all the places in the codebase you need to edit! |
| 6778 | pub const packed_struct_layout_version = 2; | 3540 | pub const packed_struct_layout_version = 2; |
| 6779 | |||
| 6780 | /// This function is used in the debugger pretty formatters in tools/ to fetch the | ||
| 6781 | /// Tag to Payload mapping to facilitate fancy debug printing for this type. | ||
| 6782 | fn dbHelper(self: *Type, tag_to_payload_map: *map: { | ||
| 6783 | const tags = @typeInfo(Tag).Enum.fields; | ||
| 6784 | var fields: [tags.len]std.builtin.Type.StructField = undefined; | ||
| 6785 | for (&fields, tags) |*field, t| field.* = .{ | ||
| 6786 | .name = t.name, | ||
| 6787 | .type = *if (t.value < Tag.no_payload_count) void else @field(Tag, t.name).Type(), | ||
| 6788 | .default_value = null, | ||
| 6789 | .is_comptime = false, | ||
| 6790 | .alignment = 0, | ||
| 6791 | }; | ||
| 6792 | break :map @Type(.{ .Struct = .{ | ||
| 6793 | .layout = .Extern, | ||
| 6794 | .fields = &fields, | ||
| 6795 | .decls = &.{}, | ||
| 6796 | .is_tuple = false, | ||
| 6797 | } }); | ||
| 6798 | }) void { | ||
| 6799 | _ = self; | ||
| 6800 | _ = tag_to_payload_map; | ||
| 6801 | } | ||
| 6802 | |||
| 6803 | comptime { | ||
| 6804 | if (builtin.mode == .Debug) { | ||
| 6805 | _ = &dbHelper; | ||
| 6806 | } | ||
| 6807 | } | ||
| 6808 | }; | 3541 | }; |
src/value.zig+2265-3741| ... | @@ -11,147 +11,27 @@ const Module = @import("Module.zig"); | ... | @@ -11,147 +11,27 @@ const Module = @import("Module.zig"); |
| 11 | const Air = @import("Air.zig"); | 11 | const Air = @import("Air.zig"); |
| 12 | const TypedValue = @import("TypedValue.zig"); | 12 | const TypedValue = @import("TypedValue.zig"); |
| 13 | const Sema = @import("Sema.zig"); | 13 | const Sema = @import("Sema.zig"); |
| 14 | 14 | const InternPool = @import("InternPool.zig"); | |
| 15 | /// This is the raw data, with no bookkeeping, no memory awareness, | 15 | |
| 16 | /// no de-duplication, and no type system awareness. | 16 | pub const Value = struct { |
| 17 | /// It's important for this type to be small. | 17 | /// We are migrating towards using this for every Value object. However, many |
| 18 | /// This union takes advantage of the fact that the first page of memory | 18 | /// values are still represented the legacy way. This is indicated by using |
| 19 | /// is unmapped, giving us 4096 possible enum tags that have no payload. | 19 | /// InternPool.Index.none. |
| 20 | pub const Value = extern union { | 20 | ip_index: InternPool.Index, |
| 21 | /// If the tag value is less than Tag.no_payload_count, then no pointer | 21 | |
| 22 | /// dereference is needed. | 22 | /// This is the raw data, with no bookkeeping, no memory awareness, |
| 23 | tag_if_small_enough: Tag, | 23 | /// no de-duplication, and no type system awareness. |
| 24 | ptr_otherwise: *Payload, | 24 | /// This union takes advantage of the fact that the first page of memory |
| 25 | /// is unmapped, giving us 4096 possible enum tags that have no payload. | ||
| 26 | legacy: extern union { | ||
| 27 | ptr_otherwise: *Payload, | ||
| 28 | }, | ||
| 25 | 29 | ||
| 26 | // Keep in sync with tools/stage2_pretty_printers_common.py | 30 | // Keep in sync with tools/stage2_pretty_printers_common.py |
| 27 | pub const Tag = enum(usize) { | 31 | pub const Tag = enum(usize) { |
| 28 | // The first section of this enum are tags that require no payload. | 32 | // The first section of this enum are tags that require no payload. |
| 29 | u1_type, | ||
| 30 | u8_type, | ||
| 31 | i8_type, | ||
| 32 | u16_type, | ||
| 33 | i16_type, | ||
| 34 | u29_type, | ||
| 35 | u32_type, | ||
| 36 | i32_type, | ||
| 37 | u64_type, | ||
| 38 | i64_type, | ||
| 39 | u128_type, | ||
| 40 | i128_type, | ||
| 41 | usize_type, | ||
| 42 | isize_type, | ||
| 43 | c_char_type, | ||
| 44 | c_short_type, | ||
| 45 | c_ushort_type, | ||
| 46 | c_int_type, | ||
| 47 | c_uint_type, | ||
| 48 | c_long_type, | ||
| 49 | c_ulong_type, | ||
| 50 | c_longlong_type, | ||
| 51 | c_ulonglong_type, | ||
| 52 | c_longdouble_type, | ||
| 53 | f16_type, | ||
| 54 | f32_type, | ||
| 55 | f64_type, | ||
| 56 | f80_type, | ||
| 57 | f128_type, | ||
| 58 | anyopaque_type, | ||
| 59 | bool_type, | ||
| 60 | void_type, | ||
| 61 | type_type, | ||
| 62 | anyerror_type, | ||
| 63 | comptime_int_type, | ||
| 64 | comptime_float_type, | ||
| 65 | noreturn_type, | ||
| 66 | anyframe_type, | ||
| 67 | null_type, | ||
| 68 | undefined_type, | ||
| 69 | enum_literal_type, | ||
| 70 | atomic_order_type, | ||
| 71 | atomic_rmw_op_type, | ||
| 72 | calling_convention_type, | ||
| 73 | address_space_type, | ||
| 74 | float_mode_type, | ||
| 75 | reduce_op_type, | ||
| 76 | modifier_type, | ||
| 77 | prefetch_options_type, | ||
| 78 | export_options_type, | ||
| 79 | extern_options_type, | ||
| 80 | type_info_type, | ||
| 81 | manyptr_u8_type, | ||
| 82 | manyptr_const_u8_type, | ||
| 83 | manyptr_const_u8_sentinel_0_type, | ||
| 84 | fn_noreturn_no_args_type, | ||
| 85 | fn_void_no_args_type, | ||
| 86 | fn_naked_noreturn_no_args_type, | ||
| 87 | fn_ccc_void_no_args_type, | ||
| 88 | single_const_pointer_to_comptime_int_type, | ||
| 89 | const_slice_u8_type, | ||
| 90 | const_slice_u8_sentinel_0_type, | ||
| 91 | anyerror_void_error_union_type, | ||
| 92 | generic_poison_type, | ||
| 93 | |||
| 94 | undef, | ||
| 95 | zero, | ||
| 96 | one, | ||
| 97 | void_value, | ||
| 98 | unreachable_value, | ||
| 99 | /// The only possible value for a particular type, which is stored externally. | ||
| 100 | the_only_possible_value, | ||
| 101 | null_value, | ||
| 102 | bool_true, | ||
| 103 | bool_false, | ||
| 104 | generic_poison, | ||
| 105 | |||
| 106 | empty_struct_value, | ||
| 107 | empty_array, // See last_no_payload_tag below. | ||
| 108 | // After this, the tag requires a payload. | 33 | // After this, the tag requires a payload. |
| 109 | 34 | ||
| 110 | ty, | ||
| 111 | int_type, | ||
| 112 | int_u64, | ||
| 113 | int_i64, | ||
| 114 | int_big_positive, | ||
| 115 | int_big_negative, | ||
| 116 | function, | ||
| 117 | extern_fn, | ||
| 118 | variable, | ||
| 119 | /// A wrapper for values which are comptime-known but should | ||
| 120 | /// semantically be runtime-known. | ||
| 121 | runtime_value, | ||
| 122 | /// Represents a pointer to a Decl. | ||
| 123 | /// When machine codegen backend sees this, it must set the Decl's `alive` field to true. | ||
| 124 | decl_ref, | ||
| 125 | /// Pointer to a Decl, but allows comptime code to mutate the Decl's Value. | ||
| 126 | /// This Tag will never be seen by machine codegen backends. It is changed into a | ||
| 127 | /// `decl_ref` when a comptime variable goes out of scope. | ||
| 128 | decl_ref_mut, | ||
| 129 | /// Behaves like `decl_ref_mut` but validates that the stored value matches the field value. | ||
| 130 | comptime_field_ptr, | ||
| 131 | /// Pointer to a specific element of an array, vector or slice. | ||
| 132 | elem_ptr, | ||
| 133 | /// Pointer to a specific field of a struct or union. | ||
| 134 | field_ptr, | ||
| 135 | /// A slice of u8 whose memory is managed externally. | ||
| 136 | bytes, | ||
| 137 | /// Similar to bytes however it stores an index relative to `Module.string_literal_bytes`. | ||
| 138 | str_lit, | ||
| 139 | /// This value is repeated some number of times. The amount of times to repeat | ||
| 140 | /// is stored externally. | ||
| 141 | repeated, | ||
| 142 | /// An array with length 0 but it has a sentinel. | ||
| 143 | empty_array_sentinel, | ||
| 144 | /// Pointer and length as sub `Value` objects. | ||
| 145 | slice, | ||
| 146 | float_16, | ||
| 147 | float_32, | ||
| 148 | float_64, | ||
| 149 | float_80, | ||
| 150 | float_128, | ||
| 151 | enum_literal, | ||
| 152 | /// A specific enum tag, indicated by the field index (declaration order). | ||
| 153 | enum_field_index, | ||
| 154 | @"error", | ||
| 155 | /// When the type is error union: | 35 | /// When the type is error union: |
| 156 | /// * If the tag is `.@"error"`, the error union is an error. | 36 | /// * If the tag is `.@"error"`, the error union is an error. |
| 157 | /// * If the tag is `.eu_payload`, the error union is a payload. | 37 | /// * If the tag is `.eu_payload`, the error union is a payload. |
| ... | @@ -159,8 +39,6 @@ pub const Value = extern union { | ... | @@ -159,8 +39,6 @@ pub const Value = extern union { |
| 159 | /// is non-error, but the inner error union is an error, is represented as | 39 | /// is non-error, but the inner error union is an error, is represented as |
| 160 | /// a tag of `.eu_payload`, with a sub-tag of `.@"error"`. | 40 | /// a tag of `.eu_payload`, with a sub-tag of `.@"error"`. |
| 161 | eu_payload, | 41 | eu_payload, |
| 162 | /// A pointer to the payload of an error union, based on a pointer to an error union. | ||
| 163 | eu_payload_ptr, | ||
| 164 | /// When the type is optional: | 42 | /// When the type is optional: |
| 165 | /// * If the tag is `.null_value`, the optional is null. | 43 | /// * If the tag is `.null_value`, the optional is null. |
| 166 | /// * If the tag is `.opt_payload`, the optional is a payload. | 44 | /// * If the tag is `.opt_payload`, the optional is a payload. |
| ... | @@ -168,8 +46,13 @@ pub const Value = extern union { | ... | @@ -168,8 +46,13 @@ pub const Value = extern union { |
| 168 | /// is non-null, but the inner optional is null, is represented as | 46 | /// is non-null, but the inner optional is null, is represented as |
| 169 | /// a tag of `.opt_payload`, with a sub-tag of `.null_value`. | 47 | /// a tag of `.opt_payload`, with a sub-tag of `.null_value`. |
| 170 | opt_payload, | 48 | opt_payload, |
| 171 | /// A pointer to the payload of an optional, based on a pointer to an optional. | 49 | /// Pointer and length as sub `Value` objects. |
| 172 | opt_payload_ptr, | 50 | slice, |
| 51 | /// A slice of u8 whose memory is managed externally. | ||
| 52 | bytes, | ||
| 53 | /// This value is repeated some number of times. The amount of times to repeat | ||
| 54 | /// is stored externally. | ||
| 55 | repeated, | ||
| 173 | /// An instance of a struct, array, or vector. | 56 | /// An instance of a struct, array, or vector. |
| 174 | /// Each element/field stored as a `Value`. | 57 | /// Each element/field stored as a `Value`. |
| 175 | /// In the case of sentinel-terminated arrays, the sentinel value *is* stored, | 58 | /// In the case of sentinel-terminated arrays, the sentinel value *is* stored, |
| ... | @@ -177,152 +60,17 @@ pub const Value = extern union { | ... | @@ -177,152 +60,17 @@ pub const Value = extern union { |
| 177 | aggregate, | 60 | aggregate, |
| 178 | /// An instance of a union. | 61 | /// An instance of a union. |
| 179 | @"union", | 62 | @"union", |
| 180 | /// This is a special value that tracks a set of types that have been stored | ||
| 181 | /// to an inferred allocation. It does not support any of the normal value queries. | ||
| 182 | inferred_alloc, | ||
| 183 | /// Used to coordinate alloc_inferred, store_to_inferred_ptr, and resolve_inferred_alloc | ||
| 184 | /// instructions for comptime code. | ||
| 185 | inferred_alloc_comptime, | ||
| 186 | /// The ABI alignment of the payload type. | ||
| 187 | lazy_align, | ||
| 188 | /// The ABI size of the payload type. | ||
| 189 | lazy_size, | ||
| 190 | |||
| 191 | pub const last_no_payload_tag = Tag.empty_array; | ||
| 192 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; | ||
| 193 | 63 | ||
| 194 | pub fn Type(comptime t: Tag) type { | 64 | pub fn Type(comptime t: Tag) type { |
| 195 | return switch (t) { | 65 | return switch (t) { |
| 196 | .u1_type, | ||
| 197 | .u8_type, | ||
| 198 | .i8_type, | ||
| 199 | .u16_type, | ||
| 200 | .i16_type, | ||
| 201 | .u29_type, | ||
| 202 | .u32_type, | ||
| 203 | .i32_type, | ||
| 204 | .u64_type, | ||
| 205 | .i64_type, | ||
| 206 | .u128_type, | ||
| 207 | .i128_type, | ||
| 208 | .usize_type, | ||
| 209 | .isize_type, | ||
| 210 | .c_char_type, | ||
| 211 | .c_short_type, | ||
| 212 | .c_ushort_type, | ||
| 213 | .c_int_type, | ||
| 214 | .c_uint_type, | ||
| 215 | .c_long_type, | ||
| 216 | .c_ulong_type, | ||
| 217 | .c_longlong_type, | ||
| 218 | .c_ulonglong_type, | ||
| 219 | .c_longdouble_type, | ||
| 220 | .f16_type, | ||
| 221 | .f32_type, | ||
| 222 | .f64_type, | ||
| 223 | .f80_type, | ||
| 224 | .f128_type, | ||
| 225 | .anyopaque_type, | ||
| 226 | .bool_type, | ||
| 227 | .void_type, | ||
| 228 | .type_type, | ||
| 229 | .anyerror_type, | ||
| 230 | .comptime_int_type, | ||
| 231 | .comptime_float_type, | ||
| 232 | .noreturn_type, | ||
| 233 | .null_type, | ||
| 234 | .undefined_type, | ||
| 235 | .fn_noreturn_no_args_type, | ||
| 236 | .fn_void_no_args_type, | ||
| 237 | .fn_naked_noreturn_no_args_type, | ||
| 238 | .fn_ccc_void_no_args_type, | ||
| 239 | .single_const_pointer_to_comptime_int_type, | ||
| 240 | .anyframe_type, | ||
| 241 | .const_slice_u8_type, | ||
| 242 | .const_slice_u8_sentinel_0_type, | ||
| 243 | .anyerror_void_error_union_type, | ||
| 244 | .generic_poison_type, | ||
| 245 | .enum_literal_type, | ||
| 246 | .undef, | ||
| 247 | .zero, | ||
| 248 | .one, | ||
| 249 | .void_value, | ||
| 250 | .unreachable_value, | ||
| 251 | .the_only_possible_value, | ||
| 252 | .empty_struct_value, | ||
| 253 | .empty_array, | ||
| 254 | .null_value, | ||
| 255 | .bool_true, | ||
| 256 | .bool_false, | ||
| 257 | .manyptr_u8_type, | ||
| 258 | .manyptr_const_u8_type, | ||
| 259 | .manyptr_const_u8_sentinel_0_type, | ||
| 260 | .atomic_order_type, | ||
| 261 | .atomic_rmw_op_type, | ||
| 262 | .calling_convention_type, | ||
| 263 | .address_space_type, | ||
| 264 | .float_mode_type, | ||
| 265 | .reduce_op_type, | ||
| 266 | .modifier_type, | ||
| 267 | .prefetch_options_type, | ||
| 268 | .export_options_type, | ||
| 269 | .extern_options_type, | ||
| 270 | .type_info_type, | ||
| 271 | .generic_poison, | ||
| 272 | => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"), | ||
| 273 | |||
| 274 | .int_big_positive, | ||
| 275 | .int_big_negative, | ||
| 276 | => Payload.BigInt, | ||
| 277 | |||
| 278 | .extern_fn => Payload.ExternFn, | ||
| 279 | |||
| 280 | .decl_ref => Payload.Decl, | ||
| 281 | |||
| 282 | .repeated, | ||
| 283 | .eu_payload, | 66 | .eu_payload, |
| 284 | .opt_payload, | 67 | .opt_payload, |
| 285 | .empty_array_sentinel, | 68 | .repeated, |
| 286 | .runtime_value, | ||
| 287 | => Payload.SubValue, | 69 | => Payload.SubValue, |
| 288 | |||
| 289 | .eu_payload_ptr, | ||
| 290 | .opt_payload_ptr, | ||
| 291 | => Payload.PayloadPtr, | ||
| 292 | |||
| 293 | .bytes, | ||
| 294 | .enum_literal, | ||
| 295 | => Payload.Bytes, | ||
| 296 | |||
| 297 | .str_lit => Payload.StrLit, | ||
| 298 | .slice => Payload.Slice, | 70 | .slice => Payload.Slice, |
| 299 | 71 | .bytes => Payload.Bytes, | |
| 300 | .enum_field_index => Payload.U32, | ||
| 301 | |||
| 302 | .ty, | ||
| 303 | .lazy_align, | ||
| 304 | .lazy_size, | ||
| 305 | => Payload.Ty, | ||
| 306 | |||
| 307 | .int_type => Payload.IntType, | ||
| 308 | .int_u64 => Payload.U64, | ||
| 309 | .int_i64 => Payload.I64, | ||
| 310 | .function => Payload.Function, | ||
| 311 | .variable => Payload.Variable, | ||
| 312 | .decl_ref_mut => Payload.DeclRefMut, | ||
| 313 | .elem_ptr => Payload.ElemPtr, | ||
| 314 | .field_ptr => Payload.FieldPtr, | ||
| 315 | .float_16 => Payload.Float_16, | ||
| 316 | .float_32 => Payload.Float_32, | ||
| 317 | .float_64 => Payload.Float_64, | ||
| 318 | .float_80 => Payload.Float_80, | ||
| 319 | .float_128 => Payload.Float_128, | ||
| 320 | .@"error" => Payload.Error, | ||
| 321 | .inferred_alloc => Payload.InferredAlloc, | ||
| 322 | .inferred_alloc_comptime => Payload.InferredAllocComptime, | ||
| 323 | .aggregate => Payload.Aggregate, | 72 | .aggregate => Payload.Aggregate, |
| 324 | .@"union" => Payload.Union, | 73 | .@"union" => Payload.Union, |
| 325 | .comptime_field_ptr => Payload.ComptimeFieldPtr, | ||
| 326 | }; | 74 | }; |
| 327 | } | 75 | } |
| 328 | 76 | ||
| ... | @@ -332,7 +80,10 @@ pub const Value = extern union { | ... | @@ -332,7 +80,10 @@ pub const Value = extern union { |
| 332 | .base = .{ .tag = t }, | 80 | .base = .{ .tag = t }, |
| 333 | .data = data, | 81 | .data = data, |
| 334 | }; | 82 | }; |
| 335 | return Value{ .ptr_otherwise = &ptr.base }; | 83 | return Value{ |
| 84 | .ip_index = .none, | ||
| 85 | .legacy = .{ .ptr_otherwise = &ptr.base }, | ||
| 86 | }; | ||
| 336 | } | 87 | } |
| 337 | 88 | ||
| 338 | pub fn Data(comptime t: Tag) type { | 89 | pub fn Data(comptime t: Tag) type { |
| ... | @@ -340,39 +91,31 @@ pub const Value = extern union { | ... | @@ -340,39 +91,31 @@ pub const Value = extern union { |
| 340 | } | 91 | } |
| 341 | }; | 92 | }; |
| 342 | 93 | ||
| 343 | pub fn initTag(small_tag: Tag) Value { | ||
| 344 | assert(@enumToInt(small_tag) < Tag.no_payload_count); | ||
| 345 | return .{ .tag_if_small_enough = small_tag }; | ||
| 346 | } | ||
| 347 | |||
| 348 | pub fn initPayload(payload: *Payload) Value { | 94 | pub fn initPayload(payload: *Payload) Value { |
| 349 | assert(@enumToInt(payload.tag) >= Tag.no_payload_count); | 95 | return Value{ |
| 350 | return .{ .ptr_otherwise = payload }; | 96 | .ip_index = .none, |
| 97 | .legacy = .{ .ptr_otherwise = payload }, | ||
| 98 | }; | ||
| 351 | } | 99 | } |
| 352 | 100 | ||
| 353 | pub fn tag(self: Value) Tag { | 101 | pub fn tag(self: Value) Tag { |
| 354 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) { | 102 | assert(self.ip_index == .none); |
| 355 | return self.tag_if_small_enough; | 103 | return self.legacy.ptr_otherwise.tag; |
| 356 | } else { | ||
| 357 | return self.ptr_otherwise.tag; | ||
| 358 | } | ||
| 359 | } | 104 | } |
| 360 | 105 | ||
| 361 | /// Prefer `castTag` to this. | 106 | /// Prefer `castTag` to this. |
| 362 | pub fn cast(self: Value, comptime T: type) ?*T { | 107 | pub fn cast(self: Value, comptime T: type) ?*T { |
| 108 | if (self.ip_index != .none) { | ||
| 109 | return null; | ||
| 110 | } | ||
| 363 | if (@hasField(T, "base_tag")) { | 111 | if (@hasField(T, "base_tag")) { |
| 364 | return self.castTag(T.base_tag); | 112 | return self.castTag(T.base_tag); |
| 365 | } | 113 | } |
| 366 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) { | ||
| 367 | return null; | ||
| 368 | } | ||
| 369 | inline for (@typeInfo(Tag).Enum.fields) |field| { | 114 | inline for (@typeInfo(Tag).Enum.fields) |field| { |
| 370 | if (field.value < Tag.no_payload_count) | ||
| 371 | continue; | ||
| 372 | const t = @intToEnum(Tag, field.value); | 115 | const t = @intToEnum(Tag, field.value); |
| 373 | if (self.ptr_otherwise.tag == t) { | 116 | if (self.legacy.ptr_otherwise.tag == t) { |
| 374 | if (T == t.Type()) { | 117 | if (T == t.Type()) { |
| 375 | return @fieldParentPtr(T, "base", self.ptr_otherwise); | 118 | return @fieldParentPtr(T, "base", self.legacy.ptr_otherwise); |
| 376 | } | 119 | } |
| 377 | return null; | 120 | return null; |
| 378 | } | 121 | } |
| ... | @@ -381,11 +124,10 @@ pub const Value = extern union { | ... | @@ -381,11 +124,10 @@ pub const Value = extern union { |
| 381 | } | 124 | } |
| 382 | 125 | ||
| 383 | pub fn castTag(self: Value, comptime t: Tag) ?*t.Type() { | 126 | pub fn castTag(self: Value, comptime t: Tag) ?*t.Type() { |
| 384 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) | 127 | if (self.ip_index != .none) return null; |
| 385 | return null; | ||
| 386 | 128 | ||
| 387 | if (self.ptr_otherwise.tag == t) | 129 | if (self.legacy.ptr_otherwise.tag == t) |
| 388 | return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise); | 130 | return @fieldParentPtr(t.Type(), "base", self.legacy.ptr_otherwise); |
| 389 | 131 | ||
| 390 | return null; | 132 | return null; |
| 391 | } | 133 | } |
| ... | @@ -393,165 +135,10 @@ pub const Value = extern union { | ... | @@ -393,165 +135,10 @@ pub const Value = extern union { |
| 393 | /// It's intentional that this function is not passed a corresponding Type, so that | 135 | /// It's intentional that this function is not passed a corresponding Type, so that |
| 394 | /// a Value can be copied from a Sema to a Decl prior to resolving struct/union field types. | 136 | /// a Value can be copied from a Sema to a Decl prior to resolving struct/union field types. |
| 395 | pub fn copy(self: Value, arena: Allocator) error{OutOfMemory}!Value { | 137 | pub fn copy(self: Value, arena: Allocator) error{OutOfMemory}!Value { |
| 396 | if (@enumToInt(self.tag_if_small_enough) < Tag.no_payload_count) { | 138 | if (self.ip_index != .none) { |
| 397 | return Value{ .tag_if_small_enough = self.tag_if_small_enough }; | 139 | return Value{ .ip_index = self.ip_index, .legacy = undefined }; |
| 398 | } else switch (self.ptr_otherwise.tag) { | 140 | } |
| 399 | .u1_type, | 141 | switch (self.legacy.ptr_otherwise.tag) { |
| 400 | .u8_type, | ||
| 401 | .i8_type, | ||
| 402 | .u16_type, | ||
| 403 | .i16_type, | ||
| 404 | .u29_type, | ||
| 405 | .u32_type, | ||
| 406 | .i32_type, | ||
| 407 | .u64_type, | ||
| 408 | .i64_type, | ||
| 409 | .u128_type, | ||
| 410 | .i128_type, | ||
| 411 | .usize_type, | ||
| 412 | .isize_type, | ||
| 413 | .c_char_type, | ||
| 414 | .c_short_type, | ||
| 415 | .c_ushort_type, | ||
| 416 | .c_int_type, | ||
| 417 | .c_uint_type, | ||
| 418 | .c_long_type, | ||
| 419 | .c_ulong_type, | ||
| 420 | .c_longlong_type, | ||
| 421 | .c_ulonglong_type, | ||
| 422 | .c_longdouble_type, | ||
| 423 | .f16_type, | ||
| 424 | .f32_type, | ||
| 425 | .f64_type, | ||
| 426 | .f80_type, | ||
| 427 | .f128_type, | ||
| 428 | .anyopaque_type, | ||
| 429 | .bool_type, | ||
| 430 | .void_type, | ||
| 431 | .type_type, | ||
| 432 | .anyerror_type, | ||
| 433 | .comptime_int_type, | ||
| 434 | .comptime_float_type, | ||
| 435 | .noreturn_type, | ||
| 436 | .null_type, | ||
| 437 | .undefined_type, | ||
| 438 | .fn_noreturn_no_args_type, | ||
| 439 | .fn_void_no_args_type, | ||
| 440 | .fn_naked_noreturn_no_args_type, | ||
| 441 | .fn_ccc_void_no_args_type, | ||
| 442 | .single_const_pointer_to_comptime_int_type, | ||
| 443 | .anyframe_type, | ||
| 444 | .const_slice_u8_type, | ||
| 445 | .const_slice_u8_sentinel_0_type, | ||
| 446 | .anyerror_void_error_union_type, | ||
| 447 | .generic_poison_type, | ||
| 448 | .enum_literal_type, | ||
| 449 | .undef, | ||
| 450 | .zero, | ||
| 451 | .one, | ||
| 452 | .void_value, | ||
| 453 | .unreachable_value, | ||
| 454 | .the_only_possible_value, | ||
| 455 | .empty_array, | ||
| 456 | .null_value, | ||
| 457 | .bool_true, | ||
| 458 | .bool_false, | ||
| 459 | .empty_struct_value, | ||
| 460 | .manyptr_u8_type, | ||
| 461 | .manyptr_const_u8_type, | ||
| 462 | .manyptr_const_u8_sentinel_0_type, | ||
| 463 | .atomic_order_type, | ||
| 464 | .atomic_rmw_op_type, | ||
| 465 | .calling_convention_type, | ||
| 466 | .address_space_type, | ||
| 467 | .float_mode_type, | ||
| 468 | .reduce_op_type, | ||
| 469 | .modifier_type, | ||
| 470 | .prefetch_options_type, | ||
| 471 | .export_options_type, | ||
| 472 | .extern_options_type, | ||
| 473 | .type_info_type, | ||
| 474 | .generic_poison, | ||
| 475 | => unreachable, | ||
| 476 | |||
| 477 | .ty, .lazy_align, .lazy_size => { | ||
| 478 | const payload = self.cast(Payload.Ty).?; | ||
| 479 | const new_payload = try arena.create(Payload.Ty); | ||
| 480 | new_payload.* = .{ | ||
| 481 | .base = payload.base, | ||
| 482 | .data = try payload.data.copy(arena), | ||
| 483 | }; | ||
| 484 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 485 | }, | ||
| 486 | .int_type => return self.copyPayloadShallow(arena, Payload.IntType), | ||
| 487 | .int_u64 => return self.copyPayloadShallow(arena, Payload.U64), | ||
| 488 | .int_i64 => return self.copyPayloadShallow(arena, Payload.I64), | ||
| 489 | .int_big_positive, .int_big_negative => { | ||
| 490 | const old_payload = self.cast(Payload.BigInt).?; | ||
| 491 | const new_payload = try arena.create(Payload.BigInt); | ||
| 492 | new_payload.* = .{ | ||
| 493 | .base = .{ .tag = self.ptr_otherwise.tag }, | ||
| 494 | .data = try arena.dupe(std.math.big.Limb, old_payload.data), | ||
| 495 | }; | ||
| 496 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 497 | }, | ||
| 498 | .function => return self.copyPayloadShallow(arena, Payload.Function), | ||
| 499 | .extern_fn => return self.copyPayloadShallow(arena, Payload.ExternFn), | ||
| 500 | .variable => return self.copyPayloadShallow(arena, Payload.Variable), | ||
| 501 | .decl_ref => return self.copyPayloadShallow(arena, Payload.Decl), | ||
| 502 | .decl_ref_mut => return self.copyPayloadShallow(arena, Payload.DeclRefMut), | ||
| 503 | .eu_payload_ptr, | ||
| 504 | .opt_payload_ptr, | ||
| 505 | => { | ||
| 506 | const payload = self.cast(Payload.PayloadPtr).?; | ||
| 507 | const new_payload = try arena.create(Payload.PayloadPtr); | ||
| 508 | new_payload.* = .{ | ||
| 509 | .base = payload.base, | ||
| 510 | .data = .{ | ||
| 511 | .container_ptr = try payload.data.container_ptr.copy(arena), | ||
| 512 | .container_ty = try payload.data.container_ty.copy(arena), | ||
| 513 | }, | ||
| 514 | }; | ||
| 515 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 516 | }, | ||
| 517 | .comptime_field_ptr => { | ||
| 518 | const payload = self.cast(Payload.ComptimeFieldPtr).?; | ||
| 519 | const new_payload = try arena.create(Payload.ComptimeFieldPtr); | ||
| 520 | new_payload.* = .{ | ||
| 521 | .base = payload.base, | ||
| 522 | .data = .{ | ||
| 523 | .field_val = try payload.data.field_val.copy(arena), | ||
| 524 | .field_ty = try payload.data.field_ty.copy(arena), | ||
| 525 | }, | ||
| 526 | }; | ||
| 527 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 528 | }, | ||
| 529 | .elem_ptr => { | ||
| 530 | const payload = self.castTag(.elem_ptr).?; | ||
| 531 | const new_payload = try arena.create(Payload.ElemPtr); | ||
| 532 | new_payload.* = .{ | ||
| 533 | .base = payload.base, | ||
| 534 | .data = .{ | ||
| 535 | .array_ptr = try payload.data.array_ptr.copy(arena), | ||
| 536 | .elem_ty = try payload.data.elem_ty.copy(arena), | ||
| 537 | .index = payload.data.index, | ||
| 538 | }, | ||
| 539 | }; | ||
| 540 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 541 | }, | ||
| 542 | .field_ptr => { | ||
| 543 | const payload = self.castTag(.field_ptr).?; | ||
| 544 | const new_payload = try arena.create(Payload.FieldPtr); | ||
| 545 | new_payload.* = .{ | ||
| 546 | .base = payload.base, | ||
| 547 | .data = .{ | ||
| 548 | .container_ptr = try payload.data.container_ptr.copy(arena), | ||
| 549 | .container_ty = try payload.data.container_ty.copy(arena), | ||
| 550 | .field_index = payload.data.field_index, | ||
| 551 | }, | ||
| 552 | }; | ||
| 553 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 554 | }, | ||
| 555 | .bytes => { | 142 | .bytes => { |
| 556 | const bytes = self.castTag(.bytes).?.data; | 143 | const bytes = self.castTag(.bytes).?.data; |
| 557 | const new_payload = try arena.create(Payload.Bytes); | 144 | const new_payload = try arena.create(Payload.Bytes); |
| ... | @@ -559,14 +146,14 @@ pub const Value = extern union { | ... | @@ -559,14 +146,14 @@ pub const Value = extern union { |
| 559 | .base = .{ .tag = .bytes }, | 146 | .base = .{ .tag = .bytes }, |
| 560 | .data = try arena.dupe(u8, bytes), | 147 | .data = try arena.dupe(u8, bytes), |
| 561 | }; | 148 | }; |
| 562 | return Value{ .ptr_otherwise = &new_payload.base }; | 149 | return Value{ |
| 150 | .ip_index = .none, | ||
| 151 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | ||
| 152 | }; | ||
| 563 | }, | 153 | }, |
| 564 | .str_lit => return self.copyPayloadShallow(arena, Payload.StrLit), | ||
| 565 | .repeated, | ||
| 566 | .eu_payload, | 154 | .eu_payload, |
| 567 | .opt_payload, | 155 | .opt_payload, |
| 568 | .empty_array_sentinel, | 156 | .repeated, |
| 569 | .runtime_value, | ||
| 570 | => { | 157 | => { |
| 571 | const payload = self.cast(Payload.SubValue).?; | 158 | const payload = self.cast(Payload.SubValue).?; |
| 572 | const new_payload = try arena.create(Payload.SubValue); | 159 | const new_payload = try arena.create(Payload.SubValue); |
| ... | @@ -574,7 +161,10 @@ pub const Value = extern union { | ... | @@ -574,7 +161,10 @@ pub const Value = extern union { |
| 574 | .base = payload.base, | 161 | .base = payload.base, |
| 575 | .data = try payload.data.copy(arena), | 162 | .data = try payload.data.copy(arena), |
| 576 | }; | 163 | }; |
| 577 | return Value{ .ptr_otherwise = &new_payload.base }; | 164 | return Value{ |
| 165 | .ip_index = .none, | ||
| 166 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | ||
| 167 | }; | ||
| 578 | }, | 168 | }, |
| 579 | .slice => { | 169 | .slice => { |
| 580 | const payload = self.castTag(.slice).?; | 170 | const payload = self.castTag(.slice).?; |
| ... | @@ -586,25 +176,11 @@ pub const Value = extern union { | ... | @@ -586,25 +176,11 @@ pub const Value = extern union { |
| 586 | .len = try payload.data.len.copy(arena), | 176 | .len = try payload.data.len.copy(arena), |
| 587 | }, | 177 | }, |
| 588 | }; | 178 | }; |
| 589 | return Value{ .ptr_otherwise = &new_payload.base }; | 179 | return Value{ |
| 590 | }, | 180 | .ip_index = .none, |
| 591 | .float_16 => return self.copyPayloadShallow(arena, Payload.Float_16), | 181 | .legacy = .{ .ptr_otherwise = &new_payload.base }, |
| 592 | .float_32 => return self.copyPayloadShallow(arena, Payload.Float_32), | ||
| 593 | .float_64 => return self.copyPayloadShallow(arena, Payload.Float_64), | ||
| 594 | .float_80 => return self.copyPayloadShallow(arena, Payload.Float_80), | ||
| 595 | .float_128 => return self.copyPayloadShallow(arena, Payload.Float_128), | ||
| 596 | .enum_literal => { | ||
| 597 | const payload = self.castTag(.enum_literal).?; | ||
| 598 | const new_payload = try arena.create(Payload.Bytes); | ||
| 599 | new_payload.* = .{ | ||
| 600 | .base = payload.base, | ||
| 601 | .data = try arena.dupe(u8, payload.data), | ||
| 602 | }; | 182 | }; |
| 603 | return Value{ .ptr_otherwise = &new_payload.base }; | ||
| 604 | }, | 183 | }, |
| 605 | .enum_field_index => return self.copyPayloadShallow(arena, Payload.U32), | ||
| 606 | .@"error" => return self.copyPayloadShallow(arena, Payload.Error), | ||
| 607 | |||
| 608 | .aggregate => { | 184 | .aggregate => { |
| 609 | const payload = self.castTag(.aggregate).?; | 185 | const payload = self.castTag(.aggregate).?; |
| 610 | const new_payload = try arena.create(Payload.Aggregate); | 186 | const new_payload = try arena.create(Payload.Aggregate); |
| ... | @@ -615,9 +191,11 @@ pub const Value = extern union { | ... | @@ -615,9 +191,11 @@ pub const Value = extern union { |
| 615 | for (new_payload.data, 0..) |*elem, i| { | 191 | for (new_payload.data, 0..) |*elem, i| { |
| 616 | elem.* = try payload.data[i].copy(arena); | 192 | elem.* = try payload.data[i].copy(arena); |
| 617 | } | 193 | } |
| 618 | return Value{ .ptr_otherwise = &new_payload.base }; | 194 | return Value{ |
| 195 | .ip_index = .none, | ||
| 196 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | ||
| 197 | }; | ||
| 619 | }, | 198 | }, |
| 620 | |||
| 621 | .@"union" => { | 199 | .@"union" => { |
| 622 | const tag_and_val = self.castTag(.@"union").?.data; | 200 | const tag_and_val = self.castTag(.@"union").?.data; |
| 623 | const new_payload = try arena.create(Payload.Union); | 201 | const new_payload = try arena.create(Payload.Union); |
| ... | @@ -628,11 +206,11 @@ pub const Value = extern union { | ... | @@ -628,11 +206,11 @@ pub const Value = extern union { |
| 628 | .val = try tag_and_val.val.copy(arena), | 206 | .val = try tag_and_val.val.copy(arena), |
| 629 | }, | 207 | }, |
| 630 | }; | 208 | }; |
| 631 | return Value{ .ptr_otherwise = &new_payload.base }; | 209 | return Value{ |
| 210 | .ip_index = .none, | ||
| 211 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | ||
| 212 | }; | ||
| 632 | }, | 213 | }, |
| 633 | |||
| 634 | .inferred_alloc => unreachable, | ||
| 635 | .inferred_alloc_comptime => unreachable, | ||
| 636 | } | 214 | } |
| 637 | } | 215 | } |
| 638 | 216 | ||
| ... | @@ -640,7 +218,10 @@ pub const Value = extern union { | ... | @@ -640,7 +218,10 @@ pub const Value = extern union { |
| 640 | const payload = self.cast(T).?; | 218 | const payload = self.cast(T).?; |
| 641 | const new_payload = try arena.create(T); | 219 | const new_payload = try arena.create(T); |
| 642 | new_payload.* = payload.*; | 220 | new_payload.* = payload.*; |
| 643 | return Value{ .ptr_otherwise = &new_payload.base }; | 221 | return Value{ |
| 222 | .ip_index = .none, | ||
| 223 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | ||
| 224 | }; | ||
| 644 | } | 225 | } |
| 645 | 226 | ||
| 646 | pub fn format(val: Value, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | 227 | pub fn format(val: Value, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { |
| ... | @@ -656,181 +237,36 @@ pub const Value = extern union { | ... | @@ -656,181 +237,36 @@ pub const Value = extern union { |
| 656 | pub fn dump( | 237 | pub fn dump( |
| 657 | start_val: Value, | 238 | start_val: Value, |
| 658 | comptime fmt: []const u8, | 239 | comptime fmt: []const u8, |
| 659 | options: std.fmt.FormatOptions, | 240 | _: std.fmt.FormatOptions, |
| 660 | out_stream: anytype, | 241 | out_stream: anytype, |
| 661 | ) !void { | 242 | ) !void { |
| 662 | comptime assert(fmt.len == 0); | 243 | comptime assert(fmt.len == 0); |
| 244 | if (start_val.ip_index != .none) { | ||
| 245 | try out_stream.print("(interned: {})", .{start_val.toIntern()}); | ||
| 246 | return; | ||
| 247 | } | ||
| 663 | var val = start_val; | 248 | var val = start_val; |
| 664 | while (true) switch (val.tag()) { | 249 | while (true) switch (val.tag()) { |
| 665 | .u1_type => return out_stream.writeAll("u1"), | ||
| 666 | .u8_type => return out_stream.writeAll("u8"), | ||
| 667 | .i8_type => return out_stream.writeAll("i8"), | ||
| 668 | .u16_type => return out_stream.writeAll("u16"), | ||
| 669 | .u29_type => return out_stream.writeAll("u29"), | ||
| 670 | .i16_type => return out_stream.writeAll("i16"), | ||
| 671 | .u32_type => return out_stream.writeAll("u32"), | ||
| 672 | .i32_type => return out_stream.writeAll("i32"), | ||
| 673 | .u64_type => return out_stream.writeAll("u64"), | ||
| 674 | .i64_type => return out_stream.writeAll("i64"), | ||
| 675 | .u128_type => return out_stream.writeAll("u128"), | ||
| 676 | .i128_type => return out_stream.writeAll("i128"), | ||
| 677 | .isize_type => return out_stream.writeAll("isize"), | ||
| 678 | .usize_type => return out_stream.writeAll("usize"), | ||
| 679 | .c_char_type => return out_stream.writeAll("c_char"), | ||
| 680 | .c_short_type => return out_stream.writeAll("c_short"), | ||
| 681 | .c_ushort_type => return out_stream.writeAll("c_ushort"), | ||
| 682 | .c_int_type => return out_stream.writeAll("c_int"), | ||
| 683 | .c_uint_type => return out_stream.writeAll("c_uint"), | ||
| 684 | .c_long_type => return out_stream.writeAll("c_long"), | ||
| 685 | .c_ulong_type => return out_stream.writeAll("c_ulong"), | ||
| 686 | .c_longlong_type => return out_stream.writeAll("c_longlong"), | ||
| 687 | .c_ulonglong_type => return out_stream.writeAll("c_ulonglong"), | ||
| 688 | .c_longdouble_type => return out_stream.writeAll("c_longdouble"), | ||
| 689 | .f16_type => return out_stream.writeAll("f16"), | ||
| 690 | .f32_type => return out_stream.writeAll("f32"), | ||
| 691 | .f64_type => return out_stream.writeAll("f64"), | ||
| 692 | .f80_type => return out_stream.writeAll("f80"), | ||
| 693 | .f128_type => return out_stream.writeAll("f128"), | ||
| 694 | .anyopaque_type => return out_stream.writeAll("anyopaque"), | ||
| 695 | .bool_type => return out_stream.writeAll("bool"), | ||
| 696 | .void_type => return out_stream.writeAll("void"), | ||
| 697 | .type_type => return out_stream.writeAll("type"), | ||
| 698 | .anyerror_type => return out_stream.writeAll("anyerror"), | ||
| 699 | .comptime_int_type => return out_stream.writeAll("comptime_int"), | ||
| 700 | .comptime_float_type => return out_stream.writeAll("comptime_float"), | ||
| 701 | .noreturn_type => return out_stream.writeAll("noreturn"), | ||
| 702 | .null_type => return out_stream.writeAll("@Type(.Null)"), | ||
| 703 | .undefined_type => return out_stream.writeAll("@Type(.Undefined)"), | ||
| 704 | .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"), | ||
| 705 | .fn_void_no_args_type => return out_stream.writeAll("fn() void"), | ||
| 706 | .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), | ||
| 707 | .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), | ||
| 708 | .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"), | ||
| 709 | .anyframe_type => return out_stream.writeAll("anyframe"), | ||
| 710 | .const_slice_u8_type => return out_stream.writeAll("[]const u8"), | ||
| 711 | .const_slice_u8_sentinel_0_type => return out_stream.writeAll("[:0]const u8"), | ||
| 712 | .anyerror_void_error_union_type => return out_stream.writeAll("anyerror!void"), | ||
| 713 | .generic_poison_type => return out_stream.writeAll("(generic poison type)"), | ||
| 714 | .generic_poison => return out_stream.writeAll("(generic poison)"), | ||
| 715 | .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"), | ||
| 716 | .manyptr_u8_type => return out_stream.writeAll("[*]u8"), | ||
| 717 | .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"), | ||
| 718 | .manyptr_const_u8_sentinel_0_type => return out_stream.writeAll("[*:0]const u8"), | ||
| 719 | .atomic_order_type => return out_stream.writeAll("std.builtin.AtomicOrder"), | ||
| 720 | .atomic_rmw_op_type => return out_stream.writeAll("std.builtin.AtomicRmwOp"), | ||
| 721 | .calling_convention_type => return out_stream.writeAll("std.builtin.CallingConvention"), | ||
| 722 | .address_space_type => return out_stream.writeAll("std.builtin.AddressSpace"), | ||
| 723 | .float_mode_type => return out_stream.writeAll("std.builtin.FloatMode"), | ||
| 724 | .reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"), | ||
| 725 | .modifier_type => return out_stream.writeAll("std.builtin.CallModifier"), | ||
| 726 | .prefetch_options_type => return out_stream.writeAll("std.builtin.PrefetchOptions"), | ||
| 727 | .export_options_type => return out_stream.writeAll("std.builtin.ExportOptions"), | ||
| 728 | .extern_options_type => return out_stream.writeAll("std.builtin.ExternOptions"), | ||
| 729 | .type_info_type => return out_stream.writeAll("std.builtin.Type"), | ||
| 730 | |||
| 731 | .empty_struct_value => return out_stream.writeAll("struct {}{}"), | ||
| 732 | .aggregate => { | 250 | .aggregate => { |
| 733 | return out_stream.writeAll("(aggregate)"); | 251 | return out_stream.writeAll("(aggregate)"); |
| 734 | }, | 252 | }, |
| 735 | .@"union" => { | 253 | .@"union" => { |
| 736 | return out_stream.writeAll("(union value)"); | 254 | return out_stream.writeAll("(union value)"); |
| 737 | }, | 255 | }, |
| 738 | .null_value => return out_stream.writeAll("null"), | ||
| 739 | .undef => return out_stream.writeAll("undefined"), | ||
| 740 | .zero => return out_stream.writeAll("0"), | ||
| 741 | .one => return out_stream.writeAll("1"), | ||
| 742 | .void_value => return out_stream.writeAll("{}"), | ||
| 743 | .unreachable_value => return out_stream.writeAll("unreachable"), | ||
| 744 | .the_only_possible_value => return out_stream.writeAll("(the only possible value)"), | ||
| 745 | .bool_true => return out_stream.writeAll("true"), | ||
| 746 | .bool_false => return out_stream.writeAll("false"), | ||
| 747 | .ty => return val.castTag(.ty).?.data.dump("", options, out_stream), | ||
| 748 | .lazy_align => { | ||
| 749 | try out_stream.writeAll("@alignOf("); | ||
| 750 | try val.castTag(.lazy_align).?.data.dump("", options, out_stream); | ||
| 751 | return try out_stream.writeAll(")"); | ||
| 752 | }, | ||
| 753 | .lazy_size => { | ||
| 754 | try out_stream.writeAll("@sizeOf("); | ||
| 755 | try val.castTag(.lazy_size).?.data.dump("", options, out_stream); | ||
| 756 | return try out_stream.writeAll(")"); | ||
| 757 | }, | ||
| 758 | .int_type => { | ||
| 759 | const int_type = val.castTag(.int_type).?.data; | ||
| 760 | return out_stream.print("{s}{d}", .{ | ||
| 761 | if (int_type.signed) "s" else "u", | ||
| 762 | int_type.bits, | ||
| 763 | }); | ||
| 764 | }, | ||
| 765 | .int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", options, out_stream), | ||
| 766 | .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, out_stream), | ||
| 767 | .int_big_positive => return out_stream.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}), | ||
| 768 | .int_big_negative => return out_stream.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}), | ||
| 769 | .runtime_value => return out_stream.writeAll("[runtime value]"), | ||
| 770 | .function => return out_stream.print("(function decl={d})", .{val.castTag(.function).?.data.owner_decl}), | ||
| 771 | .extern_fn => return out_stream.writeAll("(extern function)"), | ||
| 772 | .variable => return out_stream.writeAll("(variable)"), | ||
| 773 | .decl_ref_mut => { | ||
| 774 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | ||
| 775 | return out_stream.print("(decl_ref_mut {d})", .{decl_index}); | ||
| 776 | }, | ||
| 777 | .decl_ref => { | ||
| 778 | const decl_index = val.castTag(.decl_ref).?.data; | ||
| 779 | return out_stream.print("(decl_ref {d})", .{decl_index}); | ||
| 780 | }, | ||
| 781 | .comptime_field_ptr => { | ||
| 782 | return out_stream.writeAll("(comptime_field_ptr)"); | ||
| 783 | }, | ||
| 784 | .elem_ptr => { | ||
| 785 | const elem_ptr = val.castTag(.elem_ptr).?.data; | ||
| 786 | try out_stream.print("&[{}] ", .{elem_ptr.index}); | ||
| 787 | val = elem_ptr.array_ptr; | ||
| 788 | }, | ||
| 789 | .field_ptr => { | ||
| 790 | const field_ptr = val.castTag(.field_ptr).?.data; | ||
| 791 | try out_stream.print("fieldptr({d}) ", .{field_ptr.field_index}); | ||
| 792 | val = field_ptr.container_ptr; | ||
| 793 | }, | ||
| 794 | .empty_array => return out_stream.writeAll(".{}"), | ||
| 795 | .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}), | ||
| 796 | .enum_field_index => return out_stream.print("(enum field {d})", .{val.castTag(.enum_field_index).?.data}), | ||
| 797 | .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}), | 256 | .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}), |
| 798 | .str_lit => { | ||
| 799 | const str_lit = val.castTag(.str_lit).?.data; | ||
| 800 | return out_stream.print("(.str_lit index={d} len={d})", .{ | ||
| 801 | str_lit.index, str_lit.len, | ||
| 802 | }); | ||
| 803 | }, | ||
| 804 | .repeated => { | 257 | .repeated => { |
| 805 | try out_stream.writeAll("(repeated) "); | 258 | try out_stream.writeAll("(repeated) "); |
| 806 | val = val.castTag(.repeated).?.data; | 259 | val = val.castTag(.repeated).?.data; |
| 807 | }, | 260 | }, |
| 808 | .empty_array_sentinel => return out_stream.writeAll("(empty array with sentinel)"), | ||
| 809 | .slice => return out_stream.writeAll("(slice)"), | ||
| 810 | .float_16 => return out_stream.print("{}", .{val.castTag(.float_16).?.data}), | ||
| 811 | .float_32 => return out_stream.print("{}", .{val.castTag(.float_32).?.data}), | ||
| 812 | .float_64 => return out_stream.print("{}", .{val.castTag(.float_64).?.data}), | ||
| 813 | .float_80 => return out_stream.print("{}", .{val.castTag(.float_80).?.data}), | ||
| 814 | .float_128 => return out_stream.print("{}", .{val.castTag(.float_128).?.data}), | ||
| 815 | .@"error" => return out_stream.print("error.{s}", .{val.castTag(.@"error").?.data.name}), | ||
| 816 | .eu_payload => { | 261 | .eu_payload => { |
| 817 | try out_stream.writeAll("(eu_payload) "); | 262 | try out_stream.writeAll("(eu_payload) "); |
| 818 | val = val.castTag(.eu_payload).?.data; | 263 | val = val.castTag(.repeated).?.data; |
| 819 | }, | 264 | }, |
| 820 | .opt_payload => { | 265 | .opt_payload => { |
| 821 | try out_stream.writeAll("(opt_payload) "); | 266 | try out_stream.writeAll("(opt_payload) "); |
| 822 | val = val.castTag(.opt_payload).?.data; | 267 | val = val.castTag(.repeated).?.data; |
| 823 | }, | ||
| 824 | .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"), | ||
| 825 | .inferred_alloc_comptime => return out_stream.writeAll("(inferred comptime allocation value)"), | ||
| 826 | .eu_payload_ptr => { | ||
| 827 | try out_stream.writeAll("(eu_payload_ptr)"); | ||
| 828 | val = val.castTag(.eu_payload_ptr).?.data.container_ptr; | ||
| 829 | }, | ||
| 830 | .opt_payload_ptr => { | ||
| 831 | try out_stream.writeAll("(opt_payload_ptr)"); | ||
| 832 | val = val.castTag(.opt_payload_ptr).?.data.container_ptr; | ||
| 833 | }, | 268 | }, |
| 269 | .slice => return out_stream.writeAll("(slice)"), | ||
| 834 | }; | 270 | }; |
| 835 | } | 271 | } |
| 836 | 272 | ||
| ... | @@ -845,421 +281,404 @@ pub const Value = extern union { | ... | @@ -845,421 +281,404 @@ pub const Value = extern union { |
| 845 | } }; | 281 | } }; |
| 846 | } | 282 | } |
| 847 | 283 | ||
| 284 | /// Asserts that the value is representable as an array of bytes. | ||
| 285 | /// Returns the value as a null-terminated string stored in the InternPool. | ||
| 286 | pub fn toIpString(val: Value, ty: Type, mod: *Module) !InternPool.NullTerminatedString { | ||
| 287 | const ip = &mod.intern_pool; | ||
| 288 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { | ||
| 289 | .enum_literal => |enum_literal| enum_literal, | ||
| 290 | .ptr => |ptr| switch (ptr.len) { | ||
| 291 | .none => unreachable, | ||
| 292 | else => try arrayToIpString(val, ptr.len.toValue().toUnsignedInt(mod), mod), | ||
| 293 | }, | ||
| 294 | .aggregate => |aggregate| switch (aggregate.storage) { | ||
| 295 | .bytes => |bytes| try ip.getOrPutString(mod.gpa, bytes), | ||
| 296 | .elems => try arrayToIpString(val, ty.arrayLen(mod), mod), | ||
| 297 | .repeated_elem => |elem| { | ||
| 298 | const byte = @intCast(u8, elem.toValue().toUnsignedInt(mod)); | ||
| 299 | const len = @intCast(usize, ty.arrayLen(mod)); | ||
| 300 | try ip.string_bytes.appendNTimes(mod.gpa, byte, len); | ||
| 301 | return ip.getOrPutTrailingString(mod.gpa, len); | ||
| 302 | }, | ||
| 303 | }, | ||
| 304 | else => unreachable, | ||
| 305 | }; | ||
| 306 | } | ||
| 307 | |||
| 848 | /// Asserts that the value is representable as an array of bytes. | 308 | /// Asserts that the value is representable as an array of bytes. |
| 849 | /// Copies the value into a freshly allocated slice of memory, which is owned by the caller. | 309 | /// Copies the value into a freshly allocated slice of memory, which is owned by the caller. |
| 850 | pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, mod: *Module) ![]u8 { | 310 | pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, mod: *Module) ![]u8 { |
| 851 | const target = mod.getTarget(); | 311 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 852 | switch (val.tag()) { | 312 | .enum_literal => |enum_literal| allocator.dupe(u8, mod.intern_pool.stringToSlice(enum_literal)), |
| 853 | .bytes => { | 313 | .ptr => |ptr| switch (ptr.len) { |
| 854 | const bytes = val.castTag(.bytes).?.data; | 314 | .none => unreachable, |
| 855 | const adjusted_len = bytes.len - @boolToInt(ty.sentinel() != null); | 315 | else => try arrayToAllocatedBytes(val, ptr.len.toValue().toUnsignedInt(mod), allocator, mod), |
| 856 | const adjusted_bytes = bytes[0..adjusted_len]; | 316 | }, |
| 857 | return allocator.dupe(u8, adjusted_bytes); | 317 | .aggregate => |aggregate| switch (aggregate.storage) { |
| 858 | }, | 318 | .bytes => |bytes| try allocator.dupe(u8, bytes), |
| 859 | .str_lit => { | 319 | .elems => try arrayToAllocatedBytes(val, ty.arrayLen(mod), allocator, mod), |
| 860 | const str_lit = val.castTag(.str_lit).?.data; | 320 | .repeated_elem => |elem| { |
| 861 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | 321 | const byte = @intCast(u8, elem.toValue().toUnsignedInt(mod)); |
| 862 | return allocator.dupe(u8, bytes); | 322 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen(mod))); |
| 863 | }, | 323 | @memset(result, byte); |
| 864 | .enum_literal => return allocator.dupe(u8, val.castTag(.enum_literal).?.data), | 324 | return result; |
| 865 | .repeated => { | 325 | }, |
| 866 | const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt(target)); | ||
| 867 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen())); | ||
| 868 | @memset(result, byte); | ||
| 869 | return result; | ||
| 870 | }, | ||
| 871 | .decl_ref => { | ||
| 872 | const decl_index = val.castTag(.decl_ref).?.data; | ||
| 873 | const decl = mod.declPtr(decl_index); | ||
| 874 | const decl_val = try decl.value(); | ||
| 875 | return decl_val.toAllocatedBytes(decl.ty, allocator, mod); | ||
| 876 | }, | ||
| 877 | .the_only_possible_value => return &[_]u8{}, | ||
| 878 | .slice => { | ||
| 879 | const slice = val.castTag(.slice).?.data; | ||
| 880 | return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(target), allocator, mod); | ||
| 881 | }, | 326 | }, |
| 882 | else => return arrayToAllocatedBytes(val, ty.arrayLen(), allocator, mod), | 327 | else => unreachable, |
| 883 | } | 328 | }; |
| 884 | } | 329 | } |
| 885 | 330 | ||
| 886 | fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator, mod: *Module) ![]u8 { | 331 | fn arrayToAllocatedBytes(val: Value, len: u64, allocator: Allocator, mod: *Module) ![]u8 { |
| 887 | const result = try allocator.alloc(u8, @intCast(usize, len)); | 332 | const result = try allocator.alloc(u8, @intCast(usize, len)); |
| 888 | var elem_value_buf: ElemValueBuffer = undefined; | ||
| 889 | for (result, 0..) |*elem, i| { | 333 | for (result, 0..) |*elem, i| { |
| 890 | const elem_val = val.elemValueBuffer(mod, i, &elem_value_buf); | 334 | const elem_val = try val.elemValue(mod, i); |
| 891 | elem.* = @intCast(u8, elem_val.toUnsignedInt(mod.getTarget())); | 335 | elem.* = @intCast(u8, elem_val.toUnsignedInt(mod)); |
| 892 | } | 336 | } |
| 893 | return result; | 337 | return result; |
| 894 | } | 338 | } |
| 895 | 339 | ||
| 896 | pub const ToTypeBuffer = Type.Payload.Bits; | 340 | fn arrayToIpString(val: Value, len_u64: u64, mod: *Module) !InternPool.NullTerminatedString { |
| 897 | 341 | const gpa = mod.gpa; | |
| 898 | /// Asserts that the value is representable as a type. | 342 | const ip = &mod.intern_pool; |
| 899 | pub fn toType(self: Value, buffer: *ToTypeBuffer) Type { | 343 | const len = @intCast(usize, len_u64); |
| 900 | return switch (self.tag()) { | 344 | try ip.string_bytes.ensureUnusedCapacity(gpa, len); |
| 901 | .ty => self.castTag(.ty).?.data, | 345 | for (0..len) |i| { |
| 902 | .u1_type => Type.initTag(.u1), | 346 | // I don't think elemValue has the possibility to affect ip.string_bytes. Let's |
| 903 | .u8_type => Type.initTag(.u8), | 347 | // assert just to be sure. |
| 904 | .i8_type => Type.initTag(.i8), | 348 | const prev = ip.string_bytes.items.len; |
| 905 | .u16_type => Type.initTag(.u16), | 349 | const elem_val = try val.elemValue(mod, i); |
| 906 | .i16_type => Type.initTag(.i16), | 350 | assert(ip.string_bytes.items.len == prev); |
| 907 | .u29_type => Type.initTag(.u29), | 351 | const byte = @intCast(u8, elem_val.toUnsignedInt(mod)); |
| 908 | .u32_type => Type.initTag(.u32), | 352 | ip.string_bytes.appendAssumeCapacity(byte); |
| 909 | .i32_type => Type.initTag(.i32), | 353 | } |
| 910 | .u64_type => Type.initTag(.u64), | 354 | return ip.getOrPutTrailingString(gpa, len); |
| 911 | .i64_type => Type.initTag(.i64), | ||
| 912 | .u128_type => Type.initTag(.u128), | ||
| 913 | .i128_type => Type.initTag(.i128), | ||
| 914 | .usize_type => Type.initTag(.usize), | ||
| 915 | .isize_type => Type.initTag(.isize), | ||
| 916 | .c_char_type => Type.initTag(.c_char), | ||
| 917 | .c_short_type => Type.initTag(.c_short), | ||
| 918 | .c_ushort_type => Type.initTag(.c_ushort), | ||
| 919 | .c_int_type => Type.initTag(.c_int), | ||
| 920 | .c_uint_type => Type.initTag(.c_uint), | ||
| 921 | .c_long_type => Type.initTag(.c_long), | ||
| 922 | .c_ulong_type => Type.initTag(.c_ulong), | ||
| 923 | .c_longlong_type => Type.initTag(.c_longlong), | ||
| 924 | .c_ulonglong_type => Type.initTag(.c_ulonglong), | ||
| 925 | .c_longdouble_type => Type.initTag(.c_longdouble), | ||
| 926 | .f16_type => Type.initTag(.f16), | ||
| 927 | .f32_type => Type.initTag(.f32), | ||
| 928 | .f64_type => Type.initTag(.f64), | ||
| 929 | .f80_type => Type.initTag(.f80), | ||
| 930 | .f128_type => Type.initTag(.f128), | ||
| 931 | .anyopaque_type => Type.initTag(.anyopaque), | ||
| 932 | .bool_type => Type.initTag(.bool), | ||
| 933 | .void_type => Type.initTag(.void), | ||
| 934 | .type_type => Type.initTag(.type), | ||
| 935 | .anyerror_type => Type.initTag(.anyerror), | ||
| 936 | .comptime_int_type => Type.initTag(.comptime_int), | ||
| 937 | .comptime_float_type => Type.initTag(.comptime_float), | ||
| 938 | .noreturn_type => Type.initTag(.noreturn), | ||
| 939 | .null_type => Type.initTag(.null), | ||
| 940 | .undefined_type => Type.initTag(.undefined), | ||
| 941 | .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args), | ||
| 942 | .fn_void_no_args_type => Type.initTag(.fn_void_no_args), | ||
| 943 | .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args), | ||
| 944 | .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args), | ||
| 945 | .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int), | ||
| 946 | .anyframe_type => Type.initTag(.@"anyframe"), | ||
| 947 | .const_slice_u8_type => Type.initTag(.const_slice_u8), | ||
| 948 | .const_slice_u8_sentinel_0_type => Type.initTag(.const_slice_u8_sentinel_0), | ||
| 949 | .anyerror_void_error_union_type => Type.initTag(.anyerror_void_error_union), | ||
| 950 | .generic_poison_type => Type.initTag(.generic_poison), | ||
| 951 | .enum_literal_type => Type.initTag(.enum_literal), | ||
| 952 | .manyptr_u8_type => Type.initTag(.manyptr_u8), | ||
| 953 | .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8), | ||
| 954 | .manyptr_const_u8_sentinel_0_type => Type.initTag(.manyptr_const_u8_sentinel_0), | ||
| 955 | .atomic_order_type => Type.initTag(.atomic_order), | ||
| 956 | .atomic_rmw_op_type => Type.initTag(.atomic_rmw_op), | ||
| 957 | .calling_convention_type => Type.initTag(.calling_convention), | ||
| 958 | .address_space_type => Type.initTag(.address_space), | ||
| 959 | .float_mode_type => Type.initTag(.float_mode), | ||
| 960 | .reduce_op_type => Type.initTag(.reduce_op), | ||
| 961 | .modifier_type => Type.initTag(.modifier), | ||
| 962 | .prefetch_options_type => Type.initTag(.prefetch_options), | ||
| 963 | .export_options_type => Type.initTag(.export_options), | ||
| 964 | .extern_options_type => Type.initTag(.extern_options), | ||
| 965 | .type_info_type => Type.initTag(.type_info), | ||
| 966 | |||
| 967 | .int_type => { | ||
| 968 | const payload = self.castTag(.int_type).?.data; | ||
| 969 | buffer.* = .{ | ||
| 970 | .base = .{ | ||
| 971 | .tag = if (payload.signed) .int_signed else .int_unsigned, | ||
| 972 | }, | ||
| 973 | .data = payload.bits, | ||
| 974 | }; | ||
| 975 | return Type.initPayload(&buffer.base); | ||
| 976 | }, | ||
| 977 | |||
| 978 | else => unreachable, | ||
| 979 | }; | ||
| 980 | } | 355 | } |
| 981 | 356 | ||
| 982 | /// Asserts the type is an enum type. | 357 | pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index { |
| 983 | pub fn toEnum(val: Value, comptime E: type) E { | 358 | if (val.ip_index != .none) return (try mod.getCoerced(val, ty)).toIntern(); |
| 984 | switch (val.tag()) { | 359 | switch (val.tag()) { |
| 985 | .enum_field_index => { | 360 | .eu_payload => { |
| 986 | const field_index = val.castTag(.enum_field_index).?.data; | 361 | const pl = val.castTag(.eu_payload).?.data; |
| 987 | return @intToEnum(E, field_index); | 362 | return mod.intern(.{ .error_union = .{ |
| 363 | .ty = ty.toIntern(), | ||
| 364 | .val = .{ .payload = try pl.intern(ty.errorUnionPayload(mod), mod) }, | ||
| 365 | } }); | ||
| 366 | }, | ||
| 367 | .opt_payload => { | ||
| 368 | const pl = val.castTag(.opt_payload).?.data; | ||
| 369 | return mod.intern(.{ .opt = .{ | ||
| 370 | .ty = ty.toIntern(), | ||
| 371 | .val = try pl.intern(ty.optionalChild(mod), mod), | ||
| 372 | } }); | ||
| 988 | }, | 373 | }, |
| 989 | .the_only_possible_value => { | 374 | .slice => { |
| 990 | const fields = std.meta.fields(E); | 375 | const pl = val.castTag(.slice).?.data; |
| 991 | assert(fields.len == 1); | 376 | const ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod); |
| 992 | return @intToEnum(E, fields[0].value); | 377 | var ptr_key = mod.intern_pool.indexToKey(ptr).ptr; |
| 378 | assert(ptr_key.len == .none); | ||
| 379 | ptr_key.ty = ty.toIntern(); | ||
| 380 | ptr_key.len = try pl.len.intern(Type.usize, mod); | ||
| 381 | return mod.intern(.{ .ptr = ptr_key }); | ||
| 382 | }, | ||
| 383 | .bytes => { | ||
| 384 | const pl = val.castTag(.bytes).?.data; | ||
| 385 | return mod.intern(.{ .aggregate = .{ | ||
| 386 | .ty = ty.toIntern(), | ||
| 387 | .storage = .{ .bytes = pl }, | ||
| 388 | } }); | ||
| 389 | }, | ||
| 390 | .repeated => { | ||
| 391 | const pl = val.castTag(.repeated).?.data; | ||
| 392 | return mod.intern(.{ .aggregate = .{ | ||
| 393 | .ty = ty.toIntern(), | ||
| 394 | .storage = .{ .repeated_elem = try pl.intern(ty.childType(mod), mod) }, | ||
| 395 | } }); | ||
| 396 | }, | ||
| 397 | .aggregate => { | ||
| 398 | const len = @intCast(usize, ty.arrayLen(mod)); | ||
| 399 | const old_elems = val.castTag(.aggregate).?.data[0..len]; | ||
| 400 | const new_elems = try mod.gpa.alloc(InternPool.Index, old_elems.len); | ||
| 401 | defer mod.gpa.free(new_elems); | ||
| 402 | const ty_key = mod.intern_pool.indexToKey(ty.toIntern()); | ||
| 403 | for (new_elems, old_elems, 0..) |*new_elem, old_elem, field_i| | ||
| 404 | new_elem.* = try old_elem.intern(switch (ty_key) { | ||
| 405 | .struct_type => ty.structFieldType(field_i, mod), | ||
| 406 | .anon_struct_type => |info| info.types[field_i].toType(), | ||
| 407 | inline .array_type, .vector_type => |info| info.child.toType(), | ||
| 408 | else => unreachable, | ||
| 409 | }, mod); | ||
| 410 | return mod.intern(.{ .aggregate = .{ | ||
| 411 | .ty = ty.toIntern(), | ||
| 412 | .storage = .{ .elems = new_elems }, | ||
| 413 | } }); | ||
| 414 | }, | ||
| 415 | .@"union" => { | ||
| 416 | const pl = val.castTag(.@"union").?.data; | ||
| 417 | return mod.intern(.{ .un = .{ | ||
| 418 | .ty = ty.toIntern(), | ||
| 419 | .tag = try pl.tag.intern(ty.unionTagTypeHypothetical(mod), mod), | ||
| 420 | .val = try pl.val.intern(ty.unionFieldType(pl.tag, mod), mod), | ||
| 421 | } }); | ||
| 993 | }, | 422 | }, |
| 994 | else => unreachable, | ||
| 995 | } | 423 | } |
| 996 | } | 424 | } |
| 997 | 425 | ||
| 998 | pub fn enumToInt(val: Value, ty: Type, buffer: *Payload.U64) Value { | 426 | pub fn unintern(val: Value, arena: Allocator, mod: *Module) Allocator.Error!Value { |
| 999 | const field_index = switch (val.tag()) { | 427 | return if (val.ip_index == .none) val else switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1000 | .enum_field_index => val.castTag(.enum_field_index).?.data, | 428 | .int_type, |
| 1001 | .the_only_possible_value => blk: { | 429 | .ptr_type, |
| 1002 | assert(ty.enumFieldCount() == 1); | 430 | .array_type, |
| 1003 | break :blk 0; | 431 | .vector_type, |
| 1004 | }, | 432 | .opt_type, |
| 1005 | .enum_literal => i: { | 433 | .anyframe_type, |
| 1006 | const name = val.castTag(.enum_literal).?.data; | 434 | .error_union_type, |
| 1007 | break :i ty.enumFieldIndex(name).?; | 435 | .simple_type, |
| 436 | .struct_type, | ||
| 437 | .anon_struct_type, | ||
| 438 | .union_type, | ||
| 439 | .opaque_type, | ||
| 440 | .enum_type, | ||
| 441 | .func_type, | ||
| 442 | .error_set_type, | ||
| 443 | .inferred_error_set_type, | ||
| 444 | |||
| 445 | .undef, | ||
| 446 | .runtime_value, | ||
| 447 | .simple_value, | ||
| 448 | .variable, | ||
| 449 | .extern_func, | ||
| 450 | .func, | ||
| 451 | .int, | ||
| 452 | .err, | ||
| 453 | .enum_literal, | ||
| 454 | .enum_tag, | ||
| 455 | .empty_enum_value, | ||
| 456 | .float, | ||
| 457 | => val, | ||
| 458 | |||
| 459 | .error_union => |error_union| switch (error_union.val) { | ||
| 460 | .err_name => val, | ||
| 461 | .payload => |payload| Tag.eu_payload.create(arena, payload.toValue()), | ||
| 1008 | }, | 462 | }, |
| 1009 | // Assume it is already an integer and return it directly. | ||
| 1010 | else => return val, | ||
| 1011 | }; | ||
| 1012 | 463 | ||
| 1013 | switch (ty.tag()) { | 464 | .ptr => |ptr| switch (ptr.len) { |
| 1014 | .enum_full, .enum_nonexhaustive => { | 465 | .none => val, |
| 1015 | const enum_full = ty.cast(Type.Payload.EnumFull).?.data; | 466 | else => |len| Tag.slice.create(arena, .{ |
| 1016 | if (enum_full.values.count() != 0) { | 467 | .ptr = val.slicePtr(mod), |
| 1017 | return enum_full.values.keys()[field_index]; | 468 | .len = len.toValue(), |
| 1018 | } else { | 469 | }), |
| 1019 | // Field index and integer values are the same. | ||
| 1020 | buffer.* = .{ | ||
| 1021 | .base = .{ .tag = .int_u64 }, | ||
| 1022 | .data = field_index, | ||
| 1023 | }; | ||
| 1024 | return Value.initPayload(&buffer.base); | ||
| 1025 | } | ||
| 1026 | }, | 470 | }, |
| 1027 | .enum_numbered => { | 471 | |
| 1028 | const enum_obj = ty.castTag(.enum_numbered).?.data; | 472 | .opt => |opt| switch (opt.val) { |
| 1029 | if (enum_obj.values.count() != 0) { | 473 | .none => val, |
| 1030 | return enum_obj.values.keys()[field_index]; | 474 | else => |payload| Tag.opt_payload.create(arena, payload.toValue()), |
| 1031 | } else { | ||
| 1032 | // Field index and integer values are the same. | ||
| 1033 | buffer.* = .{ | ||
| 1034 | .base = .{ .tag = .int_u64 }, | ||
| 1035 | .data = field_index, | ||
| 1036 | }; | ||
| 1037 | return Value.initPayload(&buffer.base); | ||
| 1038 | } | ||
| 1039 | }, | 475 | }, |
| 1040 | .enum_simple => { | 476 | |
| 1041 | // Field index and integer values are the same. | 477 | .aggregate => |aggregate| switch (aggregate.storage) { |
| 1042 | buffer.* = .{ | 478 | .bytes => |bytes| Tag.bytes.create(arena, try arena.dupe(u8, bytes)), |
| 1043 | .base = .{ .tag = .int_u64 }, | 479 | .elems => |old_elems| { |
| 1044 | .data = field_index, | 480 | const new_elems = try arena.alloc(Value, old_elems.len); |
| 1045 | }; | 481 | for (new_elems, old_elems) |*new_elem, old_elem| new_elem.* = old_elem.toValue(); |
| 1046 | return Value.initPayload(&buffer.base); | 482 | return Tag.aggregate.create(arena, new_elems); |
| 483 | }, | ||
| 484 | .repeated_elem => |elem| Tag.repeated.create(arena, elem.toValue()), | ||
| 1047 | }, | 485 | }, |
| 1048 | else => unreachable, | 486 | |
| 1049 | } | 487 | .un => |un| Tag.@"union".create(arena, .{ |
| 488 | .tag = un.tag.toValue(), | ||
| 489 | .val = un.val.toValue(), | ||
| 490 | }), | ||
| 491 | |||
| 492 | .memoized_call => unreachable, | ||
| 493 | }; | ||
| 1050 | } | 494 | } |
| 1051 | 495 | ||
| 1052 | pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 { | 496 | pub fn toIntern(val: Value) InternPool.Index { |
| 1053 | if (ty.zigTypeTag() == .Union) return val.unionTag().tagName(ty.unionTagTypeHypothetical(), mod); | 497 | assert(val.ip_index != .none); |
| 498 | return val.ip_index; | ||
| 499 | } | ||
| 1054 | 500 | ||
| 1055 | const field_index = switch (val.tag()) { | 501 | /// Asserts that the value is representable as a type. |
| 1056 | .enum_field_index => val.castTag(.enum_field_index).?.data, | 502 | pub fn toType(self: Value) Type { |
| 1057 | .the_only_possible_value => blk: { | 503 | return self.toIntern().toType(); |
| 1058 | assert(ty.enumFieldCount() == 1); | 504 | } |
| 1059 | break :blk 0; | 505 | |
| 1060 | }, | 506 | pub fn enumToInt(val: Value, ty: Type, mod: *Module) Allocator.Error!Value { |
| 1061 | .enum_literal => return val.castTag(.enum_literal).?.data, | 507 | const ip = &mod.intern_pool; |
| 1062 | else => field_index: { | 508 | return switch (ip.indexToKey(ip.typeOf(val.toIntern()))) { |
| 1063 | const values = switch (ty.tag()) { | 509 | // Assume it is already an integer and return it directly. |
| 1064 | .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.values, | 510 | .simple_type, .int_type => val, |
| 1065 | .enum_numbered => ty.castTag(.enum_numbered).?.data.values, | 511 | .enum_literal => |enum_literal| { |
| 1066 | .enum_simple => Module.EnumFull.ValueMap{}, | 512 | const field_index = ty.enumFieldIndex(enum_literal, mod).?; |
| 513 | return switch (ip.indexToKey(ty.toIntern())) { | ||
| 514 | // Assume it is already an integer and return it directly. | ||
| 515 | .simple_type, .int_type => val, | ||
| 516 | .enum_type => |enum_type| if (enum_type.values.len != 0) | ||
| 517 | enum_type.values[field_index].toValue() | ||
| 518 | else // Field index and integer values are the same. | ||
| 519 | mod.intValue(enum_type.tag_ty.toType(), field_index), | ||
| 1067 | else => unreachable, | 520 | else => unreachable, |
| 1068 | }; | 521 | }; |
| 1069 | if (values.entries.len == 0) { | ||
| 1070 | // auto-numbered enum | ||
| 1071 | break :field_index @intCast(u32, val.toUnsignedInt(mod.getTarget())); | ||
| 1072 | } | ||
| 1073 | var buffer: Type.Payload.Bits = undefined; | ||
| 1074 | const int_tag_ty = ty.intTagType(&buffer); | ||
| 1075 | break :field_index @intCast(u32, values.getIndexContext(val, .{ .ty = int_tag_ty, .mod = mod }).?); | ||
| 1076 | }, | 522 | }, |
| 1077 | }; | 523 | .enum_type => |enum_type| try mod.getCoerced(val, enum_type.tag_ty.toType()), |
| 1078 | |||
| 1079 | const fields = switch (ty.tag()) { | ||
| 1080 | .enum_full, .enum_nonexhaustive => ty.cast(Type.Payload.EnumFull).?.data.fields, | ||
| 1081 | .enum_numbered => ty.castTag(.enum_numbered).?.data.fields, | ||
| 1082 | .enum_simple => ty.castTag(.enum_simple).?.data.fields, | ||
| 1083 | else => unreachable, | 524 | else => unreachable, |
| 1084 | }; | 525 | }; |
| 1085 | return fields.keys()[field_index]; | ||
| 1086 | } | 526 | } |
| 1087 | 527 | ||
| 1088 | /// Asserts the value is an integer. | 528 | /// Asserts the value is an integer. |
| 1089 | pub fn toBigInt(val: Value, space: *BigIntSpace, target: Target) BigIntConst { | 529 | pub fn toBigInt(val: Value, space: *BigIntSpace, mod: *Module) BigIntConst { |
| 1090 | return val.toBigIntAdvanced(space, target, null) catch unreachable; | 530 | return val.toBigIntAdvanced(space, mod, null) catch unreachable; |
| 1091 | } | 531 | } |
| 1092 | 532 | ||
| 1093 | /// Asserts the value is an integer. | 533 | /// Asserts the value is an integer. |
| 1094 | pub fn toBigIntAdvanced( | 534 | pub fn toBigIntAdvanced( |
| 1095 | val: Value, | 535 | val: Value, |
| 1096 | space: *BigIntSpace, | 536 | space: *BigIntSpace, |
| 1097 | target: Target, | 537 | mod: *Module, |
| 1098 | opt_sema: ?*Sema, | 538 | opt_sema: ?*Sema, |
| 1099 | ) Module.CompileError!BigIntConst { | 539 | ) Module.CompileError!BigIntConst { |
| 1100 | switch (val.tag()) { | 540 | return switch (val.toIntern()) { |
| 1101 | .null_value, | 541 | .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(), |
| 1102 | .zero, | 542 | .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(), |
| 1103 | .bool_false, | 543 | .null_value => BigIntMutable.init(&space.limbs, 0).toConst(), |
| 1104 | .the_only_possible_value, // i0, u0 | 544 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1105 | => return BigIntMutable.init(&space.limbs, 0).toConst(), | 545 | .runtime_value => |runtime_value| runtime_value.val.toValue().toBigIntAdvanced(space, mod, opt_sema), |
| 1106 | 546 | .int => |int| switch (int.storage) { | |
| 1107 | .one, | 547 | .u64, .i64, .big_int => int.storage.toBigInt(space), |
| 1108 | .bool_true, | 548 | .lazy_align, .lazy_size => |ty| { |
| 1109 | => return BigIntMutable.init(&space.limbs, 1).toConst(), | 549 | if (opt_sema) |sema| try sema.resolveTypeLayout(ty.toType()); |
| 1110 | 550 | const x = switch (int.storage) { | |
| 1111 | .enum_field_index => { | 551 | else => unreachable, |
| 1112 | const index = val.castTag(.enum_field_index).?.data; | 552 | .lazy_align => ty.toType().abiAlignment(mod), |
| 1113 | return BigIntMutable.init(&space.limbs, index).toConst(); | 553 | .lazy_size => ty.toType().abiSize(mod), |
| 1114 | }, | 554 | }; |
| 1115 | .runtime_value => { | 555 | return BigIntMutable.init(&space.limbs, x).toConst(); |
| 1116 | const sub_val = val.castTag(.runtime_value).?.data; | 556 | }, |
| 1117 | return sub_val.toBigIntAdvanced(space, target, opt_sema); | 557 | }, |
| 558 | .enum_tag => |enum_tag| enum_tag.int.toValue().toBigIntAdvanced(space, mod, opt_sema), | ||
| 559 | .opt, .ptr => BigIntMutable.init( | ||
| 560 | &space.limbs, | ||
| 561 | (try val.getUnsignedIntAdvanced(mod, opt_sema)).?, | ||
| 562 | ).toConst(), | ||
| 563 | else => unreachable, | ||
| 1118 | }, | 564 | }, |
| 1119 | .int_u64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_u64).?.data).toConst(), | 565 | }; |
| 1120 | .int_i64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(), | 566 | } |
| 1121 | .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(), | ||
| 1122 | .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(), | ||
| 1123 | 567 | ||
| 1124 | .undef => unreachable, | 568 | pub fn getFunction(val: Value, mod: *Module) ?*Module.Fn { |
| 569 | return mod.funcPtrUnwrap(val.getFunctionIndex(mod)); | ||
| 570 | } | ||
| 1125 | 571 | ||
| 1126 | .lazy_align => { | 572 | pub fn getFunctionIndex(val: Value, mod: *Module) Module.Fn.OptionalIndex { |
| 1127 | const ty = val.castTag(.lazy_align).?.data; | 573 | return if (val.ip_index != .none) mod.intern_pool.indexToFunc(val.toIntern()) else .none; |
| 1128 | if (opt_sema) |sema| { | 574 | } |
| 1129 | try sema.resolveTypeLayout(ty); | ||
| 1130 | } | ||
| 1131 | const x = ty.abiAlignment(target); | ||
| 1132 | return BigIntMutable.init(&space.limbs, x).toConst(); | ||
| 1133 | }, | ||
| 1134 | .lazy_size => { | ||
| 1135 | const ty = val.castTag(.lazy_size).?.data; | ||
| 1136 | if (opt_sema) |sema| { | ||
| 1137 | try sema.resolveTypeLayout(ty); | ||
| 1138 | } | ||
| 1139 | const x = ty.abiSize(target); | ||
| 1140 | return BigIntMutable.init(&space.limbs, x).toConst(); | ||
| 1141 | }, | ||
| 1142 | 575 | ||
| 1143 | .elem_ptr => { | 576 | pub fn getExternFunc(val: Value, mod: *Module) ?InternPool.Key.ExternFunc { |
| 1144 | const elem_ptr = val.castTag(.elem_ptr).?.data; | 577 | return if (val.ip_index != .none) switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1145 | const array_addr = (try elem_ptr.array_ptr.getUnsignedIntAdvanced(target, opt_sema)).?; | 578 | .extern_func => |extern_func| extern_func, |
| 1146 | const elem_size = elem_ptr.elem_ty.abiSize(target); | 579 | else => null, |
| 1147 | const new_addr = array_addr + elem_size * elem_ptr.index; | 580 | } else null; |
| 1148 | return BigIntMutable.init(&space.limbs, new_addr).toConst(); | 581 | } |
| 1149 | }, | ||
| 1150 | 582 | ||
| 1151 | else => unreachable, | 583 | pub fn getVariable(val: Value, mod: *Module) ?InternPool.Key.Variable { |
| 1152 | } | 584 | return if (val.ip_index != .none) switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 585 | .variable => |variable| variable, | ||
| 586 | else => null, | ||
| 587 | } else null; | ||
| 1153 | } | 588 | } |
| 1154 | 589 | ||
| 1155 | /// If the value fits in a u64, return it, otherwise null. | 590 | /// If the value fits in a u64, return it, otherwise null. |
| 1156 | /// Asserts not undefined. | 591 | /// Asserts not undefined. |
| 1157 | pub fn getUnsignedInt(val: Value, target: Target) ?u64 { | 592 | pub fn getUnsignedInt(val: Value, mod: *Module) ?u64 { |
| 1158 | return getUnsignedIntAdvanced(val, target, null) catch unreachable; | 593 | return getUnsignedIntAdvanced(val, mod, null) catch unreachable; |
| 1159 | } | 594 | } |
| 1160 | 595 | ||
| 1161 | /// If the value fits in a u64, return it, otherwise null. | 596 | /// If the value fits in a u64, return it, otherwise null. |
| 1162 | /// Asserts not undefined. | 597 | /// Asserts not undefined. |
| 1163 | pub fn getUnsignedIntAdvanced(val: Value, target: Target, opt_sema: ?*Sema) !?u64 { | 598 | pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64 { |
| 1164 | switch (val.tag()) { | 599 | return switch (val.toIntern()) { |
| 1165 | .zero, | ||
| 1166 | .bool_false, | ||
| 1167 | .the_only_possible_value, // i0, u0 | ||
| 1168 | => return 0, | ||
| 1169 | |||
| 1170 | .one, | ||
| 1171 | .bool_true, | ||
| 1172 | => return 1, | ||
| 1173 | |||
| 1174 | .int_u64 => return val.castTag(.int_u64).?.data, | ||
| 1175 | .int_i64 => return @intCast(u64, val.castTag(.int_i64).?.data), | ||
| 1176 | .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(u64) catch null, | ||
| 1177 | .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(u64) catch null, | ||
| 1178 | |||
| 1179 | .undef => unreachable, | 600 | .undef => unreachable, |
| 1180 | 601 | .bool_false => 0, | |
| 1181 | .lazy_align => { | 602 | .bool_true => 1, |
| 1182 | const ty = val.castTag(.lazy_align).?.data; | 603 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1183 | if (opt_sema) |sema| { | 604 | .undef => unreachable, |
| 1184 | return (try ty.abiAlignmentAdvanced(target, .{ .sema = sema })).scalar; | 605 | .int => |int| switch (int.storage) { |
| 1185 | } else { | 606 | .big_int => |big_int| big_int.to(u64) catch null, |
| 1186 | return ty.abiAlignment(target); | 607 | .u64 => |x| x, |
| 1187 | } | 608 | .i64 => |x| std.math.cast(u64, x), |
| 1188 | }, | 609 | .lazy_align => |ty| if (opt_sema) |sema| |
| 1189 | .lazy_size => { | 610 | (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar |
| 1190 | const ty = val.castTag(.lazy_size).?.data; | 611 | else |
| 1191 | if (opt_sema) |sema| { | 612 | ty.toType().abiAlignment(mod), |
| 1192 | return (try ty.abiSizeAdvanced(target, .{ .sema = sema })).scalar; | 613 | .lazy_size => |ty| if (opt_sema) |sema| |
| 1193 | } else { | 614 | (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar |
| 1194 | return ty.abiSize(target); | 615 | else |
| 1195 | } | 616 | ty.toType().abiSize(mod), |
| 617 | }, | ||
| 618 | .ptr => |ptr| switch (ptr.addr) { | ||
| 619 | .int => |int| int.toValue().getUnsignedIntAdvanced(mod, opt_sema), | ||
| 620 | .elem => |elem| { | ||
| 621 | const base_addr = (try elem.base.toValue().getUnsignedIntAdvanced(mod, opt_sema)) orelse return null; | ||
| 622 | const elem_ty = mod.intern_pool.typeOf(elem.base).toType().elemType2(mod); | ||
| 623 | return base_addr + elem.index * elem_ty.abiSize(mod); | ||
| 624 | }, | ||
| 625 | .field => |field| { | ||
| 626 | const base_addr = (try field.base.toValue().getUnsignedIntAdvanced(mod, opt_sema)) orelse return null; | ||
| 627 | const struct_ty = mod.intern_pool.typeOf(field.base).toType().childType(mod); | ||
| 628 | if (opt_sema) |sema| try sema.resolveTypeLayout(struct_ty); | ||
| 629 | return base_addr + struct_ty.structFieldOffset(@intCast(usize, field.index), mod); | ||
| 630 | }, | ||
| 631 | else => null, | ||
| 632 | }, | ||
| 633 | .opt => |opt| switch (opt.val) { | ||
| 634 | .none => 0, | ||
| 635 | else => |payload| payload.toValue().getUnsignedIntAdvanced(mod, opt_sema), | ||
| 636 | }, | ||
| 637 | else => null, | ||
| 1196 | }, | 638 | }, |
| 1197 | 639 | }; | |
| 1198 | else => return null, | ||
| 1199 | } | ||
| 1200 | } | 640 | } |
| 1201 | 641 | ||
| 1202 | /// Asserts the value is an integer and it fits in a u64 | 642 | /// Asserts the value is an integer and it fits in a u64 |
| 1203 | pub fn toUnsignedInt(val: Value, target: Target) u64 { | 643 | pub fn toUnsignedInt(val: Value, mod: *Module) u64 { |
| 1204 | return getUnsignedInt(val, target).?; | 644 | return getUnsignedInt(val, mod).?; |
| 1205 | } | 645 | } |
| 1206 | 646 | ||
| 1207 | /// Asserts the value is an integer and it fits in a i64 | 647 | /// Asserts the value is an integer and it fits in a i64 |
| 1208 | pub fn toSignedInt(val: Value, target: Target) i64 { | 648 | pub fn toSignedInt(val: Value, mod: *Module) i64 { |
| 1209 | switch (val.tag()) { | 649 | return switch (val.toIntern()) { |
| 1210 | .zero, | 650 | .bool_false => 0, |
| 1211 | .bool_false, | 651 | .bool_true => 1, |
| 1212 | .the_only_possible_value, // i0, u0 | 652 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1213 | => return 0, | 653 | .int => |int| switch (int.storage) { |
| 1214 | 654 | .big_int => |big_int| big_int.to(i64) catch unreachable, | |
| 1215 | .one, | 655 | .i64 => |x| x, |
| 1216 | .bool_true, | 656 | .u64 => |x| @intCast(i64, x), |
| 1217 | => return 1, | 657 | .lazy_align => |ty| @intCast(i64, ty.toType().abiAlignment(mod)), |
| 1218 | 658 | .lazy_size => |ty| @intCast(i64, ty.toType().abiSize(mod)), | |
| 1219 | .int_u64 => return @intCast(i64, val.castTag(.int_u64).?.data), | 659 | }, |
| 1220 | .int_i64 => return val.castTag(.int_i64).?.data, | 660 | else => unreachable, |
| 1221 | .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable, | ||
| 1222 | .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable, | ||
| 1223 | |||
| 1224 | .lazy_align => { | ||
| 1225 | const ty = val.castTag(.lazy_align).?.data; | ||
| 1226 | return @intCast(i64, ty.abiAlignment(target)); | ||
| 1227 | }, | ||
| 1228 | .lazy_size => { | ||
| 1229 | const ty = val.castTag(.lazy_size).?.data; | ||
| 1230 | return @intCast(i64, ty.abiSize(target)); | ||
| 1231 | }, | 661 | }, |
| 1232 | 662 | }; | |
| 1233 | .undef => unreachable, | ||
| 1234 | else => unreachable, | ||
| 1235 | } | ||
| 1236 | } | 663 | } |
| 1237 | 664 | ||
| 1238 | pub fn toBool(self: Value) bool { | 665 | pub fn toBool(val: Value) bool { |
| 1239 | return switch (self.tag()) { | 666 | return switch (val.toIntern()) { |
| 1240 | .bool_true, .one => true, | 667 | .bool_true => true, |
| 1241 | .bool_false, .zero => false, | 668 | .bool_false => false, |
| 1242 | .int_u64 => switch (self.castTag(.int_u64).?.data) { | ||
| 1243 | 0 => false, | ||
| 1244 | 1 => true, | ||
| 1245 | else => unreachable, | ||
| 1246 | }, | ||
| 1247 | .int_i64 => switch (self.castTag(.int_i64).?.data) { | ||
| 1248 | 0 => false, | ||
| 1249 | 1 => true, | ||
| 1250 | else => unreachable, | ||
| 1251 | }, | ||
| 1252 | else => unreachable, | 669 | else => unreachable, |
| 1253 | }; | 670 | }; |
| 1254 | } | 671 | } |
| 1255 | 672 | ||
| 1256 | fn isDeclRef(val: Value) bool { | 673 | fn isDeclRef(val: Value, mod: *Module) bool { |
| 1257 | var check = val; | 674 | var check = val; |
| 1258 | while (true) switch (check.tag()) { | 675 | while (true) switch (mod.intern_pool.indexToKey(check.toIntern())) { |
| 1259 | .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return true, | 676 | .ptr => |ptr| switch (ptr.addr) { |
| 1260 | .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr, | 677 | .decl, .mut_decl, .comptime_field => return true, |
| 1261 | .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr, | 678 | .eu_payload, .opt_payload => |base| check = base.toValue(), |
| 1262 | .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr, | 679 | .elem, .field => |base_index| check = base_index.base.toValue(), |
| 680 | else => return false, | ||
| 681 | }, | ||
| 1263 | else => return false, | 682 | else => return false, |
| 1264 | }; | 683 | }; |
| 1265 | } | 684 | } |
| ... | @@ -1272,62 +691,45 @@ pub const Value = extern union { | ... | @@ -1272,62 +691,45 @@ pub const Value = extern union { |
| 1272 | ReinterpretDeclRef, | 691 | ReinterpretDeclRef, |
| 1273 | IllDefinedMemoryLayout, | 692 | IllDefinedMemoryLayout, |
| 1274 | Unimplemented, | 693 | Unimplemented, |
| 694 | OutOfMemory, | ||
| 1275 | }!void { | 695 | }!void { |
| 1276 | const target = mod.getTarget(); | 696 | const target = mod.getTarget(); |
| 1277 | const endian = target.cpu.arch.endian(); | 697 | const endian = target.cpu.arch.endian(); |
| 1278 | if (val.isUndef()) { | 698 | if (val.isUndef(mod)) { |
| 1279 | const size = @intCast(usize, ty.abiSize(target)); | 699 | const size = @intCast(usize, ty.abiSize(mod)); |
| 1280 | @memset(buffer[0..size], 0xaa); | 700 | @memset(buffer[0..size], 0xaa); |
| 1281 | return; | 701 | return; |
| 1282 | } | 702 | } |
| 1283 | switch (ty.zigTypeTag()) { | 703 | switch (ty.zigTypeTag(mod)) { |
| 1284 | .Void => {}, | 704 | .Void => {}, |
| 1285 | .Bool => { | 705 | .Bool => { |
| 1286 | buffer[0] = @boolToInt(val.toBool()); | 706 | buffer[0] = @boolToInt(val.toBool()); |
| 1287 | }, | 707 | }, |
| 1288 | .Int, .Enum => { | 708 | .Int, .Enum => { |
| 1289 | const int_info = ty.intInfo(target); | 709 | const int_info = ty.intInfo(mod); |
| 1290 | const bits = int_info.bits; | 710 | const bits = int_info.bits; |
| 1291 | const byte_count = (bits + 7) / 8; | 711 | const byte_count = (bits + 7) / 8; |
| 1292 | 712 | ||
| 1293 | var enum_buffer: Payload.U64 = undefined; | 713 | var bigint_buffer: BigIntSpace = undefined; |
| 1294 | const int_val = val.enumToInt(ty, &enum_buffer); | 714 | const bigint = val.toBigInt(&bigint_buffer, mod); |
| 1295 | 715 | bigint.writeTwosComplement(buffer[0..byte_count], endian); | |
| 1296 | if (byte_count <= @sizeOf(u64)) { | ||
| 1297 | const int: u64 = switch (int_val.tag()) { | ||
| 1298 | .zero => 0, | ||
| 1299 | .one => 1, | ||
| 1300 | .int_u64 => int_val.castTag(.int_u64).?.data, | ||
| 1301 | .int_i64 => @bitCast(u64, int_val.castTag(.int_i64).?.data), | ||
| 1302 | else => unreachable, | ||
| 1303 | }; | ||
| 1304 | for (buffer[0..byte_count], 0..) |_, i| switch (endian) { | ||
| 1305 | .Little => buffer[i] = @truncate(u8, (int >> @intCast(u6, (8 * i)))), | ||
| 1306 | .Big => buffer[byte_count - i - 1] = @truncate(u8, (int >> @intCast(u6, (8 * i)))), | ||
| 1307 | }; | ||
| 1308 | } else { | ||
| 1309 | var bigint_buffer: BigIntSpace = undefined; | ||
| 1310 | const bigint = int_val.toBigInt(&bigint_buffer, target); | ||
| 1311 | bigint.writeTwosComplement(buffer[0..byte_count], endian); | ||
| 1312 | } | ||
| 1313 | }, | 716 | }, |
| 1314 | .Float => switch (ty.floatBits(target)) { | 717 | .Float => switch (ty.floatBits(target)) { |
| 1315 | 16 => std.mem.writeInt(u16, buffer[0..2], @bitCast(u16, val.toFloat(f16)), endian), | 718 | 16 => std.mem.writeInt(u16, buffer[0..2], @bitCast(u16, val.toFloat(f16, mod)), endian), |
| 1316 | 32 => std.mem.writeInt(u32, buffer[0..4], @bitCast(u32, val.toFloat(f32)), endian), | 719 | 32 => std.mem.writeInt(u32, buffer[0..4], @bitCast(u32, val.toFloat(f32, mod)), endian), |
| 1317 | 64 => std.mem.writeInt(u64, buffer[0..8], @bitCast(u64, val.toFloat(f64)), endian), | 720 | 64 => std.mem.writeInt(u64, buffer[0..8], @bitCast(u64, val.toFloat(f64, mod)), endian), |
| 1318 | 80 => std.mem.writeInt(u80, buffer[0..10], @bitCast(u80, val.toFloat(f80)), endian), | 721 | 80 => std.mem.writeInt(u80, buffer[0..10], @bitCast(u80, val.toFloat(f80, mod)), endian), |
| 1319 | 128 => std.mem.writeInt(u128, buffer[0..16], @bitCast(u128, val.toFloat(f128)), endian), | 722 | 128 => std.mem.writeInt(u128, buffer[0..16], @bitCast(u128, val.toFloat(f128, mod)), endian), |
| 1320 | else => unreachable, | 723 | else => unreachable, |
| 1321 | }, | 724 | }, |
| 1322 | .Array => { | 725 | .Array => { |
| 1323 | const len = ty.arrayLen(); | 726 | const len = ty.arrayLen(mod); |
| 1324 | const elem_ty = ty.childType(); | 727 | const elem_ty = ty.childType(mod); |
| 1325 | const elem_size = @intCast(usize, elem_ty.abiSize(target)); | 728 | const elem_size = @intCast(usize, elem_ty.abiSize(mod)); |
| 1326 | var elem_i: usize = 0; | 729 | var elem_i: usize = 0; |
| 1327 | var elem_value_buf: ElemValueBuffer = undefined; | ||
| 1328 | var buf_off: usize = 0; | 730 | var buf_off: usize = 0; |
| 1329 | while (elem_i < len) : (elem_i += 1) { | 731 | while (elem_i < len) : (elem_i += 1) { |
| 1330 | const elem_val = val.elemValueBuffer(mod, elem_i, &elem_value_buf); | 732 | const elem_val = try val.elemValue(mod, elem_i); |
| 1331 | try elem_val.writeToMemory(elem_ty, mod, buffer[buf_off..]); | 733 | try elem_val.writeToMemory(elem_ty, mod, buffer[buf_off..]); |
| 1332 | buf_off += elem_size; | 734 | buf_off += elem_size; |
| 1333 | } | 735 | } |
| ... | @@ -1335,52 +737,63 @@ pub const Value = extern union { | ... | @@ -1335,52 +737,63 @@ pub const Value = extern union { |
| 1335 | .Vector => { | 737 | .Vector => { |
| 1336 | // We use byte_count instead of abi_size here, so that any padding bytes | 738 | // We use byte_count instead of abi_size here, so that any padding bytes |
| 1337 | // follow the data bytes, on both big- and little-endian systems. | 739 | // follow the data bytes, on both big- and little-endian systems. |
| 1338 | const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8; | 740 | const byte_count = (@intCast(usize, ty.bitSize(mod)) + 7) / 8; |
| 1339 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | 741 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); |
| 1340 | }, | 742 | }, |
| 1341 | .Struct => switch (ty.containerLayout()) { | 743 | .Struct => switch (ty.containerLayout(mod)) { |
| 1342 | .Auto => return error.IllDefinedMemoryLayout, | 744 | .Auto => return error.IllDefinedMemoryLayout, |
| 1343 | .Extern => { | 745 | .Extern => for (ty.structFields(mod).values(), 0..) |field, i| { |
| 1344 | const fields = ty.structFields().values(); | 746 | const off = @intCast(usize, ty.structFieldOffset(i, mod)); |
| 1345 | const field_vals = val.castTag(.aggregate).?.data; | 747 | const field_val = switch (val.ip_index) { |
| 1346 | for (fields, 0..) |field, i| { | 748 | .none => val.castTag(.aggregate).?.data[i], |
| 1347 | const off = @intCast(usize, ty.structFieldOffset(i, target)); | 749 | else => switch (mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage) { |
| 1348 | try writeToMemory(field_vals[i], field.ty, mod, buffer[off..]); | 750 | .bytes => |bytes| { |
| 1349 | } | 751 | buffer[off] = bytes[i]; |
| 752 | continue; | ||
| 753 | }, | ||
| 754 | .elems => |elems| elems[i], | ||
| 755 | .repeated_elem => |elem| elem, | ||
| 756 | }.toValue(), | ||
| 757 | }; | ||
| 758 | try writeToMemory(field_val, field.ty, mod, buffer[off..]); | ||
| 1350 | }, | 759 | }, |
| 1351 | .Packed => { | 760 | .Packed => { |
| 1352 | const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8; | 761 | const byte_count = (@intCast(usize, ty.bitSize(mod)) + 7) / 8; |
| 1353 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | 762 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); |
| 1354 | }, | 763 | }, |
| 1355 | }, | 764 | }, |
| 1356 | .ErrorSet => { | 765 | .ErrorSet => { |
| 1357 | // TODO revisit this when we have the concept of the error tag type | 766 | // TODO revisit this when we have the concept of the error tag type |
| 1358 | const Int = u16; | 767 | const Int = u16; |
| 1359 | const int = mod.global_error_set.get(val.castTag(.@"error").?.data.name).?; | 768 | const name = switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 769 | .err => |err| err.name, | ||
| 770 | .error_union => |error_union| error_union.val.err_name, | ||
| 771 | else => unreachable, | ||
| 772 | }; | ||
| 773 | const int = @intCast(Module.ErrorInt, mod.global_error_set.getIndex(name).?); | ||
| 1360 | std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], @intCast(Int, int), endian); | 774 | std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], @intCast(Int, int), endian); |
| 1361 | }, | 775 | }, |
| 1362 | .Union => switch (ty.containerLayout()) { | 776 | .Union => switch (ty.containerLayout(mod)) { |
| 1363 | .Auto => return error.IllDefinedMemoryLayout, | 777 | .Auto => return error.IllDefinedMemoryLayout, |
| 1364 | .Extern => return error.Unimplemented, | 778 | .Extern => return error.Unimplemented, |
| 1365 | .Packed => { | 779 | .Packed => { |
| 1366 | const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8; | 780 | const byte_count = (@intCast(usize, ty.bitSize(mod)) + 7) / 8; |
| 1367 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); | 781 | return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); |
| 1368 | }, | 782 | }, |
| 1369 | }, | 783 | }, |
| 1370 | .Pointer => { | 784 | .Pointer => { |
| 1371 | if (ty.isSlice()) return error.IllDefinedMemoryLayout; | 785 | if (ty.isSlice(mod)) return error.IllDefinedMemoryLayout; |
| 1372 | if (val.isDeclRef()) return error.ReinterpretDeclRef; | 786 | if (val.isDeclRef(mod)) return error.ReinterpretDeclRef; |
| 1373 | return val.writeToMemory(Type.usize, mod, buffer); | 787 | return val.writeToMemory(Type.usize, mod, buffer); |
| 1374 | }, | 788 | }, |
| 1375 | .Optional => { | 789 | .Optional => { |
| 1376 | if (!ty.isPtrLikeOptional()) return error.IllDefinedMemoryLayout; | 790 | if (!ty.isPtrLikeOptional(mod)) return error.IllDefinedMemoryLayout; |
| 1377 | var buf: Type.Payload.ElemType = undefined; | 791 | const child = ty.optionalChild(mod); |
| 1378 | const child = ty.optionalChild(&buf); | 792 | const opt_val = val.optionalValue(mod); |
| 1379 | const opt_val = val.optionalValue(); | ||
| 1380 | if (opt_val) |some| { | 793 | if (opt_val) |some| { |
| 1381 | return some.writeToMemory(child, mod, buffer); | 794 | return some.writeToMemory(child, mod, buffer); |
| 1382 | } else { | 795 | } else { |
| 1383 | return writeToMemory(Value.zero, Type.usize, mod, buffer); | 796 | return writeToMemory(try mod.intValue(Type.usize, 0), Type.usize, mod, buffer); |
| 1384 | } | 797 | } |
| 1385 | }, | 798 | }, |
| 1386 | else => return error.Unimplemented, | 799 | else => return error.Unimplemented, |
| ... | @@ -1391,15 +804,21 @@ pub const Value = extern union { | ... | @@ -1391,15 +804,21 @@ pub const Value = extern union { |
| 1391 | /// | 804 | /// |
| 1392 | /// Both the start and the end of the provided buffer must be tight, since | 805 | /// Both the start and the end of the provided buffer must be tight, since |
| 1393 | /// big-endian packed memory layouts start at the end of the buffer. | 806 | /// big-endian packed memory layouts start at the end of the buffer. |
| 1394 | pub fn writeToPackedMemory(val: Value, ty: Type, mod: *Module, buffer: []u8, bit_offset: usize) error{ReinterpretDeclRef}!void { | 807 | pub fn writeToPackedMemory( |
| 808 | val: Value, | ||
| 809 | ty: Type, | ||
| 810 | mod: *Module, | ||
| 811 | buffer: []u8, | ||
| 812 | bit_offset: usize, | ||
| 813 | ) error{ ReinterpretDeclRef, OutOfMemory }!void { | ||
| 1395 | const target = mod.getTarget(); | 814 | const target = mod.getTarget(); |
| 1396 | const endian = target.cpu.arch.endian(); | 815 | const endian = target.cpu.arch.endian(); |
| 1397 | if (val.isUndef()) { | 816 | if (val.isUndef(mod)) { |
| 1398 | const bit_size = @intCast(usize, ty.bitSize(target)); | 817 | const bit_size = @intCast(usize, ty.bitSize(mod)); |
| 1399 | std.mem.writeVarPackedInt(buffer, bit_offset, bit_size, @as(u1, 0), endian); | 818 | std.mem.writeVarPackedInt(buffer, bit_offset, bit_size, @as(u1, 0), endian); |
| 1400 | return; | 819 | return; |
| 1401 | } | 820 | } |
| 1402 | switch (ty.zigTypeTag()) { | 821 | switch (ty.zigTypeTag(mod)) { |
| 1403 | .Void => {}, | 822 | .Void => {}, |
| 1404 | .Bool => { | 823 | .Bool => { |
| 1405 | const byte_index = switch (endian) { | 824 | const byte_index = switch (endian) { |
| ... | @@ -1413,91 +832,82 @@ pub const Value = extern union { | ... | @@ -1413,91 +832,82 @@ pub const Value = extern union { |
| 1413 | } | 832 | } |
| 1414 | }, | 833 | }, |
| 1415 | .Int, .Enum => { | 834 | .Int, .Enum => { |
| 1416 | const bits = ty.intInfo(target).bits; | 835 | if (buffer.len == 0) return; |
| 1417 | const abi_size = @intCast(usize, ty.abiSize(target)); | 836 | const bits = ty.intInfo(mod).bits; |
| 1418 | 837 | if (bits == 0) return; | |
| 1419 | var enum_buffer: Payload.U64 = undefined; | 838 | |
| 1420 | const int_val = val.enumToInt(ty, &enum_buffer); | 839 | switch (mod.intern_pool.indexToKey((try val.enumToInt(ty, mod)).toIntern()).int.storage) { |
| 1421 | 840 | inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian), | |
| 1422 | if (abi_size == 0) return; | 841 | .big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian), |
| 1423 | if (abi_size <= @sizeOf(u64)) { | 842 | else => unreachable, |
| 1424 | const int: u64 = switch (int_val.tag()) { | ||
| 1425 | .zero => 0, | ||
| 1426 | .one => 1, | ||
| 1427 | .int_u64 => int_val.castTag(.int_u64).?.data, | ||
| 1428 | .int_i64 => @bitCast(u64, int_val.castTag(.int_i64).?.data), | ||
| 1429 | else => unreachable, | ||
| 1430 | }; | ||
| 1431 | std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian); | ||
| 1432 | } else { | ||
| 1433 | var bigint_buffer: BigIntSpace = undefined; | ||
| 1434 | const bigint = int_val.toBigInt(&bigint_buffer, target); | ||
| 1435 | bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian); | ||
| 1436 | } | 843 | } |
| 1437 | }, | 844 | }, |
| 1438 | .Float => switch (ty.floatBits(target)) { | 845 | .Float => switch (ty.floatBits(target)) { |
| 1439 | 16 => std.mem.writePackedInt(u16, buffer, bit_offset, @bitCast(u16, val.toFloat(f16)), endian), | 846 | 16 => std.mem.writePackedInt(u16, buffer, bit_offset, @bitCast(u16, val.toFloat(f16, mod)), endian), |
| 1440 | 32 => std.mem.writePackedInt(u32, buffer, bit_offset, @bitCast(u32, val.toFloat(f32)), endian), | 847 | 32 => std.mem.writePackedInt(u32, buffer, bit_offset, @bitCast(u32, val.toFloat(f32, mod)), endian), |
| 1441 | 64 => std.mem.writePackedInt(u64, buffer, bit_offset, @bitCast(u64, val.toFloat(f64)), endian), | 848 | 64 => std.mem.writePackedInt(u64, buffer, bit_offset, @bitCast(u64, val.toFloat(f64, mod)), endian), |
| 1442 | 80 => std.mem.writePackedInt(u80, buffer, bit_offset, @bitCast(u80, val.toFloat(f80)), endian), | 849 | 80 => std.mem.writePackedInt(u80, buffer, bit_offset, @bitCast(u80, val.toFloat(f80, mod)), endian), |
| 1443 | 128 => std.mem.writePackedInt(u128, buffer, bit_offset, @bitCast(u128, val.toFloat(f128)), endian), | 850 | 128 => std.mem.writePackedInt(u128, buffer, bit_offset, @bitCast(u128, val.toFloat(f128, mod)), endian), |
| 1444 | else => unreachable, | 851 | else => unreachable, |
| 1445 | }, | 852 | }, |
| 1446 | .Vector => { | 853 | .Vector => { |
| 1447 | const elem_ty = ty.childType(); | 854 | const elem_ty = ty.childType(mod); |
| 1448 | const elem_bit_size = @intCast(u16, elem_ty.bitSize(target)); | 855 | const elem_bit_size = @intCast(u16, elem_ty.bitSize(mod)); |
| 1449 | const len = @intCast(usize, ty.arrayLen()); | 856 | const len = @intCast(usize, ty.arrayLen(mod)); |
| 1450 | 857 | ||
| 1451 | var bits: u16 = 0; | 858 | var bits: u16 = 0; |
| 1452 | var elem_i: usize = 0; | 859 | var elem_i: usize = 0; |
| 1453 | var elem_value_buf: ElemValueBuffer = undefined; | ||
| 1454 | while (elem_i < len) : (elem_i += 1) { | 860 | while (elem_i < len) : (elem_i += 1) { |
| 1455 | // On big-endian systems, LLVM reverses the element order of vectors by default | 861 | // On big-endian systems, LLVM reverses the element order of vectors by default |
| 1456 | const tgt_elem_i = if (endian == .Big) len - elem_i - 1 else elem_i; | 862 | const tgt_elem_i = if (endian == .Big) len - elem_i - 1 else elem_i; |
| 1457 | const elem_val = val.elemValueBuffer(mod, tgt_elem_i, &elem_value_buf); | 863 | const elem_val = try val.elemValue(mod, tgt_elem_i); |
| 1458 | try elem_val.writeToPackedMemory(elem_ty, mod, buffer, bit_offset + bits); | 864 | try elem_val.writeToPackedMemory(elem_ty, mod, buffer, bit_offset + bits); |
| 1459 | bits += elem_bit_size; | 865 | bits += elem_bit_size; |
| 1460 | } | 866 | } |
| 1461 | }, | 867 | }, |
| 1462 | .Struct => switch (ty.containerLayout()) { | 868 | .Struct => switch (ty.containerLayout(mod)) { |
| 1463 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | 869 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already |
| 1464 | .Extern => unreachable, // Handled in non-packed writeToMemory | 870 | .Extern => unreachable, // Handled in non-packed writeToMemory |
| 1465 | .Packed => { | 871 | .Packed => { |
| 1466 | var bits: u16 = 0; | 872 | var bits: u16 = 0; |
| 1467 | const fields = ty.structFields().values(); | 873 | const fields = ty.structFields(mod).values(); |
| 1468 | const field_vals = val.castTag(.aggregate).?.data; | 874 | const storage = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage; |
| 1469 | for (fields, 0..) |field, i| { | 875 | for (fields, 0..) |field, i| { |
| 1470 | const field_bits = @intCast(u16, field.ty.bitSize(target)); | 876 | const field_bits = @intCast(u16, field.ty.bitSize(mod)); |
| 1471 | try field_vals[i].writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits); | 877 | const field_val = switch (storage) { |
| 878 | .bytes => unreachable, | ||
| 879 | .elems => |elems| elems[i], | ||
| 880 | .repeated_elem => |elem| elem, | ||
| 881 | }; | ||
| 882 | try field_val.toValue().writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits); | ||
| 1472 | bits += field_bits; | 883 | bits += field_bits; |
| 1473 | } | 884 | } |
| 1474 | }, | 885 | }, |
| 1475 | }, | 886 | }, |
| 1476 | .Union => switch (ty.containerLayout()) { | 887 | .Union => switch (ty.containerLayout(mod)) { |
| 1477 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | 888 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already |
| 1478 | .Extern => unreachable, // Handled in non-packed writeToMemory | 889 | .Extern => unreachable, // Handled in non-packed writeToMemory |
| 1479 | .Packed => { | 890 | .Packed => { |
| 1480 | const field_index = ty.unionTagFieldIndex(val.unionTag(), mod); | 891 | const field_index = ty.unionTagFieldIndex(val.unionTag(mod), mod); |
| 1481 | const field_type = ty.unionFields().values()[field_index.?].ty; | 892 | const field_type = ty.unionFields(mod).values()[field_index.?].ty; |
| 1482 | const field_val = val.fieldValue(field_type, field_index.?); | 893 | const field_val = try val.fieldValue(mod, field_index.?); |
| 1483 | 894 | ||
| 1484 | return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset); | 895 | return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset); |
| 1485 | }, | 896 | }, |
| 1486 | }, | 897 | }, |
| 1487 | .Pointer => { | 898 | .Pointer => { |
| 1488 | assert(!ty.isSlice()); // No well defined layout. | 899 | assert(!ty.isSlice(mod)); // No well defined layout. |
| 1489 | if (val.isDeclRef()) return error.ReinterpretDeclRef; | 900 | if (val.isDeclRef(mod)) return error.ReinterpretDeclRef; |
| 1490 | return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset); | 901 | return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset); |
| 1491 | }, | 902 | }, |
| 1492 | .Optional => { | 903 | .Optional => { |
| 1493 | assert(ty.isPtrLikeOptional()); | 904 | assert(ty.isPtrLikeOptional(mod)); |
| 1494 | var buf: Type.Payload.ElemType = undefined; | 905 | const child = ty.optionalChild(mod); |
| 1495 | const child = ty.optionalChild(&buf); | 906 | const opt_val = val.optionalValue(mod); |
| 1496 | const opt_val = val.optionalValue(); | ||
| 1497 | if (opt_val) |some| { | 907 | if (opt_val) |some| { |
| 1498 | return some.writeToPackedMemory(child, mod, buffer, bit_offset); | 908 | return some.writeToPackedMemory(child, mod, buffer, bit_offset); |
| 1499 | } else { | 909 | } else { |
| 1500 | return writeToPackedMemory(Value.zero, Type.usize, mod, buffer, bit_offset); | 910 | return writeToPackedMemory(try mod.intValue(Type.usize, 0), Type.usize, mod, buffer, bit_offset); |
| 1501 | } | 911 | } |
| 1502 | }, | 912 | }, |
| 1503 | else => @panic("TODO implement writeToPackedMemory for more types"), | 913 | else => @panic("TODO implement writeToPackedMemory for more types"), |
| ... | @@ -1516,7 +926,7 @@ pub const Value = extern union { | ... | @@ -1516,7 +926,7 @@ pub const Value = extern union { |
| 1516 | ) Allocator.Error!Value { | 926 | ) Allocator.Error!Value { |
| 1517 | const target = mod.getTarget(); | 927 | const target = mod.getTarget(); |
| 1518 | const endian = target.cpu.arch.endian(); | 928 | const endian = target.cpu.arch.endian(); |
| 1519 | switch (ty.zigTypeTag()) { | 929 | switch (ty.zigTypeTag(mod)) { |
| 1520 | .Void => return Value.void, | 930 | .Void => return Value.void, |
| 1521 | .Bool => { | 931 | .Bool => { |
| 1522 | if (buffer[0] == 0) { | 932 | if (buffer[0] == 0) { |
| ... | @@ -1525,20 +935,27 @@ pub const Value = extern union { | ... | @@ -1525,20 +935,27 @@ pub const Value = extern union { |
| 1525 | return Value.true; | 935 | return Value.true; |
| 1526 | } | 936 | } |
| 1527 | }, | 937 | }, |
| 1528 | .Int, .Enum => { | 938 | .Int, .Enum => |ty_tag| { |
| 1529 | const int_info = ty.intInfo(target); | 939 | const int_ty = switch (ty_tag) { |
| 940 | .Int => ty, | ||
| 941 | .Enum => ty.intTagType(mod), | ||
| 942 | else => unreachable, | ||
| 943 | }; | ||
| 944 | const int_info = int_ty.intInfo(mod); | ||
| 1530 | const bits = int_info.bits; | 945 | const bits = int_info.bits; |
| 1531 | const byte_count = (bits + 7) / 8; | 946 | const byte_count = (bits + 7) / 8; |
| 1532 | if (bits == 0 or buffer.len == 0) return Value.zero; | 947 | if (bits == 0 or buffer.len == 0) return mod.getCoerced(try mod.intValue(int_ty, 0), ty); |
| 1533 | 948 | ||
| 1534 | if (bits <= 64) switch (int_info.signedness) { // Fast path for integers <= u64 | 949 | if (bits <= 64) switch (int_info.signedness) { // Fast path for integers <= u64 |
| 1535 | .signed => { | 950 | .signed => { |
| 1536 | const val = std.mem.readVarInt(i64, buffer[0..byte_count], endian); | 951 | const val = std.mem.readVarInt(i64, buffer[0..byte_count], endian); |
| 1537 | return Value.Tag.int_i64.create(arena, (val << @intCast(u6, 64 - bits)) >> @intCast(u6, 64 - bits)); | 952 | const result = (val << @intCast(u6, 64 - bits)) >> @intCast(u6, 64 - bits); |
| 953 | return mod.getCoerced(try mod.intValue(int_ty, result), ty); | ||
| 1538 | }, | 954 | }, |
| 1539 | .unsigned => { | 955 | .unsigned => { |
| 1540 | const val = std.mem.readVarInt(u64, buffer[0..byte_count], endian); | 956 | const val = std.mem.readVarInt(u64, buffer[0..byte_count], endian); |
| 1541 | return Value.Tag.int_u64.create(arena, (val << @intCast(u6, 64 - bits)) >> @intCast(u6, 64 - bits)); | 957 | const result = (val << @intCast(u6, 64 - bits)) >> @intCast(u6, 64 - bits); |
| 958 | return mod.getCoerced(try mod.intValue(int_ty, result), ty); | ||
| 1542 | }, | 959 | }, |
| 1543 | } else { // Slow path, we have to construct a big-int | 960 | } else { // Slow path, we have to construct a big-int |
| 1544 | const Limb = std.math.big.Limb; | 961 | const Limb = std.math.big.Limb; |
| ... | @@ -1547,48 +964,57 @@ pub const Value = extern union { | ... | @@ -1547,48 +964,57 @@ pub const Value = extern union { |
| 1547 | 964 | ||
| 1548 | var bigint = BigIntMutable.init(limbs_buffer, 0); | 965 | var bigint = BigIntMutable.init(limbs_buffer, 0); |
| 1549 | bigint.readTwosComplement(buffer[0..byte_count], bits, endian, int_info.signedness); | 966 | bigint.readTwosComplement(buffer[0..byte_count], bits, endian, int_info.signedness); |
| 1550 | return fromBigInt(arena, bigint.toConst()); | 967 | return mod.getCoerced(try mod.intValue_big(int_ty, bigint.toConst()), ty); |
| 1551 | } | 968 | } |
| 1552 | }, | 969 | }, |
| 1553 | .Float => switch (ty.floatBits(target)) { | 970 | .Float => return (try mod.intern(.{ .float = .{ |
| 1554 | 16 => return Value.Tag.float_16.create(arena, @bitCast(f16, std.mem.readInt(u16, buffer[0..2], endian))), | 971 | .ty = ty.toIntern(), |
| 1555 | 32 => return Value.Tag.float_32.create(arena, @bitCast(f32, std.mem.readInt(u32, buffer[0..4], endian))), | 972 | .storage = switch (ty.floatBits(target)) { |
| 1556 | 64 => return Value.Tag.float_64.create(arena, @bitCast(f64, std.mem.readInt(u64, buffer[0..8], endian))), | 973 | 16 => .{ .f16 = @bitCast(f16, std.mem.readInt(u16, buffer[0..2], endian)) }, |
| 1557 | 80 => return Value.Tag.float_80.create(arena, @bitCast(f80, std.mem.readInt(u80, buffer[0..10], endian))), | 974 | 32 => .{ .f32 = @bitCast(f32, std.mem.readInt(u32, buffer[0..4], endian)) }, |
| 1558 | 128 => return Value.Tag.float_128.create(arena, @bitCast(f128, std.mem.readInt(u128, buffer[0..16], endian))), | 975 | 64 => .{ .f64 = @bitCast(f64, std.mem.readInt(u64, buffer[0..8], endian)) }, |
| 1559 | else => unreachable, | 976 | 80 => .{ .f80 = @bitCast(f80, std.mem.readInt(u80, buffer[0..10], endian)) }, |
| 1560 | }, | 977 | 128 => .{ .f128 = @bitCast(f128, std.mem.readInt(u128, buffer[0..16], endian)) }, |
| 978 | else => unreachable, | ||
| 979 | }, | ||
| 980 | } })).toValue(), | ||
| 1561 | .Array => { | 981 | .Array => { |
| 1562 | const elem_ty = ty.childType(); | 982 | const elem_ty = ty.childType(mod); |
| 1563 | const elem_size = elem_ty.abiSize(target); | 983 | const elem_size = elem_ty.abiSize(mod); |
| 1564 | const elems = try arena.alloc(Value, @intCast(usize, ty.arrayLen())); | 984 | const elems = try arena.alloc(InternPool.Index, @intCast(usize, ty.arrayLen(mod))); |
| 1565 | var offset: usize = 0; | 985 | var offset: usize = 0; |
| 1566 | for (elems) |*elem| { | 986 | for (elems) |*elem| { |
| 1567 | elem.* = try readFromMemory(elem_ty, mod, buffer[offset..], arena); | 987 | elem.* = try (try readFromMemory(elem_ty, mod, buffer[offset..], arena)).intern(elem_ty, mod); |
| 1568 | offset += @intCast(usize, elem_size); | 988 | offset += @intCast(usize, elem_size); |
| 1569 | } | 989 | } |
| 1570 | return Tag.aggregate.create(arena, elems); | 990 | return (try mod.intern(.{ .aggregate = .{ |
| 991 | .ty = ty.toIntern(), | ||
| 992 | .storage = .{ .elems = elems }, | ||
| 993 | } })).toValue(); | ||
| 1571 | }, | 994 | }, |
| 1572 | .Vector => { | 995 | .Vector => { |
| 1573 | // We use byte_count instead of abi_size here, so that any padding bytes | 996 | // We use byte_count instead of abi_size here, so that any padding bytes |
| 1574 | // follow the data bytes, on both big- and little-endian systems. | 997 | // follow the data bytes, on both big- and little-endian systems. |
| 1575 | const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8; | 998 | const byte_count = (@intCast(usize, ty.bitSize(mod)) + 7) / 8; |
| 1576 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); | 999 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); |
| 1577 | }, | 1000 | }, |
| 1578 | .Struct => switch (ty.containerLayout()) { | 1001 | .Struct => switch (ty.containerLayout(mod)) { |
| 1579 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | 1002 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already |
| 1580 | .Extern => { | 1003 | .Extern => { |
| 1581 | const fields = ty.structFields().values(); | 1004 | const fields = ty.structFields(mod).values(); |
| 1582 | const field_vals = try arena.alloc(Value, fields.len); | 1005 | const field_vals = try arena.alloc(InternPool.Index, fields.len); |
| 1583 | for (fields, 0..) |field, i| { | 1006 | for (field_vals, fields, 0..) |*field_val, field, i| { |
| 1584 | const off = @intCast(usize, ty.structFieldOffset(i, target)); | 1007 | const off = @intCast(usize, ty.structFieldOffset(i, mod)); |
| 1585 | const sz = @intCast(usize, ty.structFieldType(i).abiSize(target)); | 1008 | const sz = @intCast(usize, field.ty.abiSize(mod)); |
| 1586 | field_vals[i] = try readFromMemory(field.ty, mod, buffer[off..(off + sz)], arena); | 1009 | field_val.* = try (try readFromMemory(field.ty, mod, buffer[off..(off + sz)], arena)).intern(field.ty, mod); |
| 1587 | } | 1010 | } |
| 1588 | return Tag.aggregate.create(arena, field_vals); | 1011 | return (try mod.intern(.{ .aggregate = .{ |
| 1012 | .ty = ty.toIntern(), | ||
| 1013 | .storage = .{ .elems = field_vals }, | ||
| 1014 | } })).toValue(); | ||
| 1589 | }, | 1015 | }, |
| 1590 | .Packed => { | 1016 | .Packed => { |
| 1591 | const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8; | 1017 | const byte_count = (@intCast(usize, ty.bitSize(mod)) + 7) / 8; |
| 1592 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); | 1018 | return readFromPackedMemory(ty, mod, buffer[0..byte_count], 0, arena); |
| 1593 | }, | 1019 | }, |
| 1594 | }, | 1020 | }, |
| ... | @@ -1596,22 +1022,19 @@ pub const Value = extern union { | ... | @@ -1596,22 +1022,19 @@ pub const Value = extern union { |
| 1596 | // TODO revisit this when we have the concept of the error tag type | 1022 | // TODO revisit this when we have the concept of the error tag type |
| 1597 | const Int = u16; | 1023 | const Int = u16; |
| 1598 | const int = std.mem.readInt(Int, buffer[0..@sizeOf(Int)], endian); | 1024 | const int = std.mem.readInt(Int, buffer[0..@sizeOf(Int)], endian); |
| 1599 | 1025 | const name = mod.global_error_set.keys()[@intCast(usize, int)]; | |
| 1600 | const payload = try arena.create(Value.Payload.Error); | 1026 | return (try mod.intern(.{ .err = .{ |
| 1601 | payload.* = .{ | 1027 | .ty = ty.toIntern(), |
| 1602 | .base = .{ .tag = .@"error" }, | 1028 | .name = name, |
| 1603 | .data = .{ .name = mod.error_name_list.items[@intCast(usize, int)] }, | 1029 | } })).toValue(); |
| 1604 | }; | ||
| 1605 | return Value.initPayload(&payload.base); | ||
| 1606 | }, | 1030 | }, |
| 1607 | .Pointer => { | 1031 | .Pointer => { |
| 1608 | assert(!ty.isSlice()); // No well defined layout. | 1032 | assert(!ty.isSlice(mod)); // No well defined layout. |
| 1609 | return readFromMemory(Type.usize, mod, buffer, arena); | 1033 | return readFromMemory(Type.usize, mod, buffer, arena); |
| 1610 | }, | 1034 | }, |
| 1611 | .Optional => { | 1035 | .Optional => { |
| 1612 | assert(ty.isPtrLikeOptional()); | 1036 | assert(ty.isPtrLikeOptional(mod)); |
| 1613 | var buf: Type.Payload.ElemType = undefined; | 1037 | const child = ty.optionalChild(mod); |
| 1614 | const child = ty.optionalChild(&buf); | ||
| 1615 | return readFromMemory(child, mod, buffer, arena); | 1038 | return readFromMemory(child, mod, buffer, arena); |
| 1616 | }, | 1039 | }, |
| 1617 | else => @panic("TODO implement readFromMemory for more types"), | 1040 | else => @panic("TODO implement readFromMemory for more types"), |
| ... | @@ -1631,7 +1054,7 @@ pub const Value = extern union { | ... | @@ -1631,7 +1054,7 @@ pub const Value = extern union { |
| 1631 | ) Allocator.Error!Value { | 1054 | ) Allocator.Error!Value { |
| 1632 | const target = mod.getTarget(); | 1055 | const target = mod.getTarget(); |
| 1633 | const endian = target.cpu.arch.endian(); | 1056 | const endian = target.cpu.arch.endian(); |
| 1634 | switch (ty.zigTypeTag()) { | 1057 | switch (ty.zigTypeTag(mod)) { |
| 1635 | .Void => return Value.void, | 1058 | .Void => return Value.void, |
| 1636 | .Bool => { | 1059 | .Bool => { |
| 1637 | const byte = switch (endian) { | 1060 | const byte = switch (endian) { |
| ... | @@ -1644,71 +1067,94 @@ pub const Value = extern union { | ... | @@ -1644,71 +1067,94 @@ pub const Value = extern union { |
| 1644 | return Value.true; | 1067 | return Value.true; |
| 1645 | } | 1068 | } |
| 1646 | }, | 1069 | }, |
| 1647 | .Int, .Enum => { | 1070 | .Int, .Enum => |ty_tag| { |
| 1648 | if (buffer.len == 0) return Value.zero; | 1071 | if (buffer.len == 0) return mod.intValue(ty, 0); |
| 1649 | const int_info = ty.intInfo(target); | 1072 | const int_info = ty.intInfo(mod); |
| 1650 | const abi_size = @intCast(usize, ty.abiSize(target)); | ||
| 1651 | |||
| 1652 | const bits = int_info.bits; | 1073 | const bits = int_info.bits; |
| 1653 | if (bits == 0) return Value.zero; | 1074 | if (bits == 0) return mod.intValue(ty, 0); |
| 1654 | if (bits <= 64) switch (int_info.signedness) { // Fast path for integers <= u64 | ||
| 1655 | .signed => return Value.Tag.int_i64.create(arena, std.mem.readVarPackedInt(i64, buffer, bit_offset, bits, endian, .signed)), | ||
| 1656 | .unsigned => return Value.Tag.int_u64.create(arena, std.mem.readVarPackedInt(u64, buffer, bit_offset, bits, endian, .unsigned)), | ||
| 1657 | } else { // Slow path, we have to construct a big-int | ||
| 1658 | const Limb = std.math.big.Limb; | ||
| 1659 | const limb_count = (abi_size + @sizeOf(Limb) - 1) / @sizeOf(Limb); | ||
| 1660 | const limbs_buffer = try arena.alloc(Limb, limb_count); | ||
| 1661 | 1075 | ||
| 1662 | var bigint = BigIntMutable.init(limbs_buffer, 0); | 1076 | // Fast path for integers <= u64 |
| 1663 | bigint.readPackedTwosComplement(buffer, bit_offset, bits, endian, int_info.signedness); | 1077 | if (bits <= 64) { |
| 1664 | return fromBigInt(arena, bigint.toConst()); | 1078 | const int_ty = switch (ty_tag) { |
| 1079 | .Int => ty, | ||
| 1080 | .Enum => ty.intTagType(mod), | ||
| 1081 | else => unreachable, | ||
| 1082 | }; | ||
| 1083 | return mod.getCoerced(switch (int_info.signedness) { | ||
| 1084 | .signed => return mod.intValue( | ||
| 1085 | int_ty, | ||
| 1086 | std.mem.readVarPackedInt(i64, buffer, bit_offset, bits, endian, .signed), | ||
| 1087 | ), | ||
| 1088 | .unsigned => return mod.intValue( | ||
| 1089 | int_ty, | ||
| 1090 | std.mem.readVarPackedInt(u64, buffer, bit_offset, bits, endian, .unsigned), | ||
| 1091 | ), | ||
| 1092 | }, ty); | ||
| 1665 | } | 1093 | } |
| 1666 | }, | 1094 | |
| 1667 | .Float => switch (ty.floatBits(target)) { | 1095 | // Slow path, we have to construct a big-int |
| 1668 | 16 => return Value.Tag.float_16.create(arena, @bitCast(f16, std.mem.readPackedInt(u16, buffer, bit_offset, endian))), | 1096 | const abi_size = @intCast(usize, ty.abiSize(mod)); |
| 1669 | 32 => return Value.Tag.float_32.create(arena, @bitCast(f32, std.mem.readPackedInt(u32, buffer, bit_offset, endian))), | 1097 | const Limb = std.math.big.Limb; |
| 1670 | 64 => return Value.Tag.float_64.create(arena, @bitCast(f64, std.mem.readPackedInt(u64, buffer, bit_offset, endian))), | 1098 | const limb_count = (abi_size + @sizeOf(Limb) - 1) / @sizeOf(Limb); |
| 1671 | 80 => return Value.Tag.float_80.create(arena, @bitCast(f80, std.mem.readPackedInt(u80, buffer, bit_offset, endian))), | 1099 | const limbs_buffer = try arena.alloc(Limb, limb_count); |
| 1672 | 128 => return Value.Tag.float_128.create(arena, @bitCast(f128, std.mem.readPackedInt(u128, buffer, bit_offset, endian))), | 1100 | |
| 1673 | else => unreachable, | 1101 | var bigint = BigIntMutable.init(limbs_buffer, 0); |
| 1674 | }, | 1102 | bigint.readPackedTwosComplement(buffer, bit_offset, bits, endian, int_info.signedness); |
| 1103 | return mod.intValue_big(ty, bigint.toConst()); | ||
| 1104 | }, | ||
| 1105 | .Float => return (try mod.intern(.{ .float = .{ | ||
| 1106 | .ty = ty.toIntern(), | ||
| 1107 | .storage = switch (ty.floatBits(target)) { | ||
| 1108 | 16 => .{ .f16 = @bitCast(f16, std.mem.readPackedInt(u16, buffer, bit_offset, endian)) }, | ||
| 1109 | 32 => .{ .f32 = @bitCast(f32, std.mem.readPackedInt(u32, buffer, bit_offset, endian)) }, | ||
| 1110 | 64 => .{ .f64 = @bitCast(f64, std.mem.readPackedInt(u64, buffer, bit_offset, endian)) }, | ||
| 1111 | 80 => .{ .f80 = @bitCast(f80, std.mem.readPackedInt(u80, buffer, bit_offset, endian)) }, | ||
| 1112 | 128 => .{ .f128 = @bitCast(f128, std.mem.readPackedInt(u128, buffer, bit_offset, endian)) }, | ||
| 1113 | else => unreachable, | ||
| 1114 | }, | ||
| 1115 | } })).toValue(), | ||
| 1675 | .Vector => { | 1116 | .Vector => { |
| 1676 | const elem_ty = ty.childType(); | 1117 | const elem_ty = ty.childType(mod); |
| 1677 | const elems = try arena.alloc(Value, @intCast(usize, ty.arrayLen())); | 1118 | const elems = try arena.alloc(InternPool.Index, @intCast(usize, ty.arrayLen(mod))); |
| 1678 | 1119 | ||
| 1679 | var bits: u16 = 0; | 1120 | var bits: u16 = 0; |
| 1680 | const elem_bit_size = @intCast(u16, elem_ty.bitSize(target)); | 1121 | const elem_bit_size = @intCast(u16, elem_ty.bitSize(mod)); |
| 1681 | for (elems, 0..) |_, i| { | 1122 | for (elems, 0..) |_, i| { |
| 1682 | // On big-endian systems, LLVM reverses the element order of vectors by default | 1123 | // On big-endian systems, LLVM reverses the element order of vectors by default |
| 1683 | const tgt_elem_i = if (endian == .Big) elems.len - i - 1 else i; | 1124 | const tgt_elem_i = if (endian == .Big) elems.len - i - 1 else i; |
| 1684 | elems[tgt_elem_i] = try readFromPackedMemory(elem_ty, mod, buffer, bit_offset + bits, arena); | 1125 | elems[tgt_elem_i] = try (try readFromPackedMemory(elem_ty, mod, buffer, bit_offset + bits, arena)).intern(elem_ty, mod); |
| 1685 | bits += elem_bit_size; | 1126 | bits += elem_bit_size; |
| 1686 | } | 1127 | } |
| 1687 | return Tag.aggregate.create(arena, elems); | 1128 | return (try mod.intern(.{ .aggregate = .{ |
| 1129 | .ty = ty.toIntern(), | ||
| 1130 | .storage = .{ .elems = elems }, | ||
| 1131 | } })).toValue(); | ||
| 1688 | }, | 1132 | }, |
| 1689 | .Struct => switch (ty.containerLayout()) { | 1133 | .Struct => switch (ty.containerLayout(mod)) { |
| 1690 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already | 1134 | .Auto => unreachable, // Sema is supposed to have emitted a compile error already |
| 1691 | .Extern => unreachable, // Handled by non-packed readFromMemory | 1135 | .Extern => unreachable, // Handled by non-packed readFromMemory |
| 1692 | .Packed => { | 1136 | .Packed => { |
| 1693 | var bits: u16 = 0; | 1137 | var bits: u16 = 0; |
| 1694 | const fields = ty.structFields().values(); | 1138 | const fields = ty.structFields(mod).values(); |
| 1695 | const field_vals = try arena.alloc(Value, fields.len); | 1139 | const field_vals = try arena.alloc(InternPool.Index, fields.len); |
| 1696 | for (fields, 0..) |field, i| { | 1140 | for (fields, 0..) |field, i| { |
| 1697 | const field_bits = @intCast(u16, field.ty.bitSize(target)); | 1141 | const field_bits = @intCast(u16, field.ty.bitSize(mod)); |
| 1698 | field_vals[i] = try readFromPackedMemory(field.ty, mod, buffer, bit_offset + bits, arena); | 1142 | field_vals[i] = try (try readFromPackedMemory(field.ty, mod, buffer, bit_offset + bits, arena)).intern(field.ty, mod); |
| 1699 | bits += field_bits; | 1143 | bits += field_bits; |
| 1700 | } | 1144 | } |
| 1701 | return Tag.aggregate.create(arena, field_vals); | 1145 | return (try mod.intern(.{ .aggregate = .{ |
| 1146 | .ty = ty.toIntern(), | ||
| 1147 | .storage = .{ .elems = field_vals }, | ||
| 1148 | } })).toValue(); | ||
| 1702 | }, | 1149 | }, |
| 1703 | }, | 1150 | }, |
| 1704 | .Pointer => { | 1151 | .Pointer => { |
| 1705 | assert(!ty.isSlice()); // No well defined layout. | 1152 | assert(!ty.isSlice(mod)); // No well defined layout. |
| 1706 | return readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena); | 1153 | return readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena); |
| 1707 | }, | 1154 | }, |
| 1708 | .Optional => { | 1155 | .Optional => { |
| 1709 | assert(ty.isPtrLikeOptional()); | 1156 | assert(ty.isPtrLikeOptional(mod)); |
| 1710 | var buf: Type.Payload.ElemType = undefined; | 1157 | const child = ty.optionalChild(mod); |
| 1711 | const child = ty.optionalChild(&buf); | ||
| 1712 | return readFromPackedMemory(child, mod, buffer, bit_offset, arena); | 1158 | return readFromPackedMemory(child, mod, buffer, bit_offset, arena); |
| 1713 | }, | 1159 | }, |
| 1714 | else => @panic("TODO implement readFromPackedMemory for more types"), | 1160 | else => @panic("TODO implement readFromPackedMemory for more types"), |
| ... | @@ -1716,31 +1162,22 @@ pub const Value = extern union { | ... | @@ -1716,31 +1162,22 @@ pub const Value = extern union { |
| 1716 | } | 1162 | } |
| 1717 | 1163 | ||
| 1718 | /// Asserts that the value is a float or an integer. | 1164 | /// Asserts that the value is a float or an integer. |
| 1719 | pub fn toFloat(val: Value, comptime T: type) T { | 1165 | pub fn toFloat(val: Value, comptime T: type, mod: *Module) T { |
| 1720 | return switch (val.tag()) { | 1166 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 1721 | .float_16 => @floatCast(T, val.castTag(.float_16).?.data), | 1167 | .int => |int| switch (int.storage) { |
| 1722 | .float_32 => @floatCast(T, val.castTag(.float_32).?.data), | 1168 | .big_int => |big_int| @floatCast(T, bigIntToFloat(big_int.limbs, big_int.positive)), |
| 1723 | .float_64 => @floatCast(T, val.castTag(.float_64).?.data), | 1169 | inline .u64, .i64 => |x| { |
| 1724 | .float_80 => @floatCast(T, val.castTag(.float_80).?.data), | 1170 | if (T == f80) { |
| 1725 | .float_128 => @floatCast(T, val.castTag(.float_128).?.data), | 1171 | @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); |
| 1726 | 1172 | } | |
| 1727 | .zero => 0, | 1173 | return @intToFloat(T, x); |
| 1728 | .one => 1, | 1174 | }, |
| 1729 | .int_u64 => { | 1175 | .lazy_align => |ty| @intToFloat(T, ty.toType().abiAlignment(mod)), |
| 1730 | if (T == f80) { | 1176 | .lazy_size => |ty| @intToFloat(T, ty.toType().abiSize(mod)), |
| 1731 | @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); | ||
| 1732 | } | ||
| 1733 | return @intToFloat(T, val.castTag(.int_u64).?.data); | ||
| 1734 | }, | 1177 | }, |
| 1735 | .int_i64 => { | 1178 | .float => |float| switch (float.storage) { |
| 1736 | if (T == f80) { | 1179 | inline else => |x| @floatCast(T, x), |
| 1737 | @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); | ||
| 1738 | } | ||
| 1739 | return @intToFloat(T, val.castTag(.int_i64).?.data); | ||
| 1740 | }, | 1180 | }, |
| 1741 | |||
| 1742 | .int_big_positive => @floatCast(T, bigIntToFloat(val.castTag(.int_big_positive).?.data, true)), | ||
| 1743 | .int_big_negative => @floatCast(T, bigIntToFloat(val.castTag(.int_big_negative).?.data, false)), | ||
| 1744 | else => unreachable, | 1181 | else => unreachable, |
| 1745 | }; | 1182 | }; |
| 1746 | } | 1183 | } |
| ... | @@ -1764,103 +1201,29 @@ pub const Value = extern union { | ... | @@ -1764,103 +1201,29 @@ pub const Value = extern union { |
| 1764 | } | 1201 | } |
| 1765 | } | 1202 | } |
| 1766 | 1203 | ||
| 1767 | pub fn clz(val: Value, ty: Type, target: Target) u64 { | 1204 | pub fn clz(val: Value, ty: Type, mod: *Module) u64 { |
| 1768 | const ty_bits = ty.intInfo(target).bits; | 1205 | var bigint_buf: BigIntSpace = undefined; |
| 1769 | switch (val.tag()) { | 1206 | const bigint = val.toBigInt(&bigint_buf, mod); |
| 1770 | .zero, .bool_false => return ty_bits, | 1207 | return bigint.clz(ty.intInfo(mod).bits); |
| 1771 | .one, .bool_true => return ty_bits - 1, | ||
| 1772 | |||
| 1773 | .int_u64 => { | ||
| 1774 | const big = @clz(val.castTag(.int_u64).?.data); | ||
| 1775 | return big + ty_bits - 64; | ||
| 1776 | }, | ||
| 1777 | .int_i64 => { | ||
| 1778 | @panic("TODO implement i64 Value clz"); | ||
| 1779 | }, | ||
| 1780 | .int_big_positive => { | ||
| 1781 | const bigint = val.castTag(.int_big_positive).?.asBigInt(); | ||
| 1782 | return bigint.clz(ty_bits); | ||
| 1783 | }, | ||
| 1784 | .int_big_negative => { | ||
| 1785 | @panic("TODO implement int_big_negative Value clz"); | ||
| 1786 | }, | ||
| 1787 | |||
| 1788 | .the_only_possible_value => { | ||
| 1789 | assert(ty_bits == 0); | ||
| 1790 | return ty_bits; | ||
| 1791 | }, | ||
| 1792 | |||
| 1793 | .lazy_align, .lazy_size => { | ||
| 1794 | var bigint_buf: BigIntSpace = undefined; | ||
| 1795 | const bigint = val.toBigIntAdvanced(&bigint_buf, target, null) catch unreachable; | ||
| 1796 | return bigint.clz(ty_bits); | ||
| 1797 | }, | ||
| 1798 | |||
| 1799 | else => unreachable, | ||
| 1800 | } | ||
| 1801 | } | 1208 | } |
| 1802 | 1209 | ||
| 1803 | pub fn ctz(val: Value, ty: Type, target: Target) u64 { | 1210 | pub fn ctz(val: Value, ty: Type, mod: *Module) u64 { |
| 1804 | const ty_bits = ty.intInfo(target).bits; | 1211 | var bigint_buf: BigIntSpace = undefined; |
| 1805 | switch (val.tag()) { | 1212 | const bigint = val.toBigInt(&bigint_buf, mod); |
| 1806 | .zero, .bool_false => return ty_bits, | 1213 | return bigint.ctz(ty.intInfo(mod).bits); |
| 1807 | .one, .bool_true => return 0, | ||
| 1808 | |||
| 1809 | .int_u64 => { | ||
| 1810 | const big = @ctz(val.castTag(.int_u64).?.data); | ||
| 1811 | return if (big == 64) ty_bits else big; | ||
| 1812 | }, | ||
| 1813 | .int_i64 => { | ||
| 1814 | @panic("TODO implement i64 Value ctz"); | ||
| 1815 | }, | ||
| 1816 | .int_big_positive => { | ||
| 1817 | const bigint = val.castTag(.int_big_positive).?.asBigInt(); | ||
| 1818 | return bigint.ctz(); | ||
| 1819 | }, | ||
| 1820 | .int_big_negative => { | ||
| 1821 | @panic("TODO implement int_big_negative Value ctz"); | ||
| 1822 | }, | ||
| 1823 | |||
| 1824 | .the_only_possible_value => { | ||
| 1825 | assert(ty_bits == 0); | ||
| 1826 | return ty_bits; | ||
| 1827 | }, | ||
| 1828 | |||
| 1829 | .lazy_align, .lazy_size => { | ||
| 1830 | var bigint_buf: BigIntSpace = undefined; | ||
| 1831 | const bigint = val.toBigIntAdvanced(&bigint_buf, target, null) catch unreachable; | ||
| 1832 | return bigint.ctz(); | ||
| 1833 | }, | ||
| 1834 | |||
| 1835 | else => unreachable, | ||
| 1836 | } | ||
| 1837 | } | 1214 | } |
| 1838 | 1215 | ||
| 1839 | pub fn popCount(val: Value, ty: Type, target: Target) u64 { | 1216 | pub fn popCount(val: Value, ty: Type, mod: *Module) u64 { |
| 1840 | assert(!val.isUndef()); | 1217 | var bigint_buf: BigIntSpace = undefined; |
| 1841 | switch (val.tag()) { | 1218 | const bigint = val.toBigInt(&bigint_buf, mod); |
| 1842 | .zero, .bool_false => return 0, | 1219 | return @intCast(u64, bigint.popCount(ty.intInfo(mod).bits)); |
| 1843 | .one, .bool_true => return 1, | ||
| 1844 | |||
| 1845 | .int_u64 => return @popCount(val.castTag(.int_u64).?.data), | ||
| 1846 | |||
| 1847 | else => { | ||
| 1848 | const info = ty.intInfo(target); | ||
| 1849 | |||
| 1850 | var buffer: Value.BigIntSpace = undefined; | ||
| 1851 | const int = val.toBigInt(&buffer, target); | ||
| 1852 | return @intCast(u64, int.popCount(info.bits)); | ||
| 1853 | }, | ||
| 1854 | } | ||
| 1855 | } | 1220 | } |
| 1856 | 1221 | ||
| 1857 | pub fn bitReverse(val: Value, ty: Type, target: Target, arena: Allocator) !Value { | 1222 | pub fn bitReverse(val: Value, ty: Type, mod: *Module, arena: Allocator) !Value { |
| 1858 | assert(!val.isUndef()); | 1223 | const info = ty.intInfo(mod); |
| 1859 | |||
| 1860 | const info = ty.intInfo(target); | ||
| 1861 | 1224 | ||
| 1862 | var buffer: Value.BigIntSpace = undefined; | 1225 | var buffer: Value.BigIntSpace = undefined; |
| 1863 | const operand_bigint = val.toBigInt(&buffer, target); | 1226 | const operand_bigint = val.toBigInt(&buffer, mod); |
| 1864 | 1227 | ||
| 1865 | const limbs = try arena.alloc( | 1228 | const limbs = try arena.alloc( |
| 1866 | std.math.big.Limb, | 1229 | std.math.big.Limb, |
| ... | @@ -1869,19 +1232,17 @@ pub const Value = extern union { | ... | @@ -1869,19 +1232,17 @@ pub const Value = extern union { |
| 1869 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 1232 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 1870 | result_bigint.bitReverse(operand_bigint, info.signedness, info.bits); | 1233 | result_bigint.bitReverse(operand_bigint, info.signedness, info.bits); |
| 1871 | 1234 | ||
| 1872 | return fromBigInt(arena, result_bigint.toConst()); | 1235 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 1873 | } | 1236 | } |
| 1874 | 1237 | ||
| 1875 | pub fn byteSwap(val: Value, ty: Type, target: Target, arena: Allocator) !Value { | 1238 | pub fn byteSwap(val: Value, ty: Type, mod: *Module, arena: Allocator) !Value { |
| 1876 | assert(!val.isUndef()); | 1239 | const info = ty.intInfo(mod); |
| 1877 | |||
| 1878 | const info = ty.intInfo(target); | ||
| 1879 | 1240 | ||
| 1880 | // Bit count must be evenly divisible by 8 | 1241 | // Bit count must be evenly divisible by 8 |
| 1881 | assert(info.bits % 8 == 0); | 1242 | assert(info.bits % 8 == 0); |
| 1882 | 1243 | ||
| 1883 | var buffer: Value.BigIntSpace = undefined; | 1244 | var buffer: Value.BigIntSpace = undefined; |
| 1884 | const operand_bigint = val.toBigInt(&buffer, target); | 1245 | const operand_bigint = val.toBigInt(&buffer, mod); |
| 1885 | 1246 | ||
| 1886 | const limbs = try arena.alloc( | 1247 | const limbs = try arena.alloc( |
| 1887 | std.math.big.Limb, | 1248 | std.math.big.Limb, |
| ... | @@ -1890,176 +1251,98 @@ pub const Value = extern union { | ... | @@ -1890,176 +1251,98 @@ pub const Value = extern union { |
| 1890 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 1251 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 1891 | result_bigint.byteSwap(operand_bigint, info.signedness, info.bits / 8); | 1252 | result_bigint.byteSwap(operand_bigint, info.signedness, info.bits / 8); |
| 1892 | 1253 | ||
| 1893 | return fromBigInt(arena, result_bigint.toConst()); | 1254 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 1894 | } | 1255 | } |
| 1895 | 1256 | ||
| 1896 | /// Asserts the value is an integer and not undefined. | 1257 | /// Asserts the value is an integer and not undefined. |
| 1897 | /// Returns the number of bits the value requires to represent stored in twos complement form. | 1258 | /// Returns the number of bits the value requires to represent stored in twos complement form. |
| 1898 | pub fn intBitCountTwosComp(self: Value, target: Target) usize { | 1259 | pub fn intBitCountTwosComp(self: Value, mod: *Module) usize { |
| 1899 | switch (self.tag()) { | 1260 | var buffer: BigIntSpace = undefined; |
| 1900 | .zero, | 1261 | const big_int = self.toBigInt(&buffer, mod); |
| 1901 | .bool_false, | 1262 | return big_int.bitCountTwosComp(); |
| 1902 | .the_only_possible_value, | ||
| 1903 | => return 0, | ||
| 1904 | |||
| 1905 | .one, | ||
| 1906 | .bool_true, | ||
| 1907 | => return 1, | ||
| 1908 | |||
| 1909 | .int_u64 => { | ||
| 1910 | const x = self.castTag(.int_u64).?.data; | ||
| 1911 | if (x == 0) return 0; | ||
| 1912 | return @intCast(usize, std.math.log2(x) + 1); | ||
| 1913 | }, | ||
| 1914 | .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(), | ||
| 1915 | .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(), | ||
| 1916 | |||
| 1917 | .decl_ref_mut, | ||
| 1918 | .comptime_field_ptr, | ||
| 1919 | .extern_fn, | ||
| 1920 | .decl_ref, | ||
| 1921 | .function, | ||
| 1922 | .variable, | ||
| 1923 | .eu_payload_ptr, | ||
| 1924 | .opt_payload_ptr, | ||
| 1925 | => return target.ptrBitWidth(), | ||
| 1926 | |||
| 1927 | else => { | ||
| 1928 | var buffer: BigIntSpace = undefined; | ||
| 1929 | return self.toBigInt(&buffer, target).bitCountTwosComp(); | ||
| 1930 | }, | ||
| 1931 | } | ||
| 1932 | } | 1263 | } |
| 1933 | 1264 | ||
| 1934 | /// Converts an integer or a float to a float. May result in a loss of information. | 1265 | /// Converts an integer or a float to a float. May result in a loss of information. |
| 1935 | /// Caller can find out by equality checking the result against the operand. | 1266 | /// Caller can find out by equality checking the result against the operand. |
| 1936 | pub fn floatCast(self: Value, arena: Allocator, dest_ty: Type, target: Target) !Value { | 1267 | pub fn floatCast(self: Value, dest_ty: Type, mod: *Module) !Value { |
| 1937 | switch (dest_ty.floatBits(target)) { | 1268 | const target = mod.getTarget(); |
| 1938 | 16 => return Value.Tag.float_16.create(arena, self.toFloat(f16)), | 1269 | return (try mod.intern(.{ .float = .{ |
| 1939 | 32 => return Value.Tag.float_32.create(arena, self.toFloat(f32)), | 1270 | .ty = dest_ty.toIntern(), |
| 1940 | 64 => return Value.Tag.float_64.create(arena, self.toFloat(f64)), | 1271 | .storage = switch (dest_ty.floatBits(target)) { |
| 1941 | 80 => return Value.Tag.float_80.create(arena, self.toFloat(f80)), | 1272 | 16 => .{ .f16 = self.toFloat(f16, mod) }, |
| 1942 | 128 => return Value.Tag.float_128.create(arena, self.toFloat(f128)), | 1273 | 32 => .{ .f32 = self.toFloat(f32, mod) }, |
| 1943 | else => unreachable, | 1274 | 64 => .{ .f64 = self.toFloat(f64, mod) }, |
| 1944 | } | 1275 | 80 => .{ .f80 = self.toFloat(f80, mod) }, |
| 1276 | 128 => .{ .f128 = self.toFloat(f128, mod) }, | ||
| 1277 | else => unreachable, | ||
| 1278 | }, | ||
| 1279 | } })).toValue(); | ||
| 1945 | } | 1280 | } |
| 1946 | 1281 | ||
| 1947 | /// Asserts the value is a float | 1282 | /// Asserts the value is a float |
| 1948 | pub fn floatHasFraction(self: Value) bool { | 1283 | pub fn floatHasFraction(self: Value, mod: *const Module) bool { |
| 1949 | return switch (self.tag()) { | 1284 | return switch (mod.intern_pool.indexToKey(self.toIntern())) { |
| 1950 | .zero, | 1285 | .float => |float| switch (float.storage) { |
| 1951 | .one, | 1286 | inline else => |x| @rem(x, 1) != 0, |
| 1952 | => false, | 1287 | }, |
| 1953 | |||
| 1954 | .float_16 => @rem(self.castTag(.float_16).?.data, 1) != 0, | ||
| 1955 | .float_32 => @rem(self.castTag(.float_32).?.data, 1) != 0, | ||
| 1956 | .float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0, | ||
| 1957 | //.float_80 => @rem(self.castTag(.float_80).?.data, 1) != 0, | ||
| 1958 | .float_80 => @panic("TODO implement __remx in compiler-rt"), | ||
| 1959 | .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0, | ||
| 1960 | |||
| 1961 | else => unreachable, | 1288 | else => unreachable, |
| 1962 | }; | 1289 | }; |
| 1963 | } | 1290 | } |
| 1964 | 1291 | ||
| 1965 | pub fn orderAgainstZero(lhs: Value) std.math.Order { | 1292 | pub fn orderAgainstZero(lhs: Value, mod: *Module) std.math.Order { |
| 1966 | return orderAgainstZeroAdvanced(lhs, null) catch unreachable; | 1293 | return orderAgainstZeroAdvanced(lhs, mod, null) catch unreachable; |
| 1967 | } | 1294 | } |
| 1968 | 1295 | ||
| 1969 | pub fn orderAgainstZeroAdvanced( | 1296 | pub fn orderAgainstZeroAdvanced( |
| 1970 | lhs: Value, | 1297 | lhs: Value, |
| 1298 | mod: *Module, | ||
| 1971 | opt_sema: ?*Sema, | 1299 | opt_sema: ?*Sema, |
| 1972 | ) Module.CompileError!std.math.Order { | 1300 | ) Module.CompileError!std.math.Order { |
| 1973 | return switch (lhs.tag()) { | 1301 | return switch (lhs.toIntern()) { |
| 1974 | .zero, | 1302 | .bool_false => .eq, |
| 1975 | .bool_false, | 1303 | .bool_true => .gt, |
| 1976 | .the_only_possible_value, | 1304 | else => switch (mod.intern_pool.indexToKey(lhs.toIntern())) { |
| 1977 | => .eq, | 1305 | .ptr => |ptr| switch (ptr.addr) { |
| 1978 | 1306 | .decl, .mut_decl, .comptime_field => .gt, | |
| 1979 | .one, | 1307 | .int => |int| int.toValue().orderAgainstZeroAdvanced(mod, opt_sema), |
| 1980 | .bool_true, | 1308 | .elem => |elem| switch (try elem.base.toValue().orderAgainstZeroAdvanced(mod, opt_sema)) { |
| 1981 | .decl_ref, | 1309 | .lt => unreachable, |
| 1982 | .decl_ref_mut, | 1310 | .gt => .gt, |
| 1983 | .comptime_field_ptr, | 1311 | .eq => if (elem.index == 0) .eq else .gt, |
| 1984 | .extern_fn, | ||
| 1985 | .function, | ||
| 1986 | .variable, | ||
| 1987 | => .gt, | ||
| 1988 | |||
| 1989 | .enum_field_index => return std.math.order(lhs.castTag(.enum_field_index).?.data, 0), | ||
| 1990 | .runtime_value => { | ||
| 1991 | // This is needed to correctly handle hashing the value. | ||
| 1992 | // Checks in Sema should prevent direct comparisons from reaching here. | ||
| 1993 | const val = lhs.castTag(.runtime_value).?.data; | ||
| 1994 | return val.orderAgainstZeroAdvanced(opt_sema); | ||
| 1995 | }, | ||
| 1996 | .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0), | ||
| 1997 | .int_i64 => std.math.order(lhs.castTag(.int_i64).?.data, 0), | ||
| 1998 | .int_big_positive => lhs.castTag(.int_big_positive).?.asBigInt().orderAgainstScalar(0), | ||
| 1999 | .int_big_negative => lhs.castTag(.int_big_negative).?.asBigInt().orderAgainstScalar(0), | ||
| 2000 | |||
| 2001 | .lazy_align => { | ||
| 2002 | const ty = lhs.castTag(.lazy_align).?.data; | ||
| 2003 | const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; | ||
| 2004 | if (ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | ||
| 2005 | error.NeedLazy => unreachable, | ||
| 2006 | else => |e| return e, | ||
| 2007 | }) { | ||
| 2008 | return .gt; | ||
| 2009 | } else { | ||
| 2010 | return .eq; | ||
| 2011 | } | ||
| 2012 | }, | ||
| 2013 | .lazy_size => { | ||
| 2014 | const ty = lhs.castTag(.lazy_size).?.data; | ||
| 2015 | const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; | ||
| 2016 | if (ty.hasRuntimeBitsAdvanced(false, strat) catch |err| switch (err) { | ||
| 2017 | error.NeedLazy => unreachable, | ||
| 2018 | else => |e| return e, | ||
| 2019 | }) { | ||
| 2020 | return .gt; | ||
| 2021 | } else { | ||
| 2022 | return .eq; | ||
| 2023 | } | ||
| 2024 | }, | ||
| 2025 | |||
| 2026 | .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0), | ||
| 2027 | .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0), | ||
| 2028 | .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0), | ||
| 2029 | .float_80 => std.math.order(lhs.castTag(.float_80).?.data, 0), | ||
| 2030 | .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0), | ||
| 2031 | |||
| 2032 | .elem_ptr => { | ||
| 2033 | const elem_ptr = lhs.castTag(.elem_ptr).?.data; | ||
| 2034 | switch (try elem_ptr.array_ptr.orderAgainstZeroAdvanced(opt_sema)) { | ||
| 2035 | .lt => unreachable, | ||
| 2036 | .gt => return .gt, | ||
| 2037 | .eq => { | ||
| 2038 | if (elem_ptr.index == 0) { | ||
| 2039 | return .eq; | ||
| 2040 | } else { | ||
| 2041 | return .gt; | ||
| 2042 | } | ||
| 2043 | }, | 1312 | }, |
| 2044 | } | 1313 | else => unreachable, |
| 1314 | }, | ||
| 1315 | .int => |int| switch (int.storage) { | ||
| 1316 | .big_int => |big_int| big_int.orderAgainstScalar(0), | ||
| 1317 | inline .u64, .i64 => |x| std.math.order(x, 0), | ||
| 1318 | .lazy_align, .lazy_size => |ty| return if (ty.toType().hasRuntimeBitsAdvanced( | ||
| 1319 | mod, | ||
| 1320 | false, | ||
| 1321 | if (opt_sema) |sema| .{ .sema = sema } else .eager, | ||
| 1322 | ) catch |err| switch (err) { | ||
| 1323 | error.NeedLazy => unreachable, | ||
| 1324 | else => |e| return e, | ||
| 1325 | }) .gt else .eq, | ||
| 1326 | }, | ||
| 1327 | .enum_tag => |enum_tag| enum_tag.int.toValue().orderAgainstZeroAdvanced(mod, opt_sema), | ||
| 1328 | .float => |float| switch (float.storage) { | ||
| 1329 | inline else => |x| std.math.order(x, 0), | ||
| 1330 | }, | ||
| 1331 | else => unreachable, | ||
| 2045 | }, | 1332 | }, |
| 2046 | |||
| 2047 | else => unreachable, | ||
| 2048 | }; | 1333 | }; |
| 2049 | } | 1334 | } |
| 2050 | 1335 | ||
| 2051 | /// Asserts the value is comparable. | 1336 | /// Asserts the value is comparable. |
| 2052 | pub fn order(lhs: Value, rhs: Value, target: Target) std.math.Order { | 1337 | pub fn order(lhs: Value, rhs: Value, mod: *Module) std.math.Order { |
| 2053 | return orderAdvanced(lhs, rhs, target, null) catch unreachable; | 1338 | return orderAdvanced(lhs, rhs, mod, null) catch unreachable; |
| 2054 | } | 1339 | } |
| 2055 | 1340 | ||
| 2056 | /// Asserts the value is comparable. | 1341 | /// Asserts the value is comparable. |
| 2057 | /// If opt_sema is null then this function asserts things are resolved and cannot fail. | 1342 | /// If opt_sema is null then this function asserts things are resolved and cannot fail. |
| 2058 | pub fn orderAdvanced(lhs: Value, rhs: Value, target: Target, opt_sema: ?*Sema) !std.math.Order { | 1343 | pub fn orderAdvanced(lhs: Value, rhs: Value, mod: *Module, opt_sema: ?*Sema) !std.math.Order { |
| 2059 | const lhs_tag = lhs.tag(); | 1344 | const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(mod, opt_sema); |
| 2060 | const rhs_tag = rhs.tag(); | 1345 | const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(mod, opt_sema); |
| 2061 | const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(opt_sema); | ||
| 2062 | const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(opt_sema); | ||
| 2063 | switch (lhs_against_zero) { | 1346 | switch (lhs_against_zero) { |
| 2064 | .lt => if (rhs_against_zero != .lt) return .lt, | 1347 | .lt => if (rhs_against_zero != .lt) return .lt, |
| 2065 | .eq => return rhs_against_zero.invert(), | 1348 | .eq => return rhs_against_zero.invert(), |
| ... | @@ -2071,48 +1354,34 @@ pub const Value = extern union { | ... | @@ -2071,48 +1354,34 @@ pub const Value = extern union { |
| 2071 | .gt => {}, | 1354 | .gt => {}, |
| 2072 | } | 1355 | } |
| 2073 | 1356 | ||
| 2074 | const lhs_float = lhs.isFloat(); | 1357 | if (lhs.isFloat(mod) or rhs.isFloat(mod)) { |
| 2075 | const rhs_float = rhs.isFloat(); | 1358 | const lhs_f128 = lhs.toFloat(f128, mod); |
| 2076 | if (lhs_float and rhs_float) { | 1359 | const rhs_f128 = rhs.toFloat(f128, mod); |
| 2077 | if (lhs_tag == rhs_tag) { | ||
| 2078 | return switch (lhs.tag()) { | ||
| 2079 | .float_16 => return std.math.order(lhs.castTag(.float_16).?.data, rhs.castTag(.float_16).?.data), | ||
| 2080 | .float_32 => return std.math.order(lhs.castTag(.float_32).?.data, rhs.castTag(.float_32).?.data), | ||
| 2081 | .float_64 => return std.math.order(lhs.castTag(.float_64).?.data, rhs.castTag(.float_64).?.data), | ||
| 2082 | .float_80 => return std.math.order(lhs.castTag(.float_80).?.data, rhs.castTag(.float_80).?.data), | ||
| 2083 | .float_128 => return std.math.order(lhs.castTag(.float_128).?.data, rhs.castTag(.float_128).?.data), | ||
| 2084 | else => unreachable, | ||
| 2085 | }; | ||
| 2086 | } | ||
| 2087 | } | ||
| 2088 | if (lhs_float or rhs_float) { | ||
| 2089 | const lhs_f128 = lhs.toFloat(f128); | ||
| 2090 | const rhs_f128 = rhs.toFloat(f128); | ||
| 2091 | return std.math.order(lhs_f128, rhs_f128); | 1360 | return std.math.order(lhs_f128, rhs_f128); |
| 2092 | } | 1361 | } |
| 2093 | 1362 | ||
| 2094 | var lhs_bigint_space: BigIntSpace = undefined; | 1363 | var lhs_bigint_space: BigIntSpace = undefined; |
| 2095 | var rhs_bigint_space: BigIntSpace = undefined; | 1364 | var rhs_bigint_space: BigIntSpace = undefined; |
| 2096 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, target, opt_sema); | 1365 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, mod, opt_sema); |
| 2097 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, target, opt_sema); | 1366 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, mod, opt_sema); |
| 2098 | return lhs_bigint.order(rhs_bigint); | 1367 | return lhs_bigint.order(rhs_bigint); |
| 2099 | } | 1368 | } |
| 2100 | 1369 | ||
| 2101 | /// Asserts the value is comparable. Does not take a type parameter because it supports | 1370 | /// Asserts the value is comparable. Does not take a type parameter because it supports |
| 2102 | /// comparisons between heterogeneous types. | 1371 | /// comparisons between heterogeneous types. |
| 2103 | pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, target: Target) bool { | 1372 | pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, mod: *Module) bool { |
| 2104 | return compareHeteroAdvanced(lhs, op, rhs, target, null) catch unreachable; | 1373 | return compareHeteroAdvanced(lhs, op, rhs, mod, null) catch unreachable; |
| 2105 | } | 1374 | } |
| 2106 | 1375 | ||
| 2107 | pub fn compareHeteroAdvanced( | 1376 | pub fn compareHeteroAdvanced( |
| 2108 | lhs: Value, | 1377 | lhs: Value, |
| 2109 | op: std.math.CompareOperator, | 1378 | op: std.math.CompareOperator, |
| 2110 | rhs: Value, | 1379 | rhs: Value, |
| 2111 | target: Target, | 1380 | mod: *Module, |
| 2112 | opt_sema: ?*Sema, | 1381 | opt_sema: ?*Sema, |
| 2113 | ) !bool { | 1382 | ) !bool { |
| 2114 | if (lhs.pointerDecl()) |lhs_decl| { | 1383 | if (lhs.pointerDecl(mod)) |lhs_decl| { |
| 2115 | if (rhs.pointerDecl()) |rhs_decl| { | 1384 | if (rhs.pointerDecl(mod)) |rhs_decl| { |
| 2116 | switch (op) { | 1385 | switch (op) { |
| 2117 | .eq => return lhs_decl == rhs_decl, | 1386 | .eq => return lhs_decl == rhs_decl, |
| 2118 | .neq => return lhs_decl != rhs_decl, | 1387 | .neq => return lhs_decl != rhs_decl, |
| ... | @@ -2125,27 +1394,25 @@ pub const Value = extern union { | ... | @@ -2125,27 +1394,25 @@ pub const Value = extern union { |
| 2125 | else => {}, | 1394 | else => {}, |
| 2126 | } | 1395 | } |
| 2127 | } | 1396 | } |
| 2128 | } else if (rhs.pointerDecl()) |_| { | 1397 | } else if (rhs.pointerDecl(mod)) |_| { |
| 2129 | switch (op) { | 1398 | switch (op) { |
| 2130 | .eq => return false, | 1399 | .eq => return false, |
| 2131 | .neq => return true, | 1400 | .neq => return true, |
| 2132 | else => {}, | 1401 | else => {}, |
| 2133 | } | 1402 | } |
| 2134 | } | 1403 | } |
| 2135 | return (try orderAdvanced(lhs, rhs, target, opt_sema)).compare(op); | 1404 | return (try orderAdvanced(lhs, rhs, mod, opt_sema)).compare(op); |
| 2136 | } | 1405 | } |
| 2137 | 1406 | ||
| 2138 | /// Asserts the values are comparable. Both operands have type `ty`. | 1407 | /// Asserts the values are comparable. Both operands have type `ty`. |
| 2139 | /// For vectors, returns true if comparison is true for ALL elements. | 1408 | /// For vectors, returns true if comparison is true for ALL elements. |
| 2140 | pub fn compareAll(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, mod: *Module) bool { | 1409 | pub fn compareAll(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, mod: *Module) !bool { |
| 2141 | if (ty.zigTypeTag() == .Vector) { | 1410 | if (ty.zigTypeTag(mod) == .Vector) { |
| 2142 | var i: usize = 0; | 1411 | const scalar_ty = ty.scalarType(mod); |
| 2143 | while (i < ty.vectorLen()) : (i += 1) { | 1412 | for (0..ty.vectorLen(mod)) |i| { |
| 2144 | var lhs_buf: Value.ElemValueBuffer = undefined; | 1413 | const lhs_elem = try lhs.elemValue(mod, i); |
| 2145 | var rhs_buf: Value.ElemValueBuffer = undefined; | 1414 | const rhs_elem = try rhs.elemValue(mod, i); |
| 2146 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 1415 | if (!compareScalar(lhs_elem, op, rhs_elem, scalar_ty, mod)) { |
| 2147 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 2148 | if (!compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(), mod)) { | ||
| 2149 | return false; | 1416 | return false; |
| 2150 | } | 1417 | } |
| 2151 | } | 1418 | } |
| ... | @@ -2165,7 +1432,7 @@ pub const Value = extern union { | ... | @@ -2165,7 +1432,7 @@ pub const Value = extern union { |
| 2165 | return switch (op) { | 1432 | return switch (op) { |
| 2166 | .eq => lhs.eql(rhs, ty, mod), | 1433 | .eq => lhs.eql(rhs, ty, mod), |
| 2167 | .neq => !lhs.eql(rhs, ty, mod), | 1434 | .neq => !lhs.eql(rhs, ty, mod), |
| 2168 | else => compareHetero(lhs, op, rhs, mod.getTarget()), | 1435 | else => compareHetero(lhs, op, rhs, mod), |
| 2169 | }; | 1436 | }; |
| 2170 | } | 1437 | } |
| 2171 | 1438 | ||
| ... | @@ -2191,47 +1458,31 @@ pub const Value = extern union { | ... | @@ -2191,47 +1458,31 @@ pub const Value = extern union { |
| 2191 | mod: *Module, | 1458 | mod: *Module, |
| 2192 | opt_sema: ?*Sema, | 1459 | opt_sema: ?*Sema, |
| 2193 | ) Module.CompileError!bool { | 1460 | ) Module.CompileError!bool { |
| 2194 | if (lhs.isInf()) { | 1461 | if (lhs.isInf(mod)) { |
| 2195 | switch (op) { | 1462 | switch (op) { |
| 2196 | .neq => return true, | 1463 | .neq => return true, |
| 2197 | .eq => return false, | 1464 | .eq => return false, |
| 2198 | .gt, .gte => return !lhs.isNegativeInf(), | 1465 | .gt, .gte => return !lhs.isNegativeInf(mod), |
| 2199 | .lt, .lte => return lhs.isNegativeInf(), | 1466 | .lt, .lte => return lhs.isNegativeInf(mod), |
| 2200 | } | 1467 | } |
| 2201 | } | 1468 | } |
| 2202 | 1469 | ||
| 2203 | switch (lhs.tag()) { | 1470 | switch (mod.intern_pool.indexToKey(lhs.toIntern())) { |
| 2204 | .repeated => return lhs.castTag(.repeated).?.data.compareAllWithZeroAdvancedExtra(op, mod, opt_sema), | 1471 | .float => |float| switch (float.storage) { |
| 2205 | .aggregate => { | 1472 | inline else => |x| if (std.math.isNan(x)) return op == .neq, |
| 2206 | for (lhs.castTag(.aggregate).?.data) |elem_val| { | ||
| 2207 | if (!(try elem_val.compareAllWithZeroAdvancedExtra(op, mod, opt_sema))) return false; | ||
| 2208 | } | ||
| 2209 | return true; | ||
| 2210 | }, | 1473 | }, |
| 2211 | .empty_array => return true, | 1474 | .aggregate => |aggregate| return switch (aggregate.storage) { |
| 2212 | .str_lit => { | 1475 | .bytes => |bytes| for (bytes) |byte| { |
| 2213 | const str_lit = lhs.castTag(.str_lit).?.data; | 1476 | if (!std.math.order(byte, 0).compare(op)) break false; |
| 2214 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | 1477 | } else true, |
| 2215 | for (bytes) |byte| { | 1478 | .elems => |elems| for (elems) |elem| { |
| 2216 | if (!std.math.compare(byte, op, 0)) return false; | 1479 | if (!try elem.toValue().compareAllWithZeroAdvancedExtra(op, mod, opt_sema)) break false; |
| 2217 | } | 1480 | } else true, |
| 2218 | return true; | 1481 | .repeated_elem => |elem| elem.toValue().compareAllWithZeroAdvancedExtra(op, mod, opt_sema), |
| 2219 | }, | ||
| 2220 | .bytes => { | ||
| 2221 | const bytes = lhs.castTag(.bytes).?.data; | ||
| 2222 | for (bytes) |byte| { | ||
| 2223 | if (!std.math.compare(byte, op, 0)) return false; | ||
| 2224 | } | ||
| 2225 | return true; | ||
| 2226 | }, | 1482 | }, |
| 2227 | .float_16 => if (std.math.isNan(lhs.castTag(.float_16).?.data)) return op == .neq, | ||
| 2228 | .float_32 => if (std.math.isNan(lhs.castTag(.float_32).?.data)) return op == .neq, | ||
| 2229 | .float_64 => if (std.math.isNan(lhs.castTag(.float_64).?.data)) return op == .neq, | ||
| 2230 | .float_80 => if (std.math.isNan(lhs.castTag(.float_80).?.data)) return op == .neq, | ||
| 2231 | .float_128 => if (std.math.isNan(lhs.castTag(.float_128).?.data)) return op == .neq, | ||
| 2232 | else => {}, | 1483 | else => {}, |
| 2233 | } | 1484 | } |
| 2234 | return (try orderAgainstZeroAdvanced(lhs, opt_sema)).compare(op); | 1485 | return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op); |
| 2235 | } | 1486 | } |
| 2236 | 1487 | ||
| 2237 | pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool { | 1488 | pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool { |
| ... | @@ -2255,109 +1506,42 @@ pub const Value = extern union { | ... | @@ -2255,109 +1506,42 @@ pub const Value = extern union { |
| 2255 | mod: *Module, | 1506 | mod: *Module, |
| 2256 | opt_sema: ?*Sema, | 1507 | opt_sema: ?*Sema, |
| 2257 | ) Module.CompileError!bool { | 1508 | ) Module.CompileError!bool { |
| 1509 | if (a.ip_index != .none or b.ip_index != .none) return a.ip_index == b.ip_index; | ||
| 1510 | |||
| 2258 | const target = mod.getTarget(); | 1511 | const target = mod.getTarget(); |
| 2259 | const a_tag = a.tag(); | 1512 | const a_tag = a.tag(); |
| 2260 | const b_tag = b.tag(); | 1513 | const b_tag = b.tag(); |
| 2261 | if (a_tag == b_tag) switch (a_tag) { | 1514 | if (a_tag == b_tag) switch (a_tag) { |
| 2262 | .undef => return true, | ||
| 2263 | .void_value, .null_value, .the_only_possible_value, .empty_struct_value => return true, | ||
| 2264 | .enum_literal => { | ||
| 2265 | const a_name = a.castTag(.enum_literal).?.data; | ||
| 2266 | const b_name = b.castTag(.enum_literal).?.data; | ||
| 2267 | return std.mem.eql(u8, a_name, b_name); | ||
| 2268 | }, | ||
| 2269 | .enum_field_index => { | ||
| 2270 | const a_field_index = a.castTag(.enum_field_index).?.data; | ||
| 2271 | const b_field_index = b.castTag(.enum_field_index).?.data; | ||
| 2272 | return a_field_index == b_field_index; | ||
| 2273 | }, | ||
| 2274 | .opt_payload => { | ||
| 2275 | const a_payload = a.castTag(.opt_payload).?.data; | ||
| 2276 | const b_payload = b.castTag(.opt_payload).?.data; | ||
| 2277 | var buffer: Type.Payload.ElemType = undefined; | ||
| 2278 | const payload_ty = ty.optionalChild(&buffer); | ||
| 2279 | return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, opt_sema); | ||
| 2280 | }, | ||
| 2281 | .slice => { | ||
| 2282 | const a_payload = a.castTag(.slice).?.data; | ||
| 2283 | const b_payload = b.castTag(.slice).?.data; | ||
| 2284 | if (!(try eqlAdvanced(a_payload.len, Type.usize, b_payload.len, Type.usize, mod, opt_sema))) { | ||
| 2285 | return false; | ||
| 2286 | } | ||
| 2287 | |||
| 2288 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 2289 | const ptr_ty = ty.slicePtrFieldType(&ptr_buf); | ||
| 2290 | |||
| 2291 | return eqlAdvanced(a_payload.ptr, ptr_ty, b_payload.ptr, ptr_ty, mod, opt_sema); | ||
| 2292 | }, | ||
| 2293 | .elem_ptr => { | ||
| 2294 | const a_payload = a.castTag(.elem_ptr).?.data; | ||
| 2295 | const b_payload = b.castTag(.elem_ptr).?.data; | ||
| 2296 | if (a_payload.index != b_payload.index) return false; | ||
| 2297 | |||
| 2298 | return eqlAdvanced(a_payload.array_ptr, ty, b_payload.array_ptr, ty, mod, opt_sema); | ||
| 2299 | }, | ||
| 2300 | .field_ptr => { | ||
| 2301 | const a_payload = a.castTag(.field_ptr).?.data; | ||
| 2302 | const b_payload = b.castTag(.field_ptr).?.data; | ||
| 2303 | if (a_payload.field_index != b_payload.field_index) return false; | ||
| 2304 | |||
| 2305 | return eqlAdvanced(a_payload.container_ptr, ty, b_payload.container_ptr, ty, mod, opt_sema); | ||
| 2306 | }, | ||
| 2307 | .@"error" => { | ||
| 2308 | const a_name = a.castTag(.@"error").?.data.name; | ||
| 2309 | const b_name = b.castTag(.@"error").?.data.name; | ||
| 2310 | return std.mem.eql(u8, a_name, b_name); | ||
| 2311 | }, | ||
| 2312 | .eu_payload => { | ||
| 2313 | const a_payload = a.castTag(.eu_payload).?.data; | ||
| 2314 | const b_payload = b.castTag(.eu_payload).?.data; | ||
| 2315 | const payload_ty = ty.errorUnionPayload(); | ||
| 2316 | return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, opt_sema); | ||
| 2317 | }, | ||
| 2318 | .eu_payload_ptr => { | ||
| 2319 | const a_payload = a.castTag(.eu_payload_ptr).?.data; | ||
| 2320 | const b_payload = b.castTag(.eu_payload_ptr).?.data; | ||
| 2321 | return eqlAdvanced(a_payload.container_ptr, ty, b_payload.container_ptr, ty, mod, opt_sema); | ||
| 2322 | }, | ||
| 2323 | .opt_payload_ptr => { | ||
| 2324 | const a_payload = a.castTag(.opt_payload_ptr).?.data; | ||
| 2325 | const b_payload = b.castTag(.opt_payload_ptr).?.data; | ||
| 2326 | return eqlAdvanced(a_payload.container_ptr, ty, b_payload.container_ptr, ty, mod, opt_sema); | ||
| 2327 | }, | ||
| 2328 | .function => { | ||
| 2329 | const a_payload = a.castTag(.function).?.data; | ||
| 2330 | const b_payload = b.castTag(.function).?.data; | ||
| 2331 | return a_payload == b_payload; | ||
| 2332 | }, | ||
| 2333 | .aggregate => { | 1515 | .aggregate => { |
| 2334 | const a_field_vals = a.castTag(.aggregate).?.data; | 1516 | const a_field_vals = a.castTag(.aggregate).?.data; |
| 2335 | const b_field_vals = b.castTag(.aggregate).?.data; | 1517 | const b_field_vals = b.castTag(.aggregate).?.data; |
| 2336 | assert(a_field_vals.len == b_field_vals.len); | 1518 | assert(a_field_vals.len == b_field_vals.len); |
| 2337 | 1519 | ||
| 2338 | if (ty.isSimpleTupleOrAnonStruct()) { | 1520 | switch (mod.intern_pool.indexToKey(ty.toIntern())) { |
| 2339 | const types = ty.tupleFields().types; | 1521 | .anon_struct_type => |anon_struct| { |
| 2340 | assert(types.len == a_field_vals.len); | 1522 | assert(anon_struct.types.len == a_field_vals.len); |
| 2341 | for (types, 0..) |field_ty, i| { | 1523 | for (anon_struct.types, 0..) |field_ty, i| { |
| 2342 | if (!(try eqlAdvanced(a_field_vals[i], field_ty, b_field_vals[i], field_ty, mod, opt_sema))) { | 1524 | if (!(try eqlAdvanced(a_field_vals[i], field_ty.toType(), b_field_vals[i], field_ty.toType(), mod, opt_sema))) { |
| 2343 | return false; | 1525 | return false; |
| 1526 | } | ||
| 2344 | } | 1527 | } |
| 2345 | } | 1528 | return true; |
| 2346 | return true; | 1529 | }, |
| 2347 | } | 1530 | .struct_type => |struct_type| { |
| 2348 | 1531 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 2349 | if (ty.zigTypeTag() == .Struct) { | 1532 | const fields = struct_obj.fields.values(); |
| 2350 | const fields = ty.structFields().values(); | 1533 | assert(fields.len == a_field_vals.len); |
| 2351 | assert(fields.len == a_field_vals.len); | 1534 | for (fields, 0..) |field, i| { |
| 2352 | for (fields, 0..) |field, i| { | 1535 | if (!(try eqlAdvanced(a_field_vals[i], field.ty, b_field_vals[i], field.ty, mod, opt_sema))) { |
| 2353 | if (!(try eqlAdvanced(a_field_vals[i], field.ty, b_field_vals[i], field.ty, mod, opt_sema))) { | 1536 | return false; |
| 2354 | return false; | 1537 | } |
| 2355 | } | 1538 | } |
| 2356 | } | 1539 | return true; |
| 2357 | return true; | 1540 | }, |
| 1541 | else => {}, | ||
| 2358 | } | 1542 | } |
| 2359 | 1543 | ||
| 2360 | const elem_ty = ty.childType(); | 1544 | const elem_ty = ty.childType(mod); |
| 2361 | for (a_field_vals, 0..) |a_elem, i| { | 1545 | for (a_field_vals, 0..) |a_elem, i| { |
| 2362 | const b_elem = b_field_vals[i]; | 1546 | const b_elem = b_field_vals[i]; |
| 2363 | 1547 | ||
| ... | @@ -2370,9 +1554,9 @@ pub const Value = extern union { | ... | @@ -2370,9 +1554,9 @@ pub const Value = extern union { |
| 2370 | .@"union" => { | 1554 | .@"union" => { |
| 2371 | const a_union = a.castTag(.@"union").?.data; | 1555 | const a_union = a.castTag(.@"union").?.data; |
| 2372 | const b_union = b.castTag(.@"union").?.data; | 1556 | const b_union = b.castTag(.@"union").?.data; |
| 2373 | switch (ty.containerLayout()) { | 1557 | switch (ty.containerLayout(mod)) { |
| 2374 | .Packed, .Extern => { | 1558 | .Packed, .Extern => { |
| 2375 | const tag_ty = ty.unionTagTypeHypothetical(); | 1559 | const tag_ty = ty.unionTagTypeHypothetical(mod); |
| 2376 | if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) { | 1560 | if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) { |
| 2377 | // In this case, we must disregard mismatching tags and compare | 1561 | // In this case, we must disregard mismatching tags and compare |
| 2378 | // based on the in-memory bytes of the payloads. | 1562 | // based on the in-memory bytes of the payloads. |
| ... | @@ -2380,7 +1564,7 @@ pub const Value = extern union { | ... | @@ -2380,7 +1564,7 @@ pub const Value = extern union { |
| 2380 | } | 1564 | } |
| 2381 | }, | 1565 | }, |
| 2382 | .Auto => { | 1566 | .Auto => { |
| 2383 | const tag_ty = ty.unionTagTypeHypothetical(); | 1567 | const tag_ty = ty.unionTagTypeHypothetical(mod); |
| 2384 | if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) { | 1568 | if (!(try eqlAdvanced(a_union.tag, tag_ty, b_union.tag, tag_ty, mod, opt_sema))) { |
| 2385 | return false; | 1569 | return false; |
| 2386 | } | 1570 | } |
| ... | @@ -2390,122 +1574,91 @@ pub const Value = extern union { | ... | @@ -2390,122 +1574,91 @@ pub const Value = extern union { |
| 2390 | return eqlAdvanced(a_union.val, active_field_ty, b_union.val, active_field_ty, mod, opt_sema); | 1574 | return eqlAdvanced(a_union.val, active_field_ty, b_union.val, active_field_ty, mod, opt_sema); |
| 2391 | }, | 1575 | }, |
| 2392 | else => {}, | 1576 | else => {}, |
| 2393 | } else if (b_tag == .null_value or b_tag == .@"error") { | 1577 | }; |
| 2394 | return false; | ||
| 2395 | } else if (a_tag == .undef or b_tag == .undef) { | ||
| 2396 | return false; | ||
| 2397 | } | ||
| 2398 | 1578 | ||
| 2399 | if (a.pointerDecl()) |a_decl| { | 1579 | if (a.pointerDecl(mod)) |a_decl| { |
| 2400 | if (b.pointerDecl()) |b_decl| { | 1580 | if (b.pointerDecl(mod)) |b_decl| { |
| 2401 | return a_decl == b_decl; | 1581 | return a_decl == b_decl; |
| 2402 | } else { | 1582 | } else { |
| 2403 | return false; | 1583 | return false; |
| 2404 | } | 1584 | } |
| 2405 | } else if (b.pointerDecl()) |_| { | 1585 | } else if (b.pointerDecl(mod)) |_| { |
| 2406 | return false; | 1586 | return false; |
| 2407 | } | 1587 | } |
| 2408 | 1588 | ||
| 2409 | switch (ty.zigTypeTag()) { | 1589 | switch (ty.zigTypeTag(mod)) { |
| 2410 | .Type => { | 1590 | .Type => { |
| 2411 | var buf_a: ToTypeBuffer = undefined; | 1591 | const a_type = a.toType(); |
| 2412 | var buf_b: ToTypeBuffer = undefined; | 1592 | const b_type = b.toType(); |
| 2413 | const a_type = a.toType(&buf_a); | ||
| 2414 | const b_type = b.toType(&buf_b); | ||
| 2415 | return a_type.eql(b_type, mod); | 1593 | return a_type.eql(b_type, mod); |
| 2416 | }, | 1594 | }, |
| 2417 | .Enum => { | 1595 | .Enum => { |
| 2418 | var buf_a: Payload.U64 = undefined; | 1596 | const a_val = try a.enumToInt(ty, mod); |
| 2419 | var buf_b: Payload.U64 = undefined; | 1597 | const b_val = try b.enumToInt(ty, mod); |
| 2420 | const a_val = a.enumToInt(ty, &buf_a); | 1598 | const int_ty = ty.intTagType(mod); |
| 2421 | const b_val = b.enumToInt(ty, &buf_b); | ||
| 2422 | var buf_ty: Type.Payload.Bits = undefined; | ||
| 2423 | const int_ty = ty.intTagType(&buf_ty); | ||
| 2424 | return eqlAdvanced(a_val, int_ty, b_val, int_ty, mod, opt_sema); | 1599 | return eqlAdvanced(a_val, int_ty, b_val, int_ty, mod, opt_sema); |
| 2425 | }, | 1600 | }, |
| 2426 | .Array, .Vector => { | 1601 | .Array, .Vector => { |
| 2427 | const len = ty.arrayLen(); | 1602 | const len = ty.arrayLen(mod); |
| 2428 | const elem_ty = ty.childType(); | 1603 | const elem_ty = ty.childType(mod); |
| 2429 | var i: usize = 0; | 1604 | var i: usize = 0; |
| 2430 | var a_buf: ElemValueBuffer = undefined; | ||
| 2431 | var b_buf: ElemValueBuffer = undefined; | ||
| 2432 | while (i < len) : (i += 1) { | 1605 | while (i < len) : (i += 1) { |
| 2433 | const a_elem = elemValueBuffer(a, mod, i, &a_buf); | 1606 | const a_elem = try elemValue(a, mod, i); |
| 2434 | const b_elem = elemValueBuffer(b, mod, i, &b_buf); | 1607 | const b_elem = try elemValue(b, mod, i); |
| 2435 | if (!(try eqlAdvanced(a_elem, elem_ty, b_elem, elem_ty, mod, opt_sema))) { | 1608 | if (!(try eqlAdvanced(a_elem, elem_ty, b_elem, elem_ty, mod, opt_sema))) { |
| 2436 | return false; | 1609 | return false; |
| 2437 | } | 1610 | } |
| 2438 | } | 1611 | } |
| 2439 | return true; | 1612 | return true; |
| 2440 | }, | 1613 | }, |
| 2441 | .Pointer => switch (ty.ptrSize()) { | 1614 | .Pointer => switch (ty.ptrSize(mod)) { |
| 2442 | .Slice => { | 1615 | .Slice => { |
| 2443 | const a_len = switch (a_ty.ptrSize()) { | 1616 | const a_len = switch (a_ty.ptrSize(mod)) { |
| 2444 | .Slice => a.sliceLen(mod), | 1617 | .Slice => a.sliceLen(mod), |
| 2445 | .One => a_ty.childType().arrayLen(), | 1618 | .One => a_ty.childType(mod).arrayLen(mod), |
| 2446 | else => unreachable, | 1619 | else => unreachable, |
| 2447 | }; | 1620 | }; |
| 2448 | if (a_len != b.sliceLen(mod)) { | 1621 | if (a_len != b.sliceLen(mod)) { |
| 2449 | return false; | 1622 | return false; |
| 2450 | } | 1623 | } |
| 2451 | 1624 | ||
| 2452 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1625 | const ptr_ty = ty.slicePtrFieldType(mod); |
| 2453 | const ptr_ty = ty.slicePtrFieldType(&ptr_buf); | 1626 | const a_ptr = switch (a_ty.ptrSize(mod)) { |
| 2454 | const a_ptr = switch (a_ty.ptrSize()) { | 1627 | .Slice => a.slicePtr(mod), |
| 2455 | .Slice => a.slicePtr(), | ||
| 2456 | .One => a, | 1628 | .One => a, |
| 2457 | else => unreachable, | 1629 | else => unreachable, |
| 2458 | }; | 1630 | }; |
| 2459 | return try eqlAdvanced(a_ptr, ptr_ty, b.slicePtr(), ptr_ty, mod, opt_sema); | 1631 | return try eqlAdvanced(a_ptr, ptr_ty, b.slicePtr(mod), ptr_ty, mod, opt_sema); |
| 2460 | }, | 1632 | }, |
| 2461 | .Many, .C, .One => {}, | 1633 | .Many, .C, .One => {}, |
| 2462 | }, | 1634 | }, |
| 2463 | .Struct => { | 1635 | .Struct => { |
| 2464 | // A struct can be represented with one of: | 1636 | // A struct can be represented with one of: |
| 2465 | // .empty_struct_value, | ||
| 2466 | // .the_one_possible_value, | 1637 | // .the_one_possible_value, |
| 2467 | // .aggregate, | 1638 | // .aggregate, |
| 2468 | // Note that we already checked above for matching tags, e.g. both .aggregate. | 1639 | // Note that we already checked above for matching tags, e.g. both .aggregate. |
| 2469 | return ty.onePossibleValue() != null; | 1640 | return (try ty.onePossibleValue(mod)) != null; |
| 2470 | }, | 1641 | }, |
| 2471 | .Union => { | 1642 | .Union => { |
| 2472 | // Here we have to check for value equality, as-if `a` has been coerced to `ty`. | 1643 | // Here we have to check for value equality, as-if `a` has been coerced to `ty`. |
| 2473 | if (ty.onePossibleValue() != null) { | 1644 | if ((try ty.onePossibleValue(mod)) != null) { |
| 2474 | return true; | 1645 | return true; |
| 2475 | } | 1646 | } |
| 2476 | if (a_ty.castTag(.anon_struct)) |payload| { | ||
| 2477 | const tuple = payload.data; | ||
| 2478 | if (tuple.values.len != 1) { | ||
| 2479 | return false; | ||
| 2480 | } | ||
| 2481 | const field_name = tuple.names[0]; | ||
| 2482 | const union_obj = ty.cast(Type.Payload.Union).?.data; | ||
| 2483 | const field_index = union_obj.fields.getIndex(field_name) orelse return false; | ||
| 2484 | const tag_and_val = b.castTag(.@"union").?.data; | ||
| 2485 | var field_tag_buf: Value.Payload.U32 = .{ | ||
| 2486 | .base = .{ .tag = .enum_field_index }, | ||
| 2487 | .data = @intCast(u32, field_index), | ||
| 2488 | }; | ||
| 2489 | const field_tag = Value.initPayload(&field_tag_buf.base); | ||
| 2490 | const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, mod); | ||
| 2491 | if (!tag_matches) return false; | ||
| 2492 | return eqlAdvanced(tag_and_val.val, union_obj.tag_ty, tuple.values[0], tuple.types[0], mod, opt_sema); | ||
| 2493 | } | ||
| 2494 | return false; | 1647 | return false; |
| 2495 | }, | 1648 | }, |
| 2496 | .Float => { | 1649 | .Float => { |
| 2497 | switch (ty.floatBits(target)) { | 1650 | switch (ty.floatBits(target)) { |
| 2498 | 16 => return @bitCast(u16, a.toFloat(f16)) == @bitCast(u16, b.toFloat(f16)), | 1651 | 16 => return @bitCast(u16, a.toFloat(f16, mod)) == @bitCast(u16, b.toFloat(f16, mod)), |
| 2499 | 32 => return @bitCast(u32, a.toFloat(f32)) == @bitCast(u32, b.toFloat(f32)), | 1652 | 32 => return @bitCast(u32, a.toFloat(f32, mod)) == @bitCast(u32, b.toFloat(f32, mod)), |
| 2500 | 64 => return @bitCast(u64, a.toFloat(f64)) == @bitCast(u64, b.toFloat(f64)), | 1653 | 64 => return @bitCast(u64, a.toFloat(f64, mod)) == @bitCast(u64, b.toFloat(f64, mod)), |
| 2501 | 80 => return @bitCast(u80, a.toFloat(f80)) == @bitCast(u80, b.toFloat(f80)), | 1654 | 80 => return @bitCast(u80, a.toFloat(f80, mod)) == @bitCast(u80, b.toFloat(f80, mod)), |
| 2502 | 128 => return @bitCast(u128, a.toFloat(f128)) == @bitCast(u128, b.toFloat(f128)), | 1655 | 128 => return @bitCast(u128, a.toFloat(f128, mod)) == @bitCast(u128, b.toFloat(f128, mod)), |
| 2503 | else => unreachable, | 1656 | else => unreachable, |
| 2504 | } | 1657 | } |
| 2505 | }, | 1658 | }, |
| 2506 | .ComptimeFloat => { | 1659 | .ComptimeFloat => { |
| 2507 | const a_float = a.toFloat(f128); | 1660 | const a_float = a.toFloat(f128, mod); |
| 2508 | const b_float = b.toFloat(f128); | 1661 | const b_float = b.toFloat(f128, mod); |
| 2509 | 1662 | ||
| 2510 | const a_nan = std.math.isNan(a_float); | 1663 | const a_nan = std.math.isNan(a_float); |
| 2511 | const b_nan = std.math.isNan(b_float); | 1664 | const b_nan = std.math.isNan(b_float); |
| ... | @@ -2514,570 +1667,215 @@ pub const Value = extern union { | ... | @@ -2514,570 +1667,215 @@ pub const Value = extern union { |
| 2514 | if (a_nan) return true; | 1667 | if (a_nan) return true; |
| 2515 | return a_float == b_float; | 1668 | return a_float == b_float; |
| 2516 | }, | 1669 | }, |
| 2517 | .Optional => if (a_tag != .null_value and b_tag == .opt_payload) { | 1670 | .Optional, |
| 2518 | var sub_pl: Payload.SubValue = .{ | 1671 | .ErrorUnion, |
| 2519 | .base = .{ .tag = b.tag() }, | 1672 | => unreachable, // handled by InternPool |
| 2520 | .data = a, | ||
| 2521 | }; | ||
| 2522 | const sub_val = Value.initPayload(&sub_pl.base); | ||
| 2523 | return eqlAdvanced(sub_val, ty, b, ty, mod, opt_sema); | ||
| 2524 | }, | ||
| 2525 | .ErrorUnion => if (a_tag != .@"error" and b_tag == .eu_payload) { | ||
| 2526 | var sub_pl: Payload.SubValue = .{ | ||
| 2527 | .base = .{ .tag = b.tag() }, | ||
| 2528 | .data = a, | ||
| 2529 | }; | ||
| 2530 | const sub_val = Value.initPayload(&sub_pl.base); | ||
| 2531 | return eqlAdvanced(sub_val, ty, b, ty, mod, opt_sema); | ||
| 2532 | }, | ||
| 2533 | else => {}, | 1673 | else => {}, |
| 2534 | } | 1674 | } |
| 2535 | if (a_tag == .null_value or a_tag == .@"error") return false; | 1675 | return (try orderAdvanced(a, b, mod, opt_sema)).compare(.eq); |
| 2536 | return (try orderAdvanced(a, b, target, opt_sema)).compare(.eq); | ||
| 2537 | } | ||
| 2538 | |||
| 2539 | /// This function is used by hash maps and so treats floating-point NaNs as equal | ||
| 2540 | /// to each other, and not equal to other floating-point values. | ||
| 2541 | pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash, mod: *Module) void { | ||
| 2542 | const zig_ty_tag = ty.zigTypeTag(); | ||
| 2543 | std.hash.autoHash(hasher, zig_ty_tag); | ||
| 2544 | if (val.isUndef()) return; | ||
| 2545 | // The value is runtime-known and shouldn't affect the hash. | ||
| 2546 | if (val.tag() == .runtime_value) return; | ||
| 2547 | |||
| 2548 | switch (zig_ty_tag) { | ||
| 2549 | .Opaque => unreachable, // Cannot hash opaque types | ||
| 2550 | |||
| 2551 | .Void, | ||
| 2552 | .NoReturn, | ||
| 2553 | .Undefined, | ||
| 2554 | .Null, | ||
| 2555 | => {}, | ||
| 2556 | |||
| 2557 | .Type => { | ||
| 2558 | var buf: ToTypeBuffer = undefined; | ||
| 2559 | return val.toType(&buf).hashWithHasher(hasher, mod); | ||
| 2560 | }, | ||
| 2561 | .Float => { | ||
| 2562 | // For hash/eql purposes, we treat floats as their IEEE integer representation. | ||
| 2563 | switch (ty.floatBits(mod.getTarget())) { | ||
| 2564 | 16 => std.hash.autoHash(hasher, @bitCast(u16, val.toFloat(f16))), | ||
| 2565 | 32 => std.hash.autoHash(hasher, @bitCast(u32, val.toFloat(f32))), | ||
| 2566 | 64 => std.hash.autoHash(hasher, @bitCast(u64, val.toFloat(f64))), | ||
| 2567 | 80 => std.hash.autoHash(hasher, @bitCast(u80, val.toFloat(f80))), | ||
| 2568 | 128 => std.hash.autoHash(hasher, @bitCast(u128, val.toFloat(f128))), | ||
| 2569 | else => unreachable, | ||
| 2570 | } | ||
| 2571 | }, | ||
| 2572 | .ComptimeFloat => { | ||
| 2573 | const float = val.toFloat(f128); | ||
| 2574 | const is_nan = std.math.isNan(float); | ||
| 2575 | std.hash.autoHash(hasher, is_nan); | ||
| 2576 | if (!is_nan) { | ||
| 2577 | std.hash.autoHash(hasher, @bitCast(u128, float)); | ||
| 2578 | } else { | ||
| 2579 | std.hash.autoHash(hasher, std.math.signbit(float)); | ||
| 2580 | } | ||
| 2581 | }, | ||
| 2582 | .Bool, .Int, .ComptimeInt, .Pointer => switch (val.tag()) { | ||
| 2583 | .slice => { | ||
| 2584 | const slice = val.castTag(.slice).?.data; | ||
| 2585 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 2586 | const ptr_ty = ty.slicePtrFieldType(&ptr_buf); | ||
| 2587 | hash(slice.ptr, ptr_ty, hasher, mod); | ||
| 2588 | hash(slice.len, Type.usize, hasher, mod); | ||
| 2589 | }, | ||
| 2590 | |||
| 2591 | else => return hashPtr(val, hasher, mod.getTarget()), | ||
| 2592 | }, | ||
| 2593 | .Array, .Vector => { | ||
| 2594 | const len = ty.arrayLen(); | ||
| 2595 | const elem_ty = ty.childType(); | ||
| 2596 | var index: usize = 0; | ||
| 2597 | var elem_value_buf: ElemValueBuffer = undefined; | ||
| 2598 | while (index < len) : (index += 1) { | ||
| 2599 | const elem_val = val.elemValueBuffer(mod, index, &elem_value_buf); | ||
| 2600 | elem_val.hash(elem_ty, hasher, mod); | ||
| 2601 | } | ||
| 2602 | }, | ||
| 2603 | .Struct => { | ||
| 2604 | switch (val.tag()) { | ||
| 2605 | .empty_struct_value => {}, | ||
| 2606 | .aggregate => { | ||
| 2607 | const field_values = val.castTag(.aggregate).?.data; | ||
| 2608 | for (field_values, 0..) |field_val, i| { | ||
| 2609 | const field_ty = ty.structFieldType(i); | ||
| 2610 | field_val.hash(field_ty, hasher, mod); | ||
| 2611 | } | ||
| 2612 | }, | ||
| 2613 | else => unreachable, | ||
| 2614 | } | ||
| 2615 | }, | ||
| 2616 | .Optional => { | ||
| 2617 | if (val.castTag(.opt_payload)) |payload| { | ||
| 2618 | std.hash.autoHash(hasher, true); // non-null | ||
| 2619 | const sub_val = payload.data; | ||
| 2620 | var buffer: Type.Payload.ElemType = undefined; | ||
| 2621 | const sub_ty = ty.optionalChild(&buffer); | ||
| 2622 | sub_val.hash(sub_ty, hasher, mod); | ||
| 2623 | } else { | ||
| 2624 | std.hash.autoHash(hasher, false); // null | ||
| 2625 | } | ||
| 2626 | }, | ||
| 2627 | .ErrorUnion => { | ||
| 2628 | if (val.tag() == .@"error") { | ||
| 2629 | std.hash.autoHash(hasher, false); // error | ||
| 2630 | const sub_ty = ty.errorUnionSet(); | ||
| 2631 | val.hash(sub_ty, hasher, mod); | ||
| 2632 | return; | ||
| 2633 | } | ||
| 2634 | |||
| 2635 | if (val.castTag(.eu_payload)) |payload| { | ||
| 2636 | std.hash.autoHash(hasher, true); // payload | ||
| 2637 | const sub_ty = ty.errorUnionPayload(); | ||
| 2638 | payload.data.hash(sub_ty, hasher, mod); | ||
| 2639 | return; | ||
| 2640 | } else unreachable; | ||
| 2641 | }, | ||
| 2642 | .ErrorSet => { | ||
| 2643 | // just hash the literal error value. this is the most stable | ||
| 2644 | // thing between compiler invocations. we can't use the error | ||
| 2645 | // int cause (1) its not stable and (2) we don't have access to mod. | ||
| 2646 | hasher.update(val.getError().?); | ||
| 2647 | }, | ||
| 2648 | .Enum => { | ||
| 2649 | var enum_space: Payload.U64 = undefined; | ||
| 2650 | const int_val = val.enumToInt(ty, &enum_space); | ||
| 2651 | hashInt(int_val, hasher, mod.getTarget()); | ||
| 2652 | }, | ||
| 2653 | .Union => { | ||
| 2654 | const union_obj = val.cast(Payload.Union).?.data; | ||
| 2655 | if (ty.unionTagType()) |tag_ty| { | ||
| 2656 | union_obj.tag.hash(tag_ty, hasher, mod); | ||
| 2657 | } | ||
| 2658 | const active_field_ty = ty.unionFieldType(union_obj.tag, mod); | ||
| 2659 | union_obj.val.hash(active_field_ty, hasher, mod); | ||
| 2660 | }, | ||
| 2661 | .Fn => { | ||
| 2662 | // Note that this hashes the *Fn/*ExternFn rather than the *Decl. | ||
| 2663 | // This is to differentiate function bodies from function pointers. | ||
| 2664 | // This is currently redundant since we already hash the zig type tag | ||
| 2665 | // at the top of this function. | ||
| 2666 | if (val.castTag(.function)) |func| { | ||
| 2667 | std.hash.autoHash(hasher, func.data); | ||
| 2668 | } else if (val.castTag(.extern_fn)) |func| { | ||
| 2669 | std.hash.autoHash(hasher, func.data); | ||
| 2670 | } else unreachable; | ||
| 2671 | }, | ||
| 2672 | .Frame => { | ||
| 2673 | @panic("TODO implement hashing frame values"); | ||
| 2674 | }, | ||
| 2675 | .AnyFrame => { | ||
| 2676 | @panic("TODO implement hashing anyframe values"); | ||
| 2677 | }, | ||
| 2678 | .EnumLiteral => { | ||
| 2679 | const bytes = val.castTag(.enum_literal).?.data; | ||
| 2680 | hasher.update(bytes); | ||
| 2681 | }, | ||
| 2682 | } | ||
| 2683 | } | 1676 | } |
| 2684 | 1677 | ||
| 2685 | /// This is a more conservative hash function that produces equal hashes for values | 1678 | pub fn isComptimeMutablePtr(val: Value, mod: *Module) bool { |
| 2686 | /// that can coerce into each other. | 1679 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 2687 | /// This function is used by hash maps and so treats floating-point NaNs as equal | 1680 | .ptr => |ptr| switch (ptr.addr) { |
| 2688 | /// to each other, and not equal to other floating-point values. | 1681 | .mut_decl, .comptime_field => true, |
| 2689 | pub fn hashUncoerced(val: Value, ty: Type, hasher: *std.hash.Wyhash, mod: *Module) void { | 1682 | .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isComptimeMutablePtr(mod), |
| 2690 | if (val.isUndef()) return; | 1683 | .elem, .field => |base_index| base_index.base.toValue().isComptimeMutablePtr(mod), |
| 2691 | // The value is runtime-known and shouldn't affect the hash. | 1684 | else => false, |
| 2692 | if (val.tag() == .runtime_value) return; | ||
| 2693 | |||
| 2694 | switch (ty.zigTypeTag()) { | ||
| 2695 | .Opaque => unreachable, // Cannot hash opaque types | ||
| 2696 | .Void, | ||
| 2697 | .NoReturn, | ||
| 2698 | .Undefined, | ||
| 2699 | .Null, | ||
| 2700 | .Struct, // It sure would be nice to do something clever with structs. | ||
| 2701 | => |zig_type_tag| std.hash.autoHash(hasher, zig_type_tag), | ||
| 2702 | .Type => { | ||
| 2703 | var buf: ToTypeBuffer = undefined; | ||
| 2704 | val.toType(&buf).hashWithHasher(hasher, mod); | ||
| 2705 | }, | ||
| 2706 | .Float, .ComptimeFloat => std.hash.autoHash(hasher, @bitCast(u128, val.toFloat(f128))), | ||
| 2707 | .Bool, .Int, .ComptimeInt, .Pointer, .Fn => switch (val.tag()) { | ||
| 2708 | .slice => { | ||
| 2709 | const slice = val.castTag(.slice).?.data; | ||
| 2710 | var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; | ||
| 2711 | const ptr_ty = ty.slicePtrFieldType(&ptr_buf); | ||
| 2712 | slice.ptr.hashUncoerced(ptr_ty, hasher, mod); | ||
| 2713 | }, | ||
| 2714 | else => val.hashPtr(hasher, mod.getTarget()), | ||
| 2715 | }, | ||
| 2716 | .Array, .Vector => { | ||
| 2717 | const len = ty.arrayLen(); | ||
| 2718 | const elem_ty = ty.childType(); | ||
| 2719 | var index: usize = 0; | ||
| 2720 | var elem_value_buf: ElemValueBuffer = undefined; | ||
| 2721 | while (index < len) : (index += 1) { | ||
| 2722 | const elem_val = val.elemValueBuffer(mod, index, &elem_value_buf); | ||
| 2723 | elem_val.hashUncoerced(elem_ty, hasher, mod); | ||
| 2724 | } | ||
| 2725 | }, | ||
| 2726 | .Optional => if (val.castTag(.opt_payload)) |payload| { | ||
| 2727 | var buf: Type.Payload.ElemType = undefined; | ||
| 2728 | const child_ty = ty.optionalChild(&buf); | ||
| 2729 | payload.data.hashUncoerced(child_ty, hasher, mod); | ||
| 2730 | } else std.hash.autoHash(hasher, std.builtin.TypeId.Null), | ||
| 2731 | .ErrorSet, .ErrorUnion => if (val.getError()) |err| hasher.update(err) else { | ||
| 2732 | const pl_ty = ty.errorUnionPayload(); | ||
| 2733 | val.castTag(.eu_payload).?.data.hashUncoerced(pl_ty, hasher, mod); | ||
| 2734 | }, | 1685 | }, |
| 2735 | .Enum, .EnumLiteral, .Union => { | ||
| 2736 | hasher.update(val.tagName(ty, mod)); | ||
| 2737 | if (val.cast(Payload.Union)) |union_obj| { | ||
| 2738 | const active_field_ty = ty.unionFieldType(union_obj.data.tag, mod); | ||
| 2739 | union_obj.data.val.hashUncoerced(active_field_ty, hasher, mod); | ||
| 2740 | } else std.hash.autoHash(hasher, std.builtin.TypeId.Void); | ||
| 2741 | }, | ||
| 2742 | .Frame => @panic("TODO implement hashing frame values"), | ||
| 2743 | .AnyFrame => @panic("TODO implement hashing anyframe values"), | ||
| 2744 | } | ||
| 2745 | } | ||
| 2746 | |||
| 2747 | pub const ArrayHashContext = struct { | ||
| 2748 | ty: Type, | ||
| 2749 | mod: *Module, | ||
| 2750 | |||
| 2751 | pub fn hash(self: @This(), val: Value) u32 { | ||
| 2752 | const other_context: HashContext = .{ .ty = self.ty, .mod = self.mod }; | ||
| 2753 | return @truncate(u32, other_context.hash(val)); | ||
| 2754 | } | ||
| 2755 | pub fn eql(self: @This(), a: Value, b: Value, b_index: usize) bool { | ||
| 2756 | _ = b_index; | ||
| 2757 | return a.eql(b, self.ty, self.mod); | ||
| 2758 | } | ||
| 2759 | }; | ||
| 2760 | |||
| 2761 | pub const HashContext = struct { | ||
| 2762 | ty: Type, | ||
| 2763 | mod: *Module, | ||
| 2764 | |||
| 2765 | pub fn hash(self: @This(), val: Value) u64 { | ||
| 2766 | var hasher = std.hash.Wyhash.init(0); | ||
| 2767 | val.hash(self.ty, &hasher, self.mod); | ||
| 2768 | return hasher.final(); | ||
| 2769 | } | ||
| 2770 | |||
| 2771 | pub fn eql(self: @This(), a: Value, b: Value) bool { | ||
| 2772 | return a.eql(b, self.ty, self.mod); | ||
| 2773 | } | ||
| 2774 | }; | ||
| 2775 | |||
| 2776 | pub fn isComptimeMutablePtr(val: Value) bool { | ||
| 2777 | return switch (val.tag()) { | ||
| 2778 | .decl_ref_mut, .comptime_field_ptr => true, | ||
| 2779 | .elem_ptr => isComptimeMutablePtr(val.castTag(.elem_ptr).?.data.array_ptr), | ||
| 2780 | .field_ptr => isComptimeMutablePtr(val.castTag(.field_ptr).?.data.container_ptr), | ||
| 2781 | .eu_payload_ptr => isComptimeMutablePtr(val.castTag(.eu_payload_ptr).?.data.container_ptr), | ||
| 2782 | .opt_payload_ptr => isComptimeMutablePtr(val.castTag(.opt_payload_ptr).?.data.container_ptr), | ||
| 2783 | .slice => isComptimeMutablePtr(val.castTag(.slice).?.data.ptr), | ||
| 2784 | |||
| 2785 | else => false, | 1686 | else => false, |
| 2786 | }; | 1687 | }; |
| 2787 | } | 1688 | } |
| 2788 | 1689 | ||
| 2789 | pub fn canMutateComptimeVarState(val: Value) bool { | 1690 | pub fn canMutateComptimeVarState(val: Value, mod: *Module) bool { |
| 2790 | if (val.isComptimeMutablePtr()) return true; | 1691 | return val.isComptimeMutablePtr(mod) or switch (val.toIntern()) { |
| 2791 | switch (val.tag()) { | 1692 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 2792 | .repeated => return val.castTag(.repeated).?.data.canMutateComptimeVarState(), | 1693 | .error_union => |error_union| switch (error_union.val) { |
| 2793 | .eu_payload => return val.castTag(.eu_payload).?.data.canMutateComptimeVarState(), | 1694 | .err_name => false, |
| 2794 | .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(), | 1695 | .payload => |payload| payload.toValue().canMutateComptimeVarState(mod), |
| 2795 | .opt_payload => return val.castTag(.opt_payload).?.data.canMutateComptimeVarState(), | 1696 | }, |
| 2796 | .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(), | 1697 | .ptr => |ptr| switch (ptr.addr) { |
| 2797 | .aggregate => { | 1698 | .eu_payload, .opt_payload => |base| base.toValue().canMutateComptimeVarState(mod), |
| 2798 | const fields = val.castTag(.aggregate).?.data; | 1699 | else => false, |
| 2799 | for (fields) |field| { | 1700 | }, |
| 2800 | if (field.canMutateComptimeVarState()) return true; | 1701 | .opt => |opt| switch (opt.val) { |
| 2801 | } | 1702 | .none => false, |
| 2802 | return false; | 1703 | else => |payload| payload.toValue().canMutateComptimeVarState(mod), |
| 1704 | }, | ||
| 1705 | .aggregate => |aggregate| for (aggregate.storage.values()) |elem| { | ||
| 1706 | if (elem.toValue().canMutateComptimeVarState(mod)) break true; | ||
| 1707 | } else false, | ||
| 1708 | .un => |un| un.val.toValue().canMutateComptimeVarState(mod), | ||
| 1709 | else => false, | ||
| 2803 | }, | 1710 | }, |
| 2804 | .@"union" => return val.cast(Payload.Union).?.data.val.canMutateComptimeVarState(), | 1711 | }; |
| 2805 | .slice => return val.castTag(.slice).?.data.ptr.canMutateComptimeVarState(), | ||
| 2806 | else => return false, | ||
| 2807 | } | ||
| 2808 | } | 1712 | } |
| 2809 | 1713 | ||
| 2810 | /// Gets the decl referenced by this pointer. If the pointer does not point | 1714 | /// Gets the decl referenced by this pointer. If the pointer does not point |
| 2811 | /// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr), | 1715 | /// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr), |
| 2812 | /// this function returns null. | 1716 | /// this function returns null. |
| 2813 | pub fn pointerDecl(val: Value) ?Module.Decl.Index { | 1717 | pub fn pointerDecl(val: Value, mod: *Module) ?Module.Decl.Index { |
| 2814 | return switch (val.tag()) { | 1718 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 2815 | .decl_ref_mut => val.castTag(.decl_ref_mut).?.data.decl_index, | 1719 | .variable => |variable| variable.decl, |
| 2816 | .extern_fn => val.castTag(.extern_fn).?.data.owner_decl, | 1720 | .extern_func => |extern_func| extern_func.decl, |
| 2817 | .function => val.castTag(.function).?.data.owner_decl, | 1721 | .func => |func| mod.funcPtr(func.index).owner_decl, |
| 2818 | .variable => val.castTag(.variable).?.data.owner_decl, | 1722 | .ptr => |ptr| switch (ptr.addr) { |
| 2819 | .decl_ref => val.cast(Payload.Decl).?.data, | 1723 | .decl => |decl| decl, |
| 1724 | .mut_decl => |mut_decl| mut_decl.decl, | ||
| 1725 | else => null, | ||
| 1726 | }, | ||
| 2820 | else => null, | 1727 | else => null, |
| 2821 | }; | 1728 | }; |
| 2822 | } | 1729 | } |
| 2823 | 1730 | ||
| 2824 | fn hashInt(int_val: Value, hasher: *std.hash.Wyhash, target: Target) void { | 1731 | fn hashInt(int_val: Value, hasher: *std.hash.Wyhash, mod: *Module) void { |
| 2825 | var buffer: BigIntSpace = undefined; | 1732 | var buffer: BigIntSpace = undefined; |
| 2826 | const big = int_val.toBigInt(&buffer, target); | 1733 | const big = int_val.toBigInt(&buffer, mod); |
| 2827 | std.hash.autoHash(hasher, big.positive); | 1734 | std.hash.autoHash(hasher, big.positive); |
| 2828 | for (big.limbs) |limb| { | 1735 | for (big.limbs) |limb| { |
| 2829 | std.hash.autoHash(hasher, limb); | 1736 | std.hash.autoHash(hasher, limb); |
| 2830 | } | 1737 | } |
| 2831 | } | 1738 | } |
| 2832 | 1739 | ||
| 2833 | fn hashPtr(ptr_val: Value, hasher: *std.hash.Wyhash, target: Target) void { | 1740 | pub const slice_ptr_index = 0; |
| 2834 | switch (ptr_val.tag()) { | 1741 | pub const slice_len_index = 1; |
| 2835 | .decl_ref, | ||
| 2836 | .decl_ref_mut, | ||
| 2837 | .extern_fn, | ||
| 2838 | .function, | ||
| 2839 | .variable, | ||
| 2840 | => { | ||
| 2841 | const decl: Module.Decl.Index = ptr_val.pointerDecl().?; | ||
| 2842 | std.hash.autoHash(hasher, decl); | ||
| 2843 | }, | ||
| 2844 | .comptime_field_ptr => { | ||
| 2845 | std.hash.autoHash(hasher, Value.Tag.comptime_field_ptr); | ||
| 2846 | }, | ||
| 2847 | |||
| 2848 | .elem_ptr => { | ||
| 2849 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | ||
| 2850 | hashPtr(elem_ptr.array_ptr, hasher, target); | ||
| 2851 | std.hash.autoHash(hasher, Value.Tag.elem_ptr); | ||
| 2852 | std.hash.autoHash(hasher, elem_ptr.index); | ||
| 2853 | }, | ||
| 2854 | .field_ptr => { | ||
| 2855 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | ||
| 2856 | std.hash.autoHash(hasher, Value.Tag.field_ptr); | ||
| 2857 | hashPtr(field_ptr.container_ptr, hasher, target); | ||
| 2858 | std.hash.autoHash(hasher, field_ptr.field_index); | ||
| 2859 | }, | ||
| 2860 | .eu_payload_ptr => { | ||
| 2861 | const err_union_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; | ||
| 2862 | std.hash.autoHash(hasher, Value.Tag.eu_payload_ptr); | ||
| 2863 | hashPtr(err_union_ptr.container_ptr, hasher, target); | ||
| 2864 | }, | ||
| 2865 | .opt_payload_ptr => { | ||
| 2866 | const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; | ||
| 2867 | std.hash.autoHash(hasher, Value.Tag.opt_payload_ptr); | ||
| 2868 | hashPtr(opt_ptr.container_ptr, hasher, target); | ||
| 2869 | }, | ||
| 2870 | |||
| 2871 | .zero, | ||
| 2872 | .one, | ||
| 2873 | .null_value, | ||
| 2874 | .int_u64, | ||
| 2875 | .int_i64, | ||
| 2876 | .int_big_positive, | ||
| 2877 | .int_big_negative, | ||
| 2878 | .bool_false, | ||
| 2879 | .bool_true, | ||
| 2880 | .the_only_possible_value, | ||
| 2881 | .lazy_align, | ||
| 2882 | .lazy_size, | ||
| 2883 | => return hashInt(ptr_val, hasher, target), | ||
| 2884 | 1742 | ||
| 2885 | else => unreachable, | 1743 | pub fn slicePtr(val: Value, mod: *Module) Value { |
| 2886 | } | 1744 | return mod.intern_pool.slicePtr(val.toIntern()).toValue(); |
| 2887 | } | ||
| 2888 | |||
| 2889 | pub fn slicePtr(val: Value) Value { | ||
| 2890 | return switch (val.tag()) { | ||
| 2891 | .slice => val.castTag(.slice).?.data.ptr, | ||
| 2892 | // TODO this should require being a slice tag, and not allow decl_ref, field_ptr, etc. | ||
| 2893 | .decl_ref, .decl_ref_mut, .field_ptr, .elem_ptr, .comptime_field_ptr => val, | ||
| 2894 | else => unreachable, | ||
| 2895 | }; | ||
| 2896 | } | 1745 | } |
| 2897 | 1746 | ||
| 2898 | pub fn sliceLen(val: Value, mod: *Module) u64 { | 1747 | pub fn sliceLen(val: Value, mod: *Module) u64 { |
| 2899 | return switch (val.tag()) { | 1748 | const ptr = mod.intern_pool.indexToKey(val.toIntern()).ptr; |
| 2900 | .slice => val.castTag(.slice).?.data.len.toUnsignedInt(mod.getTarget()), | 1749 | return switch (ptr.len) { |
| 2901 | .decl_ref => { | 1750 | .none => switch (mod.intern_pool.indexToKey(switch (ptr.addr) { |
| 2902 | const decl_index = val.castTag(.decl_ref).?.data; | 1751 | .decl => |decl| mod.declPtr(decl).ty.toIntern(), |
| 2903 | const decl = mod.declPtr(decl_index); | 1752 | .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(), |
| 2904 | if (decl.ty.zigTypeTag() == .Array) { | 1753 | .comptime_field => |comptime_field| mod.intern_pool.typeOf(comptime_field), |
| 2905 | return decl.ty.arrayLen(); | 1754 | else => unreachable, |
| 2906 | } else { | 1755 | })) { |
| 2907 | return 1; | 1756 | .array_type => |array_type| array_type.len, |
| 2908 | } | 1757 | else => 1, |
| 2909 | }, | ||
| 2910 | .decl_ref_mut => { | ||
| 2911 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | ||
| 2912 | const decl = mod.declPtr(decl_index); | ||
| 2913 | if (decl.ty.zigTypeTag() == .Array) { | ||
| 2914 | return decl.ty.arrayLen(); | ||
| 2915 | } else { | ||
| 2916 | return 1; | ||
| 2917 | } | ||
| 2918 | }, | ||
| 2919 | .comptime_field_ptr => { | ||
| 2920 | const payload = val.castTag(.comptime_field_ptr).?.data; | ||
| 2921 | if (payload.field_ty.zigTypeTag() == .Array) { | ||
| 2922 | return payload.field_ty.arrayLen(); | ||
| 2923 | } else { | ||
| 2924 | return 1; | ||
| 2925 | } | ||
| 2926 | }, | 1758 | }, |
| 2927 | else => unreachable, | 1759 | else => ptr.len.toValue().toUnsignedInt(mod), |
| 2928 | }; | 1760 | }; |
| 2929 | } | 1761 | } |
| 2930 | 1762 | ||
| 2931 | /// Asserts the value is a single-item pointer to an array, or an array, | 1763 | /// Asserts the value is a single-item pointer to an array, or an array, |
| 2932 | /// or an unknown-length pointer, and returns the element value at the index. | 1764 | /// or an unknown-length pointer, and returns the element value at the index. |
| 2933 | pub fn elemValue(val: Value, mod: *Module, arena: Allocator, index: usize) !Value { | 1765 | pub fn elemValue(val: Value, mod: *Module, index: usize) Allocator.Error!Value { |
| 2934 | return elemValueAdvanced(val, mod, index, arena, undefined); | 1766 | return switch (val.ip_index) { |
| 2935 | } | 1767 | .none => switch (val.tag()) { |
| 2936 | 1768 | .bytes => try mod.intValue(Type.u8, val.castTag(.bytes).?.data[index]), | |
| 2937 | pub const ElemValueBuffer = Payload.U64; | 1769 | .repeated => val.castTag(.repeated).?.data, |
| 2938 | 1770 | .aggregate => val.castTag(.aggregate).?.data[index], | |
| 2939 | pub fn elemValueBuffer(val: Value, mod: *Module, index: usize, buffer: *ElemValueBuffer) Value { | 1771 | .slice => val.castTag(.slice).?.data.ptr.elemValue(mod, index), |
| 2940 | return elemValueAdvanced(val, mod, index, null, buffer) catch unreachable; | 1772 | else => unreachable, |
| 2941 | } | ||
| 2942 | |||
| 2943 | pub fn elemValueAdvanced( | ||
| 2944 | val: Value, | ||
| 2945 | mod: *Module, | ||
| 2946 | index: usize, | ||
| 2947 | arena: ?Allocator, | ||
| 2948 | buffer: *ElemValueBuffer, | ||
| 2949 | ) error{OutOfMemory}!Value { | ||
| 2950 | switch (val.tag()) { | ||
| 2951 | // This is the case of accessing an element of an undef array. | ||
| 2952 | .undef => return Value.undef, | ||
| 2953 | .empty_array => unreachable, // out of bounds array index | ||
| 2954 | .empty_struct_value => unreachable, // out of bounds array index | ||
| 2955 | |||
| 2956 | .empty_array_sentinel => { | ||
| 2957 | assert(index == 0); // The only valid index for an empty array with sentinel. | ||
| 2958 | return val.castTag(.empty_array_sentinel).?.data; | ||
| 2959 | }, | ||
| 2960 | |||
| 2961 | .bytes => { | ||
| 2962 | const byte = val.castTag(.bytes).?.data[index]; | ||
| 2963 | if (arena) |a| { | ||
| 2964 | return Tag.int_u64.create(a, byte); | ||
| 2965 | } else { | ||
| 2966 | buffer.* = .{ | ||
| 2967 | .base = .{ .tag = .int_u64 }, | ||
| 2968 | .data = byte, | ||
| 2969 | }; | ||
| 2970 | return initPayload(&buffer.base); | ||
| 2971 | } | ||
| 2972 | }, | ||
| 2973 | .str_lit => { | ||
| 2974 | const str_lit = val.castTag(.str_lit).?.data; | ||
| 2975 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | ||
| 2976 | const byte = bytes[index]; | ||
| 2977 | if (arena) |a| { | ||
| 2978 | return Tag.int_u64.create(a, byte); | ||
| 2979 | } else { | ||
| 2980 | buffer.* = .{ | ||
| 2981 | .base = .{ .tag = .int_u64 }, | ||
| 2982 | .data = byte, | ||
| 2983 | }; | ||
| 2984 | return initPayload(&buffer.base); | ||
| 2985 | } | ||
| 2986 | }, | ||
| 2987 | |||
| 2988 | // No matter the index; all the elements are the same! | ||
| 2989 | .repeated => return val.castTag(.repeated).?.data, | ||
| 2990 | |||
| 2991 | .aggregate => return val.castTag(.aggregate).?.data[index], | ||
| 2992 | .slice => return val.castTag(.slice).?.data.ptr.elemValueAdvanced(mod, index, arena, buffer), | ||
| 2993 | |||
| 2994 | .decl_ref => return mod.declPtr(val.castTag(.decl_ref).?.data).val.elemValueAdvanced(mod, index, arena, buffer), | ||
| 2995 | .decl_ref_mut => return mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.elemValueAdvanced(mod, index, arena, buffer), | ||
| 2996 | .comptime_field_ptr => return val.castTag(.comptime_field_ptr).?.data.field_val.elemValueAdvanced(mod, index, arena, buffer), | ||
| 2997 | .elem_ptr => { | ||
| 2998 | const data = val.castTag(.elem_ptr).?.data; | ||
| 2999 | return data.array_ptr.elemValueAdvanced(mod, index + data.index, arena, buffer); | ||
| 3000 | }, | 1773 | }, |
| 3001 | .field_ptr => { | 1774 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3002 | const data = val.castTag(.field_ptr).?.data; | 1775 | .undef => |ty| (try mod.intern(.{ |
| 3003 | if (data.container_ptr.pointerDecl()) |decl_index| { | 1776 | .undef = ty.toType().elemType2(mod).toIntern(), |
| 3004 | const container_decl = mod.declPtr(decl_index); | 1777 | })).toValue(), |
| 3005 | const field_type = data.container_ty.structFieldType(data.field_index); | 1778 | .ptr => |ptr| switch (ptr.addr) { |
| 3006 | const field_val = container_decl.val.fieldValue(field_type, data.field_index); | 1779 | .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index), |
| 3007 | return field_val.elemValueAdvanced(mod, index, arena, buffer); | 1780 | .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)) |
| 3008 | } else unreachable; | 1781 | .toValue().elemValue(mod, index), |
| 1782 | .int, .eu_payload => unreachable, | ||
| 1783 | .opt_payload => |base| base.toValue().elemValue(mod, index), | ||
| 1784 | .comptime_field => |field_val| field_val.toValue().elemValue(mod, index), | ||
| 1785 | .elem => |elem| elem.base.toValue().elemValue(mod, index + @intCast(usize, elem.index)), | ||
| 1786 | .field => |field| if (field.base.toValue().pointerDecl(mod)) |decl_index| { | ||
| 1787 | const base_decl = mod.declPtr(decl_index); | ||
| 1788 | const field_val = try base_decl.val.fieldValue(mod, @intCast(usize, field.index)); | ||
| 1789 | return field_val.elemValue(mod, index); | ||
| 1790 | } else unreachable, | ||
| 1791 | }, | ||
| 1792 | .opt => |opt| opt.val.toValue().elemValue(mod, index), | ||
| 1793 | .aggregate => |aggregate| { | ||
| 1794 | const len = mod.intern_pool.aggregateTypeLen(aggregate.ty); | ||
| 1795 | if (index < len) return switch (aggregate.storage) { | ||
| 1796 | .bytes => |bytes| try mod.intern(.{ .int = .{ | ||
| 1797 | .ty = .u8_type, | ||
| 1798 | .storage = .{ .u64 = bytes[index] }, | ||
| 1799 | } }), | ||
| 1800 | .elems => |elems| elems[index], | ||
| 1801 | .repeated_elem => |elem| elem, | ||
| 1802 | }.toValue(); | ||
| 1803 | assert(index == len); | ||
| 1804 | return mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel.toValue(); | ||
| 1805 | }, | ||
| 1806 | else => unreachable, | ||
| 3009 | }, | 1807 | }, |
| 1808 | }; | ||
| 1809 | } | ||
| 3010 | 1810 | ||
| 3011 | // The child type of arrays which have only one possible value need | 1811 | pub fn isLazyAlign(val: Value, mod: *Module) bool { |
| 3012 | // to have only one possible value itself. | 1812 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3013 | .the_only_possible_value => return val, | 1813 | .int => |int| int.storage == .lazy_align, |
| 3014 | 1814 | else => false, | |
| 3015 | .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer), | 1815 | }; |
| 3016 | .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.elemValueAdvanced(mod, index, arena, buffer), | 1816 | } |
| 3017 | |||
| 3018 | .opt_payload => return val.castTag(.opt_payload).?.data.elemValueAdvanced(mod, index, arena, buffer), | ||
| 3019 | .eu_payload => return val.castTag(.eu_payload).?.data.elemValueAdvanced(mod, index, arena, buffer), | ||
| 3020 | 1817 | ||
| 3021 | // These values will implicitly be treated as `repeated`. | 1818 | pub fn isLazySize(val: Value, mod: *Module) bool { |
| 3022 | .zero, | 1819 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3023 | .one, | 1820 | .int => |int| int.storage == .lazy_size, |
| 3024 | .bool_false, | 1821 | else => false, |
| 3025 | .bool_true, | 1822 | }; |
| 3026 | .int_i64, | 1823 | } |
| 3027 | .int_u64, | ||
| 3028 | => return val, | ||
| 3029 | 1824 | ||
| 3030 | else => unreachable, | 1825 | pub fn isRuntimeValue(val: Value, mod: *Module) bool { |
| 3031 | } | 1826 | return mod.intern_pool.indexToKey(val.toIntern()) == .runtime_value; |
| 3032 | } | 1827 | } |
| 3033 | 1828 | ||
| 3034 | /// Returns true if a Value is backed by a variable | 1829 | /// Returns true if a Value is backed by a variable |
| 3035 | pub fn isVariable( | 1830 | pub fn isVariable(val: Value, mod: *Module) bool { |
| 3036 | val: Value, | 1831 | return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3037 | mod: *Module, | ||
| 3038 | ) bool { | ||
| 3039 | return switch (val.tag()) { | ||
| 3040 | .slice => val.castTag(.slice).?.data.ptr.isVariable(mod), | ||
| 3041 | .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isVariable(mod), | ||
| 3042 | .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isVariable(mod), | ||
| 3043 | .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isVariable(mod), | ||
| 3044 | .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isVariable(mod), | ||
| 3045 | .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isVariable(mod), | ||
| 3046 | .decl_ref => { | ||
| 3047 | const decl = mod.declPtr(val.castTag(.decl_ref).?.data); | ||
| 3048 | assert(decl.has_tv); | ||
| 3049 | return decl.val.isVariable(mod); | ||
| 3050 | }, | ||
| 3051 | .decl_ref_mut => { | ||
| 3052 | const decl = mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index); | ||
| 3053 | assert(decl.has_tv); | ||
| 3054 | return decl.val.isVariable(mod); | ||
| 3055 | }, | ||
| 3056 | |||
| 3057 | .variable => true, | 1832 | .variable => true, |
| 1833 | .ptr => |ptr| switch (ptr.addr) { | ||
| 1834 | .decl => |decl_index| { | ||
| 1835 | const decl = mod.declPtr(decl_index); | ||
| 1836 | assert(decl.has_tv); | ||
| 1837 | return decl.val.isVariable(mod); | ||
| 1838 | }, | ||
| 1839 | .mut_decl => |mut_decl| { | ||
| 1840 | const decl = mod.declPtr(mut_decl.decl); | ||
| 1841 | assert(decl.has_tv); | ||
| 1842 | return decl.val.isVariable(mod); | ||
| 1843 | }, | ||
| 1844 | .int => false, | ||
| 1845 | .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isVariable(mod), | ||
| 1846 | .comptime_field => |comptime_field| comptime_field.toValue().isVariable(mod), | ||
| 1847 | .elem, .field => |base_index| base_index.base.toValue().isVariable(mod), | ||
| 1848 | }, | ||
| 3058 | else => false, | 1849 | else => false, |
| 3059 | }; | 1850 | }; |
| 3060 | } | 1851 | } |
| 3061 | 1852 | ||
| 3062 | pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool { | 1853 | pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool { |
| 3063 | return switch (val.tag()) { | 1854 | return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3064 | .variable => false, | 1855 | .variable => false, |
| 3065 | else => val.isPtrToThreadLocalInner(mod), | 1856 | else => val.isPtrToThreadLocalInner(mod), |
| 3066 | }; | 1857 | }; |
| 3067 | } | 1858 | } |
| 3068 | 1859 | ||
| 3069 | fn isPtrToThreadLocalInner(val: Value, mod: *Module) bool { | 1860 | pub fn isPtrToThreadLocalInner(val: Value, mod: *Module) bool { |
| 3070 | return switch (val.tag()) { | 1861 | return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3071 | .slice => val.castTag(.slice).?.data.ptr.isPtrToThreadLocalInner(mod), | 1862 | .variable => |variable| variable.is_threadlocal, |
| 3072 | .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isPtrToThreadLocalInner(mod), | 1863 | .ptr => |ptr| switch (ptr.addr) { |
| 3073 | .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isPtrToThreadLocalInner(mod), | 1864 | .decl => |decl_index| { |
| 3074 | .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), | 1865 | const decl = mod.declPtr(decl_index); |
| 3075 | .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), | 1866 | assert(decl.has_tv); |
| 3076 | .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), | 1867 | return decl.val.isPtrToThreadLocalInner(mod); |
| 3077 | .decl_ref => mod.declPtr(val.castTag(.decl_ref).?.data).val.isPtrToThreadLocalInner(mod), | 1868 | }, |
| 3078 | .decl_ref_mut => mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.isPtrToThreadLocalInner(mod), | 1869 | .mut_decl => |mut_decl| { |
| 3079 | 1870 | const decl = mod.declPtr(mut_decl.decl); | |
| 3080 | .variable => val.castTag(.variable).?.data.is_threadlocal, | 1871 | assert(decl.has_tv); |
| 1872 | return decl.val.isPtrToThreadLocalInner(mod); | ||
| 1873 | }, | ||
| 1874 | .int => false, | ||
| 1875 | .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocalInner(mod), | ||
| 1876 | .comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocalInner(mod), | ||
| 1877 | .elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocalInner(mod), | ||
| 1878 | }, | ||
| 3081 | else => false, | 1879 | else => false, |
| 3082 | }; | 1880 | }; |
| 3083 | } | 1881 | } |
| ... | @@ -3090,238 +1888,239 @@ pub const Value = extern union { | ... | @@ -3090,238 +1888,239 @@ pub const Value = extern union { |
| 3090 | start: usize, | 1888 | start: usize, |
| 3091 | end: usize, | 1889 | end: usize, |
| 3092 | ) error{OutOfMemory}!Value { | 1890 | ) error{OutOfMemory}!Value { |
| 3093 | return switch (val.tag()) { | 1891 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 3094 | .empty_array_sentinel => if (start == 0 and end == 1) val else Value.initTag(.empty_array), | 1892 | return switch (val.ip_index) { |
| 3095 | .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]), | 1893 | .none => switch (val.tag()) { |
| 3096 | .str_lit => { | 1894 | .slice => val.castTag(.slice).?.data.ptr.sliceArray(mod, arena, start, end), |
| 3097 | const str_lit = val.castTag(.str_lit).?.data; | 1895 | .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]), |
| 3098 | return Tag.str_lit.create(arena, .{ | 1896 | .repeated => val, |
| 3099 | .index = @intCast(u32, str_lit.index + start), | 1897 | .aggregate => Tag.aggregate.create(arena, val.castTag(.aggregate).?.data[start..end]), |
| 3100 | .len = @intCast(u32, end - start), | 1898 | else => unreachable, |
| 3101 | }); | ||
| 3102 | }, | 1899 | }, |
| 3103 | .aggregate => Tag.aggregate.create(arena, val.castTag(.aggregate).?.data[start..end]), | 1900 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3104 | .slice => sliceArray(val.castTag(.slice).?.data.ptr, mod, arena, start, end), | 1901 | .ptr => |ptr| switch (ptr.addr) { |
| 3105 | 1902 | .decl => |decl| try mod.declPtr(decl).val.sliceArray(mod, arena, start, end), | |
| 3106 | .decl_ref => sliceArray(mod.declPtr(val.castTag(.decl_ref).?.data).val, mod, arena, start, end), | 1903 | .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)).toValue() |
| 3107 | .decl_ref_mut => sliceArray(mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val, mod, arena, start, end), | 1904 | .sliceArray(mod, arena, start, end), |
| 3108 | .comptime_field_ptr => sliceArray(val.castTag(.comptime_field_ptr).?.data.field_val, mod, arena, start, end), | 1905 | .comptime_field => |comptime_field| comptime_field.toValue() |
| 3109 | .elem_ptr => blk: { | 1906 | .sliceArray(mod, arena, start, end), |
| 3110 | const elem_ptr = val.castTag(.elem_ptr).?.data; | 1907 | .elem => |elem| elem.base.toValue() |
| 3111 | break :blk sliceArray(elem_ptr.array_ptr, mod, arena, start + elem_ptr.index, end + elem_ptr.index); | 1908 | .sliceArray(mod, arena, start + @intCast(usize, elem.index), end + @intCast(usize, elem.index)), |
| 1909 | else => unreachable, | ||
| 1910 | }, | ||
| 1911 | .aggregate => |aggregate| (try mod.intern(.{ .aggregate = .{ | ||
| 1912 | .ty = switch (mod.intern_pool.indexToKey(mod.intern_pool.typeOf(val.toIntern()))) { | ||
| 1913 | .array_type => |array_type| try mod.arrayType(.{ | ||
| 1914 | .len = @intCast(u32, end - start), | ||
| 1915 | .child = array_type.child, | ||
| 1916 | .sentinel = if (end == array_type.len) array_type.sentinel else .none, | ||
| 1917 | }), | ||
| 1918 | .vector_type => |vector_type| try mod.vectorType(.{ | ||
| 1919 | .len = @intCast(u32, end - start), | ||
| 1920 | .child = vector_type.child, | ||
| 1921 | }), | ||
| 1922 | else => unreachable, | ||
| 1923 | }.toIntern(), | ||
| 1924 | .storage = switch (aggregate.storage) { | ||
| 1925 | .bytes => .{ .bytes = try arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) }, | ||
| 1926 | .elems => .{ .elems = try arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) }, | ||
| 1927 | .repeated_elem => |elem| .{ .repeated_elem = elem }, | ||
| 1928 | }, | ||
| 1929 | } })).toValue(), | ||
| 1930 | else => unreachable, | ||
| 3112 | }, | 1931 | }, |
| 3113 | |||
| 3114 | .repeated, | ||
| 3115 | .the_only_possible_value, | ||
| 3116 | => val, | ||
| 3117 | |||
| 3118 | else => unreachable, | ||
| 3119 | }; | 1932 | }; |
| 3120 | } | 1933 | } |
| 3121 | 1934 | ||
| 3122 | pub fn fieldValue(val: Value, ty: Type, index: usize) Value { | 1935 | pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value { |
| 3123 | switch (val.tag()) { | 1936 | return switch (val.ip_index) { |
| 3124 | .aggregate => { | 1937 | .none => switch (val.tag()) { |
| 3125 | const field_values = val.castTag(.aggregate).?.data; | 1938 | .aggregate => { |
| 3126 | return field_values[index]; | 1939 | const field_values = val.castTag(.aggregate).?.data; |
| 1940 | return field_values[index]; | ||
| 1941 | }, | ||
| 1942 | .@"union" => { | ||
| 1943 | const payload = val.castTag(.@"union").?.data; | ||
| 1944 | // TODO assert the tag is correct | ||
| 1945 | return payload.val; | ||
| 1946 | }, | ||
| 1947 | else => unreachable, | ||
| 3127 | }, | 1948 | }, |
| 3128 | .@"union" => { | 1949 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3129 | const payload = val.castTag(.@"union").?.data; | 1950 | .undef => |ty| (try mod.intern(.{ |
| 1951 | .undef = ty.toType().structFieldType(index, mod).toIntern(), | ||
| 1952 | })).toValue(), | ||
| 1953 | .aggregate => |aggregate| switch (aggregate.storage) { | ||
| 1954 | .bytes => |bytes| try mod.intern(.{ .int = .{ | ||
| 1955 | .ty = .u8_type, | ||
| 1956 | .storage = .{ .u64 = bytes[index] }, | ||
| 1957 | } }), | ||
| 1958 | .elems => |elems| elems[index], | ||
| 1959 | .repeated_elem => |elem| elem, | ||
| 1960 | }.toValue(), | ||
| 3130 | // TODO assert the tag is correct | 1961 | // TODO assert the tag is correct |
| 3131 | return payload.val; | 1962 | .un => |un| un.val.toValue(), |
| 3132 | }, | 1963 | else => unreachable, |
| 3133 | |||
| 3134 | .the_only_possible_value => return ty.onePossibleValue().?, | ||
| 3135 | |||
| 3136 | .empty_struct_value => { | ||
| 3137 | if (ty.isSimpleTupleOrAnonStruct()) { | ||
| 3138 | const tuple = ty.tupleFields(); | ||
| 3139 | return tuple.values[index]; | ||
| 3140 | } | ||
| 3141 | if (ty.structFieldValueComptime(index)) |some| { | ||
| 3142 | return some; | ||
| 3143 | } | ||
| 3144 | unreachable; | ||
| 3145 | }, | 1964 | }, |
| 3146 | .undef => return Value.undef, | 1965 | }; |
| 3147 | |||
| 3148 | else => unreachable, | ||
| 3149 | } | ||
| 3150 | } | 1966 | } |
| 3151 | 1967 | ||
| 3152 | pub fn unionTag(val: Value) Value { | 1968 | pub fn unionTag(val: Value, mod: *Module) Value { |
| 3153 | switch (val.tag()) { | 1969 | if (val.ip_index == .none) return val.castTag(.@"union").?.data.tag; |
| 3154 | .undef, .enum_field_index => return val, | 1970 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3155 | .@"union" => return val.castTag(.@"union").?.data.tag, | 1971 | .undef, .enum_tag => val, |
| 1972 | .un => |un| un.tag.toValue(), | ||
| 3156 | else => unreachable, | 1973 | else => unreachable, |
| 3157 | } | 1974 | }; |
| 3158 | } | 1975 | } |
| 3159 | 1976 | ||
| 3160 | /// Returns a pointer to the element value at the index. | 1977 | /// Returns a pointer to the element value at the index. |
| 3161 | pub fn elemPtr( | 1978 | pub fn elemPtr( |
| 3162 | val: Value, | 1979 | val: Value, |
| 3163 | ty: Type, | 1980 | elem_ptr_ty: Type, |
| 3164 | arena: Allocator, | ||
| 3165 | index: usize, | 1981 | index: usize, |
| 3166 | mod: *Module, | 1982 | mod: *Module, |
| 3167 | ) Allocator.Error!Value { | 1983 | ) Allocator.Error!Value { |
| 3168 | const elem_ty = ty.elemType2(); | 1984 | const elem_ty = elem_ptr_ty.childType(mod); |
| 3169 | const ptr_val = switch (val.tag()) { | 1985 | const ptr_val = switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3170 | .slice => val.castTag(.slice).?.data.ptr, | 1986 | .ptr => |ptr| ptr: { |
| 1987 | switch (ptr.addr) { | ||
| 1988 | .elem => |elem| if (mod.intern_pool.typeOf(elem.base).toType().elemType2(mod).eql(elem_ty, mod)) | ||
| 1989 | return (try mod.intern(.{ .ptr = .{ | ||
| 1990 | .ty = elem_ptr_ty.toIntern(), | ||
| 1991 | .addr = .{ .elem = .{ | ||
| 1992 | .base = elem.base, | ||
| 1993 | .index = elem.index + index, | ||
| 1994 | } }, | ||
| 1995 | } })).toValue(), | ||
| 1996 | else => {}, | ||
| 1997 | } | ||
| 1998 | break :ptr switch (ptr.len) { | ||
| 1999 | .none => val, | ||
| 2000 | else => val.slicePtr(mod), | ||
| 2001 | }; | ||
| 2002 | }, | ||
| 3171 | else => val, | 2003 | else => val, |
| 3172 | }; | 2004 | }; |
| 3173 | 2005 | var ptr_ty_key = mod.intern_pool.indexToKey(elem_ptr_ty.toIntern()).ptr_type; | |
| 3174 | if (ptr_val.tag() == .elem_ptr) { | 2006 | assert(ptr_ty_key.flags.size != .Slice); |
| 3175 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | 2007 | ptr_ty_key.flags.size = .Many; |
| 3176 | if (elem_ptr.elem_ty.eql(elem_ty, mod)) { | 2008 | return (try mod.intern(.{ .ptr = .{ |
| 3177 | return Tag.elem_ptr.create(arena, .{ | 2009 | .ty = elem_ptr_ty.toIntern(), |
| 3178 | .array_ptr = elem_ptr.array_ptr, | 2010 | .addr = .{ .elem = .{ |
| 3179 | .elem_ty = elem_ptr.elem_ty, | 2011 | .base = (try mod.getCoerced(ptr_val, try mod.ptrType(ptr_ty_key))).toIntern(), |
| 3180 | .index = elem_ptr.index + index, | 2012 | .index = index, |
| 3181 | }); | 2013 | } }, |
| 3182 | } | 2014 | } })).toValue(); |
| 3183 | } | 2015 | } |
| 3184 | return Tag.elem_ptr.create(arena, .{ | 2016 | |
| 3185 | .array_ptr = ptr_val, | 2017 | pub fn isUndef(val: Value, mod: *Module) bool { |
| 3186 | .elem_ty = elem_ty, | 2018 | if (val.ip_index == .none) return false; |
| 3187 | .index = index, | 2019 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3188 | }); | 2020 | .undef => true, |
| 3189 | } | 2021 | .simple_value => |v| v == .undefined, |
| 3190 | 2022 | else => false, | |
| 3191 | pub fn isUndef(self: Value) bool { | 2023 | }; |
| 3192 | return self.tag() == .undef; | ||
| 3193 | } | 2024 | } |
| 3194 | 2025 | ||
| 3195 | /// TODO: check for cases such as array that is not marked undef but all the element | 2026 | /// TODO: check for cases such as array that is not marked undef but all the element |
| 3196 | /// values are marked undef, or struct that is not marked undef but all fields are marked | 2027 | /// values are marked undef, or struct that is not marked undef but all fields are marked |
| 3197 | /// undef, etc. | 2028 | /// undef, etc. |
| 3198 | pub fn isUndefDeep(self: Value) bool { | 2029 | pub fn isUndefDeep(val: Value, mod: *Module) bool { |
| 3199 | return self.isUndef(); | 2030 | return val.isUndef(mod); |
| 3200 | } | 2031 | } |
| 3201 | 2032 | ||
| 3202 | /// Returns true if any value contained in `self` is undefined. | 2033 | /// Returns true if any value contained in `self` is undefined. |
| 3203 | /// TODO: check for cases such as array that is not marked undef but all the element | 2034 | pub fn anyUndef(val: Value, mod: *Module) !bool { |
| 3204 | /// values are marked undef, or struct that is not marked undef but all fields are marked | 2035 | if (val.ip_index == .none) return false; |
| 3205 | /// undef, etc. | 2036 | return switch (val.toIntern()) { |
| 3206 | pub fn anyUndef(self: Value, mod: *Module) bool { | 2037 | .undef => true, |
| 3207 | switch (self.tag()) { | 2038 | else => switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3208 | .slice => { | 2039 | .undef => true, |
| 3209 | const payload = self.castTag(.slice).?; | 2040 | .simple_value => |v| v == .undefined, |
| 3210 | const len = payload.data.len.toUnsignedInt(mod.getTarget()); | 2041 | .ptr => |ptr| switch (ptr.len) { |
| 3211 | 2042 | .none => false, | |
| 3212 | var elem_value_buf: ElemValueBuffer = undefined; | 2043 | else => for (0..@intCast(usize, ptr.len.toValue().toUnsignedInt(mod))) |index| { |
| 3213 | var i: usize = 0; | 2044 | if (try (try val.elemValue(mod, index)).anyUndef(mod)) break true; |
| 3214 | while (i < len) : (i += 1) { | 2045 | } else false, |
| 3215 | const elem_val = payload.data.ptr.elemValueBuffer(mod, i, &elem_value_buf); | 2046 | }, |
| 3216 | if (elem_val.anyUndef(mod)) return true; | 2047 | .aggregate => |aggregate| for (0..aggregate.storage.values().len) |i| { |
| 3217 | } | 2048 | const elem = mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.values()[i]; |
| 3218 | }, | 2049 | if (try anyUndef(elem.toValue(), mod)) break true; |
| 3219 | 2050 | } else false, | |
| 3220 | .aggregate => { | 2051 | else => false, |
| 3221 | const payload = self.castTag(.aggregate).?; | ||
| 3222 | for (payload.data) |val| { | ||
| 3223 | if (val.anyUndef(mod)) return true; | ||
| 3224 | } | ||
| 3225 | }, | 2052 | }, |
| 3226 | 2053 | }; | |
| 3227 | .undef => return true, | ||
| 3228 | else => {}, | ||
| 3229 | } | ||
| 3230 | |||
| 3231 | return false; | ||
| 3232 | } | 2054 | } |
| 3233 | 2055 | ||
| 3234 | /// Asserts the value is not undefined and not unreachable. | 2056 | /// Asserts the value is not undefined and not unreachable. |
| 3235 | /// Integer value 0 is considered null because of C pointers. | 2057 | /// C pointers with an integer value of 0 are also considered null. |
| 3236 | pub fn isNull(self: Value) bool { | 2058 | pub fn isNull(val: Value, mod: *Module) bool { |
| 3237 | return switch (self.tag()) { | 2059 | return switch (val.toIntern()) { |
| 3238 | .null_value => true, | ||
| 3239 | .opt_payload => false, | ||
| 3240 | |||
| 3241 | // If it's not one of those two tags then it must be a C pointer value, | ||
| 3242 | // in which case the value 0 is null and other values are non-null. | ||
| 3243 | |||
| 3244 | .zero, | ||
| 3245 | .bool_false, | ||
| 3246 | .the_only_possible_value, | ||
| 3247 | => true, | ||
| 3248 | |||
| 3249 | .one, | ||
| 3250 | .bool_true, | ||
| 3251 | => false, | ||
| 3252 | |||
| 3253 | .int_u64, | ||
| 3254 | .int_i64, | ||
| 3255 | .int_big_positive, | ||
| 3256 | .int_big_negative, | ||
| 3257 | => self.orderAgainstZero().compare(.eq), | ||
| 3258 | |||
| 3259 | .undef => unreachable, | 2060 | .undef => unreachable, |
| 3260 | .unreachable_value => unreachable, | 2061 | .unreachable_value => unreachable, |
| 3261 | .inferred_alloc => unreachable, | 2062 | .null_value => true, |
| 3262 | .inferred_alloc_comptime => unreachable, | 2063 | else => return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3263 | 2064 | .undef => unreachable, | |
| 3264 | else => false, | 2065 | .ptr => |ptr| switch (ptr.addr) { |
| 2066 | .int => { | ||
| 2067 | var buf: BigIntSpace = undefined; | ||
| 2068 | return val.toBigInt(&buf, mod).eqZero(); | ||
| 2069 | }, | ||
| 2070 | else => false, | ||
| 2071 | }, | ||
| 2072 | .opt => |opt| opt.val == .none, | ||
| 2073 | else => false, | ||
| 2074 | }, | ||
| 3265 | }; | 2075 | }; |
| 3266 | } | 2076 | } |
| 3267 | 2077 | ||
| 3268 | /// Valid only for error (union) types. Asserts the value is not undefined and not | 2078 | /// Valid only for error (union) types. Asserts the value is not undefined and not unreachable. |
| 3269 | /// unreachable. For error unions, prefer `errorUnionIsPayload` to find out whether | 2079 | pub fn getErrorName(val: Value, mod: *const Module) InternPool.OptionalNullTerminatedString { |
| 3270 | /// something is an error or not because it works without having to figure out the | 2080 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3271 | /// string. | 2081 | .err => |err| err.name.toOptional(), |
| 3272 | pub fn getError(self: Value) ?[]const u8 { | 2082 | .error_union => |error_union| switch (error_union.val) { |
| 3273 | return switch (self.tag()) { | 2083 | .err_name => |err_name| err_name.toOptional(), |
| 3274 | .@"error" => self.castTag(.@"error").?.data.name, | 2084 | .payload => .none, |
| 3275 | .int_u64 => @panic("TODO"), | 2085 | }, |
| 3276 | .int_i64 => @panic("TODO"), | 2086 | else => unreachable, |
| 3277 | .int_big_positive => @panic("TODO"), | ||
| 3278 | .int_big_negative => @panic("TODO"), | ||
| 3279 | .one => @panic("TODO"), | ||
| 3280 | .undef => unreachable, | ||
| 3281 | .unreachable_value => unreachable, | ||
| 3282 | .inferred_alloc => unreachable, | ||
| 3283 | .inferred_alloc_comptime => unreachable, | ||
| 3284 | |||
| 3285 | else => null, | ||
| 3286 | }; | 2087 | }; |
| 3287 | } | 2088 | } |
| 3288 | 2089 | ||
| 2090 | pub fn getErrorInt(val: Value, mod: *const Module) Module.ErrorInt { | ||
| 2091 | return if (getErrorName(val, mod).unwrap()) |err_name| | ||
| 2092 | @intCast(Module.ErrorInt, mod.global_error_set.getIndex(err_name).?) | ||
| 2093 | else | ||
| 2094 | 0; | ||
| 2095 | } | ||
| 2096 | |||
| 3289 | /// Assumes the type is an error union. Returns true if and only if the value is | 2097 | /// Assumes the type is an error union. Returns true if and only if the value is |
| 3290 | /// the error union payload, not an error. | 2098 | /// the error union payload, not an error. |
| 3291 | pub fn errorUnionIsPayload(val: Value) bool { | 2099 | pub fn errorUnionIsPayload(val: Value, mod: *const Module) bool { |
| 3292 | return switch (val.tag()) { | 2100 | return mod.intern_pool.indexToKey(val.toIntern()).error_union.val == .payload; |
| 3293 | .eu_payload => true, | ||
| 3294 | else => false, | ||
| 3295 | |||
| 3296 | .undef => unreachable, | ||
| 3297 | .inferred_alloc => unreachable, | ||
| 3298 | .inferred_alloc_comptime => unreachable, | ||
| 3299 | }; | ||
| 3300 | } | 2101 | } |
| 3301 | 2102 | ||
| 3302 | /// Value of the optional, null if optional has no payload. | 2103 | /// Value of the optional, null if optional has no payload. |
| 3303 | pub fn optionalValue(val: Value) ?Value { | 2104 | pub fn optionalValue(val: Value, mod: *const Module) ?Value { |
| 3304 | if (val.isNull()) return null; | 2105 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3305 | 2106 | .opt => |opt| switch (opt.val) { | |
| 3306 | // Valid for optional representation to be the direct value | 2107 | .none => null, |
| 3307 | // and not use opt_payload. | 2108 | else => |payload| payload.toValue(), |
| 3308 | return if (val.castTag(.opt_payload)) |p| p.data else val; | 2109 | }, |
| 2110 | .ptr => val, | ||
| 2111 | else => unreachable, | ||
| 2112 | }; | ||
| 3309 | } | 2113 | } |
| 3310 | 2114 | ||
| 3311 | /// Valid for all types. Asserts the value is not undefined. | 2115 | /// Valid for all types. Asserts the value is not undefined. |
| 3312 | pub fn isFloat(self: Value) bool { | 2116 | pub fn isFloat(self: Value, mod: *const Module) bool { |
| 3313 | return switch (self.tag()) { | 2117 | return switch (self.toIntern()) { |
| 3314 | .undef => unreachable, | 2118 | .undef => unreachable, |
| 3315 | .inferred_alloc => unreachable, | 2119 | else => switch (mod.intern_pool.indexToKey(self.toIntern())) { |
| 3316 | .inferred_alloc_comptime => unreachable, | 2120 | .undef => unreachable, |
| 3317 | 2121 | .float => true, | |
| 3318 | .float_16, | 2122 | else => false, |
| 3319 | .float_32, | 2123 | }, |
| 3320 | .float_64, | ||
| 3321 | .float_80, | ||
| 3322 | .float_128, | ||
| 3323 | => true, | ||
| 3324 | else => false, | ||
| 3325 | }; | 2124 | }; |
| 3326 | } | 2125 | } |
| 3327 | 2126 | ||
| ... | @@ -3333,79 +2132,59 @@ pub const Value = extern union { | ... | @@ -3333,79 +2132,59 @@ pub const Value = extern union { |
| 3333 | } | 2132 | } |
| 3334 | 2133 | ||
| 3335 | pub fn intToFloatAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value { | 2134 | pub fn intToFloatAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value { |
| 3336 | const target = mod.getTarget(); | 2135 | if (int_ty.zigTypeTag(mod) == .Vector) { |
| 3337 | if (int_ty.zigTypeTag() == .Vector) { | 2136 | const result_data = try arena.alloc(InternPool.Index, int_ty.vectorLen(mod)); |
| 3338 | const result_data = try arena.alloc(Value, int_ty.vectorLen()); | 2137 | const scalar_ty = float_ty.scalarType(mod); |
| 3339 | for (result_data, 0..) |*scalar, i| { | 2138 | for (result_data, 0..) |*scalar, i| { |
| 3340 | var buf: Value.ElemValueBuffer = undefined; | 2139 | const elem_val = try val.elemValue(mod, i); |
| 3341 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 2140 | scalar.* = try (try intToFloatScalar(elem_val, scalar_ty, mod, opt_sema)).intern(scalar_ty, mod); |
| 3342 | scalar.* = try intToFloatScalar(elem_val, arena, float_ty.scalarType(), target, opt_sema); | ||
| 3343 | } | 2141 | } |
| 3344 | return Value.Tag.aggregate.create(arena, result_data); | 2142 | return (try mod.intern(.{ .aggregate = .{ |
| 2143 | .ty = float_ty.toIntern(), | ||
| 2144 | .storage = .{ .elems = result_data }, | ||
| 2145 | } })).toValue(); | ||
| 3345 | } | 2146 | } |
| 3346 | return intToFloatScalar(val, arena, float_ty, target, opt_sema); | 2147 | return intToFloatScalar(val, float_ty, mod, opt_sema); |
| 3347 | } | 2148 | } |
| 3348 | 2149 | ||
| 3349 | pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target, opt_sema: ?*Sema) !Value { | 2150 | pub fn intToFloatScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value { |
| 3350 | switch (val.tag()) { | 2151 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 3351 | .undef, .zero, .one => return val, | 2152 | .undef => (try mod.intern(.{ .undef = float_ty.toIntern() })).toValue(), |
| 3352 | .the_only_possible_value => return Value.initTag(.zero), // for i0, u0 | 2153 | .int => |int| switch (int.storage) { |
| 3353 | .int_u64 => { | 2154 | .big_int => |big_int| { |
| 3354 | return intToFloatInner(val.castTag(.int_u64).?.data, arena, float_ty, target); | 2155 | const float = bigIntToFloat(big_int.limbs, big_int.positive); |
| 3355 | }, | 2156 | return mod.floatValue(float_ty, float); |
| 3356 | .int_i64 => { | 2157 | }, |
| 3357 | return intToFloatInner(val.castTag(.int_i64).?.data, arena, float_ty, target); | 2158 | inline .u64, .i64 => |x| intToFloatInner(x, float_ty, mod), |
| 3358 | }, | 2159 | .lazy_align => |ty| if (opt_sema) |sema| { |
| 3359 | .int_big_positive => { | 2160 | return intToFloatInner((try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); |
| 3360 | const limbs = val.castTag(.int_big_positive).?.data; | ||
| 3361 | const float = bigIntToFloat(limbs, true); | ||
| 3362 | return floatToValue(float, arena, float_ty, target); | ||
| 3363 | }, | ||
| 3364 | .int_big_negative => { | ||
| 3365 | const limbs = val.castTag(.int_big_negative).?.data; | ||
| 3366 | const float = bigIntToFloat(limbs, false); | ||
| 3367 | return floatToValue(float, arena, float_ty, target); | ||
| 3368 | }, | ||
| 3369 | .lazy_align => { | ||
| 3370 | const ty = val.castTag(.lazy_align).?.data; | ||
| 3371 | if (opt_sema) |sema| { | ||
| 3372 | return intToFloatInner((try ty.abiAlignmentAdvanced(target, .{ .sema = sema })).scalar, arena, float_ty, target); | ||
| 3373 | } else { | 2161 | } else { |
| 3374 | return intToFloatInner(ty.abiAlignment(target), arena, float_ty, target); | 2162 | return intToFloatInner(ty.toType().abiAlignment(mod), float_ty, mod); |
| 3375 | } | 2163 | }, |
| 3376 | }, | 2164 | .lazy_size => |ty| if (opt_sema) |sema| { |
| 3377 | .lazy_size => { | 2165 | return intToFloatInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); |
| 3378 | const ty = val.castTag(.lazy_size).?.data; | ||
| 3379 | if (opt_sema) |sema| { | ||
| 3380 | return intToFloatInner((try ty.abiSizeAdvanced(target, .{ .sema = sema })).scalar, arena, float_ty, target); | ||
| 3381 | } else { | 2166 | } else { |
| 3382 | return intToFloatInner(ty.abiSize(target), arena, float_ty, target); | 2167 | return intToFloatInner(ty.toType().abiSize(mod), float_ty, mod); |
| 3383 | } | 2168 | }, |
| 3384 | }, | 2169 | }, |
| 3385 | else => unreachable, | 2170 | else => unreachable, |
| 3386 | } | 2171 | }; |
| 3387 | } | ||
| 3388 | |||
| 3389 | fn intToFloatInner(x: anytype, arena: Allocator, dest_ty: Type, target: Target) !Value { | ||
| 3390 | switch (dest_ty.floatBits(target)) { | ||
| 3391 | 16 => return Value.Tag.float_16.create(arena, @intToFloat(f16, x)), | ||
| 3392 | 32 => return Value.Tag.float_32.create(arena, @intToFloat(f32, x)), | ||
| 3393 | 64 => return Value.Tag.float_64.create(arena, @intToFloat(f64, x)), | ||
| 3394 | 80 => return Value.Tag.float_80.create(arena, @intToFloat(f80, x)), | ||
| 3395 | 128 => return Value.Tag.float_128.create(arena, @intToFloat(f128, x)), | ||
| 3396 | else => unreachable, | ||
| 3397 | } | ||
| 3398 | } | 2172 | } |
| 3399 | 2173 | ||
| 3400 | pub fn floatToValue(float: f128, arena: Allocator, dest_ty: Type, target: Target) !Value { | 2174 | fn intToFloatInner(x: anytype, dest_ty: Type, mod: *Module) !Value { |
| 3401 | switch (dest_ty.floatBits(target)) { | 2175 | const target = mod.getTarget(); |
| 3402 | 16 => return Value.Tag.float_16.create(arena, @floatCast(f16, float)), | 2176 | const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) { |
| 3403 | 32 => return Value.Tag.float_32.create(arena, @floatCast(f32, float)), | 2177 | 16 => .{ .f16 = @intToFloat(f16, x) }, |
| 3404 | 64 => return Value.Tag.float_64.create(arena, @floatCast(f64, float)), | 2178 | 32 => .{ .f32 = @intToFloat(f32, x) }, |
| 3405 | 80 => return Value.Tag.float_80.create(arena, @floatCast(f80, float)), | 2179 | 64 => .{ .f64 = @intToFloat(f64, x) }, |
| 3406 | 128 => return Value.Tag.float_128.create(arena, float), | 2180 | 80 => .{ .f80 = @intToFloat(f80, x) }, |
| 2181 | 128 => .{ .f128 = @intToFloat(f128, x) }, | ||
| 3407 | else => unreachable, | 2182 | else => unreachable, |
| 3408 | } | 2183 | }; |
| 2184 | return (try mod.intern(.{ .float = .{ | ||
| 2185 | .ty = dest_ty.toIntern(), | ||
| 2186 | .storage = storage, | ||
| 2187 | } })).toValue(); | ||
| 3409 | } | 2188 | } |
| 3410 | 2189 | ||
| 3411 | fn calcLimbLenFloat(scalar: anytype) usize { | 2190 | fn calcLimbLenFloat(scalar: anytype) usize { |
| ... | @@ -3422,22 +2201,6 @@ pub const Value = extern union { | ... | @@ -3422,22 +2201,6 @@ pub const Value = extern union { |
| 3422 | wrapped_result: Value, | 2201 | wrapped_result: Value, |
| 3423 | }; | 2202 | }; |
| 3424 | 2203 | ||
| 3425 | pub fn fromBigInt(arena: Allocator, big_int: BigIntConst) !Value { | ||
| 3426 | if (big_int.positive) { | ||
| 3427 | if (big_int.to(u64)) |x| { | ||
| 3428 | return Value.Tag.int_u64.create(arena, x); | ||
| 3429 | } else |_| { | ||
| 3430 | return Value.Tag.int_big_positive.create(arena, big_int.limbs); | ||
| 3431 | } | ||
| 3432 | } else { | ||
| 3433 | if (big_int.to(i64)) |x| { | ||
| 3434 | return Value.Tag.int_i64.create(arena, x); | ||
| 3435 | } else |_| { | ||
| 3436 | return Value.Tag.int_big_negative.create(arena, big_int.limbs); | ||
| 3437 | } | ||
| 3438 | } | ||
| 3439 | } | ||
| 3440 | |||
| 3441 | /// Supports (vectors of) integers only; asserts neither operand is undefined. | 2204 | /// Supports (vectors of) integers only; asserts neither operand is undefined. |
| 3442 | pub fn intAddSat( | 2205 | pub fn intAddSat( |
| 3443 | lhs: Value, | 2206 | lhs: Value, |
| ... | @@ -3446,19 +2209,20 @@ pub const Value = extern union { | ... | @@ -3446,19 +2209,20 @@ pub const Value = extern union { |
| 3446 | arena: Allocator, | 2209 | arena: Allocator, |
| 3447 | mod: *Module, | 2210 | mod: *Module, |
| 3448 | ) !Value { | 2211 | ) !Value { |
| 3449 | const target = mod.getTarget(); | 2212 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3450 | if (ty.zigTypeTag() == .Vector) { | 2213 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3451 | const result_data = try arena.alloc(Value, ty.vectorLen()); | 2214 | const scalar_ty = ty.scalarType(mod); |
| 3452 | for (result_data, 0..) |*scalar, i| { | 2215 | for (result_data, 0..) |*scalar, i| { |
| 3453 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2216 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3454 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2217 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3455 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2218 | scalar.* = try (try intAddSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); |
| 3456 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 3457 | scalar.* = try intAddSatScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); | ||
| 3458 | } | 2219 | } |
| 3459 | return Value.Tag.aggregate.create(arena, result_data); | 2220 | return (try mod.intern(.{ .aggregate = .{ |
| 2221 | .ty = ty.toIntern(), | ||
| 2222 | .storage = .{ .elems = result_data }, | ||
| 2223 | } })).toValue(); | ||
| 3460 | } | 2224 | } |
| 3461 | return intAddSatScalar(lhs, rhs, ty, arena, target); | 2225 | return intAddSatScalar(lhs, rhs, ty, arena, mod); |
| 3462 | } | 2226 | } |
| 3463 | 2227 | ||
| 3464 | /// Supports integers only; asserts neither operand is undefined. | 2228 | /// Supports integers only; asserts neither operand is undefined. |
| ... | @@ -3467,24 +2231,24 @@ pub const Value = extern union { | ... | @@ -3467,24 +2231,24 @@ pub const Value = extern union { |
| 3467 | rhs: Value, | 2231 | rhs: Value, |
| 3468 | ty: Type, | 2232 | ty: Type, |
| 3469 | arena: Allocator, | 2233 | arena: Allocator, |
| 3470 | target: Target, | 2234 | mod: *Module, |
| 3471 | ) !Value { | 2235 | ) !Value { |
| 3472 | assert(!lhs.isUndef()); | 2236 | assert(!lhs.isUndef(mod)); |
| 3473 | assert(!rhs.isUndef()); | 2237 | assert(!rhs.isUndef(mod)); |
| 3474 | 2238 | ||
| 3475 | const info = ty.intInfo(target); | 2239 | const info = ty.intInfo(mod); |
| 3476 | 2240 | ||
| 3477 | var lhs_space: Value.BigIntSpace = undefined; | 2241 | var lhs_space: Value.BigIntSpace = undefined; |
| 3478 | var rhs_space: Value.BigIntSpace = undefined; | 2242 | var rhs_space: Value.BigIntSpace = undefined; |
| 3479 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 2243 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 3480 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 2244 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 3481 | const limbs = try arena.alloc( | 2245 | const limbs = try arena.alloc( |
| 3482 | std.math.big.Limb, | 2246 | std.math.big.Limb, |
| 3483 | std.math.big.int.calcTwosCompLimbCount(info.bits), | 2247 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| 3484 | ); | 2248 | ); |
| 3485 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 2249 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3486 | result_bigint.addSat(lhs_bigint, rhs_bigint, info.signedness, info.bits); | 2250 | result_bigint.addSat(lhs_bigint, rhs_bigint, info.signedness, info.bits); |
| 3487 | return fromBigInt(arena, result_bigint.toConst()); | 2251 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 3488 | } | 2252 | } |
| 3489 | 2253 | ||
| 3490 | /// Supports (vectors of) integers only; asserts neither operand is undefined. | 2254 | /// Supports (vectors of) integers only; asserts neither operand is undefined. |
| ... | @@ -3495,19 +2259,20 @@ pub const Value = extern union { | ... | @@ -3495,19 +2259,20 @@ pub const Value = extern union { |
| 3495 | arena: Allocator, | 2259 | arena: Allocator, |
| 3496 | mod: *Module, | 2260 | mod: *Module, |
| 3497 | ) !Value { | 2261 | ) !Value { |
| 3498 | const target = mod.getTarget(); | 2262 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3499 | if (ty.zigTypeTag() == .Vector) { | 2263 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3500 | const result_data = try arena.alloc(Value, ty.vectorLen()); | 2264 | const scalar_ty = ty.scalarType(mod); |
| 3501 | for (result_data, 0..) |*scalar, i| { | 2265 | for (result_data, 0..) |*scalar, i| { |
| 3502 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2266 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3503 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2267 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3504 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2268 | scalar.* = try (try intSubSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); |
| 3505 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 3506 | scalar.* = try intSubSatScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); | ||
| 3507 | } | 2269 | } |
| 3508 | return Value.Tag.aggregate.create(arena, result_data); | 2270 | return (try mod.intern(.{ .aggregate = .{ |
| 2271 | .ty = ty.toIntern(), | ||
| 2272 | .storage = .{ .elems = result_data }, | ||
| 2273 | } })).toValue(); | ||
| 3509 | } | 2274 | } |
| 3510 | return intSubSatScalar(lhs, rhs, ty, arena, target); | 2275 | return intSubSatScalar(lhs, rhs, ty, arena, mod); |
| 3511 | } | 2276 | } |
| 3512 | 2277 | ||
| 3513 | /// Supports integers only; asserts neither operand is undefined. | 2278 | /// Supports integers only; asserts neither operand is undefined. |
| ... | @@ -3516,24 +2281,24 @@ pub const Value = extern union { | ... | @@ -3516,24 +2281,24 @@ pub const Value = extern union { |
| 3516 | rhs: Value, | 2281 | rhs: Value, |
| 3517 | ty: Type, | 2282 | ty: Type, |
| 3518 | arena: Allocator, | 2283 | arena: Allocator, |
| 3519 | target: Target, | 2284 | mod: *Module, |
| 3520 | ) !Value { | 2285 | ) !Value { |
| 3521 | assert(!lhs.isUndef()); | 2286 | assert(!lhs.isUndef(mod)); |
| 3522 | assert(!rhs.isUndef()); | 2287 | assert(!rhs.isUndef(mod)); |
| 3523 | 2288 | ||
| 3524 | const info = ty.intInfo(target); | 2289 | const info = ty.intInfo(mod); |
| 3525 | 2290 | ||
| 3526 | var lhs_space: Value.BigIntSpace = undefined; | 2291 | var lhs_space: Value.BigIntSpace = undefined; |
| 3527 | var rhs_space: Value.BigIntSpace = undefined; | 2292 | var rhs_space: Value.BigIntSpace = undefined; |
| 3528 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 2293 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 3529 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 2294 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 3530 | const limbs = try arena.alloc( | 2295 | const limbs = try arena.alloc( |
| 3531 | std.math.big.Limb, | 2296 | std.math.big.Limb, |
| 3532 | std.math.big.int.calcTwosCompLimbCount(info.bits), | 2297 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| 3533 | ); | 2298 | ); |
| 3534 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 2299 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3535 | result_bigint.subSat(lhs_bigint, rhs_bigint, info.signedness, info.bits); | 2300 | result_bigint.subSat(lhs_bigint, rhs_bigint, info.signedness, info.bits); |
| 3536 | return fromBigInt(arena, result_bigint.toConst()); | 2301 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 3537 | } | 2302 | } |
| 3538 | 2303 | ||
| 3539 | pub fn intMulWithOverflow( | 2304 | pub fn intMulWithOverflow( |
| ... | @@ -3543,25 +2308,30 @@ pub const Value = extern union { | ... | @@ -3543,25 +2308,30 @@ pub const Value = extern union { |
| 3543 | arena: Allocator, | 2308 | arena: Allocator, |
| 3544 | mod: *Module, | 2309 | mod: *Module, |
| 3545 | ) !OverflowArithmeticResult { | 2310 | ) !OverflowArithmeticResult { |
| 3546 | const target = mod.getTarget(); | 2311 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3547 | if (ty.zigTypeTag() == .Vector) { | 2312 | const vec_len = ty.vectorLen(mod); |
| 3548 | const overflowed_data = try arena.alloc(Value, ty.vectorLen()); | 2313 | const overflowed_data = try arena.alloc(InternPool.Index, vec_len); |
| 3549 | const result_data = try arena.alloc(Value, ty.vectorLen()); | 2314 | const result_data = try arena.alloc(InternPool.Index, vec_len); |
| 3550 | for (result_data, 0..) |*scalar, i| { | 2315 | const scalar_ty = ty.scalarType(mod); |
| 3551 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2316 | for (overflowed_data, result_data, 0..) |*of, *scalar, i| { |
| 3552 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2317 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3553 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2318 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3554 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | 2319 | const of_math_result = try intMulWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod); |
| 3555 | const of_math_result = try intMulWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); | 2320 | of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); |
| 3556 | overflowed_data[i] = of_math_result.overflow_bit; | 2321 | scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); |
| 3557 | scalar.* = of_math_result.wrapped_result; | ||
| 3558 | } | 2322 | } |
| 3559 | return OverflowArithmeticResult{ | 2323 | return OverflowArithmeticResult{ |
| 3560 | .overflow_bit = try Value.Tag.aggregate.create(arena, overflowed_data), | 2324 | .overflow_bit = (try mod.intern(.{ .aggregate = .{ |
| 3561 | .wrapped_result = try Value.Tag.aggregate.create(arena, result_data), | 2325 | .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(), |
| 2326 | .storage = .{ .elems = overflowed_data }, | ||
| 2327 | } })).toValue(), | ||
| 2328 | .wrapped_result = (try mod.intern(.{ .aggregate = .{ | ||
| 2329 | .ty = ty.toIntern(), | ||
| 2330 | .storage = .{ .elems = result_data }, | ||
| 2331 | } })).toValue(), | ||
| 3562 | }; | 2332 | }; |
| 3563 | } | 2333 | } |
| 3564 | return intMulWithOverflowScalar(lhs, rhs, ty, arena, target); | 2334 | return intMulWithOverflowScalar(lhs, rhs, ty, arena, mod); |
| 3565 | } | 2335 | } |
| 3566 | 2336 | ||
| 3567 | pub fn intMulWithOverflowScalar( | 2337 | pub fn intMulWithOverflowScalar( |
| ... | @@ -3569,14 +2339,14 @@ pub const Value = extern union { | ... | @@ -3569,14 +2339,14 @@ pub const Value = extern union { |
| 3569 | rhs: Value, | 2339 | rhs: Value, |
| 3570 | ty: Type, | 2340 | ty: Type, |
| 3571 | arena: Allocator, | 2341 | arena: Allocator, |
| 3572 | target: Target, | 2342 | mod: *Module, |
| 3573 | ) !OverflowArithmeticResult { | 2343 | ) !OverflowArithmeticResult { |
| 3574 | const info = ty.intInfo(target); | 2344 | const info = ty.intInfo(mod); |
| 3575 | 2345 | ||
| 3576 | var lhs_space: Value.BigIntSpace = undefined; | 2346 | var lhs_space: Value.BigIntSpace = undefined; |
| 3577 | var rhs_space: Value.BigIntSpace = undefined; | 2347 | var rhs_space: Value.BigIntSpace = undefined; |
| 3578 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 2348 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 3579 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 2349 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 3580 | const limbs = try arena.alloc( | 2350 | const limbs = try arena.alloc( |
| 3581 | std.math.big.Limb, | 2351 | std.math.big.Limb, |
| 3582 | lhs_bigint.limbs.len + rhs_bigint.limbs.len, | 2352 | lhs_bigint.limbs.len + rhs_bigint.limbs.len, |
| ... | @@ -3594,8 +2364,8 @@ pub const Value = extern union { | ... | @@ -3594,8 +2364,8 @@ pub const Value = extern union { |
| 3594 | } | 2364 | } |
| 3595 | 2365 | ||
| 3596 | return OverflowArithmeticResult{ | 2366 | return OverflowArithmeticResult{ |
| 3597 | .overflow_bit = boolToInt(overflowed), | 2367 | .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)), |
| 3598 | .wrapped_result = try fromBigInt(arena, result_bigint.toConst()), | 2368 | .wrapped_result = try mod.intValue_big(ty, result_bigint.toConst()), |
| 3599 | }; | 2369 | }; |
| 3600 | } | 2370 | } |
| 3601 | 2371 | ||
| ... | @@ -3607,16 +2377,18 @@ pub const Value = extern union { | ... | @@ -3607,16 +2377,18 @@ pub const Value = extern union { |
| 3607 | arena: Allocator, | 2377 | arena: Allocator, |
| 3608 | mod: *Module, | 2378 | mod: *Module, |
| 3609 | ) !Value { | 2379 | ) !Value { |
| 3610 | if (ty.zigTypeTag() == .Vector) { | 2380 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3611 | const result_data = try arena.alloc(Value, ty.vectorLen()); | 2381 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 2382 | const scalar_ty = ty.scalarType(mod); | ||
| 3612 | for (result_data, 0..) |*scalar, i| { | 2383 | for (result_data, 0..) |*scalar, i| { |
| 3613 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2384 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3614 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2385 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3615 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2386 | scalar.* = try (try numberMulWrapScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); |
| 3616 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 3617 | scalar.* = try numberMulWrapScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, mod); | ||
| 3618 | } | 2387 | } |
| 3619 | return Value.Tag.aggregate.create(arena, result_data); | 2388 | return (try mod.intern(.{ .aggregate = .{ |
| 2389 | .ty = ty.toIntern(), | ||
| 2390 | .storage = .{ .elems = result_data }, | ||
| 2391 | } })).toValue(); | ||
| 3620 | } | 2392 | } |
| 3621 | return numberMulWrapScalar(lhs, rhs, ty, arena, mod); | 2393 | return numberMulWrapScalar(lhs, rhs, ty, arena, mod); |
| 3622 | } | 2394 | } |
| ... | @@ -3629,10 +2401,10 @@ pub const Value = extern union { | ... | @@ -3629,10 +2401,10 @@ pub const Value = extern union { |
| 3629 | arena: Allocator, | 2401 | arena: Allocator, |
| 3630 | mod: *Module, | 2402 | mod: *Module, |
| 3631 | ) !Value { | 2403 | ) !Value { |
| 3632 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | 2404 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef; |
| 3633 | 2405 | ||
| 3634 | if (ty.zigTypeTag() == .ComptimeInt) { | 2406 | if (ty.zigTypeTag(mod) == .ComptimeInt) { |
| 3635 | return intMul(lhs, rhs, ty, arena, mod); | 2407 | return intMul(lhs, rhs, ty, undefined, arena, mod); |
| 3636 | } | 2408 | } |
| 3637 | 2409 | ||
| 3638 | if (ty.isAnyFloat()) { | 2410 | if (ty.isAnyFloat()) { |
| ... | @@ -3651,19 +2423,20 @@ pub const Value = extern union { | ... | @@ -3651,19 +2423,20 @@ pub const Value = extern union { |
| 3651 | arena: Allocator, | 2423 | arena: Allocator, |
| 3652 | mod: *Module, | 2424 | mod: *Module, |
| 3653 | ) !Value { | 2425 | ) !Value { |
| 3654 | const target = mod.getTarget(); | 2426 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3655 | if (ty.zigTypeTag() == .Vector) { | 2427 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3656 | const result_data = try arena.alloc(Value, ty.vectorLen()); | 2428 | const scalar_ty = ty.scalarType(mod); |
| 3657 | for (result_data, 0..) |*scalar, i| { | 2429 | for (result_data, 0..) |*scalar, i| { |
| 3658 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2430 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3659 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2431 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3660 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2432 | scalar.* = try (try intMulSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); |
| 3661 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 3662 | scalar.* = try intMulSatScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); | ||
| 3663 | } | 2433 | } |
| 3664 | return Value.Tag.aggregate.create(arena, result_data); | 2434 | return (try mod.intern(.{ .aggregate = .{ |
| 2435 | .ty = ty.toIntern(), | ||
| 2436 | .storage = .{ .elems = result_data }, | ||
| 2437 | } })).toValue(); | ||
| 3665 | } | 2438 | } |
| 3666 | return intMulSatScalar(lhs, rhs, ty, arena, target); | 2439 | return intMulSatScalar(lhs, rhs, ty, arena, mod); |
| 3667 | } | 2440 | } |
| 3668 | 2441 | ||
| 3669 | /// Supports (vectors of) integers only; asserts neither operand is undefined. | 2442 | /// Supports (vectors of) integers only; asserts neither operand is undefined. |
| ... | @@ -3672,17 +2445,17 @@ pub const Value = extern union { | ... | @@ -3672,17 +2445,17 @@ pub const Value = extern union { |
| 3672 | rhs: Value, | 2445 | rhs: Value, |
| 3673 | ty: Type, | 2446 | ty: Type, |
| 3674 | arena: Allocator, | 2447 | arena: Allocator, |
| 3675 | target: Target, | 2448 | mod: *Module, |
| 3676 | ) !Value { | 2449 | ) !Value { |
| 3677 | assert(!lhs.isUndef()); | 2450 | assert(!lhs.isUndef(mod)); |
| 3678 | assert(!rhs.isUndef()); | 2451 | assert(!rhs.isUndef(mod)); |
| 3679 | 2452 | ||
| 3680 | const info = ty.intInfo(target); | 2453 | const info = ty.intInfo(mod); |
| 3681 | 2454 | ||
| 3682 | var lhs_space: Value.BigIntSpace = undefined; | 2455 | var lhs_space: Value.BigIntSpace = undefined; |
| 3683 | var rhs_space: Value.BigIntSpace = undefined; | 2456 | var rhs_space: Value.BigIntSpace = undefined; |
| 3684 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 2457 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 3685 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 2458 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 3686 | const limbs = try arena.alloc( | 2459 | const limbs = try arena.alloc( |
| 3687 | std.math.big.Limb, | 2460 | std.math.big.Limb, |
| 3688 | std.math.max( | 2461 | std.math.max( |
| ... | @@ -3698,28 +2471,28 @@ pub const Value = extern union { | ... | @@ -3698,28 +2471,28 @@ pub const Value = extern union { |
| 3698 | ); | 2471 | ); |
| 3699 | result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena); | 2472 | result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, arena); |
| 3700 | result_bigint.saturate(result_bigint.toConst(), info.signedness, info.bits); | 2473 | result_bigint.saturate(result_bigint.toConst(), info.signedness, info.bits); |
| 3701 | return fromBigInt(arena, result_bigint.toConst()); | 2474 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 3702 | } | 2475 | } |
| 3703 | 2476 | ||
| 3704 | /// Supports both floats and ints; handles undefined. | 2477 | /// Supports both floats and ints; handles undefined. |
| 3705 | pub fn numberMax(lhs: Value, rhs: Value, target: Target) Value { | 2478 | pub fn numberMax(lhs: Value, rhs: Value, mod: *Module) Value { |
| 3706 | if (lhs.isUndef() or rhs.isUndef()) return undef; | 2479 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return undef; |
| 3707 | if (lhs.isNan()) return rhs; | 2480 | if (lhs.isNan(mod)) return rhs; |
| 3708 | if (rhs.isNan()) return lhs; | 2481 | if (rhs.isNan(mod)) return lhs; |
| 3709 | 2482 | ||
| 3710 | return switch (order(lhs, rhs, target)) { | 2483 | return switch (order(lhs, rhs, mod)) { |
| 3711 | .lt => rhs, | 2484 | .lt => rhs, |
| 3712 | .gt, .eq => lhs, | 2485 | .gt, .eq => lhs, |
| 3713 | }; | 2486 | }; |
| 3714 | } | 2487 | } |
| 3715 | 2488 | ||
| 3716 | /// Supports both floats and ints; handles undefined. | 2489 | /// Supports both floats and ints; handles undefined. |
| 3717 | pub fn numberMin(lhs: Value, rhs: Value, target: Target) Value { | 2490 | pub fn numberMin(lhs: Value, rhs: Value, mod: *Module) Value { |
| 3718 | if (lhs.isUndef() or rhs.isUndef()) return undef; | 2491 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return undef; |
| 3719 | if (lhs.isNan()) return rhs; | 2492 | if (lhs.isNan(mod)) return rhs; |
| 3720 | if (rhs.isNan()) return lhs; | 2493 | if (rhs.isNan(mod)) return lhs; |
| 3721 | 2494 | ||
| 3722 | return switch (order(lhs, rhs, target)) { | 2495 | return switch (order(lhs, rhs, mod)) { |
| 3723 | .lt => lhs, | 2496 | .lt => lhs, |
| 3724 | .gt, .eq => rhs, | 2497 | .gt, .eq => rhs, |
| 3725 | }; | 2498 | }; |
| ... | @@ -3727,24 +2500,27 @@ pub const Value = extern union { | ... | @@ -3727,24 +2500,27 @@ pub const Value = extern union { |
| 3727 | 2500 | ||
| 3728 | /// operands must be (vectors of) integers; handles undefined scalars. | 2501 | /// operands must be (vectors of) integers; handles undefined scalars. |
| 3729 | pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value { | 2502 | pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3730 | const target = mod.getTarget(); | 2503 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3731 | if (ty.zigTypeTag() == .Vector) { | 2504 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3732 | const result_data = try arena.alloc(Value, ty.vectorLen()); | 2505 | const scalar_ty = ty.scalarType(mod); |
| 3733 | for (result_data, 0..) |*scalar, i| { | 2506 | for (result_data, 0..) |*scalar, i| { |
| 3734 | var buf: Value.ElemValueBuffer = undefined; | 2507 | const elem_val = try val.elemValue(mod, i); |
| 3735 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 2508 | scalar.* = try (try bitwiseNotScalar(elem_val, scalar_ty, arena, mod)).intern(scalar_ty, mod); |
| 3736 | scalar.* = try bitwiseNotScalar(elem_val, ty.scalarType(), arena, target); | ||
| 3737 | } | 2509 | } |
| 3738 | return Value.Tag.aggregate.create(arena, result_data); | 2510 | return (try mod.intern(.{ .aggregate = .{ |
| 2511 | .ty = ty.toIntern(), | ||
| 2512 | .storage = .{ .elems = result_data }, | ||
| 2513 | } })).toValue(); | ||
| 3739 | } | 2514 | } |
| 3740 | return bitwiseNotScalar(val, ty, arena, target); | 2515 | return bitwiseNotScalar(val, ty, arena, mod); |
| 3741 | } | 2516 | } |
| 3742 | 2517 | ||
| 3743 | /// operands must be integers; handles undefined. | 2518 | /// operands must be integers; handles undefined. |
| 3744 | pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, target: Target) !Value { | 2519 | pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3745 | if (val.isUndef()) return Value.initTag(.undef); | 2520 | if (val.isUndef(mod)) return (try mod.intern(.{ .undef = ty.toIntern() })).toValue(); |
| 2521 | if (ty.toIntern() == .bool_type) return makeBool(!val.toBool()); | ||
| 3746 | 2522 | ||
| 3747 | const info = ty.intInfo(target); | 2523 | const info = ty.intInfo(mod); |
| 3748 | 2524 | ||
| 3749 | if (info.bits == 0) { | 2525 | if (info.bits == 0) { |
| 3750 | return val; | 2526 | return val; |
| ... | @@ -3753,7 +2529,7 @@ pub const Value = extern union { | ... | @@ -3753,7 +2529,7 @@ pub const Value = extern union { |
| 3753 | // TODO is this a performance issue? maybe we should try the operation without | 2529 | // TODO is this a performance issue? maybe we should try the operation without |
| 3754 | // resorting to BigInt first. | 2530 | // resorting to BigInt first. |
| 3755 | var val_space: Value.BigIntSpace = undefined; | 2531 | var val_space: Value.BigIntSpace = undefined; |
| 3756 | const val_bigint = val.toBigInt(&val_space, target); | 2532 | const val_bigint = val.toBigInt(&val_space, mod); |
| 3757 | const limbs = try arena.alloc( | 2533 | const limbs = try arena.alloc( |
| 3758 | std.math.big.Limb, | 2534 | std.math.big.Limb, |
| 3759 | std.math.big.int.calcTwosCompLimbCount(info.bits), | 2535 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| ... | @@ -3761,36 +2537,38 @@ pub const Value = extern union { | ... | @@ -3761,36 +2537,38 @@ pub const Value = extern union { |
| 3761 | 2537 | ||
| 3762 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 2538 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3763 | result_bigint.bitNotWrap(val_bigint, info.signedness, info.bits); | 2539 | result_bigint.bitNotWrap(val_bigint, info.signedness, info.bits); |
| 3764 | return fromBigInt(arena, result_bigint.toConst()); | 2540 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 3765 | } | 2541 | } |
| 3766 | 2542 | ||
| 3767 | /// operands must be (vectors of) integers; handles undefined scalars. | 2543 | /// operands must be (vectors of) integers; handles undefined scalars. |
| 3768 | pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 2544 | pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3769 | const target = mod.getTarget(); | 2545 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3770 | if (ty.zigTypeTag() == .Vector) { | 2546 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3771 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 2547 | const scalar_ty = ty.scalarType(mod); |
| 3772 | for (result_data, 0..) |*scalar, i| { | 2548 | for (result_data, 0..) |*scalar, i| { |
| 3773 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2549 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3774 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2550 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3775 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2551 | scalar.* = try (try bitwiseAndScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); |
| 3776 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 3777 | scalar.* = try bitwiseAndScalar(lhs_elem, rhs_elem, allocator, target); | ||
| 3778 | } | 2552 | } |
| 3779 | return Value.Tag.aggregate.create(allocator, result_data); | 2553 | return (try mod.intern(.{ .aggregate = .{ |
| 2554 | .ty = ty.toIntern(), | ||
| 2555 | .storage = .{ .elems = result_data }, | ||
| 2556 | } })).toValue(); | ||
| 3780 | } | 2557 | } |
| 3781 | return bitwiseAndScalar(lhs, rhs, allocator, target); | 2558 | return bitwiseAndScalar(lhs, rhs, ty, allocator, mod); |
| 3782 | } | 2559 | } |
| 3783 | 2560 | ||
| 3784 | /// operands must be integers; handles undefined. | 2561 | /// operands must be integers; handles undefined. |
| 3785 | pub fn bitwiseAndScalar(lhs: Value, rhs: Value, arena: Allocator, target: Target) !Value { | 2562 | pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3786 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | 2563 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return (try mod.intern(.{ .undef = ty.toIntern() })).toValue(); |
| 2564 | if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() and rhs.toBool()); | ||
| 3787 | 2565 | ||
| 3788 | // TODO is this a performance issue? maybe we should try the operation without | 2566 | // TODO is this a performance issue? maybe we should try the operation without |
| 3789 | // resorting to BigInt first. | 2567 | // resorting to BigInt first. |
| 3790 | var lhs_space: Value.BigIntSpace = undefined; | 2568 | var lhs_space: Value.BigIntSpace = undefined; |
| 3791 | var rhs_space: Value.BigIntSpace = undefined; | 2569 | var rhs_space: Value.BigIntSpace = undefined; |
| 3792 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 2570 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 3793 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 2571 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 3794 | const limbs = try arena.alloc( | 2572 | const limbs = try arena.alloc( |
| 3795 | std.math.big.Limb, | 2573 | std.math.big.Limb, |
| 3796 | // + 1 for negatives | 2574 | // + 1 for negatives |
| ... | @@ -3798,102 +2576,104 @@ pub const Value = extern union { | ... | @@ -3798,102 +2576,104 @@ pub const Value = extern union { |
| 3798 | ); | 2576 | ); |
| 3799 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 2577 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3800 | result_bigint.bitAnd(lhs_bigint, rhs_bigint); | 2578 | result_bigint.bitAnd(lhs_bigint, rhs_bigint); |
| 3801 | return fromBigInt(arena, result_bigint.toConst()); | 2579 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 3802 | } | 2580 | } |
| 3803 | 2581 | ||
| 3804 | /// operands must be (vectors of) integers; handles undefined scalars. | 2582 | /// operands must be (vectors of) integers; handles undefined scalars. |
| 3805 | pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { | 2583 | pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3806 | if (ty.zigTypeTag() == .Vector) { | 2584 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3807 | const result_data = try arena.alloc(Value, ty.vectorLen()); | 2585 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 2586 | const scalar_ty = ty.scalarType(mod); | ||
| 3808 | for (result_data, 0..) |*scalar, i| { | 2587 | for (result_data, 0..) |*scalar, i| { |
| 3809 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2588 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3810 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2589 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3811 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2590 | scalar.* = try (try bitwiseNandScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); |
| 3812 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 3813 | scalar.* = try bitwiseNandScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, mod); | ||
| 3814 | } | 2591 | } |
| 3815 | return Value.Tag.aggregate.create(arena, result_data); | 2592 | return (try mod.intern(.{ .aggregate = .{ |
| 2593 | .ty = ty.toIntern(), | ||
| 2594 | .storage = .{ .elems = result_data }, | ||
| 2595 | } })).toValue(); | ||
| 3816 | } | 2596 | } |
| 3817 | return bitwiseNandScalar(lhs, rhs, ty, arena, mod); | 2597 | return bitwiseNandScalar(lhs, rhs, ty, arena, mod); |
| 3818 | } | 2598 | } |
| 3819 | 2599 | ||
| 3820 | /// operands must be integers; handles undefined. | 2600 | /// operands must be integers; handles undefined. |
| 3821 | pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { | 2601 | pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3822 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | 2602 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return (try mod.intern(.{ .undef = ty.toIntern() })).toValue(); |
| 2603 | if (ty.toIntern() == .bool_type) return makeBool(!(lhs.toBool() and rhs.toBool())); | ||
| 3823 | 2604 | ||
| 3824 | const anded = try bitwiseAnd(lhs, rhs, ty, arena, mod); | 2605 | const anded = try bitwiseAnd(lhs, rhs, ty, arena, mod); |
| 3825 | 2606 | const all_ones = if (ty.isSignedInt(mod)) try mod.intValue(ty, -1) else try ty.maxIntScalar(mod, ty); | |
| 3826 | const all_ones = if (ty.isSignedInt()) | ||
| 3827 | try Value.Tag.int_i64.create(arena, -1) | ||
| 3828 | else | ||
| 3829 | try ty.maxInt(arena, mod.getTarget()); | ||
| 3830 | |||
| 3831 | return bitwiseXor(anded, all_ones, ty, arena, mod); | 2607 | return bitwiseXor(anded, all_ones, ty, arena, mod); |
| 3832 | } | 2608 | } |
| 3833 | 2609 | ||
| 3834 | /// operands must be (vectors of) integers; handles undefined scalars. | 2610 | /// operands must be (vectors of) integers; handles undefined scalars. |
| 3835 | pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 2611 | pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3836 | const target = mod.getTarget(); | 2612 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3837 | if (ty.zigTypeTag() == .Vector) { | 2613 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3838 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 2614 | const scalar_ty = ty.scalarType(mod); |
| 3839 | for (result_data, 0..) |*scalar, i| { | 2615 | for (result_data, 0..) |*scalar, i| { |
| 3840 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2616 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3841 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2617 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3842 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2618 | scalar.* = try (try bitwiseOrScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); |
| 3843 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 3844 | scalar.* = try bitwiseOrScalar(lhs_elem, rhs_elem, allocator, target); | ||
| 3845 | } | 2619 | } |
| 3846 | return Value.Tag.aggregate.create(allocator, result_data); | 2620 | return (try mod.intern(.{ .aggregate = .{ |
| 2621 | .ty = ty.toIntern(), | ||
| 2622 | .storage = .{ .elems = result_data }, | ||
| 2623 | } })).toValue(); | ||
| 3847 | } | 2624 | } |
| 3848 | return bitwiseOrScalar(lhs, rhs, allocator, target); | 2625 | return bitwiseOrScalar(lhs, rhs, ty, allocator, mod); |
| 3849 | } | 2626 | } |
| 3850 | 2627 | ||
| 3851 | /// operands must be integers; handles undefined. | 2628 | /// operands must be integers; handles undefined. |
| 3852 | pub fn bitwiseOrScalar(lhs: Value, rhs: Value, arena: Allocator, target: Target) !Value { | 2629 | pub fn bitwiseOrScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3853 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | 2630 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return (try mod.intern(.{ .undef = ty.toIntern() })).toValue(); |
| 2631 | if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() or rhs.toBool()); | ||
| 3854 | 2632 | ||
| 3855 | // TODO is this a performance issue? maybe we should try the operation without | 2633 | // TODO is this a performance issue? maybe we should try the operation without |
| 3856 | // resorting to BigInt first. | 2634 | // resorting to BigInt first. |
| 3857 | var lhs_space: Value.BigIntSpace = undefined; | 2635 | var lhs_space: Value.BigIntSpace = undefined; |
| 3858 | var rhs_space: Value.BigIntSpace = undefined; | 2636 | var rhs_space: Value.BigIntSpace = undefined; |
| 3859 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 2637 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 3860 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 2638 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 3861 | const limbs = try arena.alloc( | 2639 | const limbs = try arena.alloc( |
| 3862 | std.math.big.Limb, | 2640 | std.math.big.Limb, |
| 3863 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len), | 2641 | std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len), |
| 3864 | ); | 2642 | ); |
| 3865 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 2643 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3866 | result_bigint.bitOr(lhs_bigint, rhs_bigint); | 2644 | result_bigint.bitOr(lhs_bigint, rhs_bigint); |
| 3867 | return fromBigInt(arena, result_bigint.toConst()); | 2645 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 3868 | } | 2646 | } |
| 3869 | 2647 | ||
| 3870 | /// operands must be (vectors of) integers; handles undefined scalars. | 2648 | /// operands must be (vectors of) integers; handles undefined scalars. |
| 3871 | pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 2649 | pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3872 | const target = mod.getTarget(); | 2650 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3873 | if (ty.zigTypeTag() == .Vector) { | 2651 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3874 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 2652 | const scalar_ty = ty.scalarType(mod); |
| 3875 | for (result_data, 0..) |*scalar, i| { | 2653 | for (result_data, 0..) |*scalar, i| { |
| 3876 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2654 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3877 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2655 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3878 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2656 | scalar.* = try (try bitwiseXorScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); |
| 3879 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 3880 | scalar.* = try bitwiseXorScalar(lhs_elem, rhs_elem, allocator, target); | ||
| 3881 | } | 2657 | } |
| 3882 | return Value.Tag.aggregate.create(allocator, result_data); | 2658 | return (try mod.intern(.{ .aggregate = .{ |
| 2659 | .ty = ty.toIntern(), | ||
| 2660 | .storage = .{ .elems = result_data }, | ||
| 2661 | } })).toValue(); | ||
| 3883 | } | 2662 | } |
| 3884 | return bitwiseXorScalar(lhs, rhs, allocator, target); | 2663 | return bitwiseXorScalar(lhs, rhs, ty, allocator, mod); |
| 3885 | } | 2664 | } |
| 3886 | 2665 | ||
| 3887 | /// operands must be integers; handles undefined. | 2666 | /// operands must be integers; handles undefined. |
| 3888 | pub fn bitwiseXorScalar(lhs: Value, rhs: Value, arena: Allocator, target: Target) !Value { | 2667 | pub fn bitwiseXorScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 3889 | if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); | 2668 | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return (try mod.intern(.{ .undef = ty.toIntern() })).toValue(); |
| 2669 | if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() != rhs.toBool()); | ||
| 3890 | 2670 | ||
| 3891 | // TODO is this a performance issue? maybe we should try the operation without | 2671 | // TODO is this a performance issue? maybe we should try the operation without |
| 3892 | // resorting to BigInt first. | 2672 | // resorting to BigInt first. |
| 3893 | var lhs_space: Value.BigIntSpace = undefined; | 2673 | var lhs_space: Value.BigIntSpace = undefined; |
| 3894 | var rhs_space: Value.BigIntSpace = undefined; | 2674 | var rhs_space: Value.BigIntSpace = undefined; |
| 3895 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 2675 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 3896 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 2676 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 3897 | const limbs = try arena.alloc( | 2677 | const limbs = try arena.alloc( |
| 3898 | std.math.big.Limb, | 2678 | std.math.big.Limb, |
| 3899 | // + 1 for negatives | 2679 | // + 1 for negatives |
| ... | @@ -3901,32 +2681,61 @@ pub const Value = extern union { | ... | @@ -3901,32 +2681,61 @@ pub const Value = extern union { |
| 3901 | ); | 2681 | ); |
| 3902 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 2682 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 3903 | result_bigint.bitXor(lhs_bigint, rhs_bigint); | 2683 | result_bigint.bitXor(lhs_bigint, rhs_bigint); |
| 3904 | return fromBigInt(arena, result_bigint.toConst()); | 2684 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 2685 | } | ||
| 2686 | |||
| 2687 | /// If the value overflowed the type, returns a comptime_int (or vector thereof) instead, setting | ||
| 2688 | /// overflow_idx to the vector index the overflow was at (or 0 for a scalar). | ||
| 2689 | pub fn intDiv(lhs: Value, rhs: Value, ty: Type, overflow_idx: *?usize, allocator: Allocator, mod: *Module) !Value { | ||
| 2690 | var overflow: usize = undefined; | ||
| 2691 | return intDivInner(lhs, rhs, ty, &overflow, allocator, mod) catch |err| switch (err) { | ||
| 2692 | error.Overflow => { | ||
| 2693 | const is_vec = ty.isVector(mod); | ||
| 2694 | overflow_idx.* = if (is_vec) overflow else 0; | ||
| 2695 | const safe_ty = if (is_vec) try mod.vectorType(.{ | ||
| 2696 | .len = ty.vectorLen(mod), | ||
| 2697 | .child = .comptime_int_type, | ||
| 2698 | }) else Type.comptime_int; | ||
| 2699 | return intDivInner(lhs, rhs, safe_ty, undefined, allocator, mod) catch |err1| switch (err1) { | ||
| 2700 | error.Overflow => unreachable, | ||
| 2701 | else => |e| return e, | ||
| 2702 | }; | ||
| 2703 | }, | ||
| 2704 | else => |e| return e, | ||
| 2705 | }; | ||
| 3905 | } | 2706 | } |
| 3906 | 2707 | ||
| 3907 | pub fn intDiv(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 2708 | fn intDivInner(lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize, allocator: Allocator, mod: *Module) !Value { |
| 3908 | const target = mod.getTarget(); | 2709 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3909 | if (ty.zigTypeTag() == .Vector) { | 2710 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3910 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 2711 | const scalar_ty = ty.scalarType(mod); |
| 3911 | for (result_data, 0..) |*scalar, i| { | 2712 | for (result_data, 0..) |*scalar, i| { |
| 3912 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2713 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3913 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2714 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3914 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2715 | const val = intDivScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod) catch |err| switch (err) { |
| 3915 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | 2716 | error.Overflow => { |
| 3916 | scalar.* = try intDivScalar(lhs_elem, rhs_elem, allocator, target); | 2717 | overflow_idx.* = i; |
| 2718 | return error.Overflow; | ||
| 2719 | }, | ||
| 2720 | else => |e| return e, | ||
| 2721 | }; | ||
| 2722 | scalar.* = try val.intern(scalar_ty, mod); | ||
| 3917 | } | 2723 | } |
| 3918 | return Value.Tag.aggregate.create(allocator, result_data); | 2724 | return (try mod.intern(.{ .aggregate = .{ |
| 2725 | .ty = ty.toIntern(), | ||
| 2726 | .storage = .{ .elems = result_data }, | ||
| 2727 | } })).toValue(); | ||
| 3919 | } | 2728 | } |
| 3920 | return intDivScalar(lhs, rhs, allocator, target); | 2729 | return intDivScalar(lhs, rhs, ty, allocator, mod); |
| 3921 | } | 2730 | } |
| 3922 | 2731 | ||
| 3923 | pub fn intDivScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { | 2732 | pub fn intDivScalar(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3924 | // TODO is this a performance issue? maybe we should try the operation without | 2733 | // TODO is this a performance issue? maybe we should try the operation without |
| 3925 | // resorting to BigInt first. | 2734 | // resorting to BigInt first. |
| 3926 | var lhs_space: Value.BigIntSpace = undefined; | 2735 | var lhs_space: Value.BigIntSpace = undefined; |
| 3927 | var rhs_space: Value.BigIntSpace = undefined; | 2736 | var rhs_space: Value.BigIntSpace = undefined; |
| 3928 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 2737 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 3929 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 2738 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 3930 | const limbs_q = try allocator.alloc( | 2739 | const limbs_q = try allocator.alloc( |
| 3931 | std.math.big.Limb, | 2740 | std.math.big.Limb, |
| 3932 | lhs_bigint.limbs.len, | 2741 | lhs_bigint.limbs.len, |
| ... | @@ -3942,32 +2751,39 @@ pub const Value = extern union { | ... | @@ -3942,32 +2751,39 @@ pub const Value = extern union { |
| 3942 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; | 2751 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; |
| 3943 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; | 2752 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; |
| 3944 | result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); | 2753 | result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); |
| 3945 | return fromBigInt(allocator, result_q.toConst()); | 2754 | if (ty.toIntern() != .comptime_int_type) { |
| 2755 | const info = ty.intInfo(mod); | ||
| 2756 | if (!result_q.toConst().fitsInTwosComp(info.signedness, info.bits)) { | ||
| 2757 | return error.Overflow; | ||
| 2758 | } | ||
| 2759 | } | ||
| 2760 | return mod.intValue_big(ty, result_q.toConst()); | ||
| 3946 | } | 2761 | } |
| 3947 | 2762 | ||
| 3948 | pub fn intDivFloor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 2763 | pub fn intDivFloor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3949 | const target = mod.getTarget(); | 2764 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3950 | if (ty.zigTypeTag() == .Vector) { | 2765 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3951 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 2766 | const scalar_ty = ty.scalarType(mod); |
| 3952 | for (result_data, 0..) |*scalar, i| { | 2767 | for (result_data, 0..) |*scalar, i| { |
| 3953 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2768 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3954 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2769 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3955 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2770 | scalar.* = try (try intDivFloorScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); |
| 3956 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 3957 | scalar.* = try intDivFloorScalar(lhs_elem, rhs_elem, allocator, target); | ||
| 3958 | } | 2771 | } |
| 3959 | return Value.Tag.aggregate.create(allocator, result_data); | 2772 | return (try mod.intern(.{ .aggregate = .{ |
| 2773 | .ty = ty.toIntern(), | ||
| 2774 | .storage = .{ .elems = result_data }, | ||
| 2775 | } })).toValue(); | ||
| 3960 | } | 2776 | } |
| 3961 | return intDivFloorScalar(lhs, rhs, allocator, target); | 2777 | return intDivFloorScalar(lhs, rhs, ty, allocator, mod); |
| 3962 | } | 2778 | } |
| 3963 | 2779 | ||
| 3964 | pub fn intDivFloorScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { | 2780 | pub fn intDivFloorScalar(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3965 | // TODO is this a performance issue? maybe we should try the operation without | 2781 | // TODO is this a performance issue? maybe we should try the operation without |
| 3966 | // resorting to BigInt first. | 2782 | // resorting to BigInt first. |
| 3967 | var lhs_space: Value.BigIntSpace = undefined; | 2783 | var lhs_space: Value.BigIntSpace = undefined; |
| 3968 | var rhs_space: Value.BigIntSpace = undefined; | 2784 | var rhs_space: Value.BigIntSpace = undefined; |
| 3969 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 2785 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 3970 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 2786 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 3971 | const limbs_q = try allocator.alloc( | 2787 | const limbs_q = try allocator.alloc( |
| 3972 | std.math.big.Limb, | 2788 | std.math.big.Limb, |
| 3973 | lhs_bigint.limbs.len, | 2789 | lhs_bigint.limbs.len, |
| ... | @@ -3983,32 +2799,33 @@ pub const Value = extern union { | ... | @@ -3983,32 +2799,33 @@ pub const Value = extern union { |
| 3983 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; | 2799 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; |
| 3984 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; | 2800 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; |
| 3985 | result_q.divFloor(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); | 2801 | result_q.divFloor(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); |
| 3986 | return fromBigInt(allocator, result_q.toConst()); | 2802 | return mod.intValue_big(ty, result_q.toConst()); |
| 3987 | } | 2803 | } |
| 3988 | 2804 | ||
| 3989 | pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 2805 | pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 3990 | const target = mod.getTarget(); | 2806 | if (ty.zigTypeTag(mod) == .Vector) { |
| 3991 | if (ty.zigTypeTag() == .Vector) { | 2807 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3992 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 2808 | const scalar_ty = ty.scalarType(mod); |
| 3993 | for (result_data, 0..) |*scalar, i| { | 2809 | for (result_data, 0..) |*scalar, i| { |
| 3994 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2810 | const lhs_elem = try lhs.elemValue(mod, i); |
| 3995 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2811 | const rhs_elem = try rhs.elemValue(mod, i); |
| 3996 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2812 | scalar.* = try (try intModScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); |
| 3997 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 3998 | scalar.* = try intModScalar(lhs_elem, rhs_elem, allocator, target); | ||
| 3999 | } | 2813 | } |
| 4000 | return Value.Tag.aggregate.create(allocator, result_data); | 2814 | return (try mod.intern(.{ .aggregate = .{ |
| 2815 | .ty = ty.toIntern(), | ||
| 2816 | .storage = .{ .elems = result_data }, | ||
| 2817 | } })).toValue(); | ||
| 4001 | } | 2818 | } |
| 4002 | return intModScalar(lhs, rhs, allocator, target); | 2819 | return intModScalar(lhs, rhs, ty, allocator, mod); |
| 4003 | } | 2820 | } |
| 4004 | 2821 | ||
| 4005 | pub fn intModScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { | 2822 | pub fn intModScalar(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 4006 | // TODO is this a performance issue? maybe we should try the operation without | 2823 | // TODO is this a performance issue? maybe we should try the operation without |
| 4007 | // resorting to BigInt first. | 2824 | // resorting to BigInt first. |
| 4008 | var lhs_space: Value.BigIntSpace = undefined; | 2825 | var lhs_space: Value.BigIntSpace = undefined; |
| 4009 | var rhs_space: Value.BigIntSpace = undefined; | 2826 | var rhs_space: Value.BigIntSpace = undefined; |
| 4010 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 2827 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 4011 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 2828 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 4012 | const limbs_q = try allocator.alloc( | 2829 | const limbs_q = try allocator.alloc( |
| 4013 | std.math.big.Limb, | 2830 | std.math.big.Limb, |
| 4014 | lhs_bigint.limbs.len, | 2831 | lhs_bigint.limbs.len, |
| ... | @@ -4024,161 +2841,164 @@ pub const Value = extern union { | ... | @@ -4024,161 +2841,164 @@ pub const Value = extern union { |
| 4024 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; | 2841 | var result_q = BigIntMutable{ .limbs = limbs_q, .positive = undefined, .len = undefined }; |
| 4025 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; | 2842 | var result_r = BigIntMutable{ .limbs = limbs_r, .positive = undefined, .len = undefined }; |
| 4026 | result_q.divFloor(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); | 2843 | result_q.divFloor(&result_r, lhs_bigint, rhs_bigint, limbs_buffer); |
| 4027 | return fromBigInt(allocator, result_r.toConst()); | 2844 | return mod.intValue_big(ty, result_r.toConst()); |
| 4028 | } | 2845 | } |
| 4029 | 2846 | ||
| 4030 | /// Returns true if the value is a floating point type and is NaN. Returns false otherwise. | 2847 | /// Returns true if the value is a floating point type and is NaN. Returns false otherwise. |
| 4031 | pub fn isNan(val: Value) bool { | 2848 | pub fn isNan(val: Value, mod: *const Module) bool { |
| 4032 | return switch (val.tag()) { | 2849 | if (val.ip_index == .none) return false; |
| 4033 | .float_16 => std.math.isNan(val.castTag(.float_16).?.data), | 2850 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 4034 | .float_32 => std.math.isNan(val.castTag(.float_32).?.data), | 2851 | .float => |float| switch (float.storage) { |
| 4035 | .float_64 => std.math.isNan(val.castTag(.float_64).?.data), | 2852 | inline else => |x| std.math.isNan(x), |
| 4036 | .float_80 => std.math.isNan(val.castTag(.float_80).?.data), | 2853 | }, |
| 4037 | .float_128 => std.math.isNan(val.castTag(.float_128).?.data), | ||
| 4038 | else => false, | 2854 | else => false, |
| 4039 | }; | 2855 | }; |
| 4040 | } | 2856 | } |
| 4041 | 2857 | ||
| 4042 | /// Returns true if the value is a floating point type and is infinite. Returns false otherwise. | 2858 | /// Returns true if the value is a floating point type and is infinite. Returns false otherwise. |
| 4043 | pub fn isInf(val: Value) bool { | 2859 | pub fn isInf(val: Value, mod: *const Module) bool { |
| 4044 | return switch (val.tag()) { | 2860 | if (val.ip_index == .none) return false; |
| 4045 | .float_16 => std.math.isInf(val.castTag(.float_16).?.data), | 2861 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 4046 | .float_32 => std.math.isInf(val.castTag(.float_32).?.data), | 2862 | .float => |float| switch (float.storage) { |
| 4047 | .float_64 => std.math.isInf(val.castTag(.float_64).?.data), | 2863 | inline else => |x| std.math.isInf(x), |
| 4048 | .float_80 => std.math.isInf(val.castTag(.float_80).?.data), | 2864 | }, |
| 4049 | .float_128 => std.math.isInf(val.castTag(.float_128).?.data), | ||
| 4050 | else => false, | 2865 | else => false, |
| 4051 | }; | 2866 | }; |
| 4052 | } | 2867 | } |
| 4053 | 2868 | ||
| 4054 | pub fn isNegativeInf(val: Value) bool { | 2869 | pub fn isNegativeInf(val: Value, mod: *const Module) bool { |
| 4055 | return switch (val.tag()) { | 2870 | if (val.ip_index == .none) return false; |
| 4056 | .float_16 => std.math.isNegativeInf(val.castTag(.float_16).?.data), | 2871 | return switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 4057 | .float_32 => std.math.isNegativeInf(val.castTag(.float_32).?.data), | 2872 | .float => |float| switch (float.storage) { |
| 4058 | .float_64 => std.math.isNegativeInf(val.castTag(.float_64).?.data), | 2873 | inline else => |x| std.math.isNegativeInf(x), |
| 4059 | .float_80 => std.math.isNegativeInf(val.castTag(.float_80).?.data), | 2874 | }, |
| 4060 | .float_128 => std.math.isNegativeInf(val.castTag(.float_128).?.data), | ||
| 4061 | else => false, | 2875 | else => false, |
| 4062 | }; | 2876 | }; |
| 4063 | } | 2877 | } |
| 4064 | 2878 | ||
| 4065 | pub fn floatRem(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 2879 | pub fn floatRem(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4066 | const target = mod.getTarget(); | 2880 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4067 | if (float_type.zigTypeTag() == .Vector) { | 2881 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4068 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 2882 | const scalar_ty = float_type.scalarType(mod); |
| 4069 | for (result_data, 0..) |*scalar, i| { | 2883 | for (result_data, 0..) |*scalar, i| { |
| 4070 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2884 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4071 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2885 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4072 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2886 | scalar.* = try (try floatRemScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4073 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 4074 | scalar.* = try floatRemScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | ||
| 4075 | } | 2887 | } |
| 4076 | return Value.Tag.aggregate.create(arena, result_data); | 2888 | return (try mod.intern(.{ .aggregate = .{ |
| 2889 | .ty = float_type.toIntern(), | ||
| 2890 | .storage = .{ .elems = result_data }, | ||
| 2891 | } })).toValue(); | ||
| 4077 | } | 2892 | } |
| 4078 | return floatRemScalar(lhs, rhs, float_type, arena, target); | 2893 | return floatRemScalar(lhs, rhs, float_type, mod); |
| 4079 | } | 2894 | } |
| 4080 | 2895 | ||
| 4081 | pub fn floatRemScalar(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value { | 2896 | pub fn floatRemScalar(lhs: Value, rhs: Value, float_type: Type, mod: *Module) !Value { |
| 4082 | switch (float_type.floatBits(target)) { | 2897 | const target = mod.getTarget(); |
| 4083 | 16 => { | 2898 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4084 | const lhs_val = lhs.toFloat(f16); | 2899 | 16 => .{ .f16 = @rem(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, |
| 4085 | const rhs_val = rhs.toFloat(f16); | 2900 | 32 => .{ .f32 = @rem(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, |
| 4086 | return Value.Tag.float_16.create(arena, @rem(lhs_val, rhs_val)); | 2901 | 64 => .{ .f64 = @rem(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, |
| 4087 | }, | 2902 | 80 => .{ .f80 = @rem(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, |
| 4088 | 32 => { | 2903 | 128 => .{ .f128 = @rem(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, |
| 4089 | const lhs_val = lhs.toFloat(f32); | ||
| 4090 | const rhs_val = rhs.toFloat(f32); | ||
| 4091 | return Value.Tag.float_32.create(arena, @rem(lhs_val, rhs_val)); | ||
| 4092 | }, | ||
| 4093 | 64 => { | ||
| 4094 | const lhs_val = lhs.toFloat(f64); | ||
| 4095 | const rhs_val = rhs.toFloat(f64); | ||
| 4096 | return Value.Tag.float_64.create(arena, @rem(lhs_val, rhs_val)); | ||
| 4097 | }, | ||
| 4098 | 80 => { | ||
| 4099 | const lhs_val = lhs.toFloat(f80); | ||
| 4100 | const rhs_val = rhs.toFloat(f80); | ||
| 4101 | return Value.Tag.float_80.create(arena, @rem(lhs_val, rhs_val)); | ||
| 4102 | }, | ||
| 4103 | 128 => { | ||
| 4104 | const lhs_val = lhs.toFloat(f128); | ||
| 4105 | const rhs_val = rhs.toFloat(f128); | ||
| 4106 | return Value.Tag.float_128.create(arena, @rem(lhs_val, rhs_val)); | ||
| 4107 | }, | ||
| 4108 | else => unreachable, | 2904 | else => unreachable, |
| 4109 | } | 2905 | }; |
| 2906 | return (try mod.intern(.{ .float = .{ | ||
| 2907 | .ty = float_type.toIntern(), | ||
| 2908 | .storage = storage, | ||
| 2909 | } })).toValue(); | ||
| 4110 | } | 2910 | } |
| 4111 | 2911 | ||
| 4112 | pub fn floatMod(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 2912 | pub fn floatMod(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4113 | const target = mod.getTarget(); | 2913 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4114 | if (float_type.zigTypeTag() == .Vector) { | 2914 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4115 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 2915 | const scalar_ty = float_type.scalarType(mod); |
| 4116 | for (result_data, 0..) |*scalar, i| { | 2916 | for (result_data, 0..) |*scalar, i| { |
| 4117 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2917 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4118 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2918 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4119 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2919 | scalar.* = try (try floatModScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4120 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 4121 | scalar.* = try floatModScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | ||
| 4122 | } | 2920 | } |
| 4123 | return Value.Tag.aggregate.create(arena, result_data); | 2921 | return (try mod.intern(.{ .aggregate = .{ |
| 2922 | .ty = float_type.toIntern(), | ||
| 2923 | .storage = .{ .elems = result_data }, | ||
| 2924 | } })).toValue(); | ||
| 4124 | } | 2925 | } |
| 4125 | return floatModScalar(lhs, rhs, float_type, arena, target); | 2926 | return floatModScalar(lhs, rhs, float_type, mod); |
| 4126 | } | 2927 | } |
| 4127 | 2928 | ||
| 4128 | pub fn floatModScalar(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value { | 2929 | pub fn floatModScalar(lhs: Value, rhs: Value, float_type: Type, mod: *Module) !Value { |
| 4129 | switch (float_type.floatBits(target)) { | 2930 | const target = mod.getTarget(); |
| 4130 | 16 => { | 2931 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4131 | const lhs_val = lhs.toFloat(f16); | 2932 | 16 => .{ .f16 = @mod(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, |
| 4132 | const rhs_val = rhs.toFloat(f16); | 2933 | 32 => .{ .f32 = @mod(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, |
| 4133 | return Value.Tag.float_16.create(arena, @mod(lhs_val, rhs_val)); | 2934 | 64 => .{ .f64 = @mod(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, |
| 4134 | }, | 2935 | 80 => .{ .f80 = @mod(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, |
| 4135 | 32 => { | 2936 | 128 => .{ .f128 = @mod(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, |
| 4136 | const lhs_val = lhs.toFloat(f32); | ||
| 4137 | const rhs_val = rhs.toFloat(f32); | ||
| 4138 | return Value.Tag.float_32.create(arena, @mod(lhs_val, rhs_val)); | ||
| 4139 | }, | ||
| 4140 | 64 => { | ||
| 4141 | const lhs_val = lhs.toFloat(f64); | ||
| 4142 | const rhs_val = rhs.toFloat(f64); | ||
| 4143 | return Value.Tag.float_64.create(arena, @mod(lhs_val, rhs_val)); | ||
| 4144 | }, | ||
| 4145 | 80 => { | ||
| 4146 | const lhs_val = lhs.toFloat(f80); | ||
| 4147 | const rhs_val = rhs.toFloat(f80); | ||
| 4148 | return Value.Tag.float_80.create(arena, @mod(lhs_val, rhs_val)); | ||
| 4149 | }, | ||
| 4150 | 128 => { | ||
| 4151 | const lhs_val = lhs.toFloat(f128); | ||
| 4152 | const rhs_val = rhs.toFloat(f128); | ||
| 4153 | return Value.Tag.float_128.create(arena, @mod(lhs_val, rhs_val)); | ||
| 4154 | }, | ||
| 4155 | else => unreachable, | 2937 | else => unreachable, |
| 4156 | } | 2938 | }; |
| 2939 | return (try mod.intern(.{ .float = .{ | ||
| 2940 | .ty = float_type.toIntern(), | ||
| 2941 | .storage = storage, | ||
| 2942 | } })).toValue(); | ||
| 2943 | } | ||
| 2944 | |||
| 2945 | /// If the value overflowed the type, returns a comptime_int (or vector thereof) instead, setting | ||
| 2946 | /// overflow_idx to the vector index the overflow was at (or 0 for a scalar). | ||
| 2947 | pub fn intMul(lhs: Value, rhs: Value, ty: Type, overflow_idx: *?usize, allocator: Allocator, mod: *Module) !Value { | ||
| 2948 | var overflow: usize = undefined; | ||
| 2949 | return intMulInner(lhs, rhs, ty, &overflow, allocator, mod) catch |err| switch (err) { | ||
| 2950 | error.Overflow => { | ||
| 2951 | const is_vec = ty.isVector(mod); | ||
| 2952 | overflow_idx.* = if (is_vec) overflow else 0; | ||
| 2953 | const safe_ty = if (is_vec) try mod.vectorType(.{ | ||
| 2954 | .len = ty.vectorLen(mod), | ||
| 2955 | .child = .comptime_int_type, | ||
| 2956 | }) else Type.comptime_int; | ||
| 2957 | return intMulInner(lhs, rhs, safe_ty, undefined, allocator, mod) catch |err1| switch (err1) { | ||
| 2958 | error.Overflow => unreachable, | ||
| 2959 | else => |e| return e, | ||
| 2960 | }; | ||
| 2961 | }, | ||
| 2962 | else => |e| return e, | ||
| 2963 | }; | ||
| 4157 | } | 2964 | } |
| 4158 | 2965 | ||
| 4159 | pub fn intMul(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 2966 | fn intMulInner(lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize, allocator: Allocator, mod: *Module) !Value { |
| 4160 | const target = mod.getTarget(); | 2967 | if (ty.zigTypeTag(mod) == .Vector) { |
| 4161 | if (ty.zigTypeTag() == .Vector) { | 2968 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 4162 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 2969 | const scalar_ty = ty.scalarType(mod); |
| 4163 | for (result_data, 0..) |*scalar, i| { | 2970 | for (result_data, 0..) |*scalar, i| { |
| 4164 | var lhs_buf: Value.ElemValueBuffer = undefined; | 2971 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4165 | var rhs_buf: Value.ElemValueBuffer = undefined; | 2972 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4166 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 2973 | const val = intMulScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod) catch |err| switch (err) { |
| 4167 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | 2974 | error.Overflow => { |
| 4168 | scalar.* = try intMulScalar(lhs_elem, rhs_elem, allocator, target); | 2975 | overflow_idx.* = i; |
| 2976 | return error.Overflow; | ||
| 2977 | }, | ||
| 2978 | else => |e| return e, | ||
| 2979 | }; | ||
| 2980 | scalar.* = try val.intern(scalar_ty, mod); | ||
| 4169 | } | 2981 | } |
| 4170 | return Value.Tag.aggregate.create(allocator, result_data); | 2982 | return (try mod.intern(.{ .aggregate = .{ |
| 2983 | .ty = ty.toIntern(), | ||
| 2984 | .storage = .{ .elems = result_data }, | ||
| 2985 | } })).toValue(); | ||
| 4171 | } | 2986 | } |
| 4172 | return intMulScalar(lhs, rhs, allocator, target); | 2987 | return intMulScalar(lhs, rhs, ty, allocator, mod); |
| 4173 | } | 2988 | } |
| 4174 | 2989 | ||
| 4175 | pub fn intMulScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { | 2990 | pub fn intMulScalar(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 2991 | if (ty.toIntern() != .comptime_int_type) { | ||
| 2992 | const res = try intMulWithOverflowScalar(lhs, rhs, ty, allocator, mod); | ||
| 2993 | if (res.overflow_bit.compareAllWithZero(.neq, mod)) return error.Overflow; | ||
| 2994 | return res.wrapped_result; | ||
| 2995 | } | ||
| 4176 | // TODO is this a performance issue? maybe we should try the operation without | 2996 | // TODO is this a performance issue? maybe we should try the operation without |
| 4177 | // resorting to BigInt first. | 2997 | // resorting to BigInt first. |
| 4178 | var lhs_space: Value.BigIntSpace = undefined; | 2998 | var lhs_space: Value.BigIntSpace = undefined; |
| 4179 | var rhs_space: Value.BigIntSpace = undefined; | 2999 | var rhs_space: Value.BigIntSpace = undefined; |
| 4180 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 3000 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 4181 | const rhs_bigint = rhs.toBigInt(&rhs_space, target); | 3001 | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 4182 | const limbs = try allocator.alloc( | 3002 | const limbs = try allocator.alloc( |
| 4183 | std.math.big.Limb, | 3003 | std.math.big.Limb, |
| 4184 | lhs_bigint.limbs.len + rhs_bigint.limbs.len, | 3004 | lhs_bigint.limbs.len + rhs_bigint.limbs.len, |
| ... | @@ -4190,21 +3010,23 @@ pub const Value = extern union { | ... | @@ -4190,21 +3010,23 @@ pub const Value = extern union { |
| 4190 | ); | 3010 | ); |
| 4191 | defer allocator.free(limbs_buffer); | 3011 | defer allocator.free(limbs_buffer); |
| 4192 | result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, allocator); | 3012 | result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, allocator); |
| 4193 | return fromBigInt(allocator, result_bigint.toConst()); | 3013 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 4194 | } | 3014 | } |
| 4195 | 3015 | ||
| 4196 | pub fn intTrunc(val: Value, ty: Type, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16, mod: *Module) !Value { | 3016 | pub fn intTrunc(val: Value, ty: Type, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16, mod: *Module) !Value { |
| 4197 | const target = mod.getTarget(); | 3017 | if (ty.zigTypeTag(mod) == .Vector) { |
| 4198 | if (ty.zigTypeTag() == .Vector) { | 3018 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 4199 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 3019 | const scalar_ty = ty.scalarType(mod); |
| 4200 | for (result_data, 0..) |*scalar, i| { | 3020 | for (result_data, 0..) |*scalar, i| { |
| 4201 | var buf: Value.ElemValueBuffer = undefined; | 3021 | const elem_val = try val.elemValue(mod, i); |
| 4202 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3022 | scalar.* = try (try intTruncScalar(elem_val, scalar_ty, allocator, signedness, bits, mod)).intern(scalar_ty, mod); |
| 4203 | scalar.* = try intTruncScalar(elem_val, allocator, signedness, bits, target); | ||
| 4204 | } | 3023 | } |
| 4205 | return Value.Tag.aggregate.create(allocator, result_data); | 3024 | return (try mod.intern(.{ .aggregate = .{ |
| 3025 | .ty = ty.toIntern(), | ||
| 3026 | .storage = .{ .elems = result_data }, | ||
| 3027 | } })).toValue(); | ||
| 4206 | } | 3028 | } |
| 4207 | return intTruncScalar(val, allocator, signedness, bits, target); | 3029 | return intTruncScalar(val, ty, allocator, signedness, bits, mod); |
| 4208 | } | 3030 | } |
| 4209 | 3031 | ||
| 4210 | /// This variant may vectorize on `bits`. Asserts that `bits` is a (vector of) `u16`. | 3032 | /// This variant may vectorize on `bits`. Asserts that `bits` is a (vector of) `u16`. |
| ... | @@ -4216,26 +3038,34 @@ pub const Value = extern union { | ... | @@ -4216,26 +3038,34 @@ pub const Value = extern union { |
| 4216 | bits: Value, | 3038 | bits: Value, |
| 4217 | mod: *Module, | 3039 | mod: *Module, |
| 4218 | ) !Value { | 3040 | ) !Value { |
| 4219 | const target = mod.getTarget(); | 3041 | if (ty.zigTypeTag(mod) == .Vector) { |
| 4220 | if (ty.zigTypeTag() == .Vector) { | 3042 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 4221 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 3043 | const scalar_ty = ty.scalarType(mod); |
| 4222 | for (result_data, 0..) |*scalar, i| { | 3044 | for (result_data, 0..) |*scalar, i| { |
| 4223 | var buf: Value.ElemValueBuffer = undefined; | 3045 | const elem_val = try val.elemValue(mod, i); |
| 4224 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3046 | const bits_elem = try bits.elemValue(mod, i); |
| 4225 | var bits_buf: Value.ElemValueBuffer = undefined; | 3047 | scalar.* = try (try intTruncScalar(elem_val, scalar_ty, allocator, signedness, @intCast(u16, bits_elem.toUnsignedInt(mod)), mod)).intern(scalar_ty, mod); |
| 4226 | const bits_elem = bits.elemValueBuffer(mod, i, &bits_buf); | ||
| 4227 | scalar.* = try intTruncScalar(elem_val, allocator, signedness, @intCast(u16, bits_elem.toUnsignedInt(target)), target); | ||
| 4228 | } | 3048 | } |
| 4229 | return Value.Tag.aggregate.create(allocator, result_data); | 3049 | return (try mod.intern(.{ .aggregate = .{ |
| 3050 | .ty = ty.toIntern(), | ||
| 3051 | .storage = .{ .elems = result_data }, | ||
| 3052 | } })).toValue(); | ||
| 4230 | } | 3053 | } |
| 4231 | return intTruncScalar(val, allocator, signedness, @intCast(u16, bits.toUnsignedInt(target)), target); | 3054 | return intTruncScalar(val, ty, allocator, signedness, @intCast(u16, bits.toUnsignedInt(mod)), mod); |
| 4232 | } | 3055 | } |
| 4233 | 3056 | ||
| 4234 | pub fn intTruncScalar(val: Value, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16, target: Target) !Value { | 3057 | pub fn intTruncScalar( |
| 4235 | if (bits == 0) return Value.zero; | 3058 | val: Value, |
| 3059 | ty: Type, | ||
| 3060 | allocator: Allocator, | ||
| 3061 | signedness: std.builtin.Signedness, | ||
| 3062 | bits: u16, | ||
| 3063 | mod: *Module, | ||
| 3064 | ) !Value { | ||
| 3065 | if (bits == 0) return mod.intValue(ty, 0); | ||
| 4236 | 3066 | ||
| 4237 | var val_space: Value.BigIntSpace = undefined; | 3067 | var val_space: Value.BigIntSpace = undefined; |
| 4238 | const val_bigint = val.toBigInt(&val_space, target); | 3068 | const val_bigint = val.toBigInt(&val_space, mod); |
| 4239 | 3069 | ||
| 4240 | const limbs = try allocator.alloc( | 3070 | const limbs = try allocator.alloc( |
| 4241 | std.math.big.Limb, | 3071 | std.math.big.Limb, |
| ... | @@ -4244,31 +3074,32 @@ pub const Value = extern union { | ... | @@ -4244,31 +3074,32 @@ pub const Value = extern union { |
| 4244 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; | 3074 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 4245 | 3075 | ||
| 4246 | result_bigint.truncate(val_bigint, signedness, bits); | 3076 | result_bigint.truncate(val_bigint, signedness, bits); |
| 4247 | return fromBigInt(allocator, result_bigint.toConst()); | 3077 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 4248 | } | 3078 | } |
| 4249 | 3079 | ||
| 4250 | pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 3080 | pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 4251 | const target = mod.getTarget(); | 3081 | if (ty.zigTypeTag(mod) == .Vector) { |
| 4252 | if (ty.zigTypeTag() == .Vector) { | 3082 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 4253 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 3083 | const scalar_ty = ty.scalarType(mod); |
| 4254 | for (result_data, 0..) |*scalar, i| { | 3084 | for (result_data, 0..) |*scalar, i| { |
| 4255 | var lhs_buf: Value.ElemValueBuffer = undefined; | 3085 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4256 | var rhs_buf: Value.ElemValueBuffer = undefined; | 3086 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4257 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 3087 | scalar.* = try (try shlScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); |
| 4258 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 4259 | scalar.* = try shlScalar(lhs_elem, rhs_elem, allocator, target); | ||
| 4260 | } | 3088 | } |
| 4261 | return Value.Tag.aggregate.create(allocator, result_data); | 3089 | return (try mod.intern(.{ .aggregate = .{ |
| 3090 | .ty = ty.toIntern(), | ||
| 3091 | .storage = .{ .elems = result_data }, | ||
| 3092 | } })).toValue(); | ||
| 4262 | } | 3093 | } |
| 4263 | return shlScalar(lhs, rhs, allocator, target); | 3094 | return shlScalar(lhs, rhs, ty, allocator, mod); |
| 4264 | } | 3095 | } |
| 4265 | 3096 | ||
| 4266 | pub fn shlScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { | 3097 | pub fn shlScalar(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 4267 | // TODO is this a performance issue? maybe we should try the operation without | 3098 | // TODO is this a performance issue? maybe we should try the operation without |
| 4268 | // resorting to BigInt first. | 3099 | // resorting to BigInt first. |
| 4269 | var lhs_space: Value.BigIntSpace = undefined; | 3100 | var lhs_space: Value.BigIntSpace = undefined; |
| 4270 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 3101 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 4271 | const shift = @intCast(usize, rhs.toUnsignedInt(target)); | 3102 | const shift = @intCast(usize, rhs.toUnsignedInt(mod)); |
| 4272 | const limbs = try allocator.alloc( | 3103 | const limbs = try allocator.alloc( |
| 4273 | std.math.big.Limb, | 3104 | std.math.big.Limb, |
| 4274 | lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1, | 3105 | lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1, |
| ... | @@ -4279,7 +3110,12 @@ pub const Value = extern union { | ... | @@ -4279,7 +3110,12 @@ pub const Value = extern union { |
| 4279 | .len = undefined, | 3110 | .len = undefined, |
| 4280 | }; | 3111 | }; |
| 4281 | result_bigint.shiftLeft(lhs_bigint, shift); | 3112 | result_bigint.shiftLeft(lhs_bigint, shift); |
| 4282 | return fromBigInt(allocator, result_bigint.toConst()); | 3113 | if (ty.toIntern() != .comptime_int_type) { |
| 3114 | const int_info = ty.intInfo(mod); | ||
| 3115 | result_bigint.truncate(result_bigint.toConst(), int_info.signedness, int_info.bits); | ||
| 3116 | } | ||
| 3117 | |||
| 3118 | return mod.intValue_big(ty, result_bigint.toConst()); | ||
| 4283 | } | 3119 | } |
| 4284 | 3120 | ||
| 4285 | pub fn shlWithOverflow( | 3121 | pub fn shlWithOverflow( |
| ... | @@ -4289,25 +3125,30 @@ pub const Value = extern union { | ... | @@ -4289,25 +3125,30 @@ pub const Value = extern union { |
| 4289 | allocator: Allocator, | 3125 | allocator: Allocator, |
| 4290 | mod: *Module, | 3126 | mod: *Module, |
| 4291 | ) !OverflowArithmeticResult { | 3127 | ) !OverflowArithmeticResult { |
| 4292 | const target = mod.getTarget(); | 3128 | if (ty.zigTypeTag(mod) == .Vector) { |
| 4293 | if (ty.zigTypeTag() == .Vector) { | 3129 | const vec_len = ty.vectorLen(mod); |
| 4294 | const overflowed_data = try allocator.alloc(Value, ty.vectorLen()); | 3130 | const overflowed_data = try allocator.alloc(InternPool.Index, vec_len); |
| 4295 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 3131 | const result_data = try allocator.alloc(InternPool.Index, vec_len); |
| 4296 | for (result_data, 0..) |*scalar, i| { | 3132 | const scalar_ty = ty.scalarType(mod); |
| 4297 | var lhs_buf: Value.ElemValueBuffer = undefined; | 3133 | for (overflowed_data, result_data, 0..) |*of, *scalar, i| { |
| 4298 | var rhs_buf: Value.ElemValueBuffer = undefined; | 3134 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4299 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 3135 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4300 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | 3136 | const of_math_result = try shlWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod); |
| 4301 | const of_math_result = try shlWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType(), allocator, target); | 3137 | of.* = try of_math_result.overflow_bit.intern(Type.u1, mod); |
| 4302 | overflowed_data[i] = of_math_result.overflow_bit; | 3138 | scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod); |
| 4303 | scalar.* = of_math_result.wrapped_result; | ||
| 4304 | } | 3139 | } |
| 4305 | return OverflowArithmeticResult{ | 3140 | return OverflowArithmeticResult{ |
| 4306 | .overflow_bit = try Value.Tag.aggregate.create(allocator, overflowed_data), | 3141 | .overflow_bit = (try mod.intern(.{ .aggregate = .{ |
| 4307 | .wrapped_result = try Value.Tag.aggregate.create(allocator, result_data), | 3142 | .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(), |
| 3143 | .storage = .{ .elems = overflowed_data }, | ||
| 3144 | } })).toValue(), | ||
| 3145 | .wrapped_result = (try mod.intern(.{ .aggregate = .{ | ||
| 3146 | .ty = ty.toIntern(), | ||
| 3147 | .storage = .{ .elems = result_data }, | ||
| 3148 | } })).toValue(), | ||
| 4308 | }; | 3149 | }; |
| 4309 | } | 3150 | } |
| 4310 | return shlWithOverflowScalar(lhs, rhs, ty, allocator, target); | 3151 | return shlWithOverflowScalar(lhs, rhs, ty, allocator, mod); |
| 4311 | } | 3152 | } |
| 4312 | 3153 | ||
| 4313 | pub fn shlWithOverflowScalar( | 3154 | pub fn shlWithOverflowScalar( |
| ... | @@ -4315,12 +3156,12 @@ pub const Value = extern union { | ... | @@ -4315,12 +3156,12 @@ pub const Value = extern union { |
| 4315 | rhs: Value, | 3156 | rhs: Value, |
| 4316 | ty: Type, | 3157 | ty: Type, |
| 4317 | allocator: Allocator, | 3158 | allocator: Allocator, |
| 4318 | target: Target, | 3159 | mod: *Module, |
| 4319 | ) !OverflowArithmeticResult { | 3160 | ) !OverflowArithmeticResult { |
| 4320 | const info = ty.intInfo(target); | 3161 | const info = ty.intInfo(mod); |
| 4321 | var lhs_space: Value.BigIntSpace = undefined; | 3162 | var lhs_space: Value.BigIntSpace = undefined; |
| 4322 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 3163 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 4323 | const shift = @intCast(usize, rhs.toUnsignedInt(target)); | 3164 | const shift = @intCast(usize, rhs.toUnsignedInt(mod)); |
| 4324 | const limbs = try allocator.alloc( | 3165 | const limbs = try allocator.alloc( |
| 4325 | std.math.big.Limb, | 3166 | std.math.big.Limb, |
| 4326 | lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1, | 3167 | lhs_bigint.limbs.len + (shift / (@sizeOf(std.math.big.Limb) * 8)) + 1, |
| ... | @@ -4336,8 +3177,8 @@ pub const Value = extern union { | ... | @@ -4336,8 +3177,8 @@ pub const Value = extern union { |
| 4336 | result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits); | 3177 | result_bigint.truncate(result_bigint.toConst(), info.signedness, info.bits); |
| 4337 | } | 3178 | } |
| 4338 | return OverflowArithmeticResult{ | 3179 | return OverflowArithmeticResult{ |
| 4339 | .overflow_bit = boolToInt(overflowed), | 3180 | .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)), |
| 4340 | .wrapped_result = try fromBigInt(allocator, result_bigint.toConst()), | 3181 | .wrapped_result = try mod.intValue_big(ty, result_bigint.toConst()), |
| 4341 | }; | 3182 | }; |
| 4342 | } | 3183 | } |
| 4343 | 3184 | ||
| ... | @@ -4348,19 +3189,20 @@ pub const Value = extern union { | ... | @@ -4348,19 +3189,20 @@ pub const Value = extern union { |
| 4348 | arena: Allocator, | 3189 | arena: Allocator, |
| 4349 | mod: *Module, | 3190 | mod: *Module, |
| 4350 | ) !Value { | 3191 | ) !Value { |
| 4351 | const target = mod.getTarget(); | 3192 | if (ty.zigTypeTag(mod) == .Vector) { |
| 4352 | if (ty.zigTypeTag() == .Vector) { | 3193 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 4353 | const result_data = try arena.alloc(Value, ty.vectorLen()); | 3194 | const scalar_ty = ty.scalarType(mod); |
| 4354 | for (result_data, 0..) |*scalar, i| { | 3195 | for (result_data, 0..) |*scalar, i| { |
| 4355 | var lhs_buf: Value.ElemValueBuffer = undefined; | 3196 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4356 | var rhs_buf: Value.ElemValueBuffer = undefined; | 3197 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4357 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 3198 | scalar.* = try (try shlSatScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); |
| 4358 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 4359 | scalar.* = try shlSatScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, target); | ||
| 4360 | } | 3199 | } |
| 4361 | return Value.Tag.aggregate.create(arena, result_data); | 3200 | return (try mod.intern(.{ .aggregate = .{ |
| 3201 | .ty = ty.toIntern(), | ||
| 3202 | .storage = .{ .elems = result_data }, | ||
| 3203 | } })).toValue(); | ||
| 4362 | } | 3204 | } |
| 4363 | return shlSatScalar(lhs, rhs, ty, arena, target); | 3205 | return shlSatScalar(lhs, rhs, ty, arena, mod); |
| 4364 | } | 3206 | } |
| 4365 | 3207 | ||
| 4366 | pub fn shlSatScalar( | 3208 | pub fn shlSatScalar( |
| ... | @@ -4368,15 +3210,15 @@ pub const Value = extern union { | ... | @@ -4368,15 +3210,15 @@ pub const Value = extern union { |
| 4368 | rhs: Value, | 3210 | rhs: Value, |
| 4369 | ty: Type, | 3211 | ty: Type, |
| 4370 | arena: Allocator, | 3212 | arena: Allocator, |
| 4371 | target: Target, | 3213 | mod: *Module, |
| 4372 | ) !Value { | 3214 | ) !Value { |
| 4373 | // TODO is this a performance issue? maybe we should try the operation without | 3215 | // TODO is this a performance issue? maybe we should try the operation without |
| 4374 | // resorting to BigInt first. | 3216 | // resorting to BigInt first. |
| 4375 | const info = ty.intInfo(target); | 3217 | const info = ty.intInfo(mod); |
| 4376 | 3218 | ||
| 4377 | var lhs_space: Value.BigIntSpace = undefined; | 3219 | var lhs_space: Value.BigIntSpace = undefined; |
| 4378 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 3220 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 4379 | const shift = @intCast(usize, rhs.toUnsignedInt(target)); | 3221 | const shift = @intCast(usize, rhs.toUnsignedInt(mod)); |
| 4380 | const limbs = try arena.alloc( | 3222 | const limbs = try arena.alloc( |
| 4381 | std.math.big.Limb, | 3223 | std.math.big.Limb, |
| 4382 | std.math.big.int.calcTwosCompLimbCount(info.bits) + 1, | 3224 | std.math.big.int.calcTwosCompLimbCount(info.bits) + 1, |
| ... | @@ -4387,7 +3229,7 @@ pub const Value = extern union { | ... | @@ -4387,7 +3229,7 @@ pub const Value = extern union { |
| 4387 | .len = undefined, | 3229 | .len = undefined, |
| 4388 | }; | 3230 | }; |
| 4389 | result_bigint.shiftLeftSat(lhs_bigint, shift, info.signedness, info.bits); | 3231 | result_bigint.shiftLeftSat(lhs_bigint, shift, info.signedness, info.bits); |
| 4390 | return fromBigInt(arena, result_bigint.toConst()); | 3232 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 4391 | } | 3233 | } |
| 4392 | 3234 | ||
| 4393 | pub fn shlTrunc( | 3235 | pub fn shlTrunc( |
| ... | @@ -4397,16 +3239,18 @@ pub const Value = extern union { | ... | @@ -4397,16 +3239,18 @@ pub const Value = extern union { |
| 4397 | arena: Allocator, | 3239 | arena: Allocator, |
| 4398 | mod: *Module, | 3240 | mod: *Module, |
| 4399 | ) !Value { | 3241 | ) !Value { |
| 4400 | if (ty.zigTypeTag() == .Vector) { | 3242 | if (ty.zigTypeTag(mod) == .Vector) { |
| 4401 | const result_data = try arena.alloc(Value, ty.vectorLen()); | 3243 | const result_data = try arena.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 3244 | const scalar_ty = ty.scalarType(mod); | ||
| 4402 | for (result_data, 0..) |*scalar, i| { | 3245 | for (result_data, 0..) |*scalar, i| { |
| 4403 | var lhs_buf: Value.ElemValueBuffer = undefined; | 3246 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4404 | var rhs_buf: Value.ElemValueBuffer = undefined; | 3247 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4405 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 3248 | scalar.* = try (try shlTruncScalar(lhs_elem, rhs_elem, scalar_ty, arena, mod)).intern(scalar_ty, mod); |
| 4406 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 4407 | scalar.* = try shlTruncScalar(lhs_elem, rhs_elem, ty.scalarType(), arena, mod); | ||
| 4408 | } | 3249 | } |
| 4409 | return Value.Tag.aggregate.create(arena, result_data); | 3250 | return (try mod.intern(.{ .aggregate = .{ |
| 3251 | .ty = ty.toIntern(), | ||
| 3252 | .storage = .{ .elems = result_data }, | ||
| 3253 | } })).toValue(); | ||
| 4410 | } | 3254 | } |
| 4411 | return shlTruncScalar(lhs, rhs, ty, arena, mod); | 3255 | return shlTruncScalar(lhs, rhs, ty, arena, mod); |
| 4412 | } | 3256 | } |
| ... | @@ -4419,42 +3263,43 @@ pub const Value = extern union { | ... | @@ -4419,42 +3263,43 @@ pub const Value = extern union { |
| 4419 | mod: *Module, | 3263 | mod: *Module, |
| 4420 | ) !Value { | 3264 | ) !Value { |
| 4421 | const shifted = try lhs.shl(rhs, ty, arena, mod); | 3265 | const shifted = try lhs.shl(rhs, ty, arena, mod); |
| 4422 | const int_info = ty.intInfo(mod.getTarget()); | 3266 | const int_info = ty.intInfo(mod); |
| 4423 | const truncated = try shifted.intTrunc(ty, arena, int_info.signedness, int_info.bits, mod); | 3267 | const truncated = try shifted.intTrunc(ty, arena, int_info.signedness, int_info.bits, mod); |
| 4424 | return truncated; | 3268 | return truncated; |
| 4425 | } | 3269 | } |
| 4426 | 3270 | ||
| 4427 | pub fn shr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { | 3271 | pub fn shr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 4428 | const target = mod.getTarget(); | 3272 | if (ty.zigTypeTag(mod) == .Vector) { |
| 4429 | if (ty.zigTypeTag() == .Vector) { | 3273 | const result_data = try allocator.alloc(InternPool.Index, ty.vectorLen(mod)); |
| 4430 | const result_data = try allocator.alloc(Value, ty.vectorLen()); | 3274 | const scalar_ty = ty.scalarType(mod); |
| 4431 | for (result_data, 0..) |*scalar, i| { | 3275 | for (result_data, 0..) |*scalar, i| { |
| 4432 | var lhs_buf: Value.ElemValueBuffer = undefined; | 3276 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4433 | var rhs_buf: Value.ElemValueBuffer = undefined; | 3277 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4434 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 3278 | scalar.* = try (try shrScalar(lhs_elem, rhs_elem, scalar_ty, allocator, mod)).intern(scalar_ty, mod); |
| 4435 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 4436 | scalar.* = try shrScalar(lhs_elem, rhs_elem, allocator, target); | ||
| 4437 | } | 3279 | } |
| 4438 | return Value.Tag.aggregate.create(allocator, result_data); | 3280 | return (try mod.intern(.{ .aggregate = .{ |
| 3281 | .ty = ty.toIntern(), | ||
| 3282 | .storage = .{ .elems = result_data }, | ||
| 3283 | } })).toValue(); | ||
| 4439 | } | 3284 | } |
| 4440 | return shrScalar(lhs, rhs, allocator, target); | 3285 | return shrScalar(lhs, rhs, ty, allocator, mod); |
| 4441 | } | 3286 | } |
| 4442 | 3287 | ||
| 4443 | pub fn shrScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { | 3288 | pub fn shrScalar(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { |
| 4444 | // TODO is this a performance issue? maybe we should try the operation without | 3289 | // TODO is this a performance issue? maybe we should try the operation without |
| 4445 | // resorting to BigInt first. | 3290 | // resorting to BigInt first. |
| 4446 | var lhs_space: Value.BigIntSpace = undefined; | 3291 | var lhs_space: Value.BigIntSpace = undefined; |
| 4447 | const lhs_bigint = lhs.toBigInt(&lhs_space, target); | 3292 | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 4448 | const shift = @intCast(usize, rhs.toUnsignedInt(target)); | 3293 | const shift = @intCast(usize, rhs.toUnsignedInt(mod)); |
| 4449 | 3294 | ||
| 4450 | const result_limbs = lhs_bigint.limbs.len -| (shift / (@sizeOf(std.math.big.Limb) * 8)); | 3295 | const result_limbs = lhs_bigint.limbs.len -| (shift / (@sizeOf(std.math.big.Limb) * 8)); |
| 4451 | if (result_limbs == 0) { | 3296 | if (result_limbs == 0) { |
| 4452 | // The shift is enough to remove all the bits from the number, which means the | 3297 | // The shift is enough to remove all the bits from the number, which means the |
| 4453 | // result is 0 or -1 depending on the sign. | 3298 | // result is 0 or -1 depending on the sign. |
| 4454 | if (lhs_bigint.positive) { | 3299 | if (lhs_bigint.positive) { |
| 4455 | return Value.zero; | 3300 | return mod.intValue(ty, 0); |
| 4456 | } else { | 3301 | } else { |
| 4457 | return Value.negative_one; | 3302 | return mod.intValue(ty, -1); |
| 4458 | } | 3303 | } |
| 4459 | } | 3304 | } |
| 4460 | 3305 | ||
| ... | @@ -4468,7 +3313,7 @@ pub const Value = extern union { | ... | @@ -4468,7 +3313,7 @@ pub const Value = extern union { |
| 4468 | .len = undefined, | 3313 | .len = undefined, |
| 4469 | }; | 3314 | }; |
| 4470 | result_bigint.shiftRight(lhs_bigint, shift); | 3315 | result_bigint.shiftRight(lhs_bigint, shift); |
| 4471 | return fromBigInt(allocator, result_bigint.toConst()); | 3316 | return mod.intValue_big(ty, result_bigint.toConst()); |
| 4472 | } | 3317 | } |
| 4473 | 3318 | ||
| 4474 | pub fn floatNeg( | 3319 | pub fn floatNeg( |
| ... | @@ -4477,33 +3322,127 @@ pub const Value = extern union { | ... | @@ -4477,33 +3322,127 @@ pub const Value = extern union { |
| 4477 | arena: Allocator, | 3322 | arena: Allocator, |
| 4478 | mod: *Module, | 3323 | mod: *Module, |
| 4479 | ) !Value { | 3324 | ) !Value { |
| 4480 | const target = mod.getTarget(); | 3325 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4481 | if (float_type.zigTypeTag() == .Vector) { | 3326 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4482 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3327 | const scalar_ty = float_type.scalarType(mod); |
| 4483 | for (result_data, 0..) |*scalar, i| { | 3328 | for (result_data, 0..) |*scalar, i| { |
| 4484 | var buf: Value.ElemValueBuffer = undefined; | 3329 | const elem_val = try val.elemValue(mod, i); |
| 4485 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3330 | scalar.* = try (try floatNegScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4486 | scalar.* = try floatNegScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 4487 | } | 3331 | } |
| 4488 | return Value.Tag.aggregate.create(arena, result_data); | 3332 | return (try mod.intern(.{ .aggregate = .{ |
| 3333 | .ty = float_type.toIntern(), | ||
| 3334 | .storage = .{ .elems = result_data }, | ||
| 3335 | } })).toValue(); | ||
| 4489 | } | 3336 | } |
| 4490 | return floatNegScalar(val, float_type, arena, target); | 3337 | return floatNegScalar(val, float_type, mod); |
| 4491 | } | 3338 | } |
| 4492 | 3339 | ||
| 4493 | pub fn floatNegScalar( | 3340 | pub fn floatNegScalar( |
| 4494 | val: Value, | 3341 | val: Value, |
| 4495 | float_type: Type, | 3342 | float_type: Type, |
| 3343 | mod: *Module, | ||
| 3344 | ) !Value { | ||
| 3345 | const target = mod.getTarget(); | ||
| 3346 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | ||
| 3347 | 16 => .{ .f16 = -val.toFloat(f16, mod) }, | ||
| 3348 | 32 => .{ .f32 = -val.toFloat(f32, mod) }, | ||
| 3349 | 64 => .{ .f64 = -val.toFloat(f64, mod) }, | ||
| 3350 | 80 => .{ .f80 = -val.toFloat(f80, mod) }, | ||
| 3351 | 128 => .{ .f128 = -val.toFloat(f128, mod) }, | ||
| 3352 | else => unreachable, | ||
| 3353 | }; | ||
| 3354 | return (try mod.intern(.{ .float = .{ | ||
| 3355 | .ty = float_type.toIntern(), | ||
| 3356 | .storage = storage, | ||
| 3357 | } })).toValue(); | ||
| 3358 | } | ||
| 3359 | |||
| 3360 | pub fn floatAdd( | ||
| 3361 | lhs: Value, | ||
| 3362 | rhs: Value, | ||
| 3363 | float_type: Type, | ||
| 4496 | arena: Allocator, | 3364 | arena: Allocator, |
| 4497 | target: Target, | 3365 | mod: *Module, |
| 3366 | ) !Value { | ||
| 3367 | if (float_type.zigTypeTag(mod) == .Vector) { | ||
| 3368 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | ||
| 3369 | const scalar_ty = float_type.scalarType(mod); | ||
| 3370 | for (result_data, 0..) |*scalar, i| { | ||
| 3371 | const lhs_elem = try lhs.elemValue(mod, i); | ||
| 3372 | const rhs_elem = try rhs.elemValue(mod, i); | ||
| 3373 | scalar.* = try (try floatAddScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); | ||
| 3374 | } | ||
| 3375 | return (try mod.intern(.{ .aggregate = .{ | ||
| 3376 | .ty = float_type.toIntern(), | ||
| 3377 | .storage = .{ .elems = result_data }, | ||
| 3378 | } })).toValue(); | ||
| 3379 | } | ||
| 3380 | return floatAddScalar(lhs, rhs, float_type, mod); | ||
| 3381 | } | ||
| 3382 | |||
| 3383 | pub fn floatAddScalar( | ||
| 3384 | lhs: Value, | ||
| 3385 | rhs: Value, | ||
| 3386 | float_type: Type, | ||
| 3387 | mod: *Module, | ||
| 4498 | ) !Value { | 3388 | ) !Value { |
| 4499 | switch (float_type.floatBits(target)) { | 3389 | const target = mod.getTarget(); |
| 4500 | 16 => return Value.Tag.float_16.create(arena, -val.toFloat(f16)), | 3390 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4501 | 32 => return Value.Tag.float_32.create(arena, -val.toFloat(f32)), | 3391 | 16 => .{ .f16 = lhs.toFloat(f16, mod) + rhs.toFloat(f16, mod) }, |
| 4502 | 64 => return Value.Tag.float_64.create(arena, -val.toFloat(f64)), | 3392 | 32 => .{ .f32 = lhs.toFloat(f32, mod) + rhs.toFloat(f32, mod) }, |
| 4503 | 80 => return Value.Tag.float_80.create(arena, -val.toFloat(f80)), | 3393 | 64 => .{ .f64 = lhs.toFloat(f64, mod) + rhs.toFloat(f64, mod) }, |
| 4504 | 128 => return Value.Tag.float_128.create(arena, -val.toFloat(f128)), | 3394 | 80 => .{ .f80 = lhs.toFloat(f80, mod) + rhs.toFloat(f80, mod) }, |
| 3395 | 128 => .{ .f128 = lhs.toFloat(f128, mod) + rhs.toFloat(f128, mod) }, | ||
| 4505 | else => unreachable, | 3396 | else => unreachable, |
| 3397 | }; | ||
| 3398 | return (try mod.intern(.{ .float = .{ | ||
| 3399 | .ty = float_type.toIntern(), | ||
| 3400 | .storage = storage, | ||
| 3401 | } })).toValue(); | ||
| 3402 | } | ||
| 3403 | |||
| 3404 | pub fn floatSub( | ||
| 3405 | lhs: Value, | ||
| 3406 | rhs: Value, | ||
| 3407 | float_type: Type, | ||
| 3408 | arena: Allocator, | ||
| 3409 | mod: *Module, | ||
| 3410 | ) !Value { | ||
| 3411 | if (float_type.zigTypeTag(mod) == .Vector) { | ||
| 3412 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); | ||
| 3413 | const scalar_ty = float_type.scalarType(mod); | ||
| 3414 | for (result_data, 0..) |*scalar, i| { | ||
| 3415 | const lhs_elem = try lhs.elemValue(mod, i); | ||
| 3416 | const rhs_elem = try rhs.elemValue(mod, i); | ||
| 3417 | scalar.* = try (try floatSubScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); | ||
| 3418 | } | ||
| 3419 | return (try mod.intern(.{ .aggregate = .{ | ||
| 3420 | .ty = float_type.toIntern(), | ||
| 3421 | .storage = .{ .elems = result_data }, | ||
| 3422 | } })).toValue(); | ||
| 4506 | } | 3423 | } |
| 3424 | return floatSubScalar(lhs, rhs, float_type, mod); | ||
| 3425 | } | ||
| 3426 | |||
| 3427 | pub fn floatSubScalar( | ||
| 3428 | lhs: Value, | ||
| 3429 | rhs: Value, | ||
| 3430 | float_type: Type, | ||
| 3431 | mod: *Module, | ||
| 3432 | ) !Value { | ||
| 3433 | const target = mod.getTarget(); | ||
| 3434 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { | ||
| 3435 | 16 => .{ .f16 = lhs.toFloat(f16, mod) - rhs.toFloat(f16, mod) }, | ||
| 3436 | 32 => .{ .f32 = lhs.toFloat(f32, mod) - rhs.toFloat(f32, mod) }, | ||
| 3437 | 64 => .{ .f64 = lhs.toFloat(f64, mod) - rhs.toFloat(f64, mod) }, | ||
| 3438 | 80 => .{ .f80 = lhs.toFloat(f80, mod) - rhs.toFloat(f80, mod) }, | ||
| 3439 | 128 => .{ .f128 = lhs.toFloat(f128, mod) - rhs.toFloat(f128, mod) }, | ||
| 3440 | else => unreachable, | ||
| 3441 | }; | ||
| 3442 | return (try mod.intern(.{ .float = .{ | ||
| 3443 | .ty = float_type.toIntern(), | ||
| 3444 | .storage = storage, | ||
| 3445 | } })).toValue(); | ||
| 4507 | } | 3446 | } |
| 4508 | 3447 | ||
| 4509 | pub fn floatDiv( | 3448 | pub fn floatDiv( |
| ... | @@ -4513,56 +3452,41 @@ pub const Value = extern union { | ... | @@ -4513,56 +3452,41 @@ pub const Value = extern union { |
| 4513 | arena: Allocator, | 3452 | arena: Allocator, |
| 4514 | mod: *Module, | 3453 | mod: *Module, |
| 4515 | ) !Value { | 3454 | ) !Value { |
| 4516 | const target = mod.getTarget(); | 3455 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4517 | if (float_type.zigTypeTag() == .Vector) { | 3456 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4518 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3457 | const scalar_ty = float_type.scalarType(mod); |
| 4519 | for (result_data, 0..) |*scalar, i| { | 3458 | for (result_data, 0..) |*scalar, i| { |
| 4520 | var lhs_buf: Value.ElemValueBuffer = undefined; | 3459 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4521 | var rhs_buf: Value.ElemValueBuffer = undefined; | 3460 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4522 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 3461 | scalar.* = try (try floatDivScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4523 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 4524 | scalar.* = try floatDivScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | ||
| 4525 | } | 3462 | } |
| 4526 | return Value.Tag.aggregate.create(arena, result_data); | 3463 | return (try mod.intern(.{ .aggregate = .{ |
| 3464 | .ty = float_type.toIntern(), | ||
| 3465 | .storage = .{ .elems = result_data }, | ||
| 3466 | } })).toValue(); | ||
| 4527 | } | 3467 | } |
| 4528 | return floatDivScalar(lhs, rhs, float_type, arena, target); | 3468 | return floatDivScalar(lhs, rhs, float_type, mod); |
| 4529 | } | 3469 | } |
| 4530 | 3470 | ||
| 4531 | pub fn floatDivScalar( | 3471 | pub fn floatDivScalar( |
| 4532 | lhs: Value, | 3472 | lhs: Value, |
| 4533 | rhs: Value, | 3473 | rhs: Value, |
| 4534 | float_type: Type, | 3474 | float_type: Type, |
| 4535 | arena: Allocator, | 3475 | mod: *Module, |
| 4536 | target: Target, | ||
| 4537 | ) !Value { | 3476 | ) !Value { |
| 4538 | switch (float_type.floatBits(target)) { | 3477 | const target = mod.getTarget(); |
| 4539 | 16 => { | 3478 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4540 | const lhs_val = lhs.toFloat(f16); | 3479 | 16 => .{ .f16 = lhs.toFloat(f16, mod) / rhs.toFloat(f16, mod) }, |
| 4541 | const rhs_val = rhs.toFloat(f16); | 3480 | 32 => .{ .f32 = lhs.toFloat(f32, mod) / rhs.toFloat(f32, mod) }, |
| 4542 | return Value.Tag.float_16.create(arena, lhs_val / rhs_val); | 3481 | 64 => .{ .f64 = lhs.toFloat(f64, mod) / rhs.toFloat(f64, mod) }, |
| 4543 | }, | 3482 | 80 => .{ .f80 = lhs.toFloat(f80, mod) / rhs.toFloat(f80, mod) }, |
| 4544 | 32 => { | 3483 | 128 => .{ .f128 = lhs.toFloat(f128, mod) / rhs.toFloat(f128, mod) }, |
| 4545 | const lhs_val = lhs.toFloat(f32); | ||
| 4546 | const rhs_val = rhs.toFloat(f32); | ||
| 4547 | return Value.Tag.float_32.create(arena, lhs_val / rhs_val); | ||
| 4548 | }, | ||
| 4549 | 64 => { | ||
| 4550 | const lhs_val = lhs.toFloat(f64); | ||
| 4551 | const rhs_val = rhs.toFloat(f64); | ||
| 4552 | return Value.Tag.float_64.create(arena, lhs_val / rhs_val); | ||
| 4553 | }, | ||
| 4554 | 80 => { | ||
| 4555 | const lhs_val = lhs.toFloat(f80); | ||
| 4556 | const rhs_val = rhs.toFloat(f80); | ||
| 4557 | return Value.Tag.float_80.create(arena, lhs_val / rhs_val); | ||
| 4558 | }, | ||
| 4559 | 128 => { | ||
| 4560 | const lhs_val = lhs.toFloat(f128); | ||
| 4561 | const rhs_val = rhs.toFloat(f128); | ||
| 4562 | return Value.Tag.float_128.create(arena, lhs_val / rhs_val); | ||
| 4563 | }, | ||
| 4564 | else => unreachable, | 3484 | else => unreachable, |
| 4565 | } | 3485 | }; |
| 3486 | return (try mod.intern(.{ .float = .{ | ||
| 3487 | .ty = float_type.toIntern(), | ||
| 3488 | .storage = storage, | ||
| 3489 | } })).toValue(); | ||
| 4566 | } | 3490 | } |
| 4567 | 3491 | ||
| 4568 | pub fn floatDivFloor( | 3492 | pub fn floatDivFloor( |
| ... | @@ -4572,56 +3496,41 @@ pub const Value = extern union { | ... | @@ -4572,56 +3496,41 @@ pub const Value = extern union { |
| 4572 | arena: Allocator, | 3496 | arena: Allocator, |
| 4573 | mod: *Module, | 3497 | mod: *Module, |
| 4574 | ) !Value { | 3498 | ) !Value { |
| 4575 | const target = mod.getTarget(); | 3499 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4576 | if (float_type.zigTypeTag() == .Vector) { | 3500 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4577 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3501 | const scalar_ty = float_type.scalarType(mod); |
| 4578 | for (result_data, 0..) |*scalar, i| { | 3502 | for (result_data, 0..) |*scalar, i| { |
| 4579 | var lhs_buf: Value.ElemValueBuffer = undefined; | 3503 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4580 | var rhs_buf: Value.ElemValueBuffer = undefined; | 3504 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4581 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 3505 | scalar.* = try (try floatDivFloorScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4582 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 4583 | scalar.* = try floatDivFloorScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | ||
| 4584 | } | 3506 | } |
| 4585 | return Value.Tag.aggregate.create(arena, result_data); | 3507 | return (try mod.intern(.{ .aggregate = .{ |
| 3508 | .ty = float_type.toIntern(), | ||
| 3509 | .storage = .{ .elems = result_data }, | ||
| 3510 | } })).toValue(); | ||
| 4586 | } | 3511 | } |
| 4587 | return floatDivFloorScalar(lhs, rhs, float_type, arena, target); | 3512 | return floatDivFloorScalar(lhs, rhs, float_type, mod); |
| 4588 | } | 3513 | } |
| 4589 | 3514 | ||
| 4590 | pub fn floatDivFloorScalar( | 3515 | pub fn floatDivFloorScalar( |
| 4591 | lhs: Value, | 3516 | lhs: Value, |
| 4592 | rhs: Value, | 3517 | rhs: Value, |
| 4593 | float_type: Type, | 3518 | float_type: Type, |
| 4594 | arena: Allocator, | 3519 | mod: *Module, |
| 4595 | target: Target, | ||
| 4596 | ) !Value { | 3520 | ) !Value { |
| 4597 | switch (float_type.floatBits(target)) { | 3521 | const target = mod.getTarget(); |
| 4598 | 16 => { | 3522 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4599 | const lhs_val = lhs.toFloat(f16); | 3523 | 16 => .{ .f16 = @divFloor(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, |
| 4600 | const rhs_val = rhs.toFloat(f16); | 3524 | 32 => .{ .f32 = @divFloor(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, |
| 4601 | return Value.Tag.float_16.create(arena, @divFloor(lhs_val, rhs_val)); | 3525 | 64 => .{ .f64 = @divFloor(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, |
| 4602 | }, | 3526 | 80 => .{ .f80 = @divFloor(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, |
| 4603 | 32 => { | 3527 | 128 => .{ .f128 = @divFloor(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, |
| 4604 | const lhs_val = lhs.toFloat(f32); | ||
| 4605 | const rhs_val = rhs.toFloat(f32); | ||
| 4606 | return Value.Tag.float_32.create(arena, @divFloor(lhs_val, rhs_val)); | ||
| 4607 | }, | ||
| 4608 | 64 => { | ||
| 4609 | const lhs_val = lhs.toFloat(f64); | ||
| 4610 | const rhs_val = rhs.toFloat(f64); | ||
| 4611 | return Value.Tag.float_64.create(arena, @divFloor(lhs_val, rhs_val)); | ||
| 4612 | }, | ||
| 4613 | 80 => { | ||
| 4614 | const lhs_val = lhs.toFloat(f80); | ||
| 4615 | const rhs_val = rhs.toFloat(f80); | ||
| 4616 | return Value.Tag.float_80.create(arena, @divFloor(lhs_val, rhs_val)); | ||
| 4617 | }, | ||
| 4618 | 128 => { | ||
| 4619 | const lhs_val = lhs.toFloat(f128); | ||
| 4620 | const rhs_val = rhs.toFloat(f128); | ||
| 4621 | return Value.Tag.float_128.create(arena, @divFloor(lhs_val, rhs_val)); | ||
| 4622 | }, | ||
| 4623 | else => unreachable, | 3528 | else => unreachable, |
| 4624 | } | 3529 | }; |
| 3530 | return (try mod.intern(.{ .float = .{ | ||
| 3531 | .ty = float_type.toIntern(), | ||
| 3532 | .storage = storage, | ||
| 3533 | } })).toValue(); | ||
| 4625 | } | 3534 | } |
| 4626 | 3535 | ||
| 4627 | pub fn floatDivTrunc( | 3536 | pub fn floatDivTrunc( |
| ... | @@ -4631,56 +3540,41 @@ pub const Value = extern union { | ... | @@ -4631,56 +3540,41 @@ pub const Value = extern union { |
| 4631 | arena: Allocator, | 3540 | arena: Allocator, |
| 4632 | mod: *Module, | 3541 | mod: *Module, |
| 4633 | ) !Value { | 3542 | ) !Value { |
| 4634 | const target = mod.getTarget(); | 3543 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4635 | if (float_type.zigTypeTag() == .Vector) { | 3544 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4636 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3545 | const scalar_ty = float_type.scalarType(mod); |
| 4637 | for (result_data, 0..) |*scalar, i| { | 3546 | for (result_data, 0..) |*scalar, i| { |
| 4638 | var lhs_buf: Value.ElemValueBuffer = undefined; | 3547 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4639 | var rhs_buf: Value.ElemValueBuffer = undefined; | 3548 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4640 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 3549 | scalar.* = try (try floatDivTruncScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4641 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 4642 | scalar.* = try floatDivTruncScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | ||
| 4643 | } | 3550 | } |
| 4644 | return Value.Tag.aggregate.create(arena, result_data); | 3551 | return (try mod.intern(.{ .aggregate = .{ |
| 3552 | .ty = float_type.toIntern(), | ||
| 3553 | .storage = .{ .elems = result_data }, | ||
| 3554 | } })).toValue(); | ||
| 4645 | } | 3555 | } |
| 4646 | return floatDivTruncScalar(lhs, rhs, float_type, arena, target); | 3556 | return floatDivTruncScalar(lhs, rhs, float_type, mod); |
| 4647 | } | 3557 | } |
| 4648 | 3558 | ||
| 4649 | pub fn floatDivTruncScalar( | 3559 | pub fn floatDivTruncScalar( |
| 4650 | lhs: Value, | 3560 | lhs: Value, |
| 4651 | rhs: Value, | 3561 | rhs: Value, |
| 4652 | float_type: Type, | 3562 | float_type: Type, |
| 4653 | arena: Allocator, | 3563 | mod: *Module, |
| 4654 | target: Target, | ||
| 4655 | ) !Value { | 3564 | ) !Value { |
| 4656 | switch (float_type.floatBits(target)) { | 3565 | const target = mod.getTarget(); |
| 4657 | 16 => { | 3566 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4658 | const lhs_val = lhs.toFloat(f16); | 3567 | 16 => .{ .f16 = @divTrunc(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, |
| 4659 | const rhs_val = rhs.toFloat(f16); | 3568 | 32 => .{ .f32 = @divTrunc(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, |
| 4660 | return Value.Tag.float_16.create(arena, @divTrunc(lhs_val, rhs_val)); | 3569 | 64 => .{ .f64 = @divTrunc(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, |
| 4661 | }, | 3570 | 80 => .{ .f80 = @divTrunc(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, |
| 4662 | 32 => { | 3571 | 128 => .{ .f128 = @divTrunc(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, |
| 4663 | const lhs_val = lhs.toFloat(f32); | ||
| 4664 | const rhs_val = rhs.toFloat(f32); | ||
| 4665 | return Value.Tag.float_32.create(arena, @divTrunc(lhs_val, rhs_val)); | ||
| 4666 | }, | ||
| 4667 | 64 => { | ||
| 4668 | const lhs_val = lhs.toFloat(f64); | ||
| 4669 | const rhs_val = rhs.toFloat(f64); | ||
| 4670 | return Value.Tag.float_64.create(arena, @divTrunc(lhs_val, rhs_val)); | ||
| 4671 | }, | ||
| 4672 | 80 => { | ||
| 4673 | const lhs_val = lhs.toFloat(f80); | ||
| 4674 | const rhs_val = rhs.toFloat(f80); | ||
| 4675 | return Value.Tag.float_80.create(arena, @divTrunc(lhs_val, rhs_val)); | ||
| 4676 | }, | ||
| 4677 | 128 => { | ||
| 4678 | const lhs_val = lhs.toFloat(f128); | ||
| 4679 | const rhs_val = rhs.toFloat(f128); | ||
| 4680 | return Value.Tag.float_128.create(arena, @divTrunc(lhs_val, rhs_val)); | ||
| 4681 | }, | ||
| 4682 | else => unreachable, | 3572 | else => unreachable, |
| 4683 | } | 3573 | }; |
| 3574 | return (try mod.intern(.{ .float = .{ | ||
| 3575 | .ty = float_type.toIntern(), | ||
| 3576 | .storage = storage, | ||
| 3577 | } })).toValue(); | ||
| 4684 | } | 3578 | } |
| 4685 | 3579 | ||
| 4686 | pub fn floatMul( | 3580 | pub fn floatMul( |
| ... | @@ -4690,616 +3584,489 @@ pub const Value = extern union { | ... | @@ -4690,616 +3584,489 @@ pub const Value = extern union { |
| 4690 | arena: Allocator, | 3584 | arena: Allocator, |
| 4691 | mod: *Module, | 3585 | mod: *Module, |
| 4692 | ) !Value { | 3586 | ) !Value { |
| 4693 | const target = mod.getTarget(); | 3587 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4694 | if (float_type.zigTypeTag() == .Vector) { | 3588 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4695 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3589 | const scalar_ty = float_type.scalarType(mod); |
| 4696 | for (result_data, 0..) |*scalar, i| { | 3590 | for (result_data, 0..) |*scalar, i| { |
| 4697 | var lhs_buf: Value.ElemValueBuffer = undefined; | 3591 | const lhs_elem = try lhs.elemValue(mod, i); |
| 4698 | var rhs_buf: Value.ElemValueBuffer = undefined; | 3592 | const rhs_elem = try rhs.elemValue(mod, i); |
| 4699 | const lhs_elem = lhs.elemValueBuffer(mod, i, &lhs_buf); | 3593 | scalar.* = try (try floatMulScalar(lhs_elem, rhs_elem, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4700 | const rhs_elem = rhs.elemValueBuffer(mod, i, &rhs_buf); | ||
| 4701 | scalar.* = try floatMulScalar(lhs_elem, rhs_elem, float_type.scalarType(), arena, target); | ||
| 4702 | } | 3594 | } |
| 4703 | return Value.Tag.aggregate.create(arena, result_data); | 3595 | return (try mod.intern(.{ .aggregate = .{ |
| 3596 | .ty = float_type.toIntern(), | ||
| 3597 | .storage = .{ .elems = result_data }, | ||
| 3598 | } })).toValue(); | ||
| 4704 | } | 3599 | } |
| 4705 | return floatMulScalar(lhs, rhs, float_type, arena, target); | 3600 | return floatMulScalar(lhs, rhs, float_type, mod); |
| 4706 | } | 3601 | } |
| 4707 | 3602 | ||
| 4708 | pub fn floatMulScalar( | 3603 | pub fn floatMulScalar( |
| 4709 | lhs: Value, | 3604 | lhs: Value, |
| 4710 | rhs: Value, | 3605 | rhs: Value, |
| 4711 | float_type: Type, | 3606 | float_type: Type, |
| 4712 | arena: Allocator, | 3607 | mod: *Module, |
| 4713 | target: Target, | ||
| 4714 | ) !Value { | 3608 | ) !Value { |
| 4715 | switch (float_type.floatBits(target)) { | 3609 | const target = mod.getTarget(); |
| 4716 | 16 => { | 3610 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4717 | const lhs_val = lhs.toFloat(f16); | 3611 | 16 => .{ .f16 = lhs.toFloat(f16, mod) * rhs.toFloat(f16, mod) }, |
| 4718 | const rhs_val = rhs.toFloat(f16); | 3612 | 32 => .{ .f32 = lhs.toFloat(f32, mod) * rhs.toFloat(f32, mod) }, |
| 4719 | return Value.Tag.float_16.create(arena, lhs_val * rhs_val); | 3613 | 64 => .{ .f64 = lhs.toFloat(f64, mod) * rhs.toFloat(f64, mod) }, |
| 4720 | }, | 3614 | 80 => .{ .f80 = lhs.toFloat(f80, mod) * rhs.toFloat(f80, mod) }, |
| 4721 | 32 => { | 3615 | 128 => .{ .f128 = lhs.toFloat(f128, mod) * rhs.toFloat(f128, mod) }, |
| 4722 | const lhs_val = lhs.toFloat(f32); | ||
| 4723 | const rhs_val = rhs.toFloat(f32); | ||
| 4724 | return Value.Tag.float_32.create(arena, lhs_val * rhs_val); | ||
| 4725 | }, | ||
| 4726 | 64 => { | ||
| 4727 | const lhs_val = lhs.toFloat(f64); | ||
| 4728 | const rhs_val = rhs.toFloat(f64); | ||
| 4729 | return Value.Tag.float_64.create(arena, lhs_val * rhs_val); | ||
| 4730 | }, | ||
| 4731 | 80 => { | ||
| 4732 | const lhs_val = lhs.toFloat(f80); | ||
| 4733 | const rhs_val = rhs.toFloat(f80); | ||
| 4734 | return Value.Tag.float_80.create(arena, lhs_val * rhs_val); | ||
| 4735 | }, | ||
| 4736 | 128 => { | ||
| 4737 | const lhs_val = lhs.toFloat(f128); | ||
| 4738 | const rhs_val = rhs.toFloat(f128); | ||
| 4739 | return Value.Tag.float_128.create(arena, lhs_val * rhs_val); | ||
| 4740 | }, | ||
| 4741 | else => unreachable, | 3616 | else => unreachable, |
| 4742 | } | 3617 | }; |
| 3618 | return (try mod.intern(.{ .float = .{ | ||
| 3619 | .ty = float_type.toIntern(), | ||
| 3620 | .storage = storage, | ||
| 3621 | } })).toValue(); | ||
| 4743 | } | 3622 | } |
| 4744 | 3623 | ||
| 4745 | pub fn sqrt(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3624 | pub fn sqrt(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4746 | const target = mod.getTarget(); | 3625 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4747 | if (float_type.zigTypeTag() == .Vector) { | 3626 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4748 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3627 | const scalar_ty = float_type.scalarType(mod); |
| 4749 | for (result_data, 0..) |*scalar, i| { | 3628 | for (result_data, 0..) |*scalar, i| { |
| 4750 | var buf: Value.ElemValueBuffer = undefined; | 3629 | const elem_val = try val.elemValue(mod, i); |
| 4751 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3630 | scalar.* = try (try sqrtScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4752 | scalar.* = try sqrtScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 4753 | } | 3631 | } |
| 4754 | return Value.Tag.aggregate.create(arena, result_data); | 3632 | return (try mod.intern(.{ .aggregate = .{ |
| 3633 | .ty = float_type.toIntern(), | ||
| 3634 | .storage = .{ .elems = result_data }, | ||
| 3635 | } })).toValue(); | ||
| 4755 | } | 3636 | } |
| 4756 | return sqrtScalar(val, float_type, arena, target); | 3637 | return sqrtScalar(val, float_type, mod); |
| 4757 | } | 3638 | } |
| 4758 | 3639 | ||
| 4759 | pub fn sqrtScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3640 | pub fn sqrtScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 4760 | switch (float_type.floatBits(target)) { | 3641 | const target = mod.getTarget(); |
| 4761 | 16 => { | 3642 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4762 | const f = val.toFloat(f16); | 3643 | 16 => .{ .f16 = @sqrt(val.toFloat(f16, mod)) }, |
| 4763 | return Value.Tag.float_16.create(arena, @sqrt(f)); | 3644 | 32 => .{ .f32 = @sqrt(val.toFloat(f32, mod)) }, |
| 4764 | }, | 3645 | 64 => .{ .f64 = @sqrt(val.toFloat(f64, mod)) }, |
| 4765 | 32 => { | 3646 | 80 => .{ .f80 = @sqrt(val.toFloat(f80, mod)) }, |
| 4766 | const f = val.toFloat(f32); | 3647 | 128 => .{ .f128 = @sqrt(val.toFloat(f128, mod)) }, |
| 4767 | return Value.Tag.float_32.create(arena, @sqrt(f)); | ||
| 4768 | }, | ||
| 4769 | 64 => { | ||
| 4770 | const f = val.toFloat(f64); | ||
| 4771 | return Value.Tag.float_64.create(arena, @sqrt(f)); | ||
| 4772 | }, | ||
| 4773 | 80 => { | ||
| 4774 | const f = val.toFloat(f80); | ||
| 4775 | return Value.Tag.float_80.create(arena, @sqrt(f)); | ||
| 4776 | }, | ||
| 4777 | 128 => { | ||
| 4778 | const f = val.toFloat(f128); | ||
| 4779 | return Value.Tag.float_128.create(arena, @sqrt(f)); | ||
| 4780 | }, | ||
| 4781 | else => unreachable, | 3648 | else => unreachable, |
| 4782 | } | 3649 | }; |
| 3650 | return (try mod.intern(.{ .float = .{ | ||
| 3651 | .ty = float_type.toIntern(), | ||
| 3652 | .storage = storage, | ||
| 3653 | } })).toValue(); | ||
| 4783 | } | 3654 | } |
| 4784 | 3655 | ||
| 4785 | pub fn sin(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3656 | pub fn sin(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4786 | const target = mod.getTarget(); | 3657 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4787 | if (float_type.zigTypeTag() == .Vector) { | 3658 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4788 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3659 | const scalar_ty = float_type.scalarType(mod); |
| 4789 | for (result_data, 0..) |*scalar, i| { | 3660 | for (result_data, 0..) |*scalar, i| { |
| 4790 | var buf: Value.ElemValueBuffer = undefined; | 3661 | const elem_val = try val.elemValue(mod, i); |
| 4791 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3662 | scalar.* = try (try sinScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4792 | scalar.* = try sinScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 4793 | } | 3663 | } |
| 4794 | return Value.Tag.aggregate.create(arena, result_data); | 3664 | return (try mod.intern(.{ .aggregate = .{ |
| 3665 | .ty = float_type.toIntern(), | ||
| 3666 | .storage = .{ .elems = result_data }, | ||
| 3667 | } })).toValue(); | ||
| 4795 | } | 3668 | } |
| 4796 | return sinScalar(val, float_type, arena, target); | 3669 | return sinScalar(val, float_type, mod); |
| 4797 | } | 3670 | } |
| 4798 | 3671 | ||
| 4799 | pub fn sinScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3672 | pub fn sinScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 4800 | switch (float_type.floatBits(target)) { | 3673 | const target = mod.getTarget(); |
| 4801 | 16 => { | 3674 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4802 | const f = val.toFloat(f16); | 3675 | 16 => .{ .f16 = @sin(val.toFloat(f16, mod)) }, |
| 4803 | return Value.Tag.float_16.create(arena, @sin(f)); | 3676 | 32 => .{ .f32 = @sin(val.toFloat(f32, mod)) }, |
| 4804 | }, | 3677 | 64 => .{ .f64 = @sin(val.toFloat(f64, mod)) }, |
| 4805 | 32 => { | 3678 | 80 => .{ .f80 = @sin(val.toFloat(f80, mod)) }, |
| 4806 | const f = val.toFloat(f32); | 3679 | 128 => .{ .f128 = @sin(val.toFloat(f128, mod)) }, |
| 4807 | return Value.Tag.float_32.create(arena, @sin(f)); | ||
| 4808 | }, | ||
| 4809 | 64 => { | ||
| 4810 | const f = val.toFloat(f64); | ||
| 4811 | return Value.Tag.float_64.create(arena, @sin(f)); | ||
| 4812 | }, | ||
| 4813 | 80 => { | ||
| 4814 | const f = val.toFloat(f80); | ||
| 4815 | return Value.Tag.float_80.create(arena, @sin(f)); | ||
| 4816 | }, | ||
| 4817 | 128 => { | ||
| 4818 | const f = val.toFloat(f128); | ||
| 4819 | return Value.Tag.float_128.create(arena, @sin(f)); | ||
| 4820 | }, | ||
| 4821 | else => unreachable, | 3680 | else => unreachable, |
| 4822 | } | 3681 | }; |
| 3682 | return (try mod.intern(.{ .float = .{ | ||
| 3683 | .ty = float_type.toIntern(), | ||
| 3684 | .storage = storage, | ||
| 3685 | } })).toValue(); | ||
| 4823 | } | 3686 | } |
| 4824 | 3687 | ||
| 4825 | pub fn cos(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3688 | pub fn cos(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4826 | const target = mod.getTarget(); | 3689 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4827 | if (float_type.zigTypeTag() == .Vector) { | 3690 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4828 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3691 | const scalar_ty = float_type.scalarType(mod); |
| 4829 | for (result_data, 0..) |*scalar, i| { | 3692 | for (result_data, 0..) |*scalar, i| { |
| 4830 | var buf: Value.ElemValueBuffer = undefined; | 3693 | const elem_val = try val.elemValue(mod, i); |
| 4831 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3694 | scalar.* = try (try cosScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4832 | scalar.* = try cosScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 4833 | } | 3695 | } |
| 4834 | return Value.Tag.aggregate.create(arena, result_data); | 3696 | return (try mod.intern(.{ .aggregate = .{ |
| 3697 | .ty = float_type.toIntern(), | ||
| 3698 | .storage = .{ .elems = result_data }, | ||
| 3699 | } })).toValue(); | ||
| 4835 | } | 3700 | } |
| 4836 | return cosScalar(val, float_type, arena, target); | 3701 | return cosScalar(val, float_type, mod); |
| 4837 | } | 3702 | } |
| 4838 | 3703 | ||
| 4839 | pub fn cosScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3704 | pub fn cosScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 4840 | switch (float_type.floatBits(target)) { | 3705 | const target = mod.getTarget(); |
| 4841 | 16 => { | 3706 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4842 | const f = val.toFloat(f16); | 3707 | 16 => .{ .f16 = @cos(val.toFloat(f16, mod)) }, |
| 4843 | return Value.Tag.float_16.create(arena, @cos(f)); | 3708 | 32 => .{ .f32 = @cos(val.toFloat(f32, mod)) }, |
| 4844 | }, | 3709 | 64 => .{ .f64 = @cos(val.toFloat(f64, mod)) }, |
| 4845 | 32 => { | 3710 | 80 => .{ .f80 = @cos(val.toFloat(f80, mod)) }, |
| 4846 | const f = val.toFloat(f32); | 3711 | 128 => .{ .f128 = @cos(val.toFloat(f128, mod)) }, |
| 4847 | return Value.Tag.float_32.create(arena, @cos(f)); | ||
| 4848 | }, | ||
| 4849 | 64 => { | ||
| 4850 | const f = val.toFloat(f64); | ||
| 4851 | return Value.Tag.float_64.create(arena, @cos(f)); | ||
| 4852 | }, | ||
| 4853 | 80 => { | ||
| 4854 | const f = val.toFloat(f80); | ||
| 4855 | return Value.Tag.float_80.create(arena, @cos(f)); | ||
| 4856 | }, | ||
| 4857 | 128 => { | ||
| 4858 | const f = val.toFloat(f128); | ||
| 4859 | return Value.Tag.float_128.create(arena, @cos(f)); | ||
| 4860 | }, | ||
| 4861 | else => unreachable, | 3712 | else => unreachable, |
| 4862 | } | 3713 | }; |
| 3714 | return (try mod.intern(.{ .float = .{ | ||
| 3715 | .ty = float_type.toIntern(), | ||
| 3716 | .storage = storage, | ||
| 3717 | } })).toValue(); | ||
| 4863 | } | 3718 | } |
| 4864 | 3719 | ||
| 4865 | pub fn tan(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3720 | pub fn tan(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4866 | const target = mod.getTarget(); | 3721 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4867 | if (float_type.zigTypeTag() == .Vector) { | 3722 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4868 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3723 | const scalar_ty = float_type.scalarType(mod); |
| 4869 | for (result_data, 0..) |*scalar, i| { | 3724 | for (result_data, 0..) |*scalar, i| { |
| 4870 | var buf: Value.ElemValueBuffer = undefined; | 3725 | const elem_val = try val.elemValue(mod, i); |
| 4871 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3726 | scalar.* = try (try tanScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4872 | scalar.* = try tanScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 4873 | } | 3727 | } |
| 4874 | return Value.Tag.aggregate.create(arena, result_data); | 3728 | return (try mod.intern(.{ .aggregate = .{ |
| 3729 | .ty = float_type.toIntern(), | ||
| 3730 | .storage = .{ .elems = result_data }, | ||
| 3731 | } })).toValue(); | ||
| 4875 | } | 3732 | } |
| 4876 | return tanScalar(val, float_type, arena, target); | 3733 | return tanScalar(val, float_type, mod); |
| 4877 | } | 3734 | } |
| 4878 | 3735 | ||
| 4879 | pub fn tanScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3736 | pub fn tanScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 4880 | switch (float_type.floatBits(target)) { | 3737 | const target = mod.getTarget(); |
| 4881 | 16 => { | 3738 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4882 | const f = val.toFloat(f16); | 3739 | 16 => .{ .f16 = @tan(val.toFloat(f16, mod)) }, |
| 4883 | return Value.Tag.float_16.create(arena, @tan(f)); | 3740 | 32 => .{ .f32 = @tan(val.toFloat(f32, mod)) }, |
| 4884 | }, | 3741 | 64 => .{ .f64 = @tan(val.toFloat(f64, mod)) }, |
| 4885 | 32 => { | 3742 | 80 => .{ .f80 = @tan(val.toFloat(f80, mod)) }, |
| 4886 | const f = val.toFloat(f32); | 3743 | 128 => .{ .f128 = @tan(val.toFloat(f128, mod)) }, |
| 4887 | return Value.Tag.float_32.create(arena, @tan(f)); | ||
| 4888 | }, | ||
| 4889 | 64 => { | ||
| 4890 | const f = val.toFloat(f64); | ||
| 4891 | return Value.Tag.float_64.create(arena, @tan(f)); | ||
| 4892 | }, | ||
| 4893 | 80 => { | ||
| 4894 | const f = val.toFloat(f80); | ||
| 4895 | return Value.Tag.float_80.create(arena, @tan(f)); | ||
| 4896 | }, | ||
| 4897 | 128 => { | ||
| 4898 | const f = val.toFloat(f128); | ||
| 4899 | return Value.Tag.float_128.create(arena, @tan(f)); | ||
| 4900 | }, | ||
| 4901 | else => unreachable, | 3744 | else => unreachable, |
| 4902 | } | 3745 | }; |
| 3746 | return (try mod.intern(.{ .float = .{ | ||
| 3747 | .ty = float_type.toIntern(), | ||
| 3748 | .storage = storage, | ||
| 3749 | } })).toValue(); | ||
| 4903 | } | 3750 | } |
| 4904 | 3751 | ||
| 4905 | pub fn exp(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3752 | pub fn exp(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4906 | const target = mod.getTarget(); | 3753 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4907 | if (float_type.zigTypeTag() == .Vector) { | 3754 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4908 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3755 | const scalar_ty = float_type.scalarType(mod); |
| 4909 | for (result_data, 0..) |*scalar, i| { | 3756 | for (result_data, 0..) |*scalar, i| { |
| 4910 | var buf: Value.ElemValueBuffer = undefined; | 3757 | const elem_val = try val.elemValue(mod, i); |
| 4911 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3758 | scalar.* = try (try expScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4912 | scalar.* = try expScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 4913 | } | 3759 | } |
| 4914 | return Value.Tag.aggregate.create(arena, result_data); | 3760 | return (try mod.intern(.{ .aggregate = .{ |
| 3761 | .ty = float_type.toIntern(), | ||
| 3762 | .storage = .{ .elems = result_data }, | ||
| 3763 | } })).toValue(); | ||
| 4915 | } | 3764 | } |
| 4916 | return expScalar(val, float_type, arena, target); | 3765 | return expScalar(val, float_type, mod); |
| 4917 | } | 3766 | } |
| 4918 | 3767 | ||
| 4919 | pub fn expScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3768 | pub fn expScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 4920 | switch (float_type.floatBits(target)) { | 3769 | const target = mod.getTarget(); |
| 4921 | 16 => { | 3770 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4922 | const f = val.toFloat(f16); | 3771 | 16 => .{ .f16 = @exp(val.toFloat(f16, mod)) }, |
| 4923 | return Value.Tag.float_16.create(arena, @exp(f)); | 3772 | 32 => .{ .f32 = @exp(val.toFloat(f32, mod)) }, |
| 4924 | }, | 3773 | 64 => .{ .f64 = @exp(val.toFloat(f64, mod)) }, |
| 4925 | 32 => { | 3774 | 80 => .{ .f80 = @exp(val.toFloat(f80, mod)) }, |
| 4926 | const f = val.toFloat(f32); | 3775 | 128 => .{ .f128 = @exp(val.toFloat(f128, mod)) }, |
| 4927 | return Value.Tag.float_32.create(arena, @exp(f)); | ||
| 4928 | }, | ||
| 4929 | 64 => { | ||
| 4930 | const f = val.toFloat(f64); | ||
| 4931 | return Value.Tag.float_64.create(arena, @exp(f)); | ||
| 4932 | }, | ||
| 4933 | 80 => { | ||
| 4934 | const f = val.toFloat(f80); | ||
| 4935 | return Value.Tag.float_80.create(arena, @exp(f)); | ||
| 4936 | }, | ||
| 4937 | 128 => { | ||
| 4938 | const f = val.toFloat(f128); | ||
| 4939 | return Value.Tag.float_128.create(arena, @exp(f)); | ||
| 4940 | }, | ||
| 4941 | else => unreachable, | 3776 | else => unreachable, |
| 4942 | } | 3777 | }; |
| 3778 | return (try mod.intern(.{ .float = .{ | ||
| 3779 | .ty = float_type.toIntern(), | ||
| 3780 | .storage = storage, | ||
| 3781 | } })).toValue(); | ||
| 4943 | } | 3782 | } |
| 4944 | 3783 | ||
| 4945 | pub fn exp2(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3784 | pub fn exp2(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4946 | const target = mod.getTarget(); | 3785 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4947 | if (float_type.zigTypeTag() == .Vector) { | 3786 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4948 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3787 | const scalar_ty = float_type.scalarType(mod); |
| 4949 | for (result_data, 0..) |*scalar, i| { | 3788 | for (result_data, 0..) |*scalar, i| { |
| 4950 | var buf: Value.ElemValueBuffer = undefined; | 3789 | const elem_val = try val.elemValue(mod, i); |
| 4951 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3790 | scalar.* = try (try exp2Scalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4952 | scalar.* = try exp2Scalar(elem_val, float_type.scalarType(), arena, target); | ||
| 4953 | } | 3791 | } |
| 4954 | return Value.Tag.aggregate.create(arena, result_data); | 3792 | return (try mod.intern(.{ .aggregate = .{ |
| 3793 | .ty = float_type.toIntern(), | ||
| 3794 | .storage = .{ .elems = result_data }, | ||
| 3795 | } })).toValue(); | ||
| 4955 | } | 3796 | } |
| 4956 | return exp2Scalar(val, float_type, arena, target); | 3797 | return exp2Scalar(val, float_type, mod); |
| 4957 | } | 3798 | } |
| 4958 | 3799 | ||
| 4959 | pub fn exp2Scalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3800 | pub fn exp2Scalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 4960 | switch (float_type.floatBits(target)) { | 3801 | const target = mod.getTarget(); |
| 4961 | 16 => { | 3802 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 4962 | const f = val.toFloat(f16); | 3803 | 16 => .{ .f16 = @exp2(val.toFloat(f16, mod)) }, |
| 4963 | return Value.Tag.float_16.create(arena, @exp2(f)); | 3804 | 32 => .{ .f32 = @exp2(val.toFloat(f32, mod)) }, |
| 4964 | }, | 3805 | 64 => .{ .f64 = @exp2(val.toFloat(f64, mod)) }, |
| 4965 | 32 => { | 3806 | 80 => .{ .f80 = @exp2(val.toFloat(f80, mod)) }, |
| 4966 | const f = val.toFloat(f32); | 3807 | 128 => .{ .f128 = @exp2(val.toFloat(f128, mod)) }, |
| 4967 | return Value.Tag.float_32.create(arena, @exp2(f)); | ||
| 4968 | }, | ||
| 4969 | 64 => { | ||
| 4970 | const f = val.toFloat(f64); | ||
| 4971 | return Value.Tag.float_64.create(arena, @exp2(f)); | ||
| 4972 | }, | ||
| 4973 | 80 => { | ||
| 4974 | const f = val.toFloat(f80); | ||
| 4975 | return Value.Tag.float_80.create(arena, @exp2(f)); | ||
| 4976 | }, | ||
| 4977 | 128 => { | ||
| 4978 | const f = val.toFloat(f128); | ||
| 4979 | return Value.Tag.float_128.create(arena, @exp2(f)); | ||
| 4980 | }, | ||
| 4981 | else => unreachable, | 3808 | else => unreachable, |
| 4982 | } | 3809 | }; |
| 3810 | return (try mod.intern(.{ .float = .{ | ||
| 3811 | .ty = float_type.toIntern(), | ||
| 3812 | .storage = storage, | ||
| 3813 | } })).toValue(); | ||
| 4983 | } | 3814 | } |
| 4984 | 3815 | ||
| 4985 | pub fn log(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3816 | pub fn log(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 4986 | const target = mod.getTarget(); | 3817 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 4987 | if (float_type.zigTypeTag() == .Vector) { | 3818 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 4988 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3819 | const scalar_ty = float_type.scalarType(mod); |
| 4989 | for (result_data, 0..) |*scalar, i| { | 3820 | for (result_data, 0..) |*scalar, i| { |
| 4990 | var buf: Value.ElemValueBuffer = undefined; | 3821 | const elem_val = try val.elemValue(mod, i); |
| 4991 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3822 | scalar.* = try (try logScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 4992 | scalar.* = try logScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 4993 | } | 3823 | } |
| 4994 | return Value.Tag.aggregate.create(arena, result_data); | 3824 | return (try mod.intern(.{ .aggregate = .{ |
| 3825 | .ty = float_type.toIntern(), | ||
| 3826 | .storage = .{ .elems = result_data }, | ||
| 3827 | } })).toValue(); | ||
| 4995 | } | 3828 | } |
| 4996 | return logScalar(val, float_type, arena, target); | 3829 | return logScalar(val, float_type, mod); |
| 4997 | } | 3830 | } |
| 4998 | 3831 | ||
| 4999 | pub fn logScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3832 | pub fn logScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 5000 | switch (float_type.floatBits(target)) { | 3833 | const target = mod.getTarget(); |
| 5001 | 16 => { | 3834 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 5002 | const f = val.toFloat(f16); | 3835 | 16 => .{ .f16 = @log(val.toFloat(f16, mod)) }, |
| 5003 | return Value.Tag.float_16.create(arena, @log(f)); | 3836 | 32 => .{ .f32 = @log(val.toFloat(f32, mod)) }, |
| 5004 | }, | 3837 | 64 => .{ .f64 = @log(val.toFloat(f64, mod)) }, |
| 5005 | 32 => { | 3838 | 80 => .{ .f80 = @log(val.toFloat(f80, mod)) }, |
| 5006 | const f = val.toFloat(f32); | 3839 | 128 => .{ .f128 = @log(val.toFloat(f128, mod)) }, |
| 5007 | return Value.Tag.float_32.create(arena, @log(f)); | ||
| 5008 | }, | ||
| 5009 | 64 => { | ||
| 5010 | const f = val.toFloat(f64); | ||
| 5011 | return Value.Tag.float_64.create(arena, @log(f)); | ||
| 5012 | }, | ||
| 5013 | 80 => { | ||
| 5014 | const f = val.toFloat(f80); | ||
| 5015 | return Value.Tag.float_80.create(arena, @log(f)); | ||
| 5016 | }, | ||
| 5017 | 128 => { | ||
| 5018 | const f = val.toFloat(f128); | ||
| 5019 | return Value.Tag.float_128.create(arena, @log(f)); | ||
| 5020 | }, | ||
| 5021 | else => unreachable, | 3840 | else => unreachable, |
| 5022 | } | 3841 | }; |
| 3842 | return (try mod.intern(.{ .float = .{ | ||
| 3843 | .ty = float_type.toIntern(), | ||
| 3844 | .storage = storage, | ||
| 3845 | } })).toValue(); | ||
| 5023 | } | 3846 | } |
| 5024 | 3847 | ||
| 5025 | pub fn log2(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3848 | pub fn log2(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5026 | const target = mod.getTarget(); | 3849 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 5027 | if (float_type.zigTypeTag() == .Vector) { | 3850 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 5028 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3851 | const scalar_ty = float_type.scalarType(mod); |
| 5029 | for (result_data, 0..) |*scalar, i| { | 3852 | for (result_data, 0..) |*scalar, i| { |
| 5030 | var buf: Value.ElemValueBuffer = undefined; | 3853 | const elem_val = try val.elemValue(mod, i); |
| 5031 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3854 | scalar.* = try (try log2Scalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 5032 | scalar.* = try log2Scalar(elem_val, float_type.scalarType(), arena, target); | ||
| 5033 | } | 3855 | } |
| 5034 | return Value.Tag.aggregate.create(arena, result_data); | 3856 | return (try mod.intern(.{ .aggregate = .{ |
| 3857 | .ty = float_type.toIntern(), | ||
| 3858 | .storage = .{ .elems = result_data }, | ||
| 3859 | } })).toValue(); | ||
| 5035 | } | 3860 | } |
| 5036 | return log2Scalar(val, float_type, arena, target); | 3861 | return log2Scalar(val, float_type, mod); |
| 5037 | } | 3862 | } |
| 5038 | 3863 | ||
| 5039 | pub fn log2Scalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3864 | pub fn log2Scalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 5040 | switch (float_type.floatBits(target)) { | 3865 | const target = mod.getTarget(); |
| 5041 | 16 => { | 3866 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 5042 | const f = val.toFloat(f16); | 3867 | 16 => .{ .f16 = @log2(val.toFloat(f16, mod)) }, |
| 5043 | return Value.Tag.float_16.create(arena, @log2(f)); | 3868 | 32 => .{ .f32 = @log2(val.toFloat(f32, mod)) }, |
| 5044 | }, | 3869 | 64 => .{ .f64 = @log2(val.toFloat(f64, mod)) }, |
| 5045 | 32 => { | 3870 | 80 => .{ .f80 = @log2(val.toFloat(f80, mod)) }, |
| 5046 | const f = val.toFloat(f32); | 3871 | 128 => .{ .f128 = @log2(val.toFloat(f128, mod)) }, |
| 5047 | return Value.Tag.float_32.create(arena, @log2(f)); | ||
| 5048 | }, | ||
| 5049 | 64 => { | ||
| 5050 | const f = val.toFloat(f64); | ||
| 5051 | return Value.Tag.float_64.create(arena, @log2(f)); | ||
| 5052 | }, | ||
| 5053 | 80 => { | ||
| 5054 | const f = val.toFloat(f80); | ||
| 5055 | return Value.Tag.float_80.create(arena, @log2(f)); | ||
| 5056 | }, | ||
| 5057 | 128 => { | ||
| 5058 | const f = val.toFloat(f128); | ||
| 5059 | return Value.Tag.float_128.create(arena, @log2(f)); | ||
| 5060 | }, | ||
| 5061 | else => unreachable, | 3872 | else => unreachable, |
| 5062 | } | 3873 | }; |
| 3874 | return (try mod.intern(.{ .float = .{ | ||
| 3875 | .ty = float_type.toIntern(), | ||
| 3876 | .storage = storage, | ||
| 3877 | } })).toValue(); | ||
| 5063 | } | 3878 | } |
| 5064 | 3879 | ||
| 5065 | pub fn log10(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3880 | pub fn log10(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5066 | const target = mod.getTarget(); | 3881 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 5067 | if (float_type.zigTypeTag() == .Vector) { | 3882 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 5068 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3883 | const scalar_ty = float_type.scalarType(mod); |
| 5069 | for (result_data, 0..) |*scalar, i| { | 3884 | for (result_data, 0..) |*scalar, i| { |
| 5070 | var buf: Value.ElemValueBuffer = undefined; | 3885 | const elem_val = try val.elemValue(mod, i); |
| 5071 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3886 | scalar.* = try (try log10Scalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 5072 | scalar.* = try log10Scalar(elem_val, float_type.scalarType(), arena, target); | ||
| 5073 | } | 3887 | } |
| 5074 | return Value.Tag.aggregate.create(arena, result_data); | 3888 | return (try mod.intern(.{ .aggregate = .{ |
| 3889 | .ty = float_type.toIntern(), | ||
| 3890 | .storage = .{ .elems = result_data }, | ||
| 3891 | } })).toValue(); | ||
| 5075 | } | 3892 | } |
| 5076 | return log10Scalar(val, float_type, arena, target); | 3893 | return log10Scalar(val, float_type, mod); |
| 5077 | } | 3894 | } |
| 5078 | 3895 | ||
| 5079 | pub fn log10Scalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3896 | pub fn log10Scalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 5080 | switch (float_type.floatBits(target)) { | 3897 | const target = mod.getTarget(); |
| 5081 | 16 => { | 3898 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 5082 | const f = val.toFloat(f16); | 3899 | 16 => .{ .f16 = @log10(val.toFloat(f16, mod)) }, |
| 5083 | return Value.Tag.float_16.create(arena, @log10(f)); | 3900 | 32 => .{ .f32 = @log10(val.toFloat(f32, mod)) }, |
| 5084 | }, | 3901 | 64 => .{ .f64 = @log10(val.toFloat(f64, mod)) }, |
| 5085 | 32 => { | 3902 | 80 => .{ .f80 = @log10(val.toFloat(f80, mod)) }, |
| 5086 | const f = val.toFloat(f32); | 3903 | 128 => .{ .f128 = @log10(val.toFloat(f128, mod)) }, |
| 5087 | return Value.Tag.float_32.create(arena, @log10(f)); | ||
| 5088 | }, | ||
| 5089 | 64 => { | ||
| 5090 | const f = val.toFloat(f64); | ||
| 5091 | return Value.Tag.float_64.create(arena, @log10(f)); | ||
| 5092 | }, | ||
| 5093 | 80 => { | ||
| 5094 | const f = val.toFloat(f80); | ||
| 5095 | return Value.Tag.float_80.create(arena, @log10(f)); | ||
| 5096 | }, | ||
| 5097 | 128 => { | ||
| 5098 | const f = val.toFloat(f128); | ||
| 5099 | return Value.Tag.float_128.create(arena, @log10(f)); | ||
| 5100 | }, | ||
| 5101 | else => unreachable, | 3904 | else => unreachable, |
| 5102 | } | 3905 | }; |
| 3906 | return (try mod.intern(.{ .float = .{ | ||
| 3907 | .ty = float_type.toIntern(), | ||
| 3908 | .storage = storage, | ||
| 3909 | } })).toValue(); | ||
| 5103 | } | 3910 | } |
| 5104 | 3911 | ||
| 5105 | pub fn fabs(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3912 | pub fn fabs(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5106 | const target = mod.getTarget(); | 3913 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 5107 | if (float_type.zigTypeTag() == .Vector) { | 3914 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 5108 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3915 | const scalar_ty = float_type.scalarType(mod); |
| 5109 | for (result_data, 0..) |*scalar, i| { | 3916 | for (result_data, 0..) |*scalar, i| { |
| 5110 | var buf: Value.ElemValueBuffer = undefined; | 3917 | const elem_val = try val.elemValue(mod, i); |
| 5111 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3918 | scalar.* = try (try fabsScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 5112 | scalar.* = try fabsScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 5113 | } | 3919 | } |
| 5114 | return Value.Tag.aggregate.create(arena, result_data); | 3920 | return (try mod.intern(.{ .aggregate = .{ |
| 3921 | .ty = float_type.toIntern(), | ||
| 3922 | .storage = .{ .elems = result_data }, | ||
| 3923 | } })).toValue(); | ||
| 5115 | } | 3924 | } |
| 5116 | return fabsScalar(val, float_type, arena, target); | 3925 | return fabsScalar(val, float_type, mod); |
| 5117 | } | 3926 | } |
| 5118 | 3927 | ||
| 5119 | pub fn fabsScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3928 | pub fn fabsScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 5120 | switch (float_type.floatBits(target)) { | 3929 | const target = mod.getTarget(); |
| 5121 | 16 => { | 3930 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 5122 | const f = val.toFloat(f16); | 3931 | 16 => .{ .f16 = @fabs(val.toFloat(f16, mod)) }, |
| 5123 | return Value.Tag.float_16.create(arena, @fabs(f)); | 3932 | 32 => .{ .f32 = @fabs(val.toFloat(f32, mod)) }, |
| 5124 | }, | 3933 | 64 => .{ .f64 = @fabs(val.toFloat(f64, mod)) }, |
| 5125 | 32 => { | 3934 | 80 => .{ .f80 = @fabs(val.toFloat(f80, mod)) }, |
| 5126 | const f = val.toFloat(f32); | 3935 | 128 => .{ .f128 = @fabs(val.toFloat(f128, mod)) }, |
| 5127 | return Value.Tag.float_32.create(arena, @fabs(f)); | ||
| 5128 | }, | ||
| 5129 | 64 => { | ||
| 5130 | const f = val.toFloat(f64); | ||
| 5131 | return Value.Tag.float_64.create(arena, @fabs(f)); | ||
| 5132 | }, | ||
| 5133 | 80 => { | ||
| 5134 | const f = val.toFloat(f80); | ||
| 5135 | return Value.Tag.float_80.create(arena, @fabs(f)); | ||
| 5136 | }, | ||
| 5137 | 128 => { | ||
| 5138 | const f = val.toFloat(f128); | ||
| 5139 | return Value.Tag.float_128.create(arena, @fabs(f)); | ||
| 5140 | }, | ||
| 5141 | else => unreachable, | 3936 | else => unreachable, |
| 5142 | } | 3937 | }; |
| 3938 | return (try mod.intern(.{ .float = .{ | ||
| 3939 | .ty = float_type.toIntern(), | ||
| 3940 | .storage = storage, | ||
| 3941 | } })).toValue(); | ||
| 5143 | } | 3942 | } |
| 5144 | 3943 | ||
| 5145 | pub fn floor(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3944 | pub fn floor(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5146 | const target = mod.getTarget(); | 3945 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 5147 | if (float_type.zigTypeTag() == .Vector) { | 3946 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 5148 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3947 | const scalar_ty = float_type.scalarType(mod); |
| 5149 | for (result_data, 0..) |*scalar, i| { | 3948 | for (result_data, 0..) |*scalar, i| { |
| 5150 | var buf: Value.ElemValueBuffer = undefined; | 3949 | const elem_val = try val.elemValue(mod, i); |
| 5151 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3950 | scalar.* = try (try floorScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 5152 | scalar.* = try floorScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 5153 | } | 3951 | } |
| 5154 | return Value.Tag.aggregate.create(arena, result_data); | 3952 | return (try mod.intern(.{ .aggregate = .{ |
| 3953 | .ty = float_type.toIntern(), | ||
| 3954 | .storage = .{ .elems = result_data }, | ||
| 3955 | } })).toValue(); | ||
| 5155 | } | 3956 | } |
| 5156 | return floorScalar(val, float_type, arena, target); | 3957 | return floorScalar(val, float_type, mod); |
| 5157 | } | 3958 | } |
| 5158 | 3959 | ||
| 5159 | pub fn floorScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3960 | pub fn floorScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 5160 | switch (float_type.floatBits(target)) { | 3961 | const target = mod.getTarget(); |
| 5161 | 16 => { | 3962 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 5162 | const f = val.toFloat(f16); | 3963 | 16 => .{ .f16 = @floor(val.toFloat(f16, mod)) }, |
| 5163 | return Value.Tag.float_16.create(arena, @floor(f)); | 3964 | 32 => .{ .f32 = @floor(val.toFloat(f32, mod)) }, |
| 5164 | }, | 3965 | 64 => .{ .f64 = @floor(val.toFloat(f64, mod)) }, |
| 5165 | 32 => { | 3966 | 80 => .{ .f80 = @floor(val.toFloat(f80, mod)) }, |
| 5166 | const f = val.toFloat(f32); | 3967 | 128 => .{ .f128 = @floor(val.toFloat(f128, mod)) }, |
| 5167 | return Value.Tag.float_32.create(arena, @floor(f)); | ||
| 5168 | }, | ||
| 5169 | 64 => { | ||
| 5170 | const f = val.toFloat(f64); | ||
| 5171 | return Value.Tag.float_64.create(arena, @floor(f)); | ||
| 5172 | }, | ||
| 5173 | 80 => { | ||
| 5174 | const f = val.toFloat(f80); | ||
| 5175 | return Value.Tag.float_80.create(arena, @floor(f)); | ||
| 5176 | }, | ||
| 5177 | 128 => { | ||
| 5178 | const f = val.toFloat(f128); | ||
| 5179 | return Value.Tag.float_128.create(arena, @floor(f)); | ||
| 5180 | }, | ||
| 5181 | else => unreachable, | 3968 | else => unreachable, |
| 5182 | } | 3969 | }; |
| 3970 | return (try mod.intern(.{ .float = .{ | ||
| 3971 | .ty = float_type.toIntern(), | ||
| 3972 | .storage = storage, | ||
| 3973 | } })).toValue(); | ||
| 5183 | } | 3974 | } |
| 5184 | 3975 | ||
| 5185 | pub fn ceil(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 3976 | pub fn ceil(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5186 | const target = mod.getTarget(); | 3977 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 5187 | if (float_type.zigTypeTag() == .Vector) { | 3978 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 5188 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 3979 | const scalar_ty = float_type.scalarType(mod); |
| 5189 | for (result_data, 0..) |*scalar, i| { | 3980 | for (result_data, 0..) |*scalar, i| { |
| 5190 | var buf: Value.ElemValueBuffer = undefined; | 3981 | const elem_val = try val.elemValue(mod, i); |
| 5191 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 3982 | scalar.* = try (try ceilScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 5192 | scalar.* = try ceilScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 5193 | } | 3983 | } |
| 5194 | return Value.Tag.aggregate.create(arena, result_data); | 3984 | return (try mod.intern(.{ .aggregate = .{ |
| 3985 | .ty = float_type.toIntern(), | ||
| 3986 | .storage = .{ .elems = result_data }, | ||
| 3987 | } })).toValue(); | ||
| 5195 | } | 3988 | } |
| 5196 | return ceilScalar(val, float_type, arena, target); | 3989 | return ceilScalar(val, float_type, mod); |
| 5197 | } | 3990 | } |
| 5198 | 3991 | ||
| 5199 | pub fn ceilScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 3992 | pub fn ceilScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 5200 | switch (float_type.floatBits(target)) { | 3993 | const target = mod.getTarget(); |
| 5201 | 16 => { | 3994 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 5202 | const f = val.toFloat(f16); | 3995 | 16 => .{ .f16 = @ceil(val.toFloat(f16, mod)) }, |
| 5203 | return Value.Tag.float_16.create(arena, @ceil(f)); | 3996 | 32 => .{ .f32 = @ceil(val.toFloat(f32, mod)) }, |
| 5204 | }, | 3997 | 64 => .{ .f64 = @ceil(val.toFloat(f64, mod)) }, |
| 5205 | 32 => { | 3998 | 80 => .{ .f80 = @ceil(val.toFloat(f80, mod)) }, |
| 5206 | const f = val.toFloat(f32); | 3999 | 128 => .{ .f128 = @ceil(val.toFloat(f128, mod)) }, |
| 5207 | return Value.Tag.float_32.create(arena, @ceil(f)); | ||
| 5208 | }, | ||
| 5209 | 64 => { | ||
| 5210 | const f = val.toFloat(f64); | ||
| 5211 | return Value.Tag.float_64.create(arena, @ceil(f)); | ||
| 5212 | }, | ||
| 5213 | 80 => { | ||
| 5214 | const f = val.toFloat(f80); | ||
| 5215 | return Value.Tag.float_80.create(arena, @ceil(f)); | ||
| 5216 | }, | ||
| 5217 | 128 => { | ||
| 5218 | const f = val.toFloat(f128); | ||
| 5219 | return Value.Tag.float_128.create(arena, @ceil(f)); | ||
| 5220 | }, | ||
| 5221 | else => unreachable, | 4000 | else => unreachable, |
| 5222 | } | 4001 | }; |
| 4002 | return (try mod.intern(.{ .float = .{ | ||
| 4003 | .ty = float_type.toIntern(), | ||
| 4004 | .storage = storage, | ||
| 4005 | } })).toValue(); | ||
| 5223 | } | 4006 | } |
| 5224 | 4007 | ||
| 5225 | pub fn round(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 4008 | pub fn round(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5226 | const target = mod.getTarget(); | 4009 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 5227 | if (float_type.zigTypeTag() == .Vector) { | 4010 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 5228 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 4011 | const scalar_ty = float_type.scalarType(mod); |
| 5229 | for (result_data, 0..) |*scalar, i| { | 4012 | for (result_data, 0..) |*scalar, i| { |
| 5230 | var buf: Value.ElemValueBuffer = undefined; | 4013 | const elem_val = try val.elemValue(mod, i); |
| 5231 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 4014 | scalar.* = try (try roundScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 5232 | scalar.* = try roundScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 5233 | } | 4015 | } |
| 5234 | return Value.Tag.aggregate.create(arena, result_data); | 4016 | return (try mod.intern(.{ .aggregate = .{ |
| 4017 | .ty = float_type.toIntern(), | ||
| 4018 | .storage = .{ .elems = result_data }, | ||
| 4019 | } })).toValue(); | ||
| 5235 | } | 4020 | } |
| 5236 | return roundScalar(val, float_type, arena, target); | 4021 | return roundScalar(val, float_type, mod); |
| 5237 | } | 4022 | } |
| 5238 | 4023 | ||
| 5239 | pub fn roundScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 4024 | pub fn roundScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 5240 | switch (float_type.floatBits(target)) { | 4025 | const target = mod.getTarget(); |
| 5241 | 16 => { | 4026 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 5242 | const f = val.toFloat(f16); | 4027 | 16 => .{ .f16 = @round(val.toFloat(f16, mod)) }, |
| 5243 | return Value.Tag.float_16.create(arena, @round(f)); | 4028 | 32 => .{ .f32 = @round(val.toFloat(f32, mod)) }, |
| 5244 | }, | 4029 | 64 => .{ .f64 = @round(val.toFloat(f64, mod)) }, |
| 5245 | 32 => { | 4030 | 80 => .{ .f80 = @round(val.toFloat(f80, mod)) }, |
| 5246 | const f = val.toFloat(f32); | 4031 | 128 => .{ .f128 = @round(val.toFloat(f128, mod)) }, |
| 5247 | return Value.Tag.float_32.create(arena, @round(f)); | ||
| 5248 | }, | ||
| 5249 | 64 => { | ||
| 5250 | const f = val.toFloat(f64); | ||
| 5251 | return Value.Tag.float_64.create(arena, @round(f)); | ||
| 5252 | }, | ||
| 5253 | 80 => { | ||
| 5254 | const f = val.toFloat(f80); | ||
| 5255 | return Value.Tag.float_80.create(arena, @round(f)); | ||
| 5256 | }, | ||
| 5257 | 128 => { | ||
| 5258 | const f = val.toFloat(f128); | ||
| 5259 | return Value.Tag.float_128.create(arena, @round(f)); | ||
| 5260 | }, | ||
| 5261 | else => unreachable, | 4032 | else => unreachable, |
| 5262 | } | 4033 | }; |
| 4034 | return (try mod.intern(.{ .float = .{ | ||
| 4035 | .ty = float_type.toIntern(), | ||
| 4036 | .storage = storage, | ||
| 4037 | } })).toValue(); | ||
| 5263 | } | 4038 | } |
| 5264 | 4039 | ||
| 5265 | pub fn trunc(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { | 4040 | pub fn trunc(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { |
| 5266 | const target = mod.getTarget(); | 4041 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 5267 | if (float_type.zigTypeTag() == .Vector) { | 4042 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 5268 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 4043 | const scalar_ty = float_type.scalarType(mod); |
| 5269 | for (result_data, 0..) |*scalar, i| { | 4044 | for (result_data, 0..) |*scalar, i| { |
| 5270 | var buf: Value.ElemValueBuffer = undefined; | 4045 | const elem_val = try val.elemValue(mod, i); |
| 5271 | const elem_val = val.elemValueBuffer(mod, i, &buf); | 4046 | scalar.* = try (try truncScalar(elem_val, scalar_ty, mod)).intern(scalar_ty, mod); |
| 5272 | scalar.* = try truncScalar(elem_val, float_type.scalarType(), arena, target); | ||
| 5273 | } | 4047 | } |
| 5274 | return Value.Tag.aggregate.create(arena, result_data); | 4048 | return (try mod.intern(.{ .aggregate = .{ |
| 4049 | .ty = float_type.toIntern(), | ||
| 4050 | .storage = .{ .elems = result_data }, | ||
| 4051 | } })).toValue(); | ||
| 5275 | } | 4052 | } |
| 5276 | return truncScalar(val, float_type, arena, target); | 4053 | return truncScalar(val, float_type, mod); |
| 5277 | } | 4054 | } |
| 5278 | 4055 | ||
| 5279 | pub fn truncScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { | 4056 | pub fn truncScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { |
| 5280 | switch (float_type.floatBits(target)) { | 4057 | const target = mod.getTarget(); |
| 5281 | 16 => { | 4058 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 5282 | const f = val.toFloat(f16); | 4059 | 16 => .{ .f16 = @trunc(val.toFloat(f16, mod)) }, |
| 5283 | return Value.Tag.float_16.create(arena, @trunc(f)); | 4060 | 32 => .{ .f32 = @trunc(val.toFloat(f32, mod)) }, |
| 5284 | }, | 4061 | 64 => .{ .f64 = @trunc(val.toFloat(f64, mod)) }, |
| 5285 | 32 => { | 4062 | 80 => .{ .f80 = @trunc(val.toFloat(f80, mod)) }, |
| 5286 | const f = val.toFloat(f32); | 4063 | 128 => .{ .f128 = @trunc(val.toFloat(f128, mod)) }, |
| 5287 | return Value.Tag.float_32.create(arena, @trunc(f)); | ||
| 5288 | }, | ||
| 5289 | 64 => { | ||
| 5290 | const f = val.toFloat(f64); | ||
| 5291 | return Value.Tag.float_64.create(arena, @trunc(f)); | ||
| 5292 | }, | ||
| 5293 | 80 => { | ||
| 5294 | const f = val.toFloat(f80); | ||
| 5295 | return Value.Tag.float_80.create(arena, @trunc(f)); | ||
| 5296 | }, | ||
| 5297 | 128 => { | ||
| 5298 | const f = val.toFloat(f128); | ||
| 5299 | return Value.Tag.float_128.create(arena, @trunc(f)); | ||
| 5300 | }, | ||
| 5301 | else => unreachable, | 4064 | else => unreachable, |
| 5302 | } | 4065 | }; |
| 4066 | return (try mod.intern(.{ .float = .{ | ||
| 4067 | .ty = float_type.toIntern(), | ||
| 4068 | .storage = storage, | ||
| 4069 | } })).toValue(); | ||
| 5303 | } | 4070 | } |
| 5304 | 4071 | ||
| 5305 | pub fn mulAdd( | 4072 | pub fn mulAdd( |
| ... | @@ -5310,28 +4077,21 @@ pub const Value = extern union { | ... | @@ -5310,28 +4077,21 @@ pub const Value = extern union { |
| 5310 | arena: Allocator, | 4077 | arena: Allocator, |
| 5311 | mod: *Module, | 4078 | mod: *Module, |
| 5312 | ) !Value { | 4079 | ) !Value { |
| 5313 | const target = mod.getTarget(); | 4080 | if (float_type.zigTypeTag(mod) == .Vector) { |
| 5314 | if (float_type.zigTypeTag() == .Vector) { | 4081 | const result_data = try arena.alloc(InternPool.Index, float_type.vectorLen(mod)); |
| 5315 | const result_data = try arena.alloc(Value, float_type.vectorLen()); | 4082 | const scalar_ty = float_type.scalarType(mod); |
| 5316 | for (result_data, 0..) |*scalar, i| { | 4083 | for (result_data, 0..) |*scalar, i| { |
| 5317 | var mulend1_buf: Value.ElemValueBuffer = undefined; | 4084 | const mulend1_elem = try mulend1.elemValue(mod, i); |
| 5318 | const mulend1_elem = mulend1.elemValueBuffer(mod, i, &mulend1_buf); | 4085 | const mulend2_elem = try mulend2.elemValue(mod, i); |
| 5319 | var mulend2_buf: Value.ElemValueBuffer = undefined; | 4086 | const addend_elem = try addend.elemValue(mod, i); |
| 5320 | const mulend2_elem = mulend2.elemValueBuffer(mod, i, &mulend2_buf); | 4087 | scalar.* = try (try mulAddScalar(scalar_ty, mulend1_elem, mulend2_elem, addend_elem, mod)).intern(scalar_ty, mod); |
| 5321 | var addend_buf: Value.ElemValueBuffer = undefined; | ||
| 5322 | const addend_elem = addend.elemValueBuffer(mod, i, &addend_buf); | ||
| 5323 | scalar.* = try mulAddScalar( | ||
| 5324 | float_type.scalarType(), | ||
| 5325 | mulend1_elem, | ||
| 5326 | mulend2_elem, | ||
| 5327 | addend_elem, | ||
| 5328 | arena, | ||
| 5329 | target, | ||
| 5330 | ); | ||
| 5331 | } | 4088 | } |
| 5332 | return Value.Tag.aggregate.create(arena, result_data); | 4089 | return (try mod.intern(.{ .aggregate = .{ |
| 4090 | .ty = float_type.toIntern(), | ||
| 4091 | .storage = .{ .elems = result_data }, | ||
| 4092 | } })).toValue(); | ||
| 5333 | } | 4093 | } |
| 5334 | return mulAddScalar(float_type, mulend1, mulend2, addend, arena, target); | 4094 | return mulAddScalar(float_type, mulend1, mulend2, addend, mod); |
| 5335 | } | 4095 | } |
| 5336 | 4096 | ||
| 5337 | pub fn mulAddScalar( | 4097 | pub fn mulAddScalar( |
| ... | @@ -5339,54 +4099,33 @@ pub const Value = extern union { | ... | @@ -5339,54 +4099,33 @@ pub const Value = extern union { |
| 5339 | mulend1: Value, | 4099 | mulend1: Value, |
| 5340 | mulend2: Value, | 4100 | mulend2: Value, |
| 5341 | addend: Value, | 4101 | addend: Value, |
| 5342 | arena: Allocator, | 4102 | mod: *Module, |
| 5343 | target: Target, | ||
| 5344 | ) Allocator.Error!Value { | 4103 | ) Allocator.Error!Value { |
| 5345 | switch (float_type.floatBits(target)) { | 4104 | const target = mod.getTarget(); |
| 5346 | 16 => { | 4105 | const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { |
| 5347 | const m1 = mulend1.toFloat(f16); | 4106 | 16 => .{ .f16 = @mulAdd(f16, mulend1.toFloat(f16, mod), mulend2.toFloat(f16, mod), addend.toFloat(f16, mod)) }, |
| 5348 | const m2 = mulend2.toFloat(f16); | 4107 | 32 => .{ .f32 = @mulAdd(f32, mulend1.toFloat(f32, mod), mulend2.toFloat(f32, mod), addend.toFloat(f32, mod)) }, |
| 5349 | const a = addend.toFloat(f16); | 4108 | 64 => .{ .f64 = @mulAdd(f64, mulend1.toFloat(f64, mod), mulend2.toFloat(f64, mod), addend.toFloat(f64, mod)) }, |
| 5350 | return Value.Tag.float_16.create(arena, @mulAdd(f16, m1, m2, a)); | 4109 | 80 => .{ .f80 = @mulAdd(f80, mulend1.toFloat(f80, mod), mulend2.toFloat(f80, mod), addend.toFloat(f80, mod)) }, |
| 5351 | }, | 4110 | 128 => .{ .f128 = @mulAdd(f128, mulend1.toFloat(f128, mod), mulend2.toFloat(f128, mod), addend.toFloat(f128, mod)) }, |
| 5352 | 32 => { | ||
| 5353 | const m1 = mulend1.toFloat(f32); | ||
| 5354 | const m2 = mulend2.toFloat(f32); | ||
| 5355 | const a = addend.toFloat(f32); | ||
| 5356 | return Value.Tag.float_32.create(arena, @mulAdd(f32, m1, m2, a)); | ||
| 5357 | }, | ||
| 5358 | 64 => { | ||
| 5359 | const m1 = mulend1.toFloat(f64); | ||
| 5360 | const m2 = mulend2.toFloat(f64); | ||
| 5361 | const a = addend.toFloat(f64); | ||
| 5362 | return Value.Tag.float_64.create(arena, @mulAdd(f64, m1, m2, a)); | ||
| 5363 | }, | ||
| 5364 | 80 => { | ||
| 5365 | const m1 = mulend1.toFloat(f80); | ||
| 5366 | const m2 = mulend2.toFloat(f80); | ||
| 5367 | const a = addend.toFloat(f80); | ||
| 5368 | return Value.Tag.float_80.create(arena, @mulAdd(f80, m1, m2, a)); | ||
| 5369 | }, | ||
| 5370 | 128 => { | ||
| 5371 | const m1 = mulend1.toFloat(f128); | ||
| 5372 | const m2 = mulend2.toFloat(f128); | ||
| 5373 | const a = addend.toFloat(f128); | ||
| 5374 | return Value.Tag.float_128.create(arena, @mulAdd(f128, m1, m2, a)); | ||
| 5375 | }, | ||
| 5376 | else => unreachable, | 4111 | else => unreachable, |
| 5377 | } | 4112 | }; |
| 4113 | return (try mod.intern(.{ .float = .{ | ||
| 4114 | .ty = float_type.toIntern(), | ||
| 4115 | .storage = storage, | ||
| 4116 | } })).toValue(); | ||
| 5378 | } | 4117 | } |
| 5379 | 4118 | ||
| 5380 | /// If the value is represented in-memory as a series of bytes that all | 4119 | /// If the value is represented in-memory as a series of bytes that all |
| 5381 | /// have the same value, return that byte value, otherwise null. | 4120 | /// have the same value, return that byte value, otherwise null. |
| 5382 | pub fn hasRepeatedByteRepr(val: Value, ty: Type, mod: *Module, value_buffer: *Payload.U64) !?Value { | 4121 | pub fn hasRepeatedByteRepr(val: Value, ty: Type, mod: *Module) !?Value { |
| 5383 | const target = mod.getTarget(); | 4122 | const abi_size = std.math.cast(usize, ty.abiSize(mod)) orelse return null; |
| 5384 | const abi_size = std.math.cast(usize, ty.abiSize(target)) orelse return null; | ||
| 5385 | assert(abi_size >= 1); | 4123 | assert(abi_size >= 1); |
| 5386 | const byte_buffer = try mod.gpa.alloc(u8, abi_size); | 4124 | const byte_buffer = try mod.gpa.alloc(u8, abi_size); |
| 5387 | defer mod.gpa.free(byte_buffer); | 4125 | defer mod.gpa.free(byte_buffer); |
| 5388 | 4126 | ||
| 5389 | writeToMemory(val, ty, mod, byte_buffer) catch |err| switch (err) { | 4127 | writeToMemory(val, ty, mod, byte_buffer) catch |err| switch (err) { |
| 4128 | error.OutOfMemory => return error.OutOfMemory, | ||
| 5390 | error.ReinterpretDeclRef => return null, | 4129 | error.ReinterpretDeclRef => return null, |
| 5391 | // TODO: The writeToMemory function was originally created for the purpose | 4130 | // TODO: The writeToMemory function was originally created for the purpose |
| 5392 | // of comptime pointer casting. However, it is now additionally being used | 4131 | // of comptime pointer casting. However, it is now additionally being used |
| ... | @@ -5400,118 +4139,22 @@ pub const Value = extern union { | ... | @@ -5400,118 +4139,22 @@ pub const Value = extern union { |
| 5400 | for (byte_buffer[1..]) |byte| { | 4139 | for (byte_buffer[1..]) |byte| { |
| 5401 | if (byte != first_byte) return null; | 4140 | if (byte != first_byte) return null; |
| 5402 | } | 4141 | } |
| 5403 | value_buffer.* = .{ | 4142 | return try mod.intValue(Type.u8, first_byte); |
| 5404 | .base = .{ .tag = .int_u64 }, | 4143 | } |
| 5405 | .data = first_byte, | 4144 | |
| 5406 | }; | 4145 | pub fn isGenericPoison(val: Value) bool { |
| 5407 | return initPayload(&value_buffer.base); | 4146 | return val.toIntern() == .generic_poison; |
| 5408 | } | 4147 | } |
| 5409 | 4148 | ||
| 5410 | /// This type is not copyable since it may contain pointers to its inner data. | 4149 | /// This type is not copyable since it may contain pointers to its inner data. |
| 5411 | pub const Payload = struct { | 4150 | pub const Payload = struct { |
| 5412 | tag: Tag, | 4151 | tag: Tag, |
| 5413 | 4152 | ||
| 5414 | pub const U32 = struct { | 4153 | pub const Slice = struct { |
| 5415 | base: Payload, | ||
| 5416 | data: u32, | ||
| 5417 | }; | ||
| 5418 | |||
| 5419 | pub const U64 = struct { | ||
| 5420 | base: Payload, | ||
| 5421 | data: u64, | ||
| 5422 | }; | ||
| 5423 | |||
| 5424 | pub const I64 = struct { | ||
| 5425 | base: Payload, | ||
| 5426 | data: i64, | ||
| 5427 | }; | ||
| 5428 | |||
| 5429 | pub const BigInt = struct { | ||
| 5430 | base: Payload, | ||
| 5431 | data: []const std.math.big.Limb, | ||
| 5432 | |||
| 5433 | pub fn asBigInt(self: BigInt) BigIntConst { | ||
| 5434 | const positive = switch (self.base.tag) { | ||
| 5435 | .int_big_positive => true, | ||
| 5436 | .int_big_negative => false, | ||
| 5437 | else => unreachable, | ||
| 5438 | }; | ||
| 5439 | return BigIntConst{ .limbs = self.data, .positive = positive }; | ||
| 5440 | } | ||
| 5441 | }; | ||
| 5442 | |||
| 5443 | pub const Function = struct { | ||
| 5444 | base: Payload, | ||
| 5445 | data: *Module.Fn, | ||
| 5446 | }; | ||
| 5447 | |||
| 5448 | pub const ExternFn = struct { | ||
| 5449 | base: Payload, | ||
| 5450 | data: *Module.ExternFn, | ||
| 5451 | }; | ||
| 5452 | |||
| 5453 | pub const Decl = struct { | ||
| 5454 | base: Payload, | ||
| 5455 | data: Module.Decl.Index, | ||
| 5456 | }; | ||
| 5457 | |||
| 5458 | pub const Variable = struct { | ||
| 5459 | base: Payload, | ||
| 5460 | data: *Module.Var, | ||
| 5461 | }; | ||
| 5462 | |||
| 5463 | pub const SubValue = struct { | ||
| 5464 | base: Payload, | ||
| 5465 | data: Value, | ||
| 5466 | }; | ||
| 5467 | |||
| 5468 | pub const DeclRefMut = struct { | ||
| 5469 | pub const base_tag = Tag.decl_ref_mut; | ||
| 5470 | |||
| 5471 | base: Payload = Payload{ .tag = base_tag }, | ||
| 5472 | data: Data, | ||
| 5473 | |||
| 5474 | pub const Data = struct { | ||
| 5475 | decl_index: Module.Decl.Index, | ||
| 5476 | runtime_index: RuntimeIndex, | ||
| 5477 | }; | ||
| 5478 | }; | ||
| 5479 | |||
| 5480 | pub const PayloadPtr = struct { | ||
| 5481 | base: Payload, | ||
| 5482 | data: struct { | ||
| 5483 | container_ptr: Value, | ||
| 5484 | container_ty: Type, | ||
| 5485 | }, | ||
| 5486 | }; | ||
| 5487 | |||
| 5488 | pub const ComptimeFieldPtr = struct { | ||
| 5489 | base: Payload, | 4154 | base: Payload, |
| 5490 | data: struct { | 4155 | data: struct { |
| 5491 | field_val: Value, | 4156 | ptr: Value, |
| 5492 | field_ty: Type, | 4157 | len: Value, |
| 5493 | }, | ||
| 5494 | }; | ||
| 5495 | |||
| 5496 | pub const ElemPtr = struct { | ||
| 5497 | pub const base_tag = Tag.elem_ptr; | ||
| 5498 | |||
| 5499 | base: Payload = Payload{ .tag = base_tag }, | ||
| 5500 | data: struct { | ||
| 5501 | array_ptr: Value, | ||
| 5502 | elem_ty: Type, | ||
| 5503 | index: usize, | ||
| 5504 | }, | ||
| 5505 | }; | ||
| 5506 | |||
| 5507 | pub const FieldPtr = struct { | ||
| 5508 | pub const base_tag = Tag.field_ptr; | ||
| 5509 | |||
| 5510 | base: Payload = Payload{ .tag = base_tag }, | ||
| 5511 | data: struct { | ||
| 5512 | container_ptr: Value, | ||
| 5513 | container_ty: Type, | ||
| 5514 | field_index: usize, | ||
| 5515 | }, | 4158 | }, |
| 5516 | }; | 4159 | }; |
| 5517 | 4160 | ||
| ... | @@ -5521,9 +4164,9 @@ pub const Value = extern union { | ... | @@ -5521,9 +4164,9 @@ pub const Value = extern union { |
| 5521 | data: []const u8, | 4164 | data: []const u8, |
| 5522 | }; | 4165 | }; |
| 5523 | 4166 | ||
| 5524 | pub const StrLit = struct { | 4167 | pub const SubValue = struct { |
| 5525 | base: Payload, | 4168 | base: Payload, |
| 5526 | data: Module.StringLiteralContext.Key, | 4169 | data: Value, |
| 5527 | }; | 4170 | }; |
| 5528 | 4171 | ||
| 5529 | pub const Aggregate = struct { | 4172 | pub const Aggregate = struct { |
| ... | @@ -5533,156 +4176,42 @@ pub const Value = extern union { | ... | @@ -5533,156 +4176,42 @@ pub const Value = extern union { |
| 5533 | data: []Value, | 4176 | data: []Value, |
| 5534 | }; | 4177 | }; |
| 5535 | 4178 | ||
| 5536 | pub const Slice = struct { | ||
| 5537 | base: Payload, | ||
| 5538 | data: struct { | ||
| 5539 | ptr: Value, | ||
| 5540 | len: Value, | ||
| 5541 | }, | ||
| 5542 | |||
| 5543 | pub const ptr_index = 0; | ||
| 5544 | pub const len_index = 1; | ||
| 5545 | }; | ||
| 5546 | |||
| 5547 | pub const Ty = struct { | ||
| 5548 | base: Payload, | ||
| 5549 | data: Type, | ||
| 5550 | }; | ||
| 5551 | |||
| 5552 | pub const IntType = struct { | ||
| 5553 | pub const base_tag = Tag.int_type; | ||
| 5554 | |||
| 5555 | base: Payload = Payload{ .tag = base_tag }, | ||
| 5556 | data: struct { | ||
| 5557 | bits: u16, | ||
| 5558 | signed: bool, | ||
| 5559 | }, | ||
| 5560 | }; | ||
| 5561 | |||
| 5562 | pub const Float_16 = struct { | ||
| 5563 | pub const base_tag = Tag.float_16; | ||
| 5564 | |||
| 5565 | base: Payload = .{ .tag = base_tag }, | ||
| 5566 | data: f16, | ||
| 5567 | }; | ||
| 5568 | |||
| 5569 | pub const Float_32 = struct { | ||
| 5570 | pub const base_tag = Tag.float_32; | ||
| 5571 | |||
| 5572 | base: Payload = .{ .tag = base_tag }, | ||
| 5573 | data: f32, | ||
| 5574 | }; | ||
| 5575 | |||
| 5576 | pub const Float_64 = struct { | ||
| 5577 | pub const base_tag = Tag.float_64; | ||
| 5578 | |||
| 5579 | base: Payload = .{ .tag = base_tag }, | ||
| 5580 | data: f64, | ||
| 5581 | }; | ||
| 5582 | |||
| 5583 | pub const Float_80 = struct { | ||
| 5584 | pub const base_tag = Tag.float_80; | ||
| 5585 | |||
| 5586 | base: Payload = .{ .tag = base_tag }, | ||
| 5587 | data: f80, | ||
| 5588 | }; | ||
| 5589 | |||
| 5590 | pub const Float_128 = struct { | ||
| 5591 | pub const base_tag = Tag.float_128; | ||
| 5592 | |||
| 5593 | base: Payload = .{ .tag = base_tag }, | ||
| 5594 | data: f128, | ||
| 5595 | }; | ||
| 5596 | |||
| 5597 | pub const Error = struct { | ||
| 5598 | base: Payload = .{ .tag = .@"error" }, | ||
| 5599 | data: struct { | ||
| 5600 | /// `name` is owned by `Module` and will be valid for the entire | ||
| 5601 | /// duration of the compilation. | ||
| 5602 | /// TODO revisit this when we have the concept of the error tag type | ||
| 5603 | name: []const u8, | ||
| 5604 | }, | ||
| 5605 | }; | ||
| 5606 | |||
| 5607 | pub const InferredAlloc = struct { | ||
| 5608 | pub const base_tag = Tag.inferred_alloc; | ||
| 5609 | |||
| 5610 | base: Payload = .{ .tag = base_tag }, | ||
| 5611 | data: struct { | ||
| 5612 | /// The value stored in the inferred allocation. This will go into | ||
| 5613 | /// peer type resolution. This is stored in a separate list so that | ||
| 5614 | /// the items are contiguous in memory and thus can be passed to | ||
| 5615 | /// `Module.resolvePeerTypes`. | ||
| 5616 | prongs: std.MultiArrayList(struct { | ||
| 5617 | /// The dummy instruction used as a peer to resolve the type. | ||
| 5618 | /// Although this has a redundant type with placeholder, this is | ||
| 5619 | /// needed in addition because it may be a constant value, which | ||
| 5620 | /// affects peer type resolution. | ||
| 5621 | stored_inst: Air.Inst.Ref, | ||
| 5622 | /// The bitcast instruction used as a placeholder when the | ||
| 5623 | /// new result pointer type is not yet known. | ||
| 5624 | placeholder: Air.Inst.Index, | ||
| 5625 | }) = .{}, | ||
| 5626 | /// 0 means ABI-aligned. | ||
| 5627 | alignment: u32, | ||
| 5628 | }, | ||
| 5629 | }; | ||
| 5630 | |||
| 5631 | pub const InferredAllocComptime = struct { | ||
| 5632 | pub const base_tag = Tag.inferred_alloc_comptime; | ||
| 5633 | |||
| 5634 | base: Payload = .{ .tag = base_tag }, | ||
| 5635 | data: struct { | ||
| 5636 | decl_index: Module.Decl.Index, | ||
| 5637 | /// 0 means ABI-aligned. | ||
| 5638 | alignment: u32, | ||
| 5639 | }, | ||
| 5640 | }; | ||
| 5641 | |||
| 5642 | pub const Union = struct { | 4179 | pub const Union = struct { |
| 5643 | pub const base_tag = Tag.@"union"; | 4180 | pub const base_tag = Tag.@"union"; |
| 5644 | 4181 | ||
| 5645 | base: Payload = .{ .tag = base_tag }, | 4182 | base: Payload = .{ .tag = base_tag }, |
| 5646 | data: struct { | 4183 | data: Data, |
| 4184 | |||
| 4185 | pub const Data = struct { | ||
| 5647 | tag: Value, | 4186 | tag: Value, |
| 5648 | val: Value, | 4187 | val: Value, |
| 5649 | }, | 4188 | }; |
| 5650 | }; | 4189 | }; |
| 5651 | }; | 4190 | }; |
| 5652 | 4191 | ||
| 5653 | /// Big enough to fit any non-BigInt value | 4192 | pub const BigIntSpace = InternPool.Key.Int.Storage.BigIntSpace; |
| 5654 | pub const BigIntSpace = struct { | ||
| 5655 | /// The +1 is headroom so that operations such as incrementing once or decrementing once | ||
| 5656 | /// are possible without using an allocator. | ||
| 5657 | limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb, | ||
| 5658 | }; | ||
| 5659 | 4193 | ||
| 5660 | pub const zero = initTag(.zero); | 4194 | pub const zero_usize: Value = .{ .ip_index = .zero_usize, .legacy = undefined }; |
| 5661 | pub const one = initTag(.one); | 4195 | pub const zero_u8: Value = .{ .ip_index = .zero_u8, .legacy = undefined }; |
| 5662 | pub const negative_one: Value = .{ .ptr_otherwise = &negative_one_payload.base }; | 4196 | pub const zero_comptime_int: Value = .{ .ip_index = .zero, .legacy = undefined }; |
| 5663 | pub const undef = initTag(.undef); | 4197 | pub const one_comptime_int: Value = .{ .ip_index = .one, .legacy = undefined }; |
| 5664 | pub const @"void" = initTag(.void_value); | 4198 | pub const negative_one_comptime_int: Value = .{ .ip_index = .negative_one, .legacy = undefined }; |
| 5665 | pub const @"null" = initTag(.null_value); | 4199 | pub const undef: Value = .{ .ip_index = .undef, .legacy = undefined }; |
| 5666 | pub const @"false" = initTag(.bool_false); | 4200 | pub const @"void": Value = .{ .ip_index = .void_value, .legacy = undefined }; |
| 5667 | pub const @"true" = initTag(.bool_true); | 4201 | pub const @"null": Value = .{ .ip_index = .null_value, .legacy = undefined }; |
| 4202 | pub const @"false": Value = .{ .ip_index = .bool_false, .legacy = undefined }; | ||
| 4203 | pub const @"true": Value = .{ .ip_index = .bool_true, .legacy = undefined }; | ||
| 4204 | pub const @"unreachable": Value = .{ .ip_index = .unreachable_value, .legacy = undefined }; | ||
| 4205 | |||
| 4206 | pub const generic_poison: Value = .{ .ip_index = .generic_poison, .legacy = undefined }; | ||
| 4207 | pub const generic_poison_type: Value = .{ .ip_index = .generic_poison_type, .legacy = undefined }; | ||
| 4208 | pub const empty_struct: Value = .{ .ip_index = .empty_struct, .legacy = undefined }; | ||
| 5668 | 4209 | ||
| 5669 | pub fn makeBool(x: bool) Value { | 4210 | pub fn makeBool(x: bool) Value { |
| 5670 | return if (x) Value.true else Value.false; | 4211 | return if (x) Value.true else Value.false; |
| 5671 | } | 4212 | } |
| 5672 | 4213 | ||
| 5673 | pub fn boolToInt(x: bool) Value { | 4214 | pub const RuntimeIndex = InternPool.RuntimeIndex; |
| 5674 | return if (x) Value.one else Value.zero; | ||
| 5675 | } | ||
| 5676 | |||
| 5677 | pub const RuntimeIndex = enum(u32) { | ||
| 5678 | zero = 0, | ||
| 5679 | comptime_field_ptr = std.math.maxInt(u32), | ||
| 5680 | _, | ||
| 5681 | |||
| 5682 | pub fn increment(ri: *RuntimeIndex) void { | ||
| 5683 | ri.* = @intToEnum(RuntimeIndex, @enumToInt(ri.*) + 1); | ||
| 5684 | } | ||
| 5685 | }; | ||
| 5686 | 4215 | ||
| 5687 | /// This function is used in the debugger pretty formatters in tools/ to fetch the | 4216 | /// This function is used in the debugger pretty formatters in tools/ to fetch the |
| 5688 | /// Tag to Payload mapping to facilitate fancy debug printing for this type. | 4217 | /// Tag to Payload mapping to facilitate fancy debug printing for this type. |
| ... | @@ -5691,7 +4220,7 @@ pub const Value = extern union { | ... | @@ -5691,7 +4220,7 @@ pub const Value = extern union { |
| 5691 | var fields: [tags.len]std.builtin.Type.StructField = undefined; | 4220 | var fields: [tags.len]std.builtin.Type.StructField = undefined; |
| 5692 | for (&fields, tags) |*field, t| field.* = .{ | 4221 | for (&fields, tags) |*field, t| field.* = .{ |
| 5693 | .name = t.name, | 4222 | .name = t.name, |
| 5694 | .type = *if (t.value < Tag.no_payload_count) void else @field(Tag, t.name).Type(), | 4223 | .type = *@field(Tag, t.name).Type(), |
| 5695 | .default_value = null, | 4224 | .default_value = null, |
| 5696 | .is_comptime = false, | 4225 | .is_comptime = false, |
| 5697 | .alignment = 0, | 4226 | .alignment = 0, |
| ... | @@ -5713,8 +4242,3 @@ pub const Value = extern union { | ... | @@ -5713,8 +4242,3 @@ pub const Value = extern union { |
| 5713 | } | 4242 | } |
| 5714 | } | 4243 | } |
| 5715 | }; | 4244 | }; |
| 5716 | |||
| 5717 | var negative_one_payload: Value.Payload.I64 = .{ | ||
| 5718 | .base = .{ .tag = .int_i64 }, | ||
| 5719 | .data = -1, | ||
| 5720 | }; |
test/behavior/bugs/1381.zig+1| ... | @@ -17,6 +17,7 @@ test "union that needs padding bytes inside an array" { | ... | @@ -17,6 +17,7 @@ test "union that needs padding bytes inside an array" { |
| 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 18 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 18 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 19 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | 19 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 20 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | ||
| 20 | 21 | ||
| 21 | var as = [_]A{ | 22 | var as = [_]A{ |
| 22 | A{ .B = B{ .D = 1 } }, | 23 | A{ .B = B{ .D = 1 } }, |
test/behavior/bugs/6456.zig+1-1| ... | @@ -24,7 +24,7 @@ test "issue 6456" { | ... | @@ -24,7 +24,7 @@ test "issue 6456" { |
| 24 | .alignment = 0, | 24 | .alignment = 0, |
| 25 | .name = name, | 25 | .name = name, |
| 26 | .type = usize, | 26 | .type = usize, |
| 27 | .default_value = &@as(?usize, null), | 27 | .default_value = null, |
| 28 | .is_comptime = false, | 28 | .is_comptime = false, |
| 29 | }}; | 29 | }}; |
| 30 | } | 30 | } |
test/behavior/cast.zig+8-8| ... | @@ -746,8 +746,8 @@ test "peer type resolution: disjoint error sets" { | ... | @@ -746,8 +746,8 @@ test "peer type resolution: disjoint error sets" { |
| 746 | try expect(error_set_info == .ErrorSet); | 746 | try expect(error_set_info == .ErrorSet); |
| 747 | try expect(error_set_info.ErrorSet.?.len == 3); | 747 | try expect(error_set_info.ErrorSet.?.len == 3); |
| 748 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); | 748 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); |
| 749 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Three")); | 749 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two")); |
| 750 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two")); | 750 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three")); |
| 751 | } | 751 | } |
| 752 | 752 | ||
| 753 | { | 753 | { |
| ... | @@ -756,8 +756,8 @@ test "peer type resolution: disjoint error sets" { | ... | @@ -756,8 +756,8 @@ test "peer type resolution: disjoint error sets" { |
| 756 | try expect(error_set_info == .ErrorSet); | 756 | try expect(error_set_info == .ErrorSet); |
| 757 | try expect(error_set_info.ErrorSet.?.len == 3); | 757 | try expect(error_set_info.ErrorSet.?.len == 3); |
| 758 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); | 758 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); |
| 759 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Three")); | 759 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two")); |
| 760 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two")); | 760 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three")); |
| 761 | } | 761 | } |
| 762 | } | 762 | } |
| 763 | 763 | ||
| ... | @@ -778,8 +778,8 @@ test "peer type resolution: error union and error set" { | ... | @@ -778,8 +778,8 @@ test "peer type resolution: error union and error set" { |
| 778 | const error_set_info = @typeInfo(info.ErrorUnion.error_set); | 778 | const error_set_info = @typeInfo(info.ErrorUnion.error_set); |
| 779 | try expect(error_set_info.ErrorSet.?.len == 3); | 779 | try expect(error_set_info.ErrorSet.?.len == 3); |
| 780 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); | 780 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); |
| 781 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Three")); | 781 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two")); |
| 782 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two")); | 782 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three")); |
| 783 | } | 783 | } |
| 784 | 784 | ||
| 785 | { | 785 | { |
| ... | @@ -790,8 +790,8 @@ test "peer type resolution: error union and error set" { | ... | @@ -790,8 +790,8 @@ test "peer type resolution: error union and error set" { |
| 790 | const error_set_info = @typeInfo(info.ErrorUnion.error_set); | 790 | const error_set_info = @typeInfo(info.ErrorUnion.error_set); |
| 791 | try expect(error_set_info.ErrorSet.?.len == 3); | 791 | try expect(error_set_info.ErrorSet.?.len == 3); |
| 792 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); | 792 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); |
| 793 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Three")); | 793 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two")); |
| 794 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two")); | 794 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three")); |
| 795 | } | 795 | } |
| 796 | } | 796 | } |
| 797 | 797 |
test/behavior/type_info.zig+2-2| ... | @@ -214,8 +214,8 @@ test "type info: error set merged" { | ... | @@ -214,8 +214,8 @@ test "type info: error set merged" { |
| 214 | try expect(error_set_info == .ErrorSet); | 214 | try expect(error_set_info == .ErrorSet); |
| 215 | try expect(error_set_info.ErrorSet.?.len == 3); | 215 | try expect(error_set_info.ErrorSet.?.len == 3); |
| 216 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); | 216 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[0].name, "One")); |
| 217 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Three")); | 217 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[1].name, "Two")); |
| 218 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Two")); | 218 | try expect(mem.eql(u8, error_set_info.ErrorSet.?[2].name, "Three")); |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | test "type info: enum info" { | 221 | test "type info: enum info" { |
test/cases/compile_errors/access_non-existent_member_of_error_set.zig-1| ... | @@ -9,4 +9,3 @@ comptime { | ... | @@ -9,4 +9,3 @@ comptime { |
| 9 | // target=native | 9 | // target=native |
| 10 | // | 10 | // |
| 11 | // :3:18: error: no error named 'Bar' in 'error{A}' | 11 | // :3:18: error: no error named 'Bar' in 'error{A}' |
| 12 | // :1:13: note: error set declared here |
test/cases/compile_errors/compile_log_statement_inside_function_which_must_be_comptime_evaluated.zig+1-1| ... | @@ -14,4 +14,4 @@ export fn entry() void { | ... | @@ -14,4 +14,4 @@ export fn entry() void { |
| 14 | // :2:5: error: found compile log statement | 14 | // :2:5: error: found compile log statement |
| 15 | // | 15 | // |
| 16 | // Compile Log Output: | 16 | // Compile Log Output: |
| 17 | // @as(*const [3:0]u8, "i32\x00") | 17 | // @as(*const [3:0]u8, "i32") |
test/cases/compile_errors/explicit_error_set_cast_known_at_comptime_violates_error_sets.zig+3-4| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const Set1 = error {A, B}; | 1 | const Set1 = error{ A, B }; |
| 2 | const Set2 = error {A, C}; | 2 | const Set2 = error{ A, C }; |
| 3 | comptime { | 3 | comptime { |
| 4 | var x = Set1.B; | 4 | var x = Set1.B; |
| 5 | var y = @errSetCast(Set2, x); | 5 | var y = @errSetCast(Set2, x); |
| ... | @@ -10,5 +10,4 @@ comptime { | ... | @@ -10,5 +10,4 @@ comptime { |
| 10 | // backend=stage2 | 10 | // backend=stage2 |
| 11 | // target=native | 11 | // target=native |
| 12 | // | 12 | // |
| 13 | // :5:13: error: 'error.B' not a member of error set 'error{A,C}' | 13 | // :5:13: error: 'error.B' not a member of error set 'error{C,A}' |
| 14 | // :2:14: note: error set declared here |
test/cases/compile_errors/implicit_cast_of_error_set_not_a_subset.zig+3-3| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const Set1 = error{A, B}; | 1 | const Set1 = error{ A, B }; |
| 2 | const Set2 = error{A, C}; | 2 | const Set2 = error{ A, C }; |
| 3 | export fn entry() void { | 3 | export fn entry() void { |
| 4 | foo(Set1.B); | 4 | foo(Set1.B); |
| 5 | } | 5 | } |
| ... | @@ -12,5 +12,5 @@ fn foo(set1: Set1) void { | ... | @@ -12,5 +12,5 @@ fn foo(set1: Set1) void { |
| 12 | // backend=stage2 | 12 | // backend=stage2 |
| 13 | // target=native | 13 | // target=native |
| 14 | // | 14 | // |
| 15 | // :7:19: error: expected type 'error{A,C}', found 'error{A,B}' | 15 | // :7:19: error: expected type 'error{C,A}', found 'error{A,B}' |
| 16 | // :7:19: note: 'error.B' not a member of destination error set | 16 | // :7:19: note: 'error.B' not a member of destination error set |
test/cases/compile_errors/int_to_err_non_global_invalid_number.zig+1-2| ... | @@ -16,5 +16,4 @@ comptime { | ... | @@ -16,5 +16,4 @@ comptime { |
| 16 | // backend=llvm | 16 | // backend=llvm |
| 17 | // target=native | 17 | // target=native |
| 18 | // | 18 | // |
| 19 | // :11:13: error: 'error.B' not a member of error set 'error{A,C}' | 19 | // :11:13: error: 'error.B' not a member of error set 'error{C,A}' |
| 20 | // :5:14: note: error set declared here |
test/cases/compile_errors/invalid_non-exhaustive_enum_to_union.zig+1-1| ... | @@ -24,5 +24,5 @@ export fn bar() void { | ... | @@ -24,5 +24,5 @@ export fn bar() void { |
| 24 | // | 24 | // |
| 25 | // :12:16: error: runtime coercion to union 'tmp.U' from non-exhaustive enum | 25 | // :12:16: error: runtime coercion to union 'tmp.U' from non-exhaustive enum |
| 26 | // :1:11: note: enum declared here | 26 | // :1:11: note: enum declared here |
| 27 | // :17:16: error: union 'tmp.U' has no tag with value '15' | 27 | // :17:16: error: union 'tmp.U' has no tag with value '@intToEnum(tmp.E, 15)' |
| 28 | // :6:11: note: union declared here | 28 | // :6:11: note: union declared here |
test/cases/compile_errors/pointer_attributes_checked_when_coercing_pointer_to_anon_literal.zig+2-2| ... | @@ -16,9 +16,9 @@ comptime { | ... | @@ -16,9 +16,9 @@ comptime { |
| 16 | // backend=stage2 | 16 | // backend=stage2 |
| 17 | // target=native | 17 | // target=native |
| 18 | // | 18 | // |
| 19 | // :2:29: error: expected type '[][]const u8', found '*const tuple{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}' | 19 | // :2:29: error: expected type '[][]const u8', found '*const struct{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}' |
| 20 | // :2:29: note: cast discards const qualifier | 20 | // :2:29: note: cast discards const qualifier |
| 21 | // :6:31: error: expected type '*[2][]const u8', found '*const tuple{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}' | 21 | // :6:31: error: expected type '*[2][]const u8', found '*const struct{comptime *const [5:0]u8 = "hello", comptime *const [5:0]u8 = "world"}' |
| 22 | // :6:31: note: cast discards const qualifier | 22 | // :6:31: note: cast discards const qualifier |
| 23 | // :11:19: error: expected type '*tmp.S', found '*const struct{comptime a: comptime_int = 2}' | 23 | // :11:19: error: expected type '*tmp.S', found '*const struct{comptime a: comptime_int = 2}' |
| 24 | // :11:19: note: cast discards const qualifier | 24 | // :11:19: note: cast discards const qualifier |
test/cases/compile_errors/return_invalid_type_from_test.zig+4-2| ... | @@ -1,8 +1,10 @@ | ... | @@ -1,8 +1,10 @@ |
| 1 | test "example" { return 1; } | 1 | test "example" { |
| 2 | return 1; | ||
| 3 | } | ||
| 2 | 4 | ||
| 3 | // error | 5 | // error |
| 4 | // backend=stage2 | 6 | // backend=stage2 |
| 5 | // target=native | 7 | // target=native |
| 6 | // is_test=1 | 8 | // is_test=1 |
| 7 | // | 9 | // |
| 8 | // :1:25: error: expected type '@typeInfo(@typeInfo(@TypeOf(tmp.test.example)).Fn.return_type.?).ErrorUnion.error_set!void', found 'comptime_int' | ||
| \ No newline at end of file | |||
| 10 | // :2:12: error: expected type 'anyerror!void', found 'comptime_int' | ||
test/cases/compile_errors/tagName_on_invalid_value_of_non-exhaustive_enum.zig+2-2| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | test "enum" { | 1 | test "enum" { |
| 2 | const E = enum(u8) {A, B, _}; | 2 | const E = enum(u8) { A, B, _ }; |
| 3 | _ = @tagName(@intToEnum(E, 5)); | 3 | _ = @tagName(@intToEnum(E, 5)); |
| 4 | } | 4 | } |
| 5 | 5 | ||
| ... | @@ -8,5 +8,5 @@ test "enum" { | ... | @@ -8,5 +8,5 @@ test "enum" { |
| 8 | // target=native | 8 | // target=native |
| 9 | // is_test=1 | 9 | // is_test=1 |
| 10 | // | 10 | // |
| 11 | // :3:9: error: no field with value '5' in enum 'test.enum.E' | 11 | // :3:9: error: no field with value '@intToEnum(tmp.test.enum.E, 5)' in enum 'test.enum.E' |
| 12 | // :2:15: note: declared here | 12 | // :2:15: note: declared here |
test/cases/compile_errors/tuple_init_edge_cases.zig+1-1| ... | @@ -41,4 +41,4 @@ pub export fn entry5() void { | ... | @@ -41,4 +41,4 @@ pub export fn entry5() void { |
| 41 | // :12:14: error: missing tuple field with index 1 | 41 | // :12:14: error: missing tuple field with index 1 |
| 42 | // :17:14: error: missing tuple field with index 1 | 42 | // :17:14: error: missing tuple field with index 1 |
| 43 | // :29:14: error: expected at most 2 tuple fields; found 3 | 43 | // :29:14: error: expected at most 2 tuple fields; found 3 |
| 44 | // :34:30: error: index '2' out of bounds of tuple 'tuple{comptime comptime_int = 123, u32}' | 44 | // :34:30: error: index '2' out of bounds of tuple 'struct{comptime comptime_int = 123, u32}' |
test/cases/compile_errors/type_mismatch_with_tuple_concatenation.zig+1-1| ... | @@ -7,4 +7,4 @@ export fn entry() void { | ... | @@ -7,4 +7,4 @@ export fn entry() void { |
| 7 | // backend=stage2 | 7 | // backend=stage2 |
| 8 | // target=native | 8 | // target=native |
| 9 | // | 9 | // |
| 10 | // :3:11: error: expected type '@TypeOf(.{})', found 'tuple{comptime comptime_int = 1, comptime comptime_int = 2, comptime comptime_int = 3}' | 10 | // :3:11: error: expected type '@TypeOf(.{})', found 'struct{comptime comptime_int = 1, comptime comptime_int = 2, comptime comptime_int = 3}' |
tools/lldb_pretty_printers.py+114-19| ... | @@ -115,7 +115,7 @@ class zig_Slice_SynthProvider: | ... | @@ -115,7 +115,7 @@ class zig_Slice_SynthProvider: |
| 115 | try: return int(name.removeprefix('[').removesuffix(']')) | 115 | try: return int(name.removeprefix('[').removesuffix(']')) |
| 116 | except: return -1 | 116 | except: return -1 |
| 117 | def get_child_at_index(self, index): | 117 | def get_child_at_index(self, index): |
| 118 | if index < 0 or index >= self.len: return None | 118 | if index not in range(self.len): return None |
| 119 | try: return self.ptr.CreateChildAtOffset('[%d]' % index, index * self.elem_size, self.elem_type) | 119 | try: return self.ptr.CreateChildAtOffset('[%d]' % index, index * self.elem_size, self.elem_type) |
| 120 | except: return None | 120 | except: return None |
| 121 | 121 | ||
| ... | @@ -176,7 +176,7 @@ class zig_TaggedUnion_SynthProvider: | ... | @@ -176,7 +176,7 @@ class zig_TaggedUnion_SynthProvider: |
| 176 | def get_child_index(self, name): | 176 | def get_child_index(self, name): |
| 177 | try: return ('tag', 'payload').index(name) | 177 | try: return ('tag', 'payload').index(name) |
| 178 | except: return -1 | 178 | except: return -1 |
| 179 | def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index >= 0 and index < 2 else None | 179 | def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None |
| 180 | 180 | ||
| 181 | # Define Zig Standard Library | 181 | # Define Zig Standard Library |
| 182 | 182 | ||
| ... | @@ -196,7 +196,7 @@ class std_SegmentedList_SynthProvider: | ... | @@ -196,7 +196,7 @@ class std_SegmentedList_SynthProvider: |
| 196 | except: return -1 | 196 | except: return -1 |
| 197 | def get_child_at_index(self, index): | 197 | def get_child_at_index(self, index): |
| 198 | try: | 198 | try: |
| 199 | if index < 0 or index >= self.len: return None | 199 | if index not in range(self.len): return None |
| 200 | prealloc_item_count = len(self.prealloc_segment) | 200 | prealloc_item_count = len(self.prealloc_segment) |
| 201 | if index < prealloc_item_count: return self.prealloc_segment.child[index] | 201 | if index < prealloc_item_count: return self.prealloc_segment.child[index] |
| 202 | prealloc_exp = prealloc_item_count.bit_length() - 1 | 202 | prealloc_exp = prealloc_item_count.bit_length() - 1 |
| ... | @@ -231,7 +231,7 @@ class std_MultiArrayList_SynthProvider: | ... | @@ -231,7 +231,7 @@ class std_MultiArrayList_SynthProvider: |
| 231 | except: return -1 | 231 | except: return -1 |
| 232 | def get_child_at_index(self, index): | 232 | def get_child_at_index(self, index): |
| 233 | try: | 233 | try: |
| 234 | if index < 0 or index >= self.len: return None | 234 | if index not in range(self.len): return None |
| 235 | offset = 0 | 235 | offset = 0 |
| 236 | data = lldb.SBData() | 236 | data = lldb.SBData() |
| 237 | for field in self.entry_type.fields: | 237 | for field in self.entry_type.fields: |
| ... | @@ -266,7 +266,7 @@ class std_MultiArrayList_Slice_SynthProvider: | ... | @@ -266,7 +266,7 @@ class std_MultiArrayList_Slice_SynthProvider: |
| 266 | except: return -1 | 266 | except: return -1 |
| 267 | def get_child_at_index(self, index): | 267 | def get_child_at_index(self, index): |
| 268 | try: | 268 | try: |
| 269 | if index < 0 or index >= self.len: return None | 269 | if index not in range(self.len): return None |
| 270 | data = lldb.SBData() | 270 | data = lldb.SBData() |
| 271 | for field in self.entry_type.fields: | 271 | for field in self.entry_type.fields: |
| 272 | field_type = field.type.GetPointeeType() | 272 | field_type = field.type.GetPointeeType() |
| ... | @@ -328,7 +328,7 @@ class std_Entry_SynthProvider: | ... | @@ -328,7 +328,7 @@ class std_Entry_SynthProvider: |
| 328 | def has_children(self): return self.num_children() != 0 | 328 | def has_children(self): return self.num_children() != 0 |
| 329 | def num_children(self): return len(self.children) | 329 | def num_children(self): return len(self.children) |
| 330 | def get_child_index(self, name): return self.indices.get(name) | 330 | def get_child_index(self, name): return self.indices.get(name) |
| 331 | def get_child_at_index(self, index): return self.children[index].deref if index >= 0 and index < len(self.children) else None | 331 | def get_child_at_index(self, index): return self.children[index].deref if index in range(len(self.children)) else None |
| 332 | 332 | ||
| 333 | # Define Zig Stage2 Compiler | 333 | # Define Zig Stage2 Compiler |
| 334 | 334 | ||
| ... | @@ -345,11 +345,17 @@ class TagAndPayload_SynthProvider: | ... | @@ -345,11 +345,17 @@ class TagAndPayload_SynthProvider: |
| 345 | def get_child_index(self, name): | 345 | def get_child_index(self, name): |
| 346 | try: return ('tag', 'payload').index(name) | 346 | try: return ('tag', 'payload').index(name) |
| 347 | except: return -1 | 347 | except: return -1 |
| 348 | def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index >= 0 and index < 2 else None | 348 | def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None |
| 349 | 349 | ||
| 350 | def Inst_Ref_SummaryProvider(value, _=None): | 350 | def Zir_Inst__Zir_Inst_Ref_SummaryProvider(value, _=None): |
| 351 | members = value.type.enum_members | 351 | members = value.type.enum_members |
| 352 | return value if any(value.unsigned == member.unsigned for member in members) else 'instructions[%d]' % (value.unsigned - len(members)) | 352 | # ignore .var_args_param_type and .none |
| 353 | return value if any(value.unsigned == member.unsigned for member in members) else 'instructions[%d]' % (value.unsigned + 2 - len(members)) | ||
| 354 | |||
| 355 | def Air_Inst__Air_Inst_Ref_SummaryProvider(value, _=None): | ||
| 356 | members = value.type.enum_members | ||
| 357 | # ignore .var_args_param_type and .none | ||
| 358 | return value if any(value.unsigned == member.unsigned for member in members) else 'instructions[%d]' % (value.unsigned + 2 - len(members)) | ||
| 353 | 359 | ||
| 354 | class Module_Decl__Module_Decl_Index_SynthProvider: | 360 | class Module_Decl__Module_Decl_Index_SynthProvider: |
| 355 | def __init__(self, value, _=None): self.value = value | 361 | def __init__(self, value, _=None): self.value = value |
| ... | @@ -359,7 +365,7 @@ class Module_Decl__Module_Decl_Index_SynthProvider: | ... | @@ -359,7 +365,7 @@ class Module_Decl__Module_Decl_Index_SynthProvider: |
| 359 | mod = frame.FindVariable('mod') or frame.FindVariable('module') | 365 | mod = frame.FindVariable('mod') or frame.FindVariable('module') |
| 360 | if mod: break | 366 | if mod: break |
| 361 | else: return | 367 | else: return |
| 362 | self.ptr = mod.GetChildMemberWithName('allocated_decls').GetChildAtIndex(self.value.unsigned).Clone('decl') | 368 | self.ptr = mod.GetChildMemberWithName('allocated_decls').GetChildAtIndex(self.value.unsigned).address_of.Clone('decl') |
| 363 | except: pass | 369 | except: pass |
| 364 | def has_children(self): return True | 370 | def has_children(self): return True |
| 365 | def num_children(self): return 1 | 371 | def num_children(self): return 1 |
| ... | @@ -392,7 +398,7 @@ class TagOrPayloadPtr_SynthProvider: | ... | @@ -392,7 +398,7 @@ class TagOrPayloadPtr_SynthProvider: |
| 392 | def get_child_index(self, name): | 398 | def get_child_index(self, name): |
| 393 | try: return ('tag', 'payload').index(name) | 399 | try: return ('tag', 'payload').index(name) |
| 394 | except: return -1 | 400 | except: return -1 |
| 395 | def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index >= 0 and index < 2 else None | 401 | def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None |
| 396 | 402 | ||
| 397 | def Module_Decl_name(decl): | 403 | def Module_Decl_name(decl): |
| 398 | error = lldb.SBError() | 404 | error = lldb.SBError() |
| ... | @@ -407,6 +413,89 @@ def Module_Decl_RenderFullyQualifiedName(decl): return '.'.join((Module_Namespac | ... | @@ -407,6 +413,89 @@ def Module_Decl_RenderFullyQualifiedName(decl): return '.'.join((Module_Namespac |
| 407 | 413 | ||
| 408 | def OwnerDecl_RenderFullyQualifiedName(payload): return Module_Decl_RenderFullyQualifiedName(payload.GetChildMemberWithName('owner_decl').GetChildMemberWithName('decl')) | 414 | def OwnerDecl_RenderFullyQualifiedName(payload): return Module_Decl_RenderFullyQualifiedName(payload.GetChildMemberWithName('owner_decl').GetChildMemberWithName('decl')) |
| 409 | 415 | ||
| 416 | def InternPool_Find(thread): | ||
| 417 | for frame in thread: | ||
| 418 | ip = frame.FindVariable('ip') or frame.FindVariable('intern_pool') | ||
| 419 | if ip: return ip | ||
| 420 | mod = frame.FindVariable('mod') or frame.FindVariable('module') | ||
| 421 | if mod: | ||
| 422 | ip = mod.GetChildMemberWithName('intern_pool') | ||
| 423 | if ip: return ip | ||
| 424 | |||
| 425 | class InternPool_Index_SynthProvider: | ||
| 426 | def __init__(self, value, _=None): self.value = value | ||
| 427 | def update(self): | ||
| 428 | try: | ||
| 429 | index_type = self.value.type | ||
| 430 | for helper in self.value.target.FindFunctions('%s.dbHelper' % index_type.name, lldb.eFunctionNameTypeFull): | ||
| 431 | ptr_self_type, ptr_tag_to_encoding_map_type = helper.function.type.GetFunctionArgumentTypes() | ||
| 432 | if ptr_self_type.GetPointeeType() == index_type: break | ||
| 433 | else: return | ||
| 434 | tag_to_encoding_map = {field.name: field.type for field in ptr_tag_to_encoding_map_type.GetPointeeType().fields} | ||
| 435 | |||
| 436 | ip = InternPool_Find(self.value.thread) | ||
| 437 | if not ip: return | ||
| 438 | self.item = ip.GetChildMemberWithName('items').GetChildAtIndex(self.value.unsigned) | ||
| 439 | extra = ip.GetChildMemberWithName('extra').GetChildMemberWithName('items') | ||
| 440 | self.tag = self.item.GetChildMemberWithName('tag').Clone('tag') | ||
| 441 | self.data = None | ||
| 442 | self.trailing = None | ||
| 443 | data = self.item.GetChildMemberWithName('data') | ||
| 444 | encoding_type = tag_to_encoding_map[self.tag.value] | ||
| 445 | dynamic_values = {} | ||
| 446 | for encoding_field in encoding_type.fields: | ||
| 447 | if encoding_field.name == 'data': | ||
| 448 | if encoding_field.type.IsPointerType(): | ||
| 449 | data_type = encoding_field.type.GetPointeeType() | ||
| 450 | extra_index = data.unsigned | ||
| 451 | self.data = extra.GetChildAtIndex(extra_index).Cast(data_type).Clone('data') | ||
| 452 | extra_index += data_type.num_fields | ||
| 453 | else: | ||
| 454 | self.data = data.Cast(encoding_field.type).Clone('data') | ||
| 455 | elif encoding_field.name == 'trailing': | ||
| 456 | trailing_data = lldb.SBData() | ||
| 457 | for trailing_field in encoding_field.type.fields: | ||
| 458 | trailing_data.Append(extra.GetChildAtIndex(extra_index).address_of.data) | ||
| 459 | trailing_len = dynamic_values['trailing.%s.len' % trailing_field.name].unsigned | ||
| 460 | trailing_data.Append(lldb.SBData.CreateDataFromInt(trailing_len, trailing_data.GetAddressByteSize())) | ||
| 461 | extra_index += trailing_len | ||
| 462 | self.trailing = self.data.CreateValueFromData('trailing', trailing_data, encoding_field.type) | ||
| 463 | else: | ||
| 464 | for path in encoding_field.type.GetPointeeType().name.removeprefix('%s::' % encoding_type.name).removeprefix('%s.' % encoding_type.name).partition('__')[0].split(' orelse '): | ||
| 465 | if path.startswith('data.'): | ||
| 466 | root = self.data | ||
| 467 | path = path[len('data'):] | ||
| 468 | else: return | ||
| 469 | dynamic_value = root.GetValueForExpressionPath(path) | ||
| 470 | if dynamic_value: | ||
| 471 | dynamic_values[encoding_field.name] = dynamic_value | ||
| 472 | break | ||
| 473 | except: pass | ||
| 474 | def has_children(self): return True | ||
| 475 | def num_children(self): return 2 + (self.trailing is not None) | ||
| 476 | def get_child_index(self, name): | ||
| 477 | try: return ('tag', 'data', 'trailing').index(name) | ||
| 478 | except: return -1 | ||
| 479 | def get_child_at_index(self, index): return (self.tag, self.data, self.trailing)[index] if index in range(3) else None | ||
| 480 | |||
| 481 | def InternPool_NullTerminatedString_SummaryProvider(value, _=None): | ||
| 482 | try: | ||
| 483 | ip = InternPool_Find(value.thread) | ||
| 484 | if not ip: return | ||
| 485 | items = ip.GetChildMemberWithName('string_bytes').GetChildMemberWithName('items') | ||
| 486 | b = bytearray() | ||
| 487 | i = 0 | ||
| 488 | while True: | ||
| 489 | x = items.GetChildAtIndex(value.unsigned + i).GetValueAsUnsigned() | ||
| 490 | if x == 0: break | ||
| 491 | b.append(x) | ||
| 492 | i += 1 | ||
| 493 | s = b.decode(encoding='utf8', errors='backslashreplace') | ||
| 494 | s1 = s if s.isprintable() else ''.join((c if c.isprintable() else '\\x%02x' % ord(c) for c in s)) | ||
| 495 | return '"%s"' % s1 | ||
| 496 | except: | ||
| 497 | pass | ||
| 498 | |||
| 410 | def type_Type_pointer(payload): | 499 | def type_Type_pointer(payload): |
| 411 | pointee_type = payload.GetChildMemberWithName('pointee_type') | 500 | pointee_type = payload.GetChildMemberWithName('pointee_type') |
| 412 | sentinel = payload.GetChildMemberWithName('sentinel').GetChildMemberWithName('child') | 501 | sentinel = payload.GetChildMemberWithName('sentinel').GetChildMemberWithName('child') |
| ... | @@ -468,8 +557,8 @@ type_tag_handlers = { | ... | @@ -468,8 +557,8 @@ type_tag_handlers = { |
| 468 | 'empty_struct_literal': lambda payload: '@TypeOf(.{})', | 557 | 'empty_struct_literal': lambda payload: '@TypeOf(.{})', |
| 469 | 558 | ||
| 470 | 'anyerror_void_error_union': lambda payload: 'anyerror!void', | 559 | 'anyerror_void_error_union': lambda payload: 'anyerror!void', |
| 471 | 'const_slice_u8': lambda payload: '[]const u8', | 560 | 'slice_const_u8': lambda payload: '[]const u8', |
| 472 | 'const_slice_u8_sentinel_0': lambda payload: '[:0]const u8', | 561 | 'slice_const_u8_sentinel_0': lambda payload: '[:0]const u8', |
| 473 | 'fn_noreturn_no_args': lambda payload: 'fn() noreturn', | 562 | 'fn_noreturn_no_args': lambda payload: 'fn() noreturn', |
| 474 | 'fn_void_no_args': lambda payload: 'fn() void', | 563 | 'fn_void_no_args': lambda payload: 'fn() void', |
| 475 | 'fn_naked_noreturn_no_args': lambda payload: 'fn() callconv(.Naked) noreturn', | 564 | 'fn_naked_noreturn_no_args': lambda payload: 'fn() callconv(.Naked) noreturn', |
| ... | @@ -495,7 +584,7 @@ type_tag_handlers = { | ... | @@ -495,7 +584,7 @@ type_tag_handlers = { |
| 495 | 'many_mut_pointer': lambda payload: '[*]%s' % type_Type_SummaryProvider(payload), | 584 | 'many_mut_pointer': lambda payload: '[*]%s' % type_Type_SummaryProvider(payload), |
| 496 | 'c_const_pointer': lambda payload: '[*c]const %s' % type_Type_SummaryProvider(payload), | 585 | 'c_const_pointer': lambda payload: '[*c]const %s' % type_Type_SummaryProvider(payload), |
| 497 | 'c_mut_pointer': lambda payload: '[*c]%s' % type_Type_SummaryProvider(payload), | 586 | 'c_mut_pointer': lambda payload: '[*c]%s' % type_Type_SummaryProvider(payload), |
| 498 | 'const_slice': lambda payload: '[]const %s' % type_Type_SummaryProvider(payload), | 587 | 'slice_const': lambda payload: '[]const %s' % type_Type_SummaryProvider(payload), |
| 499 | 'mut_slice': lambda payload: '[]%s' % type_Type_SummaryProvider(payload), | 588 | 'mut_slice': lambda payload: '[]%s' % type_Type_SummaryProvider(payload), |
| 500 | 'int_signed': lambda payload: 'i%d' % payload.unsigned, | 589 | 'int_signed': lambda payload: 'i%d' % payload.unsigned, |
| 501 | 'int_unsigned': lambda payload: 'u%d' % payload.unsigned, | 590 | 'int_unsigned': lambda payload: 'u%d' % payload.unsigned, |
| ... | @@ -611,13 +700,19 @@ def __lldb_init_module(debugger, _=None): | ... | @@ -611,13 +700,19 @@ def __lldb_init_module(debugger, _=None): |
| 611 | add(debugger, category='zig.stage2', type='Zir.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True) | 700 | add(debugger, category='zig.stage2', type='Zir.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True) |
| 612 | add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Zir\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True) | 701 | add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Zir\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True) |
| 613 | add(debugger, category='zig.stage2', regex=True, type='^Zir\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True) | 702 | add(debugger, category='zig.stage2', regex=True, type='^Zir\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True) |
| 614 | add(debugger, category='zig.stage2', type='Zir.Inst::Zir.Inst.Ref', identifier='Inst_Ref', summary=True) | 703 | add(debugger, category='zig.stage2', type='Zir.Inst::Zir.Inst.Ref', summary=True) |
| 615 | add(debugger, category='zig.stage2', type='Air.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True) | 704 | add(debugger, category='zig.stage2', type='Air.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True) |
| 705 | add(debugger, category='zig.stage2', type='Air.Inst::Air.Inst.Ref', summary=True) | ||
| 616 | add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True) | 706 | add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True) |
| 617 | add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True) | 707 | add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True) |
| 618 | add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True) | 708 | add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True) |
| 619 | add(debugger, category='zig.stage2', type='type.Type', identifier='TagOrPayloadPtr', synth=True) | 709 | add(debugger, category='zig.stage2', type='Module.LazySrcLoc', identifier='zig_TaggedUnion', synth=True) |
| 620 | add(debugger, category='zig.stage2', type='type.Type', summary=True) | 710 | add(debugger, category='zig.stage2', type='InternPool.Index', synth=True) |
| 621 | add(debugger, category='zig.stage2', type='value.Value', identifier='TagOrPayloadPtr', synth=True) | 711 | add(debugger, category='zig.stage2', type='InternPool.NullTerminatedString', summary=True) |
| 622 | add(debugger, category='zig.stage2', type='value.Value', summary=True) | 712 | add(debugger, category='zig.stage2', type='InternPool.Key', identifier='zig_TaggedUnion', synth=True) |
| 713 | add(debugger, category='zig.stage2', type='InternPool.Key.Int.Storage', identifier='zig_TaggedUnion', synth=True) | ||
| 714 | add(debugger, category='zig.stage2', type='InternPool.Key.ErrorUnion.Value', identifier='zig_TaggedUnion', synth=True) | ||
| 715 | add(debugger, category='zig.stage2', type='InternPool.Key.Float.Storage', identifier='zig_TaggedUnion', synth=True) | ||
| 716 | add(debugger, category='zig.stage2', type='InternPool.Key.Ptr.Addr', identifier='zig_TaggedUnion', synth=True) | ||
| 717 | add(debugger, category='zig.stage2', type='InternPool.Key.Aggregate.Storage', identifier='zig_TaggedUnion', synth=True) | ||
| 623 | add(debugger, category='zig.stage2', type='arch.x86_64.CodeGen.MCValue', identifier='zig_TaggedUnion', synth=True, inline_children=True, summary=True) | 718 | add(debugger, category='zig.stage2', type='arch.x86_64.CodeGen.MCValue', identifier='zig_TaggedUnion', synth=True, inline_children=True, summary=True) |
tools/stage2_gdb_pretty_printers.py+1-1| ... | @@ -18,7 +18,7 @@ class TypePrinter: | ... | @@ -18,7 +18,7 @@ class TypePrinter: |
| 18 | 'many_mut_pointer': 'Type.Payload.ElemType', | 18 | 'many_mut_pointer': 'Type.Payload.ElemType', |
| 19 | 'c_const_pointer': 'Type.Payload.ElemType', | 19 | 'c_const_pointer': 'Type.Payload.ElemType', |
| 20 | 'c_mut_pointer': 'Type.Payload.ElemType', | 20 | 'c_mut_pointer': 'Type.Payload.ElemType', |
| 21 | 'const_slice': 'Type.Payload.ElemType', | 21 | 'slice_const': 'Type.Payload.ElemType', |
| 22 | 'mut_slice': 'Type.Payload.ElemType', | 22 | 'mut_slice': 'Type.Payload.ElemType', |
| 23 | 'optional': 'Type.Payload.ElemType', | 23 | 'optional': 'Type.Payload.ElemType', |
| 24 | 'optional_single_mut_pointer': 'Type.Payload.ElemType', | 24 | 'optional_single_mut_pointer': 'Type.Payload.ElemType', |